Merge "Fix IME window can't show on keyguard with setShowWhenLocked."
diff --git a/Android.bp b/Android.bp
index 7e97e66..54b6619 100644
--- a/Android.bp
+++ b/Android.bp
@@ -305,6 +305,7 @@
         "core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl",
         "core/java/android/service/gatekeeper/IGateKeeperService.aidl",
         "core/java/android/service/contentcapture/IContentCaptureService.aidl",
+        "core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl",
         "core/java/android/service/notification/INotificationListener.aidl",
         "core/java/android/service/notification/IStatusBarNotificationHolder.aidl",
         "core/java/android/service/notification/IConditionListener.aidl",
@@ -476,6 +477,7 @@
         "media/java/android/media/IMediaRouterClient.aidl",
         "media/java/android/media/IMediaRouterService.aidl",
         "media/java/android/media/IMediaSession2.aidl",
+        "media/java/android/media/IMediaSession2Service.aidl",
         "media/java/android/media/IMediaScannerListener.aidl",
         "media/java/android/media/IMediaScannerService.aidl",
         "media/java/android/media/IPlaybackConfigDispatcher.aidl",
@@ -887,7 +889,12 @@
         "core/java/android/net/IIpMemoryStore.aidl",
         "core/java/android/net/INetworkStackConnector.aidl",
         "core/java/android/net/INetworkStackStatusCallback.aidl",
+        "core/java/android/net/IpPrefixParcelable.aidl",
+        "core/java/android/net/LinkAddressParcelable.aidl",
+        "core/java/android/net/LinkPropertiesParcelable.aidl",
         "core/java/android/net/PrivateDnsConfigParcel.aidl",
+        "core/java/android/net/ProxyInfoParcelable.aidl",
+        "core/java/android/net/RouteInfoParcelable.aidl",
         "core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
         "core/java/android/net/dhcp/IDhcpServer.aidl",
         "core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
@@ -1067,6 +1074,7 @@
         "core/java/android/annotation/IntDef.java",
         "core/java/android/annotation/NonNull.java",
         "core/java/android/annotation/SystemApi.java",
+        "core/java/android/annotation/TestApi.java",
         "core/java/android/os/HwBinder.java",
         "core/java/android/os/HwBlob.java",
         "core/java/android/os/HwParcel.java",
@@ -1316,7 +1324,6 @@
         "ext",
         "framework",
         "voip-common",
-        "android.test.mock.impl",
     ],
     local_sourcepaths: frameworks_base_subdirs,
     installable: false,
diff --git a/api/current.txt b/api/current.txt
index 88da7e9..ae84d93 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5245,8 +5245,8 @@
     method public android.app.Notification clone();
     method public int describeContents();
     method public boolean getAllowSystemGeneratedContextualActions();
-    method public android.app.PendingIntent getAppOverlayIntent();
     method public int getBadgeIconType();
+    method public android.app.Notification.BubbleMetadata getBubbleMetadata();
     method public java.lang.String getChannelId();
     method public java.lang.String getGroup();
     method public int getGroupAlertBehavior();
@@ -5459,6 +5459,25 @@
     method public android.app.Notification.BigTextStyle setSummaryText(java.lang.CharSequence);
   }
 
+  public static final class Notification.BubbleMetadata implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getDesiredHeight();
+    method public android.graphics.drawable.Icon getIcon();
+    method public android.app.PendingIntent getIntent();
+    method public java.lang.CharSequence getTitle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR;
+  }
+
+  public static class Notification.BubbleMetadata.Builder {
+    ctor public Notification.BubbleMetadata.Builder();
+    method public android.app.Notification.BubbleMetadata build();
+    method public android.app.Notification.BubbleMetadata.Builder setDesiredHeight(int);
+    method public android.app.Notification.BubbleMetadata.Builder setIcon(android.graphics.drawable.Icon);
+    method public android.app.Notification.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
+    method public android.app.Notification.BubbleMetadata.Builder setTitle(java.lang.CharSequence);
+  }
+
   public static class Notification.Builder {
     ctor public Notification.Builder(android.content.Context, java.lang.String);
     ctor public deprecated Notification.Builder(android.content.Context);
@@ -5478,9 +5497,9 @@
     method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
     method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
     method public android.app.Notification.Builder setAllowSystemGeneratedContextualActions(boolean);
-    method public android.app.Notification.Builder setAppOverlayIntent(android.app.PendingIntent);
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setBadgeIconType(int);
+    method public android.app.Notification.Builder setBubbleMetadata(android.app.Notification.BubbleMetadata);
     method public android.app.Notification.Builder setCategory(java.lang.String);
     method public android.app.Notification.Builder setChannelId(java.lang.String);
     method public android.app.Notification.Builder setChronometerCountDown(boolean);
@@ -5695,8 +5714,8 @@
 
   public final class NotificationChannel implements android.os.Parcelable {
     ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int);
+    method public boolean canBubble();
     method public boolean canBypassDnd();
-    method public boolean canOverlayApps();
     method public boolean canShowBadge();
     method public int describeContents();
     method public void enableLights(boolean);
@@ -5712,7 +5731,7 @@
     method public android.net.Uri getSound();
     method public long[] getVibrationPattern();
     method public boolean hasUserSetImportance();
-    method public void setAllowAppOverlay(boolean);
+    method public void setAllowBubbles(boolean);
     method public void setBypassDnd(boolean);
     method public void setDescription(java.lang.String);
     method public void setGroup(java.lang.String);
@@ -5746,7 +5765,7 @@
 
   public class NotificationManager {
     method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
-    method public boolean areAppOverlaysAllowed();
+    method public boolean areBubblesAllowed();
     method public boolean areNotificationsEnabled();
     method public boolean canNotifyAsPackage(java.lang.String);
     method public void cancel(int);
@@ -6765,9 +6784,11 @@
     method public void wipeData(int);
     method public void wipeData(int, java.lang.CharSequence);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
+    field public static final java.lang.String ACTION_ADMIN_POLICY_COMPLIANCE = "android.app.action.ADMIN_POLICY_COMPLIANCE";
     field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
     field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
     field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
+    field public static final java.lang.String ACTION_GET_PROVISIONING_MODE = "android.app.action.GET_PROVISIONING_MODE";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROFILE_OWNER_CHANGED = "android.app.action.PROFILE_OWNER_CHANGED";
     field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
@@ -6810,12 +6831,15 @@
     field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMER_CONTENT = "android.app.extra.PROVISIONING_DISCLAIMER_CONTENT";
     field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMER_HEADER = "android.app.extra.PROVISIONING_DISCLAIMER_HEADER";
     field public static final deprecated java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
+    field public static final java.lang.String EXTRA_PROVISIONING_IMEI = "android.app.extra.PROVISIONING_IMEI";
     field public static final java.lang.String EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION = "android.app.extra.PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION";
     field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
     field public static final java.lang.String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
     field public static final java.lang.String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
+    field public static final java.lang.String EXTRA_PROVISIONING_MODE = "android.app.extra.PROVISIONING_MODE";
+    field public static final java.lang.String EXTRA_PROVISIONING_SERIAL_NUMBER = "android.app.extra.PROVISIONING_SERIAL_NUMBER";
     field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
     field public static final java.lang.String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
@@ -6892,6 +6916,9 @@
     field public static final int PRIVATE_DNS_SET_ERROR_FAILURE_SETTING = 2; // 0x2
     field public static final int PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING = 1; // 0x1
     field public static final int PRIVATE_DNS_SET_SUCCESS = 0; // 0x0
+    field public static final int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1; // 0x1
+    field public static final int PROVISIONING_MODE_MANAGED_PROFILE = 2; // 0x2
+    field public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE = 3; // 0x3
     field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
     field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
     field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
@@ -7663,6 +7690,7 @@
     field public static final int ACTIVITY_RESUMED = 1; // 0x1
     field public static final int ACTIVITY_STOPPED = 23; // 0x17
     field public static final int CONFIGURATION_CHANGE = 5; // 0x5
+    field public static final int DEVICE_SHUTDOWN = 26; // 0x1a
     field public static final int FOREGROUND_SERVICE_START = 19; // 0x13
     field public static final int FOREGROUND_SERVICE_STOP = 20; // 0x14
     field public static final int KEYGUARD_HIDDEN = 18; // 0x12
@@ -10347,6 +10375,7 @@
     field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
     field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
     field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
+    field public static final java.lang.String EXTRA_SHORTCUT_ID = "android.intent.extra.shortcut.ID";
     field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
     field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
@@ -11922,6 +11951,9 @@
     method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
     method public android.content.pm.ShortcutInfo.Builder setIntents(android.content.Intent[]);
     method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
+    method public android.content.pm.ShortcutInfo.Builder setLongLived();
+    method public android.content.pm.ShortcutInfo.Builder setPerson(android.app.Person);
+    method public android.content.pm.ShortcutInfo.Builder setPersons(android.app.Person[]);
     method public android.content.pm.ShortcutInfo.Builder setRank(int);
     method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
   }
@@ -12262,6 +12294,7 @@
     method public void parseBundleExtra(java.lang.String, android.util.AttributeSet, android.os.Bundle) throws org.xmlpull.v1.XmlPullParserException;
     method public void parseBundleExtras(android.content.res.XmlResourceParser, android.os.Bundle) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public deprecated void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
+    field public static final int ID_NULL = 0; // 0x0
   }
 
   public static class Resources.NotFoundException extends java.lang.RuntimeException {
@@ -12305,6 +12338,7 @@
     method public java.lang.String getPositionDescription();
     method public int getResourceId(int, int);
     method public android.content.res.Resources getResources();
+    method public int getSourceStyleResourceId(int, int);
     method public java.lang.String getString(int);
     method public java.lang.CharSequence getText(int);
     method public java.lang.CharSequence[] getTextArray(int);
@@ -13737,6 +13771,7 @@
     method public void drawTextOnPath(java.lang.String, android.graphics.Path, float, float, android.graphics.Paint);
     method public void drawTextRun(char[], int, int, int, int, float, float, boolean, android.graphics.Paint);
     method public void drawTextRun(java.lang.CharSequence, int, int, int, int, float, float, boolean, android.graphics.Paint);
+    method public void drawTextRun(android.graphics.text.MeasuredText, int, int, int, int, float, float, boolean, android.graphics.Paint);
     method public void drawVertices(android.graphics.Canvas.VertexMode, int, float[], int, float[], int, int[], int, short[], int, int, android.graphics.Paint);
     method public void enableZ();
     method public boolean getClipBounds(android.graphics.Rect);
@@ -16437,9 +16472,9 @@
 
   public class BiometricManager {
     method public int canAuthenticate();
-    field public static final int BIOMETRIC_ERROR_NO_BIOMETRICS = 11; // 0xb
+    field public static final int BIOMETRIC_ERROR_HW_UNAVAILABLE = 1; // 0x1
+    field public static final int BIOMETRIC_ERROR_NONE_ENROLLED = 11; // 0xb
     field public static final int BIOMETRIC_ERROR_NO_HARDWARE = 12; // 0xc
-    field public static final int BIOMETRIC_ERROR_UNAVAILABLE = 1; // 0x1
     field public static final int BIOMETRIC_SUCCESS = 0; // 0x0
   }
 
@@ -16482,6 +16517,7 @@
     method public android.hardware.biometrics.BiometricPrompt build();
     method public android.hardware.biometrics.BiometricPrompt.Builder setDescription(java.lang.CharSequence);
     method public android.hardware.biometrics.BiometricPrompt.Builder setNegativeButton(java.lang.CharSequence, java.util.concurrent.Executor, android.content.DialogInterface.OnClickListener);
+    method public android.hardware.biometrics.BiometricPrompt.Builder setRequireConfirmation(boolean);
     method public android.hardware.biometrics.BiometricPrompt.Builder setSubtitle(java.lang.CharSequence);
     method public android.hardware.biometrics.BiometricPrompt.Builder setTitle(java.lang.CharSequence);
   }
@@ -22663,6 +22699,7 @@
     method public deprecated double getCarrierPhase();
     method public deprecated double getCarrierPhaseUncertainty();
     method public double getCn0DbHz();
+    method public int getCodeType();
     method public int getConstellationType();
     method public int getMultipathIndicator();
     method public double getPseudorangeRateMetersPerSecond();
@@ -22678,6 +22715,7 @@
     method public boolean hasCarrierFrequencyHz();
     method public deprecated boolean hasCarrierPhase();
     method public deprecated boolean hasCarrierPhaseUncertainty();
+    method public boolean hasCodeType();
     method public boolean hasSnrInDb();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
@@ -22686,6 +22724,21 @@
     field public static final int ADR_STATE_RESET = 2; // 0x2
     field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
     field public static final int ADR_STATE_VALID = 1; // 0x1
+    field public static final int CODE_TYPE_A = 0; // 0x0
+    field public static final int CODE_TYPE_B = 1; // 0x1
+    field public static final int CODE_TYPE_C = 2; // 0x2
+    field public static final int CODE_TYPE_CODELESS = 13; // 0xd
+    field public static final int CODE_TYPE_I = 3; // 0x3
+    field public static final int CODE_TYPE_L = 4; // 0x4
+    field public static final int CODE_TYPE_M = 5; // 0x5
+    field public static final int CODE_TYPE_P = 6; // 0x6
+    field public static final int CODE_TYPE_Q = 7; // 0x7
+    field public static final int CODE_TYPE_S = 8; // 0x8
+    field public static final int CODE_TYPE_UNKNOWN = -1; // 0xffffffff
+    field public static final int CODE_TYPE_W = 9; // 0x9
+    field public static final int CODE_TYPE_X = 10; // 0xa
+    field public static final int CODE_TYPE_Y = 11; // 0xb
+    field public static final int CODE_TYPE_Z = 12; // 0xc
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
     field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
     field public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2; // 0x2
@@ -24098,6 +24151,7 @@
     method public int dequeueOutputBuffer(android.media.MediaCodec.BufferInfo, long);
     method protected void finalize();
     method public void flush();
+    method public java.lang.String getCanonicalName();
     method public android.media.MediaCodecInfo getCodecInfo();
     method public java.nio.ByteBuffer getInputBuffer(int);
     method public deprecated java.nio.ByteBuffer[] getInputBuffers();
@@ -24224,10 +24278,15 @@
   }
 
   public final class MediaCodecInfo {
+    method public java.lang.String getCanonicalName();
     method public android.media.MediaCodecInfo.CodecCapabilities getCapabilitiesForType(java.lang.String);
     method public java.lang.String getName();
     method public java.lang.String[] getSupportedTypes();
+    method public boolean isAlias();
     method public boolean isEncoder();
+    method public boolean isHardwareAccelerated();
+    method public boolean isSoftwareOnly();
+    method public boolean isVendor();
   }
 
   public static final class MediaCodecInfo.AudioCapabilities {
@@ -24303,7 +24362,10 @@
     field public static final deprecated int COLOR_QCOM_FormatYUV420SemiPlanar = 2141391872; // 0x7fa30c00
     field public static final deprecated int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
     field public static final java.lang.String FEATURE_AdaptivePlayback = "adaptive-playback";
+    field public static final java.lang.String FEATURE_DynamicTimestamp = "dynamic-timestamp";
+    field public static final java.lang.String FEATURE_FrameParsing = "frame-parsing";
     field public static final java.lang.String FEATURE_IntraRefresh = "intra-refresh";
+    field public static final java.lang.String FEATURE_MultipleFrames = "multiple-frames";
     field public static final java.lang.String FEATURE_PartialFrame = "partial-frame";
     field public static final java.lang.String FEATURE_SecurePlayback = "secure-playback";
     field public static final java.lang.String FEATURE_TunneledPlayback = "tunneled-playback";
@@ -24325,6 +24387,33 @@
     field public static final int AACObjectSSR = 3; // 0x3
     field public static final int AACObjectScalable = 6; // 0x6
     field public static final int AACObjectXHE = 42; // 0x2a
+    field public static final int AV1Level2 = 1; // 0x1
+    field public static final int AV1Level21 = 2; // 0x2
+    field public static final int AV1Level22 = 4; // 0x4
+    field public static final int AV1Level23 = 8; // 0x8
+    field public static final int AV1Level3 = 16; // 0x10
+    field public static final int AV1Level31 = 32; // 0x20
+    field public static final int AV1Level32 = 64; // 0x40
+    field public static final int AV1Level33 = 128; // 0x80
+    field public static final int AV1Level4 = 256; // 0x100
+    field public static final int AV1Level41 = 512; // 0x200
+    field public static final int AV1Level42 = 1024; // 0x400
+    field public static final int AV1Level43 = 2048; // 0x800
+    field public static final int AV1Level5 = 4096; // 0x1000
+    field public static final int AV1Level51 = 8192; // 0x2000
+    field public static final int AV1Level52 = 16384; // 0x4000
+    field public static final int AV1Level53 = 32768; // 0x8000
+    field public static final int AV1Level6 = 65536; // 0x10000
+    field public static final int AV1Level61 = 131072; // 0x20000
+    field public static final int AV1Level62 = 262144; // 0x40000
+    field public static final int AV1Level63 = 524288; // 0x80000
+    field public static final int AV1Level7 = 1048576; // 0x100000
+    field public static final int AV1Level71 = 2097152; // 0x200000
+    field public static final int AV1Level72 = 4194304; // 0x400000
+    field public static final int AV1Level73 = 8388608; // 0x800000
+    field public static final int AV1Profile0 = 1; // 0x1
+    field public static final int AV1Profile1 = 2; // 0x2
+    field public static final int AV1Profile2 = 4; // 0x4
     field public static final int AVCLevel1 = 1; // 0x1
     field public static final int AVCLevel11 = 4; // 0x4
     field public static final int AVCLevel12 = 8; // 0x8
@@ -24342,6 +24431,9 @@
     field public static final int AVCLevel5 = 16384; // 0x4000
     field public static final int AVCLevel51 = 32768; // 0x8000
     field public static final int AVCLevel52 = 65536; // 0x10000
+    field public static final int AVCLevel6 = 131072; // 0x20000
+    field public static final int AVCLevel61 = 262144; // 0x40000
+    field public static final int AVCLevel62 = 524288; // 0x80000
     field public static final int AVCProfileBaseline = 1; // 0x1
     field public static final int AVCProfileConstrainedBaseline = 65536; // 0x10000
     field public static final int AVCProfileConstrainedHigh = 524288; // 0x80000
@@ -24504,12 +24596,53 @@
     method public android.util.Range<java.lang.Double> getSupportedFrameRatesFor(int, int);
     method public android.util.Range<java.lang.Integer> getSupportedHeights();
     method public android.util.Range<java.lang.Integer> getSupportedHeightsFor(int);
+    method public java.util.List<android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint> getSupportedPerformancePoints();
     method public android.util.Range<java.lang.Integer> getSupportedWidths();
     method public android.util.Range<java.lang.Integer> getSupportedWidthsFor(int);
     method public int getWidthAlignment();
     method public boolean isSizeSupported(int, int);
   }
 
+  public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint {
+    method public boolean covers(android.media.MediaFormat);
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_100;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_120;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_200;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_24;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_240;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_25;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_30;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_50;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_60;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_100;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_120;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_200;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_24;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_240;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_25;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_30;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_50;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_60;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_24;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_25;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_30;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_48;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_50;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_60;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_100;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_120;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_200;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_24;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_240;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_25;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_30;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_50;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_60;
+    field public final int frameRate;
+    field public final int height;
+    field public final int width;
+  }
+
   public final class MediaCodecList {
     ctor public MediaCodecList(int);
     method public java.lang.String findDecoderForFormat(android.media.MediaFormat);
@@ -24521,6 +24654,22 @@
     field public static final int REGULAR_CODECS = 0; // 0x0
   }
 
+  public class MediaController2 implements java.lang.AutoCloseable {
+    ctor public MediaController2(android.content.Context, android.media.Session2Token);
+    ctor public MediaController2(android.content.Context, android.media.Session2Token, java.util.concurrent.Executor, android.media.MediaController2.ControllerCallback);
+    method public void cancelSessionCommand(java.lang.Object);
+    method public void close();
+    method public java.lang.Object sendSessionCommand(android.media.Session2Command, android.os.Bundle);
+  }
+
+  public static abstract class MediaController2.ControllerCallback {
+    ctor public MediaController2.ControllerCallback();
+    method public void onCommandResult(android.media.MediaController2, java.lang.Object, android.media.Session2Command, android.media.Session2Command.Result);
+    method public void onConnected(android.media.MediaController2, android.media.Session2CommandGroup);
+    method public void onDisconnected(android.media.MediaController2);
+    method public android.media.Session2Command.Result onSessionCommand(android.media.MediaController2, android.media.Session2Command, android.os.Bundle);
+  }
+
   public final class MediaCrypto {
     ctor public MediaCrypto(java.util.UUID, byte[]) throws android.media.MediaCryptoException;
     method protected void finalize();
@@ -24946,6 +25095,7 @@
     field public static final java.lang.String MIMETYPE_TEXT_CEA_708 = "text/cea-708";
     field public static final java.lang.String MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
     field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
+    field public static final java.lang.String MIMETYPE_VIDEO_AV1 = "video/av01";
     field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
     field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
     field public static final java.lang.String MIMETYPE_VIDEO_H263 = "video/3gpp";
@@ -25423,6 +25573,7 @@
     method public java.lang.Object setAuxEffectSendLevel(float);
     method public java.lang.Object setDataSource(android.media.DataSourceDesc);
     method public java.lang.Object setDisplay(android.view.SurfaceHolder);
+    method public void setDrmEventCallback(java.util.concurrent.Executor, android.media.MediaPlayer2.DrmEventCallback);
     method public java.lang.Object setNextDataSource(android.media.DataSourceDesc);
     method public java.lang.Object setNextDataSources(java.util.List<android.media.DataSourceDesc>);
     method public java.lang.Object setPlaybackParams(android.media.PlaybackParams);
@@ -25501,6 +25652,33 @@
     field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0
   }
 
+  public static class MediaPlayer2.DrmEventCallback {
+    ctor public MediaPlayer2.DrmEventCallback();
+    method public void onDrmConfig(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaDrm);
+    method public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaPlayer2.DrmInfo);
+    method public byte[] onDrmKeyRequest(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaDrm.KeyRequest);
+    method public void onDrmPrepared(android.media.MediaPlayer2, android.media.DataSourceDesc, int, byte[]);
+  }
+
+  public static final class MediaPlayer2.DrmInfo {
+    method public java.util.Map<java.util.UUID, byte[]> getPssh();
+    method public java.util.List<java.util.UUID> getSupportedSchemes();
+  }
+
+  public static final class MediaPlayer2.DrmPreparationInfo {
+  }
+
+  public static final class MediaPlayer2.DrmPreparationInfo.Builder {
+    ctor public MediaPlayer2.DrmPreparationInfo.Builder();
+    method public android.media.MediaPlayer2.DrmPreparationInfo build();
+    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(byte[]);
+    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(byte[]);
+    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int);
+    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(java.lang.String);
+    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(java.util.Map<java.lang.String, java.lang.String>);
+    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(java.util.UUID);
+  }
+
   public static class MediaPlayer2.EventCallback {
     ctor public MediaPlayer2.EventCallback();
     method public void onCallCompleted(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
@@ -25528,6 +25706,10 @@
     field public static final java.lang.String WIDTH = "android.media.mediaplayer.width";
   }
 
+  public static final class MediaPlayer2.NoDrmSchemeException extends android.media.MediaDrmException {
+    ctor public MediaPlayer2.NoDrmSchemeException(java.lang.String);
+  }
+
   public static class MediaPlayer2.TrackInfo {
     method public android.media.MediaFormat getFormat();
     method public java.lang.String getLanguage();
@@ -25619,6 +25801,7 @@
     field public static final int VOICE_CALL = 4; // 0x4
     field public static final int VOICE_COMMUNICATION = 7; // 0x7
     field public static final int VOICE_DOWNLINK = 3; // 0x3
+    field public static final int VOICE_PERFORMANCE = 10; // 0xa
     field public static final int VOICE_RECOGNITION = 6; // 0x6
     field public static final int VOICE_UPLINK = 2; // 0x2
   }
@@ -25820,6 +26003,37 @@
     method public abstract void onScanCompleted(java.lang.String, android.net.Uri);
   }
 
+  public class MediaSession2 implements java.lang.AutoCloseable {
+    method public void broadcastSessionCommand(android.media.Session2Command, android.os.Bundle);
+    method public void cancelSessionCommand(android.media.MediaSession2.ControllerInfo, java.lang.Object);
+    method public void close();
+    method public java.lang.String getSessionId();
+    method public android.media.Session2Token getSessionToken();
+    method public java.lang.Object sendSessionCommand(android.media.MediaSession2.ControllerInfo, android.media.Session2Command, android.os.Bundle);
+  }
+
+  public static final class MediaSession2.Builder {
+    ctor public MediaSession2.Builder(android.content.Context);
+    method public android.media.MediaSession2 build();
+    method public android.media.MediaSession2.Builder setId(java.lang.String);
+    method public android.media.MediaSession2.Builder setSessionActivity(android.app.PendingIntent);
+    method public android.media.MediaSession2.Builder setSessionCallback(java.util.concurrent.Executor, android.media.MediaSession2.SessionCallback);
+  }
+
+  public static final class MediaSession2.ControllerInfo {
+    method public java.lang.String getPackageName();
+    method public android.media.session.MediaSessionManager.RemoteUserInfo getRemoteUserInfo();
+    method public int getUid();
+  }
+
+  public static abstract class MediaSession2.SessionCallback {
+    ctor public MediaSession2.SessionCallback();
+    method public void onCommandResult(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, java.lang.Object, android.media.Session2Command, android.media.Session2Command.Result);
+    method public android.media.Session2CommandGroup onConnect(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo);
+    method public void onDisconnected(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo);
+    method public android.media.Session2Command.Result onSessionCommand(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, android.media.Session2Command, android.os.Bundle);
+  }
+
   public final class MediaSync {
     ctor public MediaSync();
     method public android.view.Surface createInputSurface();
@@ -26133,6 +26347,19 @@
     method public android.media.Session2CommandGroup.Builder removeCommand(int);
   }
 
+  public final class Session2Token implements android.os.Parcelable {
+    ctor public Session2Token(android.content.Context, android.content.ComponentName);
+    method public int describeContents();
+    method public java.lang.String getPackageName();
+    method public java.lang.String getServiceName();
+    method public int getType();
+    method public int getUid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.Session2Token> CREATOR;
+    field public static final int TYPE_SESSION = 0; // 0x0
+    field public static final int TYPE_SESSION_SERVICE = 1; // 0x1
+  }
+
   public class SoundPool {
     ctor public deprecated SoundPool(int, int, int);
     method public final void autoPause();
@@ -29664,8 +29891,10 @@
     method public java.lang.String getMacAddress();
     method public int getNetworkId();
     method public int getRssi();
+    method public int getRxLinkSpeedMbps();
     method public java.lang.String getSSID();
     method public android.net.wifi.SupplicantState getSupplicantState();
+    method public int getTxLinkSpeedMbps();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final java.lang.String FREQUENCY_UNITS = "MHz";
     field public static final java.lang.String LINK_SPEED_UNITS = "Mbps";
@@ -29688,7 +29917,7 @@
     method public android.net.wifi.WifiInfo getConnectionInfo();
     method public android.net.DhcpInfo getDhcpInfo();
     method public int getMaxNumberOfNetworkSuggestionsPerApp();
-    method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
+    method public deprecated java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
     method public int getWifiState();
     method public boolean is5GHzBandSupported();
@@ -29708,7 +29937,7 @@
     method public deprecated boolean reconnect();
     method public deprecated boolean removeNetwork(int);
     method public int removeNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>);
-    method public void removePasspointConfiguration(java.lang.String);
+    method public deprecated void removePasspointConfiguration(java.lang.String);
     method public deprecated boolean saveConfiguration();
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
@@ -41604,6 +41833,7 @@
     field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10
     field public static final int SHOW_SOURCE_APPLICATION = 8; // 0x8
     field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4
+    field public static final int SHOW_SOURCE_AUTOMOTIVE_SYSTEM_UI = 128; // 0x80
     field public static final int SHOW_SOURCE_NOTIFICATION = 64; // 0x40
     field public static final int SHOW_SOURCE_PUSH_TO_TALK = 32; // 0x20
     field public static final int SHOW_WITH_ASSIST = 1; // 0x1
@@ -45018,6 +45248,7 @@
   }
 
   public class EuiccManager {
+    method public android.telephony.euicc.EuiccManager createForCardId(int);
     method public void deleteSubscription(int, android.app.PendingIntent);
     method public void downloadSubscription(android.telephony.euicc.DownloadableSubscription, boolean, android.app.PendingIntent);
     method public java.lang.String getEid();
@@ -47020,7 +47251,7 @@
   public class Linkify {
     ctor public Linkify();
     method public static final boolean addLinks(android.text.Spannable, int);
-    method public static final boolean addLinks(android.text.Spannable, int, android.text.util.Linkify.UrlSpanFactory);
+    method public static final boolean addLinks(android.text.Spannable, int, java.util.function.Function<java.lang.String, android.text.style.URLSpan>);
     method public static final boolean addLinks(android.widget.TextView, int);
     method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String);
     method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
@@ -47028,7 +47259,7 @@
     method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String);
     method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
     method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
-    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter, android.text.util.Linkify.UrlSpanFactory);
+    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter, java.util.function.Function<java.lang.String, android.text.style.URLSpan>);
     field public static final int ALL = 15; // 0xf
     field public static final int EMAIL_ADDRESSES = 2; // 0x2
     field public static final deprecated int MAP_ADDRESSES = 8; // 0x8
@@ -47047,11 +47278,6 @@
     method public abstract java.lang.String transformUrl(java.util.regex.Matcher, java.lang.String);
   }
 
-  public static class Linkify.UrlSpanFactory {
-    ctor public Linkify.UrlSpanFactory();
-    method public android.text.style.URLSpan create(java.lang.String);
-  }
-
   public class Rfc822Token {
     ctor public Rfc822Token(java.lang.String, java.lang.String, java.lang.String);
     method public java.lang.String getAddress();
@@ -48124,6 +48350,7 @@
     field public int data;
     field public int density;
     field public int resourceId;
+    field public int sourceStyleResourceId;
     field public java.lang.CharSequence string;
     field public int type;
   }
@@ -52448,6 +52675,7 @@
     method public final void notifyViewAppeared(android.view.ViewStructure);
     method public final void notifyViewDisappeared(android.view.autofill.AutofillId);
     method public final void notifyViewTextChanged(android.view.autofill.AutofillId, java.lang.CharSequence, int);
+    method public final void notifyViewsDisappeared(android.view.autofill.AutofillId, int[]);
     field public static final int FLAG_USER_INPUT = 1; // 0x1
   }
 
@@ -52885,19 +53113,8 @@
     ctor public InspectionCompanion.UninitializedPropertyMapException();
   }
 
-  public final class IntEnumMapping {
-    method public java.lang.String nameOf(int);
-  }
-
-  public static final class IntEnumMapping.Builder {
-    ctor public IntEnumMapping.Builder();
-    method public android.view.inspector.IntEnumMapping.Builder addValue(java.lang.String, int);
-    method public android.view.inspector.IntEnumMapping build();
-    method public void clear();
-  }
-
   public final class IntFlagMapping {
-    method public java.lang.String[] namesOf(int);
+    method public java.util.Set<java.lang.String> get(int);
   }
 
   public static final class IntFlagMapping.Builder {
@@ -52905,7 +53122,6 @@
     method public android.view.inspector.IntFlagMapping.Builder addFlag(java.lang.String, int);
     method public android.view.inspector.IntFlagMapping.Builder addFlag(java.lang.String, int, int);
     method public android.view.inspector.IntFlagMapping build();
-    method public void clear();
   }
 
   public abstract interface PropertyMapper {
@@ -52917,7 +53133,7 @@
     method public abstract int mapFloat(java.lang.String, int);
     method public abstract int mapGravity(java.lang.String, int);
     method public abstract int mapInt(java.lang.String, int);
-    method public abstract int mapIntEnum(java.lang.String, int, android.view.inspector.IntEnumMapping);
+    method public abstract int mapIntEnum(java.lang.String, int, android.util.SparseArray<java.lang.String>);
     method public abstract int mapIntFlag(java.lang.String, int, android.view.inspector.IntFlagMapping);
     method public abstract int mapLong(java.lang.String, int);
     method public abstract int mapObject(java.lang.String, int);
@@ -52955,15 +53171,15 @@
 
 package android.view.textclassifier {
 
-  public final class ConversationActions implements android.os.Parcelable {
-    ctor public ConversationActions(java.util.List<android.view.textclassifier.ConversationActions.ConversationAction>, java.lang.String);
+  public final class ConversationAction implements android.os.Parcelable {
     method public int describeContents();
-    method public java.util.List<android.view.textclassifier.ConversationActions.ConversationAction> getConversationActions();
-    method public java.lang.String getId();
+    method public android.app.RemoteAction getAction();
+    method public float getConfidenceScore();
+    method public android.os.Bundle getExtras();
+    method public java.lang.CharSequence getTextReply();
+    method public java.lang.String getType();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions> CREATOR;
-    field public static final java.lang.String HINT_FOR_IN_APP = "in_app";
-    field public static final java.lang.String HINT_FOR_NOTIFICATION = "notification";
+    field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationAction> CREATOR;
     field public static final java.lang.String TYPE_CALL_PHONE = "call_phone";
     field public static final java.lang.String TYPE_CREATE_REMINDER = "create_reminder";
     field public static final java.lang.String TYPE_OPEN_URL = "open_url";
@@ -52976,24 +53192,22 @@
     field public static final java.lang.String TYPE_VIEW_MAP = "view_map";
   }
 
-  public static final class ConversationActions.ConversationAction implements android.os.Parcelable {
-    method public int describeContents();
-    method public android.app.RemoteAction getAction();
-    method public float getConfidenceScore();
-    method public android.os.Bundle getExtras();
-    method public java.lang.CharSequence getTextReply();
-    method public java.lang.String getType();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions.ConversationAction> CREATOR;
+  public static final class ConversationAction.Builder {
+    ctor public ConversationAction.Builder(java.lang.String);
+    method public android.view.textclassifier.ConversationAction build();
+    method public android.view.textclassifier.ConversationAction.Builder setAction(android.app.RemoteAction);
+    method public android.view.textclassifier.ConversationAction.Builder setConfidenceScore(float);
+    method public android.view.textclassifier.ConversationAction.Builder setExtras(android.os.Bundle);
+    method public android.view.textclassifier.ConversationAction.Builder setTextReply(java.lang.CharSequence);
   }
 
-  public static final class ConversationActions.ConversationAction.Builder {
-    ctor public ConversationActions.ConversationAction.Builder(java.lang.String);
-    method public android.view.textclassifier.ConversationActions.ConversationAction build();
-    method public android.view.textclassifier.ConversationActions.ConversationAction.Builder setAction(android.app.RemoteAction);
-    method public android.view.textclassifier.ConversationActions.ConversationAction.Builder setConfidenceScore(float);
-    method public android.view.textclassifier.ConversationActions.ConversationAction.Builder setExtras(android.os.Bundle);
-    method public android.view.textclassifier.ConversationActions.ConversationAction.Builder setTextReply(java.lang.CharSequence);
+  public final class ConversationActions implements android.os.Parcelable {
+    ctor public ConversationActions(java.util.List<android.view.textclassifier.ConversationAction>, java.lang.String);
+    method public int describeContents();
+    method public java.util.List<android.view.textclassifier.ConversationAction> getConversationActions();
+    method public java.lang.String getId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions> CREATOR;
   }
 
   public static final class ConversationActions.Message implements android.os.Parcelable {
@@ -53023,9 +53237,11 @@
     method public java.lang.String getConversationId();
     method public java.util.List<java.lang.String> getHints();
     method public int getMaxSuggestions();
-    method public android.view.textclassifier.ConversationActions.TypeConfig getTypeConfig();
+    method public android.view.textclassifier.TextClassifier.EntityConfig getTypeConfig();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions.Request> CREATOR;
+    field public static final java.lang.String HINT_FOR_IN_APP = "in_app";
+    field public static final java.lang.String HINT_FOR_NOTIFICATION = "notification";
   }
 
   public static final class ConversationActions.Request.Builder {
@@ -53034,23 +53250,7 @@
     method public android.view.textclassifier.ConversationActions.Request.Builder setConversationId(java.lang.String);
     method public android.view.textclassifier.ConversationActions.Request.Builder setHints(java.util.List<java.lang.String>);
     method public android.view.textclassifier.ConversationActions.Request.Builder setMaxSuggestions(int);
-    method public android.view.textclassifier.ConversationActions.Request.Builder setTypeConfig(android.view.textclassifier.ConversationActions.TypeConfig);
-  }
-
-  public static final class ConversationActions.TypeConfig implements android.os.Parcelable {
-    method public int describeContents();
-    method public java.util.Collection<java.lang.String> resolveTypes(java.util.Collection<java.lang.String>);
-    method public boolean shouldIncludeTypesFromTextClassifier();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions.TypeConfig> CREATOR;
-  }
-
-  public static final class ConversationActions.TypeConfig.Builder {
-    ctor public ConversationActions.TypeConfig.Builder();
-    method public android.view.textclassifier.ConversationActions.TypeConfig build();
-    method public android.view.textclassifier.ConversationActions.TypeConfig.Builder includeTypesFromTextClassifier(boolean);
-    method public android.view.textclassifier.ConversationActions.TypeConfig.Builder setExcludedTypes(java.util.Collection<java.lang.String>);
-    method public android.view.textclassifier.ConversationActions.TypeConfig.Builder setIncludedTypes(java.util.Collection<java.lang.String>);
+    method public android.view.textclassifier.ConversationActions.Request.Builder setTypeConfig(android.view.textclassifier.TextClassifier.EntityConfig);
   }
 
   public final class SelectionEvent implements android.os.Parcelable {
@@ -53224,16 +53424,26 @@
   }
 
   public static final class TextClassifier.EntityConfig implements android.os.Parcelable {
-    method public static android.view.textclassifier.TextClassifier.EntityConfig create(java.util.Collection<java.lang.String>, java.util.Collection<java.lang.String>, java.util.Collection<java.lang.String>);
-    method public static android.view.textclassifier.TextClassifier.EntityConfig createWithExplicitEntityList(java.util.Collection<java.lang.String>);
-    method public static android.view.textclassifier.TextClassifier.EntityConfig createWithHints(java.util.Collection<java.lang.String>);
+    method public static deprecated android.view.textclassifier.TextClassifier.EntityConfig create(java.util.Collection<java.lang.String>, java.util.Collection<java.lang.String>, java.util.Collection<java.lang.String>);
+    method public static deprecated android.view.textclassifier.TextClassifier.EntityConfig createWithExplicitEntityList(java.util.Collection<java.lang.String>);
+    method public static deprecated android.view.textclassifier.TextClassifier.EntityConfig createWithHints(java.util.Collection<java.lang.String>);
     method public int describeContents();
     method public java.util.Collection<java.lang.String> getHints();
     method public java.util.Collection<java.lang.String> resolveEntityListModifications(java.util.Collection<java.lang.String>);
+    method public boolean shouldIncludeTypesFromTextClassifier();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifier.EntityConfig> CREATOR;
   }
 
+  public static final class TextClassifier.EntityConfig.Builder {
+    ctor public TextClassifier.EntityConfig.Builder();
+    method public android.view.textclassifier.TextClassifier.EntityConfig build();
+    method public android.view.textclassifier.TextClassifier.EntityConfig.Builder includeTypesFromTextClassifier(boolean);
+    method public android.view.textclassifier.TextClassifier.EntityConfig.Builder setExcludedTypes(java.util.Collection<java.lang.String>);
+    method public android.view.textclassifier.TextClassifier.EntityConfig.Builder setHints(java.util.Collection<java.lang.String>);
+    method public android.view.textclassifier.TextClassifier.EntityConfig.Builder setIncludedTypes(java.util.Collection<java.lang.String>);
+  }
+
   public final class TextClassifierEvent implements android.os.Parcelable {
     method public int describeContents();
     method public int[] getActionIndices();
@@ -54130,6 +54340,8 @@
     method public static java.lang.ClassLoader getWebViewClassLoader();
     method public android.webkit.WebViewClient getWebViewClient();
     method public android.os.Looper getWebViewLooper();
+    method public android.webkit.WebViewRenderer getWebViewRenderer();
+    method public android.webkit.WebViewRendererClient getWebViewRendererClient();
     method public void goBack();
     method public void goBackOrForward(int);
     method public void goForward();
@@ -54179,6 +54391,8 @@
     method public void setWebChromeClient(android.webkit.WebChromeClient);
     method public static void setWebContentsDebuggingEnabled(boolean);
     method public void setWebViewClient(android.webkit.WebViewClient);
+    method public void setWebViewRendererClient(java.util.concurrent.Executor, android.webkit.WebViewRendererClient);
+    method public void setWebViewRendererClient(android.webkit.WebViewRendererClient);
     method public deprecated boolean shouldDelayChildPressedState();
     method public deprecated boolean showFindDialog(java.lang.String, boolean);
     method public static void startSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
@@ -54294,6 +54508,16 @@
     method public android.webkit.WebView getWebView();
   }
 
+  public abstract class WebViewRenderer {
+    method public abstract boolean terminate();
+  }
+
+  public abstract class WebViewRendererClient {
+    ctor public WebViewRendererClient();
+    method public abstract void onRendererResponsive(android.webkit.WebView, android.webkit.WebViewRenderer);
+    method public abstract void onRendererUnresponsive(android.webkit.WebView, android.webkit.WebViewRenderer);
+  }
+
 }
 
 package android.widget {
diff --git a/api/system-current.txt b/api/system-current.txt
index e5b65b1..5b153f0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -94,7 +94,6 @@
     field public static final java.lang.String MANAGE_CONTENT_CAPTURE = "android.permission.MANAGE_CONTENT_CAPTURE";
     field public static final java.lang.String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS";
     field public static final java.lang.String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
-    field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
     field public static final java.lang.String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
     field public static final java.lang.String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
     field public static final java.lang.String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
@@ -129,6 +128,7 @@
     field public static final java.lang.String QUERY_TIME_ZONE_RULES = "android.permission.QUERY_TIME_ZONE_RULES";
     field public static final java.lang.String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
     field public static final java.lang.String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
+    field public static final java.lang.String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
     field public static final java.lang.String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
     field public static final java.lang.String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS";
     field public static final java.lang.String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY";
@@ -151,6 +151,7 @@
     field public static final java.lang.String REGISTER_CALL_PROVIDER = "android.permission.REGISTER_CALL_PROVIDER";
     field public static final java.lang.String REGISTER_CONNECTION_MANAGER = "android.permission.REGISTER_CONNECTION_MANAGER";
     field public static final java.lang.String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
+    field public static final java.lang.String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER";
     field public static final java.lang.String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
     field public static final java.lang.String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
     field public static final java.lang.String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
@@ -184,6 +185,7 @@
     field public static final java.lang.String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES";
     field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
     field public static final java.lang.String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
+    field public static final java.lang.String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
     field public static final java.lang.String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
     field public static final java.lang.String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS";
     field public static final java.lang.String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
@@ -195,6 +197,7 @@
   }
 
   public static final class R.array {
+    field public static final int config_defaultRoleHolders = 17235974; // 0x1070006
     field public static final int config_keySystemUuidMapping = 17235973; // 0x1070005
   }
 
@@ -1284,8 +1287,8 @@
     field public static final java.lang.String EXTRA_LONG_VERSION_CODE = "android.intent.extra.LONG_VERSION_CODE";
     field public static final java.lang.String EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID";
     field public static final java.lang.String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
-    field public static final java.lang.String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
     field public static final java.lang.String EXTRA_PERMISSION_GROUP_NAME = "android.intent.extra.PERMISSION_GROUP_NAME";
+    field public static final java.lang.String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
     field public static final java.lang.String EXTRA_REASON = "android.intent.extra.REASON";
     field public static final java.lang.String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
     field public static final java.lang.String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
@@ -1559,6 +1562,7 @@
 
   public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
     field public static final int FLAG_REMOVED = 2; // 0x2
+    field public static final int PROTECTION_FLAG_CONFIGURATOR = 524288; // 0x80000
     field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
     field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
     field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
@@ -1567,6 +1571,18 @@
     field public int requestRes;
   }
 
+  public class ShortcutManager {
+    method public java.util.List<android.content.pm.ShortcutManager.ShareShortcutInfo> getShareTargets(android.content.IntentFilter);
+  }
+
+  public static final class ShortcutManager.ShareShortcutInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.pm.ShortcutInfo getShortcutInfo();
+    method public android.content.ComponentName getTargetComponent();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutManager.ShareShortcutInfo> CREATOR;
+  }
+
   public final class SuspendDialogInfo implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -3301,6 +3317,7 @@
   }
 
   public final class MediaRecorder.AudioSource {
+    field public static final int ECHO_REFERENCE = 1997; // 0x7cd
     field public static final int HOTWORD = 1999; // 0x7cf
     field public static final int RADIO_TUNER = 1998; // 0x7ce
   }
@@ -3908,24 +3925,24 @@
 
 package android.net.wifi {
 
-  public abstract class DppStatusCallback {
-    ctor public DppStatusCallback();
+  public abstract class EasyConnectStatusCallback {
+    ctor public EasyConnectStatusCallback();
     method public abstract void onConfiguratorSuccess(int);
     method public abstract void onEnrolleeSuccess(int);
     method public abstract void onFailure(int);
     method public abstract void onProgress(int);
-    field public static final int DPP_EVENT_FAILURE = -7; // 0xfffffff9
-    field public static final int DPP_EVENT_FAILURE_AUTHENTICATION = -2; // 0xfffffffe
-    field public static final int DPP_EVENT_FAILURE_BUSY = -5; // 0xfffffffb
-    field public static final int DPP_EVENT_FAILURE_CONFIGURATION = -4; // 0xfffffffc
-    field public static final int DPP_EVENT_FAILURE_INVALID_NETWORK = -9; // 0xfffffff7
-    field public static final int DPP_EVENT_FAILURE_INVALID_URI = -1; // 0xffffffff
-    field public static final int DPP_EVENT_FAILURE_NOT_COMPATIBLE = -3; // 0xfffffffd
-    field public static final int DPP_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
-    field public static final int DPP_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
-    field public static final int DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0; // 0x0
-    field public static final int DPP_EVENT_PROGRESS_RESPONSE_PENDING = 1; // 0x1
-    field public static final int DPP_EVENT_SUCCESS_CONFIGURATION_SENT = 0; // 0x0
+    field public static final int EASY_CONNECT_EVENT_FAILURE = -7; // 0xfffffff9
+    field public static final int EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION = -2; // 0xfffffffe
+    field public static final int EASY_CONNECT_EVENT_FAILURE_BUSY = -5; // 0xfffffffb
+    field public static final int EASY_CONNECT_EVENT_FAILURE_CONFIGURATION = -4; // 0xfffffffc
+    field public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = -9; // 0xfffffff7
+    field public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_URI = -1; // 0xffffffff
+    field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE = -3; // 0xfffffffd
+    field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
+    field public static final int EASY_CONNECT_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
+    field public static final int EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0; // 0x0
+    field public static final int EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING = 1; // 0x1
+    field public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 0; // 0x0
   }
 
   public deprecated class RttManager {
@@ -4139,12 +4156,19 @@
     field public static final int WPA2_PSK = 4; // 0x4
   }
 
+  public class WifiInfo implements android.os.Parcelable {
+    method public boolean isOsuAp();
+  }
+
   public class WifiManager {
     method public void connect(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener);
     method public void connect(int, android.net.wifi.WifiManager.ActionListener);
     method public void disable(int, android.net.wifi.WifiManager.ActionListener);
     method public void disableEphemeralNetwork(java.lang.String);
     method public void forget(int, android.net.wifi.WifiManager.ActionListener);
+    method public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration, java.util.Map<java.lang.Integer, java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(java.util.List<android.net.wifi.ScanResult>);
+    method public java.util.Map<android.net.wifi.hotspot2.OsuProvider, java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(java.util.List<android.net.wifi.ScanResult>);
+    method public java.util.Map<android.net.wifi.hotspot2.OsuProvider, android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
     method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
     method public android.net.wifi.WifiConfiguration getWifiApConfiguration();
     method public int getWifiApState();
@@ -4156,10 +4180,11 @@
     method public void save(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener);
     method public void setDeviceMobilityState(int);
     method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
-    method public void startDppAsConfiguratorInitiator(java.lang.String, int, int, android.os.Handler, android.net.wifi.DppStatusCallback);
-    method public void startDppAsEnrolleeInitiator(java.lang.String, android.os.Handler, android.net.wifi.DppStatusCallback);
+    method public void startEasyConnectAsConfiguratorInitiator(java.lang.String, int, int, android.os.Handler, android.net.wifi.EasyConnectStatusCallback);
+    method public void startEasyConnectAsEnrolleeInitiator(java.lang.String, android.os.Handler, android.net.wifi.EasyConnectStatusCallback);
     method public boolean startScan(android.os.WorkSource);
-    method public void stopDppSession();
+    method public void startSubscriptionProvisioning(android.net.wifi.hotspot2.OsuProvider, android.net.wifi.hotspot2.ProvisioningCallback, android.os.Handler);
+    method public void stopEasyConnectSession();
     method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback);
     field public static final int CHANGE_REASON_ADDED = 0; // 0x0
     field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
@@ -4169,8 +4194,8 @@
     field public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2; // 0x2
     field public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3; // 0x3
     field public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0; // 0x0
-    field public static final int DPP_NETWORK_ROLE_AP = 1; // 0x1
-    field public static final int DPP_NETWORK_ROLE_STA = 0; // 0x0
+    field public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1; // 0x1
+    field public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0; // 0x0
     field public static final java.lang.String EXTRA_CHANGE_REASON = "changeReason";
     field public static final java.lang.String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
     field public static final java.lang.String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
@@ -4178,6 +4203,8 @@
     field public static final java.lang.String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
     field public static final java.lang.String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
     field public static final java.lang.String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
+    field public static final int PASSPOINT_HOME_NETWORK = 0; // 0x0
+    field public static final int PASSPOINT_ROAMING_NETWORK = 1; // 0x1
     field public static final java.lang.String WIFI_AP_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_AP_STATE_CHANGED";
     field public static final int WIFI_AP_STATE_DISABLED = 11; // 0xb
     field public static final int WIFI_AP_STATE_DISABLING = 10; // 0xa
@@ -4354,6 +4381,59 @@
 
 }
 
+package android.net.wifi.hotspot2 {
+
+  public final class OsuProvider implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.lang.String getFriendlyName();
+    method public android.net.Uri getServerUri();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.OsuProvider> CREATOR;
+  }
+
+  public abstract class ProvisioningCallback {
+    ctor public ProvisioningCallback();
+    method public abstract void onProvisioningComplete();
+    method public abstract void onProvisioningFailure(int);
+    method public abstract void onProvisioningStatus(int);
+    field public static final int OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION = 22; // 0x16
+    field public static final int OSU_FAILURE_AP_CONNECTION = 1; // 0x1
+    field public static final int OSU_FAILURE_INVALID_SERVER_URL = 8; // 0x8
+    field public static final int OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE = 17; // 0x11
+    field public static final int OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE = 21; // 0x15
+    field public static final int OSU_FAILURE_NO_OSU_ACTIVITY_FOUND = 14; // 0xe
+    field public static final int OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE = 19; // 0x13
+    field public static final int OSU_FAILURE_NO_PPS_MO = 16; // 0x10
+    field public static final int OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE = 18; // 0x12
+    field public static final int OSU_FAILURE_OSU_PROVIDER_NOT_FOUND = 23; // 0x17
+    field public static final int OSU_FAILURE_PROVISIONING_ABORTED = 6; // 0x6
+    field public static final int OSU_FAILURE_PROVISIONING_NOT_AVAILABLE = 7; // 0x7
+    field public static final int OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES = 20; // 0x14
+    field public static final int OSU_FAILURE_SERVER_CONNECTION = 3; // 0x3
+    field public static final int OSU_FAILURE_SERVER_URL_INVALID = 2; // 0x2
+    field public static final int OSU_FAILURE_SERVER_VALIDATION = 4; // 0x4
+    field public static final int OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION = 5; // 0x5
+    field public static final int OSU_FAILURE_SOAP_MESSAGE_EXCHANGE = 11; // 0xb
+    field public static final int OSU_FAILURE_START_REDIRECT_LISTENER = 12; // 0xc
+    field public static final int OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER = 13; // 0xd
+    field public static final int OSU_FAILURE_UNEXPECTED_COMMAND_TYPE = 9; // 0x9
+    field public static final int OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS = 15; // 0xf
+    field public static final int OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE = 10; // 0xa
+    field public static final int OSU_STATUS_AP_CONNECTED = 2; // 0x2
+    field public static final int OSU_STATUS_AP_CONNECTING = 1; // 0x1
+    field public static final int OSU_STATUS_INIT_SOAP_EXCHANGE = 6; // 0x6
+    field public static final int OSU_STATUS_REDIRECT_RESPONSE_RECEIVED = 8; // 0x8
+    field public static final int OSU_STATUS_RETRIEVING_TRUST_ROOT_CERTS = 11; // 0xb
+    field public static final int OSU_STATUS_SECOND_SOAP_EXCHANGE = 9; // 0x9
+    field public static final int OSU_STATUS_SERVER_CONNECTED = 5; // 0x5
+    field public static final int OSU_STATUS_SERVER_CONNECTING = 3; // 0x3
+    field public static final int OSU_STATUS_SERVER_VALIDATED = 4; // 0x4
+    field public static final int OSU_STATUS_THIRD_SOAP_EXCHANGE = 10; // 0xa
+    field public static final int OSU_STATUS_WAITING_FOR_REDIRECT_RESPONSE = 7; // 0x7
+  }
+
+}
+
 package android.net.wifi.rtt {
 
   public static final class RangingRequest.Builder {
@@ -4445,6 +4525,10 @@
     method public abstract java.lang.Object onTransactStarted(android.os.IBinder, int);
   }
 
+  public static class Build.VERSION {
+    field public static final java.lang.String PREVIEW_SDK_FINGERPRINT;
+  }
+
   public final class ConfigUpdate {
     field public static final java.lang.String ACTION_UPDATE_CARRIER_ID_DB = "android.os.action.UPDATE_CARRIER_ID_DB";
     field public static final java.lang.String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
@@ -4863,6 +4947,8 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract int onCountPermissionApps(java.util.List<java.lang.String>, boolean, boolean);
     method public abstract java.util.List<android.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String);
+    method public abstract void onGetRuntimePermissionsBackup(android.os.UserHandle, java.io.OutputStream);
+    method public abstract java.util.List<android.permission.RuntimePermissionUsageInfo> onPermissionUsageResult(boolean, long);
     method public abstract void onRevokeRuntimePermission(java.lang.String, java.lang.String);
     method public abstract java.util.Map<java.lang.String, java.util.List<java.lang.String>> onRevokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>, boolean, int, java.lang.String);
     field public static final java.lang.String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
@@ -4891,11 +4977,12 @@
   public final class RuntimePermissionUsageInfo implements android.os.Parcelable {
     ctor public RuntimePermissionUsageInfo(java.lang.CharSequence, int);
     method public int describeContents();
-    method public java.lang.CharSequence getName();
     method public int getAppAccessCount();
+    method public java.lang.CharSequence getName();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.permission.RuntimePermissionUsageInfo> CREATOR;
   }
+
 }
 
 package android.permissionpresenterservice {
@@ -5017,6 +5104,7 @@
     method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener);
     method public static void resetToDefaults(int, java.lang.String);
     method public static boolean setProperty(java.lang.String, java.lang.String, java.lang.String, boolean);
+    field public static final java.lang.String NAMESPACE_GAME_DRIVER = "game_driver";
     field public static final java.lang.String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
   }
 
@@ -6259,6 +6347,30 @@
     field public static final java.lang.String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string";
   }
 
+  public final class CarrierRestrictionRules implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers();
+    method public int getDefaultCarrierRestriction();
+    method public java.util.List<android.service.carrier.CarrierIdentifier> getExcludedCarriers();
+    method public int getMultiSimPolicy();
+    method public boolean isAllCarriersAllowed();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CARRIER_RESTRICTION_DEFAULT_ALLOWED = 1; // 0x1
+    field public static final int CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED = 0; // 0x0
+    field public static final android.os.Parcelable.Creator<android.telephony.CarrierRestrictionRules> CREATOR;
+    field public static final int MULTISIM_POLICY_NONE = 0; // 0x0
+    field public static final int MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT = 1; // 0x1
+  }
+
+  public static class CarrierRestrictionRules.Builder {
+    method public android.telephony.CarrierRestrictionRules build();
+    method public android.telephony.CarrierRestrictionRules.Builder setAllCarriersAllowed();
+    method public android.telephony.CarrierRestrictionRules.Builder setAllowedCarriers(java.util.List<android.service.carrier.CarrierIdentifier>);
+    method public android.telephony.CarrierRestrictionRules.Builder setDefaultCarrierRestriction(int);
+    method public android.telephony.CarrierRestrictionRules.Builder setExcludedCarriers(java.util.List<android.service.carrier.CarrierIdentifier>);
+    method public android.telephony.CarrierRestrictionRules.Builder setMultiSimPolicy(int);
+  }
+
   public final class DataFailCause {
     field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e
     field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f
@@ -6754,10 +6866,11 @@
     method public boolean enableDataConnectivity();
     method public void enableVideoCalling(boolean);
     method public java.lang.String getAidForAppType(int);
-    method public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
+    method public deprecated java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
     method public int getCardIdForDefaultEuicc();
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
+    method public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
     method public java.lang.String getCdmaMdn();
     method public java.lang.String getCdmaMdn(int);
     method public java.lang.String getCdmaMin();
@@ -6796,8 +6909,9 @@
     method public void requestCellInfoUpdate(android.os.WorkSource, java.util.concurrent.Executor, android.telephony.TelephonyManager.CellInfoCallback);
     method public void requestNumberVerification(android.telephony.PhoneNumberRange, long, java.util.concurrent.Executor, android.telephony.NumberVerificationCallback);
     method public boolean resetRadioConfig();
-    method public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
+    method public deprecated int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
     method public void setCarrierDataEnabled(boolean);
+    method public int setCarrierRestrictionRules(android.telephony.CarrierRestrictionRules);
     method public void setDataActivationState(int);
     method public deprecated void setDataEnabled(int, boolean);
     method public void setDataRoamingEnabled(boolean);
@@ -6849,6 +6963,9 @@
     field public static final int RADIO_POWER_OFF = 0; // 0x0
     field public static final int RADIO_POWER_ON = 1; // 0x1
     field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2
+    field public static final int SET_CARRIER_RESTRICTION_ERROR = 2; // 0x2
+    field public static final int SET_CARRIER_RESTRICTION_NOT_SUPPORTED = 1; // 0x1
+    field public static final int SET_CARRIER_RESTRICTION_SUCCESS = 0; // 0x0
     field public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2; // 0x2
     field public static final int SIM_ACTIVATION_STATE_ACTIVATING = 1; // 0x1
     field public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3; // 0x3
@@ -7179,6 +7296,7 @@
     method public int getServiceType();
     method public static int getVideoStateFromCallType(int);
     method public static int getVideoStateFromImsCallProfile(android.telephony.ims.ImsCallProfile);
+    method public boolean isEmergencyCallTesting();
     method public boolean isVideoCall();
     method public boolean isVideoPaused();
     method public static int presentationToOir(int);
@@ -7187,6 +7305,7 @@
     method public void setCallExtraInt(java.lang.String, int);
     method public void setCallRestrictCause(int);
     method public void setEmergencyCallRouting(int);
+    method public void setEmergencyCallTesting(boolean);
     method public void setEmergencyServiceCategories(int);
     method public void setEmergencyUrns(java.util.List<java.lang.String>);
     method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
@@ -7251,7 +7370,6 @@
     method public void callSessionInviteParticipantsRequestDelivered();
     method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo);
     method public void callSessionMayHandover(int, int);
-    method public void callSessionRttAudioIndicatorChanged(android.telephony.ims.ImsStreamMediaProfile);
     method public void callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase);
     method public void callSessionMergeFailed(android.telephony.ims.ImsReasonInfo);
     method public void callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
@@ -7262,6 +7380,7 @@
     method public void callSessionResumeFailed(android.telephony.ims.ImsReasonInfo);
     method public void callSessionResumeReceived(android.telephony.ims.ImsCallProfile);
     method public void callSessionResumed(android.telephony.ims.ImsCallProfile);
+    method public void callSessionRttAudioIndicatorChanged(android.telephony.ims.ImsStreamMediaProfile);
     method public void callSessionRttMessageReceived(java.lang.String);
     method public void callSessionRttModifyRequestReceived(android.telephony.ims.ImsCallProfile);
     method public void callSessionRttModifyResponseReceived(int);
@@ -8492,6 +8611,8 @@
     method public abstract int getVisibleTitleHeight();
     method public abstract android.webkit.WebChromeClient getWebChromeClient();
     method public abstract android.webkit.WebViewClient getWebViewClient();
+    method public abstract android.webkit.WebViewRenderer getWebViewRenderer();
+    method public abstract android.webkit.WebViewRendererClient getWebViewRendererClient();
     method public abstract android.view.View getZoomControls();
     method public abstract void goBack();
     method public abstract void goBackOrForward(int);
@@ -8541,6 +8662,7 @@
     method public abstract void setVerticalScrollbarOverlay(boolean);
     method public abstract void setWebChromeClient(android.webkit.WebChromeClient);
     method public abstract void setWebViewClient(android.webkit.WebViewClient);
+    method public abstract void setWebViewRendererClient(java.util.concurrent.Executor, android.webkit.WebViewRendererClient);
     method public abstract boolean showFindDialog(java.lang.String, boolean);
     method public abstract void stopLoading();
     method public abstract boolean zoomBy(float);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 4beb699..5a7ec8b 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -1,3 +1,11 @@
+package android {
+
+  public static final class Manifest.permission {
+    field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
+  }
+
+}
+
 package android.app {
 
   public class Notification implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 6d40e69..e0e0f35 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -420,7 +420,9 @@
   }
 
   public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+    field public static final int PROTECTION_FLAG_CONFIGURATOR = 524288; // 0x80000
     field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
+    field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
     field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
     field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000
     field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
@@ -500,10 +502,19 @@
 
 package android.graphics {
 
+  public final class Bitmap implements android.os.Parcelable {
+    method public void eraseColor(long);
+  }
+
   public final class ImageDecoder implements java.lang.AutoCloseable {
     method public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, java.io.InputStream, int);
   }
 
+  public class Paint {
+    method public void setColor(long);
+    method public void setShadowLayer(float, float, float, long);
+  }
+
 }
 
 package android.graphics.drawable {
@@ -569,6 +580,8 @@
 
   public final class BrightnessConfiguration implements android.os.Parcelable {
     method public int describeContents();
+    method public android.hardware.display.BrightnessCorrection getCorrectionByCategory(int);
+    method public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(java.lang.String);
     method public android.util.Pair<float[], float[]> getCurve();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR;
@@ -576,10 +589,22 @@
 
   public static class BrightnessConfiguration.Builder {
     ctor public BrightnessConfiguration.Builder(float[], float[]);
+    method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByCategory(int, android.hardware.display.BrightnessCorrection);
+    method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByPackageName(java.lang.String, android.hardware.display.BrightnessCorrection);
     method public android.hardware.display.BrightnessConfiguration build();
+    method public int getMaxCorrectionsByCategory();
+    method public int getMaxCorrectionsByPackageName();
     method public android.hardware.display.BrightnessConfiguration.Builder setDescription(java.lang.String);
   }
 
+  public final class BrightnessCorrection implements android.os.Parcelable {
+    method public float apply(float);
+    method public static android.hardware.display.BrightnessCorrection createScaleAndTranslateLog(float, float);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessCorrection> CREATOR;
+  }
+
   public final class DisplayManager {
     method public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
     method public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration();
@@ -623,6 +648,7 @@
     method public void resetCarrierFrequencyHz();
     method public deprecated void resetCarrierPhase();
     method public deprecated void resetCarrierPhaseUncertainty();
+    method public void resetCodeType();
     method public void resetSnrInDb();
     method public void set(android.location.GnssMeasurement);
     method public void setAccumulatedDeltaRangeMeters(double);
@@ -634,6 +660,7 @@
     method public deprecated void setCarrierPhase(double);
     method public deprecated void setCarrierPhaseUncertainty(double);
     method public void setCn0DbHz(double);
+    method public void setCodeType(int);
     method public void setConstellationType(int);
     method public void setMultipathIndicator(int);
     method public void setPseudorangeRateMetersPerSecond(double);
@@ -790,6 +817,134 @@
     method public static java.io.File getStorageDirectory();
   }
 
+  public abstract class HwBinder implements android.os.IHwBinder {
+    ctor public HwBinder();
+    method public static final void configureRpcThreadpool(long, boolean);
+    method public static void enableInstrumentation();
+    method public static final android.os.IHwBinder getService(java.lang.String, java.lang.String) throws java.util.NoSuchElementException, android.os.RemoteException;
+    method public static final android.os.IHwBinder getService(java.lang.String, java.lang.String, boolean) throws java.util.NoSuchElementException, android.os.RemoteException;
+    method public static final void joinRpcThreadpool();
+    method public abstract void onTransact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
+    method public final void registerService(java.lang.String) throws android.os.RemoteException;
+    method public final void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
+  }
+
+  public class HwBlob {
+    ctor public HwBlob(int);
+    method public final void copyToBoolArray(long, boolean[], int);
+    method public final void copyToDoubleArray(long, double[], int);
+    method public final void copyToFloatArray(long, float[], int);
+    method public final void copyToInt16Array(long, short[], int);
+    method public final void copyToInt32Array(long, int[], int);
+    method public final void copyToInt64Array(long, long[], int);
+    method public final void copyToInt8Array(long, byte[], int);
+    method public final boolean getBool(long);
+    method public final double getDouble(long);
+    method public final float getFloat(long);
+    method public final short getInt16(long);
+    method public final int getInt32(long);
+    method public final long getInt64(long);
+    method public final byte getInt8(long);
+    method public final java.lang.String getString(long);
+    method public final long handle();
+    method public final void putBlob(long, android.os.HwBlob);
+    method public final void putBool(long, boolean);
+    method public final void putBoolArray(long, boolean[]);
+    method public final void putDouble(long, double);
+    method public final void putDoubleArray(long, double[]);
+    method public final void putFloat(long, float);
+    method public final void putFloatArray(long, float[]);
+    method public final void putInt16(long, short);
+    method public final void putInt16Array(long, short[]);
+    method public final void putInt32(long, int);
+    method public final void putInt32Array(long, int[]);
+    method public final void putInt64(long, long);
+    method public final void putInt64Array(long, long[]);
+    method public final void putInt8(long, byte);
+    method public final void putInt8Array(long, byte[]);
+    method public final void putNativeHandle(long, android.os.NativeHandle);
+    method public final void putString(long, java.lang.String);
+    method public static java.lang.Boolean[] wrapArray(boolean[]);
+    method public static java.lang.Long[] wrapArray(long[]);
+    method public static java.lang.Byte[] wrapArray(byte[]);
+    method public static java.lang.Short[] wrapArray(short[]);
+    method public static java.lang.Integer[] wrapArray(int[]);
+    method public static java.lang.Float[] wrapArray(float[]);
+    method public static java.lang.Double[] wrapArray(double[]);
+  }
+
+  public class HwParcel {
+    ctor public HwParcel();
+    method public final void enforceInterface(java.lang.String);
+    method public final boolean readBool();
+    method public final java.util.ArrayList<java.lang.Boolean> readBoolVector();
+    method public final android.os.HwBlob readBuffer(long);
+    method public final double readDouble();
+    method public final java.util.ArrayList<java.lang.Double> readDoubleVector();
+    method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean);
+    method public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
+    method public final float readFloat();
+    method public final java.util.ArrayList<java.lang.Float> readFloatVector();
+    method public final short readInt16();
+    method public final java.util.ArrayList<java.lang.Short> readInt16Vector();
+    method public final int readInt32();
+    method public final java.util.ArrayList<java.lang.Integer> readInt32Vector();
+    method public final long readInt64();
+    method public final java.util.ArrayList<java.lang.Long> readInt64Vector();
+    method public final byte readInt8();
+    method public final java.util.ArrayList<java.lang.Byte> readInt8Vector();
+    method public final android.os.NativeHandle readNativeHandle();
+    method public final java.util.ArrayList<android.os.NativeHandle> readNativeHandleVector();
+    method public final java.lang.String readString();
+    method public final java.util.ArrayList<java.lang.String> readStringVector();
+    method public final android.os.IHwBinder readStrongBinder();
+    method public final void release();
+    method public final void releaseTemporaryStorage();
+    method public final void send();
+    method public final void verifySuccess();
+    method public final void writeBool(boolean);
+    method public final void writeBoolVector(java.util.ArrayList<java.lang.Boolean>);
+    method public final void writeBuffer(android.os.HwBlob);
+    method public final void writeDouble(double);
+    method public final void writeDoubleVector(java.util.ArrayList<java.lang.Double>);
+    method public final void writeFloat(float);
+    method public final void writeFloatVector(java.util.ArrayList<java.lang.Float>);
+    method public final void writeInt16(short);
+    method public final void writeInt16Vector(java.util.ArrayList<java.lang.Short>);
+    method public final void writeInt32(int);
+    method public final void writeInt32Vector(java.util.ArrayList<java.lang.Integer>);
+    method public final void writeInt64(long);
+    method public final void writeInt64Vector(java.util.ArrayList<java.lang.Long>);
+    method public final void writeInt8(byte);
+    method public final void writeInt8Vector(java.util.ArrayList<java.lang.Byte>);
+    method public final void writeInterfaceToken(java.lang.String);
+    method public final void writeNativeHandle(android.os.NativeHandle);
+    method public final void writeNativeHandleVector(java.util.ArrayList<android.os.NativeHandle>);
+    method public final void writeStatus(int);
+    method public final void writeString(java.lang.String);
+    method public final void writeStringVector(java.util.ArrayList<java.lang.String>);
+    method public final void writeStrongBinder(android.os.IHwBinder);
+    field public static final int STATUS_SUCCESS = 0; // 0x0
+  }
+
+  public static abstract class HwParcel.Status implements java.lang.annotation.Annotation {
+  }
+
+  public abstract interface IHwBinder {
+    method public abstract boolean linkToDeath(android.os.IHwBinder.DeathRecipient, long);
+    method public abstract android.os.IHwInterface queryLocalInterface(java.lang.String);
+    method public abstract void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
+    method public abstract boolean unlinkToDeath(android.os.IHwBinder.DeathRecipient);
+  }
+
+  public static abstract interface IHwBinder.DeathRecipient {
+    method public abstract void serviceDied(long);
+  }
+
+  public abstract interface IHwInterface {
+    method public abstract android.os.IHwBinder asBinder();
+  }
+
   public class IncidentManager {
     method public void reportIncident(android.os.IncidentReportArgs);
   }
@@ -815,6 +970,18 @@
     method public void removeSyncBarrier(int);
   }
 
+  public final class NativeHandle implements java.io.Closeable {
+    ctor public NativeHandle();
+    ctor public NativeHandle(java.io.FileDescriptor, boolean);
+    ctor public NativeHandle(java.io.FileDescriptor[], int[], boolean);
+    method public void close() throws java.io.IOException;
+    method public android.os.NativeHandle dup() throws java.io.IOException;
+    method public java.io.FileDescriptor getFileDescriptor();
+    method public java.io.FileDescriptor[] getFileDescriptors();
+    method public int[] getInts();
+    method public boolean hasSingleFileDescriptor();
+  }
+
   public final class PowerManager {
     method public int getPowerSaveMode();
     method public boolean setDynamicPowerSavings(boolean, int);
@@ -825,6 +992,11 @@
 
   public class Process {
     method public static final int getThreadScheduler(int) throws java.lang.IllegalArgumentException;
+    field public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000; // 0x15f90
+    field public static final int FIRST_ISOLATED_UID = 99000; // 0x182b8
+    field public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999; // 0x182b7
+    field public static final int LAST_ISOLATED_UID = 99999; // 0x1869f
+    field public static final int NUM_UIDS_PER_APP_ZYGOTE = 100; // 0x64
   }
 
   public final class RemoteCallback implements android.os.Parcelable {
@@ -946,6 +1118,24 @@
     field public static final android.os.Parcelable.Creator<android.os.VibrationEffect.Waveform> CREATOR;
   }
 
+  public class VintfObject {
+    method public static java.lang.String[] getHalNamesAndVersions();
+    method public static java.lang.String getSepolicyVersion();
+    method public static java.lang.Long getTargetFrameworkCompatibilityMatrixVersion();
+    method public static java.util.Map<java.lang.String, java.lang.String[]> getVndkSnapshots();
+    method public static java.lang.String[] report();
+  }
+
+  public class VintfRuntimeInfo {
+    method public static java.lang.String getCpuInfo();
+    method public static java.lang.String getHardwareId();
+    method public static java.lang.String getKernelVersion();
+    method public static java.lang.String getNodeName();
+    method public static java.lang.String getOsName();
+    method public static java.lang.String getOsRelease();
+    method public static java.lang.String getOsVersion();
+  }
+
   public class WorkSource implements android.os.Parcelable {
     ctor public WorkSource(int);
     method public boolean add(int);
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index abe18ba..803f83c 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -20,6 +20,7 @@
         "misc-*",
         "modernize-*",
         "readability-*",
+        "-modernize-avoid-c-arrays",
     ],
     tidy_flags: [
         "-system-headers",
@@ -38,6 +39,7 @@
         "libidmap2/CommandLineOptions.cpp",
         "libidmap2/FileUtils.cpp",
         "libidmap2/Idmap.cpp",
+        "libidmap2/Policies.cpp",
         "libidmap2/PrettyPrintVisitor.cpp",
         "libidmap2/RawPrintVisitor.cpp",
         "libidmap2/ResourceUtils.cpp",
@@ -87,6 +89,7 @@
         "tests/Idmap2BinaryTests.cpp",
         "tests/IdmapTests.cpp",
         "tests/Main.cpp",
+        "tests/PoliciesTests.cpp",
         "tests/PrettyPrintVisitorTests.cpp",
         "tests/RawPrintVisitorTests.cpp",
         "tests/ResourceUtilsTests.cpp",
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index b075673..c455ac0 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -27,17 +27,25 @@
 #include "idmap2/CommandLineOptions.h"
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
+#include "idmap2/Result.h"
 
 using android::ApkAssets;
 using android::idmap2::BinaryStreamVisitor;
 using android::idmap2::CommandLineOptions;
 using android::idmap2::Idmap;
+using android::idmap2::PoliciesToBitmask;
+using android::idmap2::PolicyBitmask;
+using android::idmap2::PolicyFlags;
+using android::idmap2::Result;
 using android::idmap2::utils::kIdmapFilePermissionMask;
 
 bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
   std::string target_apk_path;
   std::string overlay_apk_path;
   std::string idmap_path;
+  std::vector<std::string> policies;
+  bool ignore_overlayable;
 
   const CommandLineOptions opts =
       CommandLineOptions("idmap2 create")
@@ -47,12 +55,28 @@
           .MandatoryOption("--overlay-apk-path",
                            "input: path to apk which contains the new resource values",
                            &overlay_apk_path)
-          .MandatoryOption("--idmap-path", "output: path to where to write idmap file",
-                           &idmap_path);
+          .MandatoryOption("--idmap-path", "output: path to where to write idmap file", &idmap_path)
+          .OptionalOption("--policy",
+                          "input: an overlayable policy this overlay fulfills "
+                          "(if none or supplied, the overlay policy will default to \"public\")",
+                          &policies)
+          .OptionalFlag("--ignore-overlayable", "disables overlayable and policy checks",
+                        &ignore_overlayable);
   if (!opts.Parse(args, out_error)) {
     return false;
   }
 
+  PolicyBitmask fulfilled_policies = 0;
+  if (auto result = PoliciesToBitmask(policies, out_error)) {
+    fulfilled_policies |= *result;
+  } else {
+    return false;
+  }
+
+  if (fulfilled_policies == 0) {
+    fulfilled_policies |= PolicyFlags::POLICY_PUBLIC;
+  }
+
   const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
   if (!target_apk) {
     out_error << "error: failed to load apk " << target_apk_path << std::endl;
@@ -66,7 +90,8 @@
   }
 
   const std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, out_error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           fulfilled_policies, !ignore_overlayable, out_error);
   if (!idmap) {
     return false;
   }
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index 4f88127..a269ee9 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -21,8 +21,11 @@
 #include <set>
 #include <sstream>
 #include <string>
+#include <utility>
 #include <vector>
 
+#include "android-base/properties.h"
+
 #include "idmap2/CommandLineOptions.h"
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
@@ -34,6 +37,10 @@
 using android::idmap2::CommandLineOptions;
 using android::idmap2::Idmap;
 using android::idmap2::MemoryChunk;
+using android::idmap2::PoliciesToBitmask;
+using android::idmap2::PolicyBitmask;
+using android::idmap2::PolicyFlags;
+using android::idmap2::Result;
 using android::idmap2::Xml;
 using android::idmap2::ZipFile;
 using android::idmap2::utils::FindFiles;
@@ -45,11 +52,19 @@
     return priority < rhs.priority || (priority == rhs.priority && apk_path < rhs.apk_path);
   }
 
-  std::string apk_path;    // NOLINT(misc-non-private-member-variables-in-classes)
-  std::string idmap_path;  // NOLINT(misc-non-private-member-variables-in-classes)
-  int priority;            // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string apk_path;               // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string idmap_path;             // NOLINT(misc-non-private-member-variables-in-classes)
+  int priority;                       // NOLINT(misc-non-private-member-variables-in-classes)
+  std::vector<std::string> policies;  // NOLINT(misc-non-private-member-variables-in-classes)
+  bool ignore_overlayable;            // NOLINT(misc-non-private-member-variables-in-classes)
 };
 
+bool VendorIsQOrLater() {
+  // STOPSHIP(b/119390857): Check api version once Q sdk version is finalized
+  std::string version = android::base::GetProperty("ro.vndk.version", "Q");
+  return version == "Q" || version == "q";
+}
+
 std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs,
                                                        bool recursive, std::ostream& out_error) {
   const auto predicate = [](unsigned char type, const std::string& path) -> bool {
@@ -70,6 +85,22 @@
   return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend());
 }
 
+PolicyBitmask PolicyForPath(const std::string& apk_path) {
+  static const std::vector<std::pair<std::string, PolicyBitmask>> values = {
+      {"/product/", PolicyFlags::POLICY_PRODUCT_PARTITION},
+      {"/system/", PolicyFlags::POLICY_SYSTEM_PARTITION},
+      {"/vendor/", PolicyFlags::POLICY_VENDOR_PARTITION},
+  };
+
+  for (auto const& pair : values) {
+    if (apk_path.compare(0, pair.first.size(), pair.first) == 0) {
+      return pair.second | PolicyFlags::POLICY_PUBLIC;
+    }
+  }
+
+  return PolicyFlags::POLICY_PUBLIC;
+}
+
 }  // namespace
 
 bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
@@ -77,6 +108,7 @@
   std::string target_package_name;
   std::string target_apk_path;
   std::string output_directory;
+  std::vector<std::string> override_policies;
   bool recursive = false;
 
   const CommandLineOptions opts =
@@ -89,7 +121,12 @@
           .MandatoryOption("--target-apk-path", "path to target apk", &target_apk_path)
           .MandatoryOption("--output-directory",
                            "directory in which to write artifacts (idmap files and overlays.list)",
-                           &output_directory);
+                           &output_directory)
+          .OptionalOption(
+              "--override-policy",
+              "input: an overlayable policy this overlay fulfills "
+              "(if none or supplied, the overlays will not have their policies overriden",
+              &override_policies);
   if (!opts.Parse(args, out_error)) {
     return false;
   }
@@ -144,29 +181,63 @@
       continue;
     }
 
-    // Sort the static overlays in ascending priority order
+    PolicyBitmask fulfilled_policies;
+    if (!override_policies.empty()) {
+      if (Result<PolicyBitmask> result = PoliciesToBitmask(override_policies, out_error)) {
+        fulfilled_policies = *result;
+      } else {
+        return false;
+      }
+    } else {
+      fulfilled_policies = PolicyForPath(path);
+    }
+
+    bool ignore_overlayable = false;
+    if ((fulfilled_policies & PolicyFlags::POLICY_VENDOR_PARTITION) != 0 && !VendorIsQOrLater()) {
+      // If the overlay is on a pre-Q vendor partition, do not enforce overlayable
+      // restrictions on this overlay because the pre-Q platform has no understanding of
+      // overlayable.
+      ignore_overlayable = true;
+    }
+
     std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path);
-    InputOverlay input{path, idmap_path, priority};
+
+    // Sort the static overlays in ascending priority order
+    InputOverlay input{path, idmap_path, priority, override_policies, ignore_overlayable};
     interesting_apks.insert(
         std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input);
   }
 
   std::stringstream stream;
   for (const auto& overlay : interesting_apks) {
+    // Create the idmap for the overlay if it currently does not exist or if it is not up to date.
     std::stringstream dev_null;
-    if (!Verify(std::vector<std::string>({"--idmap-path", overlay.idmap_path}), dev_null) &&
-        !Create(std::vector<std::string>({
-                    "--target-apk-path",
-                    target_apk_path,
-                    "--overlay-apk-path",
-                    overlay.apk_path,
-                    "--idmap-path",
-                    overlay.idmap_path,
-                }),
-                out_error)) {
-      return false;
+
+    std::vector<std::string> verify_args = {"--idmap-path", overlay.idmap_path};
+    for (const std::string& policy : overlay.policies) {
+      verify_args.emplace_back("--policy");
+      verify_args.emplace_back(policy);
     }
-    stream <<  overlay.idmap_path << std::endl;
+
+    if (!Verify(std::vector<std::string>(verify_args), dev_null)) {
+      std::vector<std::string> create_args = {"--target-apk-path",  target_apk_path,
+                                              "--overlay-apk-path", overlay.apk_path,
+                                              "--idmap-path",       overlay.idmap_path};
+      if (overlay.ignore_overlayable) {
+        create_args.emplace_back("--ignore-overlayable");
+      }
+
+      for (const std::string& policy : overlay.policies) {
+        verify_args.emplace_back("--policy");
+        verify_args.emplace_back(policy);
+      }
+
+      if (!Create(create_args, out_error)) {
+        return false;
+      }
+    }
+
+    stream << overlay.idmap_path << std::endl;
   }
 
   std::cout << stream.str();
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index d2e46e1..a3c7527 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -26,12 +26,15 @@
 #include <string>
 
 #include "android-base/macros.h"
+#include "android-base/stringprintf.h"
 #include "utils/String8.h"
 #include "utils/Trace.h"
 
 #include "idmap2/BinaryStreamVisitor.h"
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
+#include "idmap2/Result.h"
 
 #include "idmap2d/Idmap2Service.h"
 
@@ -39,6 +42,8 @@
 using android::idmap2::BinaryStreamVisitor;
 using android::idmap2::Idmap;
 using android::idmap2::IdmapHeader;
+using android::idmap2::PolicyBitmask;
+using android::idmap2::Result;
 using android::idmap2::utils::kIdmapFilePermissionMask;
 
 namespace {
@@ -54,6 +59,10 @@
   return Status::fromExceptionCode(Status::EX_NONE, msg.c_str());
 }
 
+PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) {
+  return static_cast<PolicyBitmask>(arg);
+}
+
 }  // namespace
 
 namespace android::os {
@@ -78,6 +87,8 @@
 }
 
 Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path,
+                                  int32_t fulfilled_policies ATTRIBUTE_UNUSED,
+                                  bool enforce_overlayable ATTRIBUTE_UNUSED,
                                   int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
   assert(_aidl_return);
   const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
@@ -86,11 +97,15 @@
   fin.close();
   std::stringstream dev_null;
   *_aidl_return = header && header->IsUpToDate(dev_null);
+
+  // TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed
+
   return ok();
 }
 
 Status Idmap2Service::createIdmap(const std::string& target_apk_path,
-                                  const std::string& overlay_apk_path, int32_t user_id,
+                                  const std::string& overlay_apk_path, int32_t fulfilled_policies,
+                                  bool enforce_overlayable, int32_t user_id,
                                   std::unique_ptr<std::string>* _aidl_return) {
   assert(_aidl_return);
   std::stringstream trace;
@@ -101,6 +116,8 @@
 
   _aidl_return->reset(nullptr);
 
+  const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies);
+
   const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
   if (!target_apk) {
     return error("failed to load apk " + target_apk_path);
@@ -113,7 +130,8 @@
 
   std::stringstream err;
   const std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, err);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           policy_bitmask, enforce_overlayable, err);
   if (!idmap) {
     return error(err.str());
   }
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index e0bc22e..1aab059 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -39,11 +39,12 @@
   binder::Status removeIdmap(const std::string& overlay_apk_path, int32_t user_id,
                              bool* _aidl_return);
 
-  binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t user_id,
-                             bool* _aidl_return);
+  binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t fulfilled_policies,
+                             bool enforce_overlayable, int32_t user_id, bool* _aidl_return);
 
   binder::Status createIdmap(const std::string& target_apk_path,
-                             const std::string& overlay_apk_path, int32_t user_id,
+                             const std::string& overlay_apk_path, int32_t fulfilled_policies,
+                             bool enforce_overlayable, int32_t user_id,
                              std::unique_ptr<std::string>* _aidl_return);
 };
 
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
index d475417..ea7274f 100644
--- a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
+++ b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
@@ -20,9 +20,18 @@
  * @hide
  */
 interface IIdmap2 {
+  const int POLICY_PUBLIC = 0x00000001;
+  const int POLICY_SYSTEM_PARTITION = 0x00000002;
+  const int POLICY_VENDOR_PARTITION = 0x00000004;
+  const int POLICY_PRODUCT_PARTITION = 0x00000008;
+
   @utf8InCpp String getIdmapPath(@utf8InCpp String overlayApkPath, int userId);
   boolean removeIdmap(@utf8InCpp String overlayApkPath, int userId);
-  boolean verifyIdmap(@utf8InCpp String overlayApkPath, int userId);
+  boolean verifyIdmap(@utf8InCpp String overlayApkPath, int fulfilledPolicies,
+                      boolean enforceOverlayable, int userId);
   @nullable @utf8InCpp String createIdmap(@utf8InCpp String targetApkPath,
-                                          @utf8InCpp String overlayApkPath, int userId);
+                                          @utf8InCpp String overlayApkPath,
+                                          int fulfilledPolicies,
+                                          boolean enforceOverlayable,
+                                          int userId);
 }
diff --git a/cmds/idmap2/include/idmap2/CommandLineOptions.h b/cmds/idmap2/include/idmap2/CommandLineOptions.h
index b93e716..6db6bf9 100644
--- a/cmds/idmap2/include/idmap2/CommandLineOptions.h
+++ b/cmds/idmap2/include/idmap2/CommandLineOptions.h
@@ -44,6 +44,8 @@
                                       std::vector<std::string>* value);
   CommandLineOptions& OptionalOption(const std::string& name, const std::string& description,
                                      std::string* value);
+  CommandLineOptions& OptionalOption(const std::string& name, const std::string& description,
+                                     std::vector<std::string>* value);
   bool Parse(const std::vector<std::string>& argv, std::ostream& outError) const;
   void Usage(std::ostream& out) const;
 
@@ -56,6 +58,7 @@
       COUNT_OPTIONAL,
       COUNT_EXACTLY_ONCE,
       COUNT_ONCE_OR_MORE,
+      COUNT_OPTIONAL_ONCE_OR_MORE,
     } count;
     bool argument;
   };
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index b989e4c..1666dc8 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -57,6 +57,8 @@
 #include "androidfw/ResourceTypes.h"
 #include "androidfw/StringPiece.h"
 
+#include "idmap2/Policies.h"
+
 namespace android::idmap2 {
 
 class Idmap;
@@ -233,11 +235,10 @@
   // file is used; change this in the next version of idmap to use a named
   // package instead; also update FromApkAssets to take additional parameters:
   // the target and overlay package names
-  static std::unique_ptr<const Idmap> FromApkAssets(const std::string& target_apk_path,
-                                                    const ApkAssets& target_apk_assets,
-                                                    const std::string& overlay_apk_path,
-                                                    const ApkAssets& overlay_apk_assets,
-                                                    std::ostream& out_error);
+  static std::unique_ptr<const Idmap> FromApkAssets(
+      const std::string& target_apk_path, const ApkAssets& target_apk_assets,
+      const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets,
+      const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error);
 
   inline const std::unique_ptr<const IdmapHeader>& GetHeader() const {
     return header_;
diff --git a/cmds/idmap2/include/idmap2/Policies.h b/cmds/idmap2/include/idmap2/Policies.h
new file mode 100644
index 0000000..eecee25
--- /dev/null
+++ b/cmds/idmap2/include/idmap2/Policies.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
+
+#include "Result.h"
+
+#ifndef IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
+#define IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
+
+namespace android::idmap2 {
+
+using PolicyFlags = ResTable_overlayable_policy_header::PolicyFlags;
+using PolicyBitmask = uint32_t;
+
+// Parses a the string representation of a set of policies into a bitmask. The format of the string
+// is the same as for the <policy> element.
+Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies,
+                                        std::ostream& err);
+
+}  // namespace android::idmap2
+
+#endif  // IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
index cabc8f3..a49a607 100644
--- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp
+++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
@@ -68,9 +68,18 @@
   return *this;
 }
 
+CommandLineOptions& CommandLineOptions::OptionalOption(const std::string& name,
+                                                       const std::string& description,
+                                                       std::vector<std::string>* value) {
+  assert(value != nullptr);
+  auto func = [value](const std::string& arg) -> void { value->push_back(arg); };
+  options_.push_back(Option{name, description, func, Option::COUNT_OPTIONAL_ONCE_OR_MORE, true});
+  return *this;
+}
+
 bool CommandLineOptions::Parse(const std::vector<std::string>& argv, std::ostream& outError) const {
   const auto pivot = std::partition(options_.begin(), options_.end(), [](const Option& opt) {
-    return opt.count != Option::COUNT_OPTIONAL;
+    return opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE;
   });
   std::set<std::string> mandatory_opts;
   std::transform(options_.begin(), pivot, std::inserter(mandatory_opts, mandatory_opts.end()),
@@ -122,7 +131,8 @@
   size_t maxLength = 0;
   out << "usage: " << name_;
   for (const Option& opt : options_) {
-    const bool mandatory = opt.count != Option::COUNT_OPTIONAL;
+    const bool mandatory =
+        opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE;
     out << " ";
     if (!mandatory) {
       out << "[";
@@ -134,9 +144,15 @@
       out << opt.name;
       maxLength = std::max(maxLength, opt.name.size());
     }
+
+    if (opt.count == Option::COUNT_OPTIONAL_ONCE_OR_MORE) {
+      out << " [..]";
+    }
+
     if (!mandatory) {
       out << "]";
     }
+
     if (opt.count == Option::COUNT_ONCE_OR_MORE) {
       out << " [" << opt.name << " arg [..]]";
     }
@@ -150,7 +166,8 @@
       out << opt.name;
     }
     out << "    " << opt.description;
-    if (opt.count == Option::COUNT_ONCE_OR_MORE) {
+    if (opt.count == Option::COUNT_ONCE_OR_MORE ||
+        opt.count == Option::COUNT_OPTIONAL_ONCE_OR_MORE) {
       out << " (can be provided multiple times)";
     }
     out << std::endl;
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 37d6af8..2890ae1 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -274,11 +274,23 @@
   return std::move(idmap);
 }
 
-std::unique_ptr<const Idmap> Idmap::FromApkAssets(const std::string& target_apk_path,
-                                                  const ApkAssets& target_apk_assets,
-                                                  const std::string& overlay_apk_path,
-                                                  const ApkAssets& overlay_apk_assets,
-                                                  std::ostream& out_error) {
+bool CheckOverlayable(const LoadedPackage& target_package, PolicyBitmask fulfilled_polices,
+                      ResourceId resid) {
+  const OverlayableInfo* info = target_package.GetOverlayableInfo(resid);
+  if (info == nullptr) {
+    // If the resource does not have an overlayable definition, allow the resource to be overlaid.
+    // Once overlayable enforcement is turned on, this check will return false.
+    return true;
+  }
+
+  // Enforce policy restrictions if the resource is declared as overlayable.
+  return (info->policy_flags & fulfilled_polices) != 0;
+}
+
+std::unique_ptr<const Idmap> Idmap::FromApkAssets(
+    const std::string& target_apk_path, const ApkAssets& target_apk_assets,
+    const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets,
+    const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error) {
   AssetManager2 target_asset_manager;
   if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true, false)) {
     out_error << "error: failed to create target asset manager" << std::endl;
@@ -380,6 +392,15 @@
     if (target_resid == 0) {
       continue;
     }
+
+    if (enforce_overlayable && !CheckOverlayable(*target_pkg, fulfilled_policies, target_resid)) {
+      // The resources must be defined as overlayable and the overlay must fulfill at least one
+      // policy enforced on the overlayable resource
+      LOG(WARNING) << "overlay \"" << overlay_apk_path << "\" is not allowed to overlay resource \""
+                   << full_name << "\"" << std::endl;
+      continue;
+    }
+
     matching_resources.Add(target_resid, overlay_resid);
   }
 
diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp
new file mode 100644
index 0000000..0f87ef0
--- /dev/null
+++ b/cmds/idmap2/libidmap2/Policies.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iterator>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "androidfw/ResourceTypes.h"
+
+#include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
+#include "idmap2/Result.h"
+
+namespace android::idmap2 {
+
+namespace {
+
+const std::map<android::StringPiece, PolicyFlags> kStringToFlag = {
+    {"public", PolicyFlags::POLICY_PUBLIC},
+    {"product", PolicyFlags::POLICY_PRODUCT_PARTITION},
+    {"system", PolicyFlags::POLICY_SYSTEM_PARTITION},
+    {"vendor", PolicyFlags::POLICY_VENDOR_PARTITION},
+};
+}  // namespace
+
+Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies,
+                                        std::ostream& err) {
+  PolicyBitmask bitmask = 0;
+  for (const std::string& policy : policies) {
+    const auto iter = kStringToFlag.find(policy);
+    if (iter != kStringToFlag.end()) {
+      bitmask |= iter->second;
+    } else {
+      err << "error: unknown policy \"" << policy << "\"";
+      return kResultError;
+    }
+  }
+
+  return Result<PolicyBitmask>(bitmask);
+}
+
+}  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index 2698ac0..35ec1ff 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -78,7 +78,8 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   std::stringstream stream;
@@ -101,25 +102,52 @@
   header = loaded_idmap->GetEntryMapForType(0x02);
   ASSERT_THAT(header, NotNull());
 
-  success = LoadedIdmap::Lookup(header, 0x0002, &entry);
+  success = LoadedIdmap::Lookup(header, 0x0000, &entry);  // string/a
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x0003, &entry);
+  success = LoadedIdmap::Lookup(header, 0x0001, &entry);  // string/b
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0002, &entry);  // string/c
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0003, &entry);  // string/not_overlayable
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0004, &entry);  // string/policy_product
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0005, &entry);  // string/policy_public
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0006, &entry);  // string/policy_system
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0007, &entry);  // string/policy_system_vendor
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0008, &entry);  // string/str1
   ASSERT_TRUE(success);
   ASSERT_EQ(entry, 0x0000);
 
-  success = LoadedIdmap::Lookup(header, 0x0004, &entry);
+  success = LoadedIdmap::Lookup(header, 0x0009, &entry);  // string/str2
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x0005, &entry);
+  success = LoadedIdmap::Lookup(header, 0x000a, &entry);  // string/str3
   ASSERT_TRUE(success);
   ASSERT_EQ(entry, 0x0001);
 
-  success = LoadedIdmap::Lookup(header, 0x0006, &entry);
+  success = LoadedIdmap::Lookup(header, 0x000b, &entry);  // string/str4
   ASSERT_TRUE(success);
   ASSERT_EQ(entry, 0x0002);
 
-  success = LoadedIdmap::Lookup(header, 0x0007, &entry);
+  success = LoadedIdmap::Lookup(header, 0x000c, &entry);  // string/x
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x000d, &entry);  // string/y
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x000e, &entry);  // string/z
   ASSERT_FALSE(success);
 }
 
diff --git a/cmds/idmap2/tests/CommandLineOptionsTests.cpp b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
index c27d27a..39f18d3 100644
--- a/cmds/idmap2/tests/CommandLineOptionsTests.cpp
+++ b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
@@ -121,6 +121,56 @@
   ASSERT_FALSE(success);
 }
 
+TEST(CommandLineOptionsTests, OptionalOptionList) {
+  std::vector<std::string> foo;
+  std::vector<std::string> bar;
+  CommandLineOptions opts = CommandLineOptions("test")
+                                .OptionalOption("--foo", "", &foo)
+                                .OptionalOption("--bar", "", &bar);
+  std::ostream fakeStdErr(nullptr);
+  bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr);
+  ASSERT_TRUE(success);
+  ASSERT_EQ(foo.size(), 1U);
+  ASSERT_EQ(foo[0], "FOO");
+  ASSERT_EQ(bar.size(), 1U);
+  ASSERT_EQ(bar[0], "BAR");
+
+  foo.clear();
+  bar.clear();
+  success = opts.Parse({"--foo", "BAZ"}, fakeStdErr);
+  ASSERT_TRUE(success);
+  ASSERT_EQ(foo.size(), 1U);
+  ASSERT_EQ(foo[0], "BAZ");
+  ASSERT_EQ(bar.size(), 0U);
+
+  foo.clear();
+  bar.clear();
+  success =
+      opts.Parse({"--foo", "BAZ", "--foo", "BIZ", "--bar", "FIZ", "--bar", "FUZZ"}, fakeStdErr);
+  ASSERT_TRUE(success);
+  ASSERT_EQ(foo.size(), 2U);
+  ASSERT_EQ(foo[0], "BAZ");
+  ASSERT_EQ(foo[1], "BIZ");
+  ASSERT_EQ(bar.size(), 2U);
+  ASSERT_EQ(bar[0], "FIZ");
+  ASSERT_EQ(bar[1], "FUZZ");
+
+  foo.clear();
+  bar.clear();
+  success = opts.Parse({"--foo"}, fakeStdErr);
+  ASSERT_FALSE(success);
+
+  foo.clear();
+  bar.clear();
+  success = opts.Parse({"--foo", "--bar", "BAR"}, fakeStdErr);
+  ASSERT_FALSE(success);
+
+  foo.clear();
+  bar.clear();
+  success = opts.Parse({"--foo", "FOO", "--bar"}, fakeStdErr);
+  ASSERT_FALSE(success);
+}
+
 TEST(CommandLineOptionsTests, CornerCases) {
   std::string foo;
   std::string bar;
@@ -172,6 +222,7 @@
   bool arg5 = false;
   bool arg6 = false;
   std::vector<std::string> arg7;
+  std::vector<std::string> arg8;
   CommandLineOptions opts = CommandLineOptions("test")
                                 .MandatoryOption("--aa", "description-aa", &arg1)
                                 .OptionalFlag("--bb", "description-bb", &arg5)
@@ -179,12 +230,13 @@
                                 .OptionalOption("--dd", "description-dd", &arg3)
                                 .MandatoryOption("--ee", "description-ee", &arg4)
                                 .OptionalFlag("--ff", "description-ff", &arg6)
-                                .MandatoryOption("--gg", "description-gg", &arg7);
+                                .MandatoryOption("--gg", "description-gg", &arg7)
+                                .OptionalOption("--hh", "description-hh", &arg8);
   std::stringstream stream;
   opts.Usage(stream);
   const std::string s = stream.str();
   ASSERT_NE(s.find("usage: test --aa arg [--bb] [--cc arg] [--dd arg] --ee arg [--ff] --gg arg "
-                   "[--gg arg [..]]"),
+                   "[--gg arg [..]] [--hh arg [..]]"),
             std::string::npos);
   ASSERT_NE(s.find("--aa arg    description-aa"), std::string::npos);
   ASSERT_NE(s.find("--ff        description-ff"), std::string::npos);
diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp
index 4bf832a..d9d9a7f 100644
--- a/cmds/idmap2/tests/FileUtilsTests.cpp
+++ b/cmds/idmap2/tests/FileUtilsTests.cpp
@@ -37,10 +37,10 @@
                             [](unsigned char type ATTRIBUTE_UNUSED,
                                const std::string& path ATTRIBUTE_UNUSED) -> bool { return true; });
   ASSERT_THAT(v, NotNull());
-  ASSERT_EQ(v->size(), 4U);
-  ASSERT_EQ(
-      std::set<std::string>(v->begin(), v->end()),
-      std::set<std::string>({root + "/.", root + "/..", root + "/overlay", root + "/target"}));
+  ASSERT_EQ(v->size(), 6U);
+  ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
+            std::set<std::string>({root + "/.", root + "/..", root + "/overlay", root + "/target",
+                                   root + "/system-overlay", root + "/system-overlay-invalid"}));
 }
 
 TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) {
@@ -49,11 +49,13 @@
     return type == DT_REG && path.size() > 4 && path.compare(path.size() - 4, 4, ".apk") == 0;
   });
   ASSERT_THAT(v, NotNull());
-  ASSERT_EQ(v->size(), 4U);
+  ASSERT_EQ(v->size(), 6U);
   ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
             std::set<std::string>({root + "/target/target.apk", root + "/overlay/overlay.apk",
                                    root + "/overlay/overlay-static-1.apk",
-                                   root + "/overlay/overlay-static-2.apk"}));
+                                   root + "/overlay/overlay-static-2.apk",
+                                   root + "/system-overlay/system-overlay.apk",
+                                   root + "/system-overlay-invalid/system-overlay-invalid.apk"}));
 }
 
 TEST(FileUtilsTests, ReadFile) {
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index 22f48e9..0c8f164 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -38,6 +38,7 @@
 #include "gtest/gtest.h"
 
 #include "androidfw/PosixUtils.h"
+
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
 
@@ -114,8 +115,9 @@
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
   ASSERT_NE(result->stdout.find("0x7f010000 -> 0x7f010000 integer/int1"), std::string::npos);
-  ASSERT_NE(result->stdout.find("0x7f020003 -> 0x7f020000 string/str1"), std::string::npos);
-  ASSERT_NE(result->stdout.find("0x7f020005 -> 0x7f020001 string/str3"), std::string::npos);
+  ASSERT_NE(result->stdout.find("0x7f020008 -> 0x7f020000 string/str1"), std::string::npos);
+  ASSERT_NE(result->stdout.find("0x7f02000a -> 0x7f020001 string/str3"), std::string::npos);
+  ASSERT_NE(result->stdout.find("0x7f02000b -> 0x7f020002 string/str4"), std::string::npos);
   ASSERT_EQ(result->stdout.find("00000210:     007f  target package id"), std::string::npos);
 
   // clang-format off
@@ -157,7 +159,8 @@
                                "--recursive",
                                "--target-package-name", "test.target",
                                "--target-apk-path", GetTargetApkPath(),
-                               "--output-directory", GetTempDirPath()});
+                               "--output-directory", GetTempDirPath(),
+                               "--override-policy", "public"});
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -190,7 +193,8 @@
                           "--input-directory", GetTestDataPath() + "/overlay",
                           "--target-package-name", "test.target",
                           "--target-apk-path", GetTargetApkPath(),
-                          "--output-directory", GetTempDirPath()});
+                          "--output-directory", GetTempDirPath(),
+                          "--override-policy", "public"});
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -207,7 +211,8 @@
                           "--recursive",
                           "--target-package-name", "test.target",
                           "--target-apk-path", GetTargetApkPath(),
-                          "--output-directory", GetTempDirPath()});
+                          "--output-directory", GetTempDirPath(),
+                          "--override-policy", "public"});
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -222,7 +227,8 @@
                           "--input-directory", GetTempDirPath(),
                           "--target-package-name", "test.target",
                           "--target-apk-path", GetTargetApkPath(),
-                          "--output-directory", GetTempDirPath()});
+                          "--output-directory", GetTempDirPath(),
+                          "--override-policy", "public"});
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -245,7 +251,7 @@
                           "lookup",
                           "--idmap-path", GetIdmapPath(),
                           "--config", "",
-                          "--resid", "0x7f020003"});  // string/str1
+                          "--resid", "0x7f020008"});  // string/str1
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -310,6 +316,18 @@
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_NE(result->status, EXIT_SUCCESS);
+
+  // unknown policy
+  // clang-format off
+  result = ExecuteBinary({"idmap2",
+                          "create",
+                          "--target-apk-path", GetTargetApkPath(),
+                          "--overlay-apk-path", GetOverlayApkPath(),
+                          "--idmap-path", GetIdmapPath(),
+                          "--policy", "this-does-not-exist"});
+  // clang-format on
+  ASSERT_THAT(result, NotNull());
+  ASSERT_NE(result->status, EXIT_SUCCESS);
 }
 
 }  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 963f22e..c6eb71c 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -184,13 +184,14 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   ASSERT_THAT(idmap->GetHeader(), NotNull());
   ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
   ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x01U);
-  ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xf5ad1d1d);
+  ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xca2093da);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0xd470336b);
   ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
@@ -216,13 +217,127 @@
   ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U);
   ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U);
   ASSERT_EQ(types[1]->GetEntryCount(), 4U);
-  ASSERT_EQ(types[1]->GetEntryOffset(), 3U);
+  ASSERT_EQ(types[1]->GetEntryOffset(), 8U);
   ASSERT_EQ(types[1]->GetEntry(0), 0x0000U);
   ASSERT_EQ(types[1]->GetEntry(1), kNoEntry);
   ASSERT_EQ(types[1]->GetEntry(2), 0x0001U);
   ASSERT_EQ(types[1]->GetEntry(3), 0x0002U);
 }
 
+TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
+  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
+  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+  ASSERT_THAT(target_apk, NotNull());
+
+  const std::string overlay_apk_path(GetTestDataPath() + "/system-overlay/system-overlay.apk");
+  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+  ASSERT_THAT(overlay_apk, NotNull());
+
+  std::stringstream error;
+  std::unique_ptr<const Idmap> idmap =
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+                           /* enforce_overlayable */ true, error);
+  ASSERT_THAT(idmap, NotNull());
+
+  const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+  ASSERT_EQ(dataBlocks.size(), 1U);
+
+  const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+
+  ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+  ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+  const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+  ASSERT_EQ(types.size(), 1U);
+
+  ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+  ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+  ASSERT_EQ(types[0]->GetEntryCount(), 3U);
+  ASSERT_EQ(types[0]->GetEntryOffset(), 5U);
+  ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);  // string/policy_public
+  ASSERT_EQ(types[0]->GetEntry(1), 0x0001U);  // string/policy_system
+  ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);  // string/policy_system_vendor
+}
+
+TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
+  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
+  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+  ASSERT_THAT(target_apk, NotNull());
+
+  const std::string overlay_apk_path(GetTestDataPath() +
+                                     "/system-overlay-invalid/system-overlay-invalid.apk");
+  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+  ASSERT_THAT(overlay_apk, NotNull());
+
+  std::stringstream error;
+  std::unique_ptr<const Idmap> idmap =
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+                           /* enforce_overlayable */ true, error);
+  ASSERT_THAT(idmap, NotNull());
+
+  const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+  ASSERT_EQ(dataBlocks.size(), 1U);
+
+  const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+
+  ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+  ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+  const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+  ASSERT_EQ(types.size(), 1U);
+
+  ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+  ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+  ASSERT_EQ(types[0]->GetEntryCount(), 5U);
+  ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
+  ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);   // string/not_overlayable
+  ASSERT_EQ(types[0]->GetEntry(1), kNoEntry);  // string/policy_product
+  ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);   // string/policy_public
+  ASSERT_EQ(types[0]->GetEntry(3), 0x0003U);   // string/policy_system
+  ASSERT_EQ(types[0]->GetEntry(4), 0x0004U);   // string/policy_system_vendor
+}
+
+TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
+  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
+  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+  ASSERT_THAT(target_apk, NotNull());
+
+  const std::string overlay_apk_path(GetTestDataPath() +
+                                     "/system-overlay-invalid/system-overlay-invalid.apk");
+  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+  ASSERT_THAT(overlay_apk, NotNull());
+
+  std::stringstream error;
+  std::unique_ptr<const Idmap> idmap =
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+                           /* enforce_overlayable */ false, error);
+  ASSERT_THAT(idmap, NotNull());
+
+  const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+  ASSERT_EQ(dataBlocks.size(), 1U);
+
+  const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+
+  ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+  ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+  const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+  ASSERT_EQ(types.size(), 1U);
+
+  ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+  ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+  ASSERT_EQ(types[0]->GetEntryCount(), 5U);
+  ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
+  ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);  // string/not_overlayable
+  ASSERT_EQ(types[0]->GetEntry(1), 0x0001U);  // string/policy_product
+  ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);  // string/policy_public
+  ASSERT_EQ(types[0]->GetEntry(3), 0x0003U);  // string/policy_system
+  ASSERT_EQ(types[0]->GetEntry(4), 0x0004U);  // string/policy_system_vendor
+}
+
 TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) {
   std::string target_apk_path(GetTestDataPath());
   for (int i = 0; i < 32; i++) {
@@ -239,7 +354,8 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, IsNull());
 }
 
@@ -255,8 +371,9 @@
   ASSERT_THAT(overlay_apk, NotNull());
 
   std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+  std::unique_ptr<const Idmap> idmap = Idmap::FromApkAssets(
+      target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+      /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   std::stringstream stream;
diff --git a/cmds/idmap2/tests/PoliciesTests.cpp b/cmds/idmap2/tests/PoliciesTests.cpp
new file mode 100644
index 0000000..ab567ad
--- /dev/null
+++ b/cmds/idmap2/tests/PoliciesTests.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include "gtest/gtest.h"
+
+#include "TestHelpers.h"
+#include "idmap2/Policies.h"
+
+using android::idmap2::PolicyBitmask;
+using android::idmap2::PolicyFlags;
+
+namespace android::idmap2 {
+
+TEST(PoliciesTests, PoliciesToBitmasks) {
+  const Result<PolicyBitmask> bitmask1 = PoliciesToBitmask({"system"}, std::cerr);
+  ASSERT_NE(bitmask1, kResultError);
+  ASSERT_EQ(bitmask1, PolicyFlags::POLICY_SYSTEM_PARTITION);
+
+  const Result<PolicyBitmask> bitmask2 = PoliciesToBitmask({"system", "vendor"}, std::cerr);
+  ASSERT_NE(bitmask2, kResultError);
+  ASSERT_EQ(bitmask2, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
+
+  const Result<PolicyBitmask> bitmask3 = PoliciesToBitmask({"vendor", "system"}, std::cerr);
+  ASSERT_NE(bitmask3, kResultError);
+  ASSERT_EQ(bitmask3, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
+
+  const Result<PolicyBitmask> bitmask4 =
+      PoliciesToBitmask({"public", "product", "system", "vendor"}, std::cerr);
+  ASSERT_NE(bitmask4, kResultError);
+  ASSERT_EQ(bitmask4, PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_PRODUCT_PARTITION |
+                          PolicyFlags::POLICY_SYSTEM_PARTITION |
+                          PolicyFlags::POLICY_VENDOR_PARTITION);
+
+  const Result<PolicyBitmask> bitmask5 =
+      PoliciesToBitmask({"system", "system", "system"}, std::cerr);
+  ASSERT_NE(bitmask5, kResultError);
+  ASSERT_EQ(bitmask5, PolicyFlags::POLICY_SYSTEM_PARTITION);
+
+  const Result<PolicyBitmask> bitmask6 = PoliciesToBitmask({""}, std::cerr);
+  ASSERT_EQ(bitmask6, kResultError);
+
+  const Result<PolicyBitmask> bitmask7 = PoliciesToBitmask({"foo"}, std::cerr);
+  ASSERT_EQ(bitmask7, kResultError);
+
+  const Result<PolicyBitmask> bitmask8 = PoliciesToBitmask({"system", "foo"}, std::cerr);
+  ASSERT_EQ(bitmask8, kResultError);
+
+  const Result<PolicyBitmask> bitmask9 = PoliciesToBitmask({"system", ""}, std::cerr);
+  ASSERT_EQ(bitmask9, kResultError);
+
+  const Result<PolicyBitmask> bitmask10 = PoliciesToBitmask({"system "}, std::cerr);
+  ASSERT_EQ(bitmask10, kResultError);
+}
+
+}  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
index 7736bc0..eaa47cd 100644
--- a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
@@ -25,6 +25,7 @@
 #include "androidfw/Idmap.h"
 
 #include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
 #include "idmap2/PrettyPrintVisitor.h"
 
 #include "TestHelpers.h"
@@ -32,6 +33,7 @@
 using ::testing::NotNull;
 
 using android::ApkAssets;
+using android::idmap2::PolicyBitmask;
 
 namespace android::idmap2 {
 
@@ -46,7 +48,8 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   std::stringstream stream;
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 0318cd2..b58c61a 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -42,7 +42,8 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   std::stringstream stream;
@@ -51,7 +52,7 @@
 
   ASSERT_NE(stream.str().find("00000000: 504d4449  magic\n"), std::string::npos);
   ASSERT_NE(stream.str().find("00000004: 00000001  version\n"), std::string::npos);
-  ASSERT_NE(stream.str().find("00000008: f5ad1d1d  target crc\n"), std::string::npos);
+  ASSERT_NE(stream.str().find("00000008: ca2093da  target crc\n"), std::string::npos);
   ASSERT_NE(stream.str().find("0000000c: d470336b  overlay crc\n"), std::string::npos);
   ASSERT_NE(stream.str().find("0000021c: 00000000  0x7f010000 -> 0x7f010000 integer/int1\n"),
             std::string::npos);
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
new file mode 100644
index 0000000..977cd97
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="test.overlay.system.invalid">
+    <overlay
+        android:targetPackage="test.target" />
+</manifest>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/build b/cmds/idmap2/tests/data/system-overlay-invalid/build
new file mode 100644
index 0000000..920e1f8
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/build
@@ -0,0 +1,26 @@
+# 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.
+
+FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
+
+aapt2 compile --dir res -o compiled.flata
+
+aapt2 link \
+    --no-resource-removal \
+    -I "$FRAMEWORK_RES_APK" \
+    --manifest AndroidManifest.xml \
+    -o system-overlay-invalid.apk \
+    compiled.flata
+
+rm compiled.flata
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
new file mode 100644
index 0000000..5127707
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <!-- This overlay will fulfill the policies "public|system". This allows it overlay the
+         following resources. -->
+    <string name="policy_system">policy_system</string>
+    <string name="policy_system_vendor">policy_system_vendor</string>
+    <string name="policy_public">policy_public</string>
+
+    <!-- It also requests to overlay a resource that belongs to a policy the overlay does not
+         fulfill.-->
+    <string name="policy_product">policy_product</string>
+
+    <!-- It also requests to overlay a resource that is not declared as overlayable.-->
+    <string name="not_overlayable">not_overlayable</string>
+</resources>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
new file mode 100644
index 0000000..c367f82
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
new file mode 100644
index 0000000..8af9064
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        package="test.overlay.system">
+    <overlay
+            android:targetPackage="test.target" />
+</manifest>
diff --git a/cmds/idmap2/tests/data/system-overlay/build b/cmds/idmap2/tests/data/system-overlay/build
new file mode 100644
index 0000000..be0d239
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/build
@@ -0,0 +1,26 @@
+# 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.
+
+FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
+
+aapt2 compile --dir res -o compiled.flata
+
+aapt2 link \
+    --no-resource-removal \
+    -I "$FRAMEWORK_RES_APK" \
+    --manifest AndroidManifest.xml \
+    -o system-overlay.apk \
+    compiled.flata
+
+rm compiled.flata
diff --git a/cmds/idmap2/tests/data/system-overlay/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay/res/values/values.xml
new file mode 100644
index 0000000..6aaa0b0
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/res/values/values.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <!-- This overlay will fulfill the policies "public|system". This allows it overlay the
+     following resources. -->
+    <string name="policy_system">policy_system</string>
+    <string name="policy_system_vendor">policy_system_vendor</string>
+    <string name="policy_public">policy_public</string>
+</resources>
diff --git a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
new file mode 100644
index 0000000..90f30eb
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
new file mode 100644
index 0000000..de19e6f
--- /dev/null
+++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+<overlayable name="TestResources">
+    <!-- Publicly overlayable resources -->
+    <item type="string" name="a" />
+    <item type="string" name="b" />
+    <item type="string" name="c" />
+    <item type="string" name="str1" />
+    <item type="string" name="str2" />
+    <item type="string" name="str3" />
+    <item type="string" name="str4" />
+    <item type="string" name="x" />
+    <item type="string" name="y" />
+    <item type="string" name="z" />
+    <item type="integer" name="int1" />
+
+    <!-- Resources with partition restrictins -->
+    <policy type="system">
+        <item type="string" name="policy_system" />
+    </policy>
+
+    <policy type="system|vendor">
+        <item type="string" name="policy_system_vendor" />
+    </policy>
+
+    <policy type="product">
+        <item type="string" name="policy_product" />
+    </policy>
+
+    <policy type="public">
+        <item type="string" name="policy_public" />
+    </policy>
+</overlayable>
+</resources>
\ No newline at end of file
diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml
index 56bf0d6..ef9012e 100644
--- a/cmds/idmap2/tests/data/target/res/values/values.xml
+++ b/cmds/idmap2/tests/data/target/res/values/values.xml
@@ -25,4 +25,12 @@
     <string name="y">y</string>
     <string name="z">z</string>
     <integer name="int1">1</integer>
+
+    <!-- This resources is not marked as overlayable -->
+    <string name="not_overlayable">not_overlayable</string>
+
+    <string name="policy_system">policy_system</string>
+    <string name="policy_system_vendor">policy_system_vendor</string>
+    <string name="policy_product">policy_product</string>
+    <string name="policy_public">policy_public</string>
 </resources>
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index 18ecc27..9a6220d 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 8fa2980..3d74f8b 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -81,8 +81,7 @@
         case ui::Dataspace::V0_SRGB:
             return SkColorSpace::MakeSRGB();
         case ui::Dataspace::DISPLAY_P3:
-            return SkColorSpace::MakeRGB(
-                    SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kDCIP3_D65_Gamut);
+            return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
         default:
             return nullptr;
     }
diff --git a/cmds/statsd/src/anomaly/subscriber_util.cpp b/cmds/statsd/src/anomaly/subscriber_util.cpp
index 9d37cdb..ad5eae3 100644
--- a/cmds/statsd/src/anomaly/subscriber_util.cpp
+++ b/cmds/statsd/src/anomaly/subscriber_util.cpp
@@ -57,7 +57,7 @@
                 break;
             case Subscription::SubscriberInformationCase::kPerfettoDetails:
                 if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details(),
-                                                            rule_id, configKey)) {
+                                                            subscription.id(), rule_id, configKey)) {
                     ALOGW("Failed to generate perfetto traces.");
                 }
                 break;
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 6267ac2f..0a8746a 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -25,6 +25,8 @@
 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/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/net/networkcapabilities.proto";
 import "frameworks/base/core/proto/android/os/enums.proto";
 import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto";
@@ -181,6 +183,11 @@
         DocsUISearchTypeReported docs_ui_search_type_reported = 120;
         DataStallEvent data_stall_event = 121;
         RescuePartyResetReported rescue_party_reset_reported = 122;
+        SignedConfigReported signed_config_reported = 123;
+        GnssNiEventReported gnss_ni_event_reported = 124;
+        BluetoothLinkLayerConnectionEvent bluetooth_link_layer_connection_event = 125;
+        BluetoothAclConnectionStateChanged bluetooth_acl_connection_state_changed = 126;
+        BluetoothScoConnectionStateChanged bluetooth_sco_connection_state_changed = 127;
     }
 
     // Pulled events will start at field 10000.
@@ -1296,10 +1303,12 @@
 }
 
 /**
- * Logs when a Bluetooth device connects and disconnects.
+ * Logs when profiles on a Bluetooth device connects and disconnects.
  *
  * Logged from:
- *    packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterProperties.java
+ *    packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java
+ *
+ * Next Tag: 5
  */
 message BluetoothConnectionStateChanged {
     // The state of the connection.
@@ -1308,13 +1317,152 @@
     // An identifier that can be used to match connect and disconnect events.
     // Currently is last two bytes of a hash of a device level ID and
     // the mac address of the bluetooth device that is connected.
-    optional int32 obfuscated_id = 2;
+    // Deprecated: use obfuscated_id instead, this one is always 0 for Q+
+    optional int32 OBSOLETE_obfuscated_id = 2 [deprecated = true];
     // The profile that is connected. Eg. GATT, A2DP, HEADSET.
     // From android.bluetooth.BluetoothAdapter.java
+    // Default: 0 when not used
     optional int32 bt_profile = 3;
+    // 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 = 4 [(android.os.statsd.log_mode) = MODE_BYTES];
 }
 
 /**
+ * Logs when a Bluetooth device connects and disconnects over ACL
+ *
+ * Logged from:
+ *    packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterProperties.java
+ *
+ * Next Tag: 3
+ */
+message BluetoothAclConnectionStateChanged {
+    // 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];
+    // The state of the connection.
+    // Eg: CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED.
+    optional android.bluetooth.ConnectionStateEnum state = 2;
+}
+
+/**
+ * Logs when a Bluetooth device connects and disconnects over SCO
+ *
+ * Logged from:
+ *    packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+ *    packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetClientStateMachine.java
+ *
+ * Next Tag: 4
+ */
+message BluetoothScoConnectionStateChanged {
+    // 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];
+    // The state of the connection.
+    // Eg: CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED.
+    optional android.bluetooth.ConnectionStateEnum state = 2;
+    // Codec used for this SCO connection
+    // Default: UNKNOWN
+    optional android.bluetooth.hfp.ScoCodec codec = 3;
+}
+
+// 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
+// - HCI commands are logged before the command is sent, after receiving command status, and after
+//   receiving command complete
+// - HCI events are logged when they arrive
+//
+// Low level log from system/bt
+//
+// Bluetooth classic commands:
+// - CMD_CREATE_CONNECTION
+// - CMD_DISCONNECT
+// - CMD_CREATE_CONNECTION_CANCEL
+// - CMD_ACCEPT_CONNECTION_REQUEST
+// - CMD_REJECT_CONNECTION_REQUEST
+// - CMD_SETUP_ESCO_CONNECTION
+// - CMD_ACCEPT_ESCO_CONNECTION
+// - CMD_REJECT_ESCO_CONNECTION
+// - CMD_ENH_SETUP_ESCO_CONNECTION
+// - CMD_ENH_ACCEPT_ESCO_CONNECTION
+//
+// Bluetooth low energy commands:
+// - CMD_BLE_CREATE_LL_CONN [Only logged on error or when initiator filter policy is 0x00]
+// - CMD_BLE_CREATE_CONN_CANCEL [Only logged when there is an error]
+// - CMD_BLE_EXTENDED_CREATE_CONNECTION [Only logged on error or when initiator filter policy is 0x00]
+// - CMD_BLE_CLEAR_WHITE_LIST
+// - CMD_BLE_ADD_WHITE_LIST
+// - CMD_BLE_REMOVE_WHITE_LIST
+//
+// Bluetooth classic events:
+// - EVT_CONNECTION_COMP
+// - EVT_CONNECTION_REQUEST
+// - EVT_DISCONNECTION_COMP
+// - EVT_ESCO_CONNECTION_COMP
+// - EVT_ESCO_CONNECTION_CHANGED
+//
+// Bluetooth low energy meta events:
+// - BLE_EVT_CONN_COMPLETE_EVT
+// - BLE_EVT_ENHANCED_CONN_COMPLETE_EVT
+//
+// Next tag: 10
+message BluetoothLinkLayerConnectionEvent {
+    // 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;
+    // Direction of the link
+    // Default: DIRECTION_UNKNOWN
+    optional android.bluetooth.DirectionEnum direction = 3;
+    // Type of this link
+    // Default: LINK_TYPE_UNKNOWN
+    optional android.bluetooth.LinkTypeEnum type = 4;
+
+    // Reason metadata for this link layer connection event, rules for interpretation:
+    // 1. If hci_cmd is set and valid, hci_event can be either EVT_COMMAND_STATUS or
+    //    EVT_COMMAND_COMPLETE, ignore hci_ble_event in this case
+    // 2. If hci_event is set to EVT_BLE_META, look at hci_ble_event; otherwise, if hci_event is
+    //    set and valid, ignore hci_ble_event
+
+    // HCI command associated with this event
+    // Default: CMD_UNKNOWN
+    optional android.bluetooth.hci.CommandEnum hci_cmd = 5;
+    // HCI event associated with this event
+    // Default: EVT_UNKNOWN
+    optional android.bluetooth.hci.EventEnum hci_event = 6;
+    // HCI BLE meta event associated with this event
+    // Default: BLE_EVT_UNKNOWN
+    optional android.bluetooth.hci.BleMetaEventEnum hci_ble_event = 7;
+    // HCI command status code if this is triggerred by hci_cmd
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum cmd_status = 8;
+    // HCI reason code associated with this event
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum reason_code = 9;
+}
+
+
+/**
  * Logs when something is plugged into or removed from the USB-C connector.
  *
  * Logged from:
@@ -3183,7 +3331,8 @@
     optional int32 process_uid = 1;
     // Process name.
     optional string process_name = 2;
-
+    // Package name.
+    optional string package_name = 7;
     // Total count of the times this association appeared.
     optional int32 total_count = 3;
 
@@ -3262,6 +3411,9 @@
     }
     repeated Status status = 7;
 
+    // Number of pages available of various types and sizes, representation fragmentation.
+    repeated ProcessStatsAvailablePagesProto available_pages = 10;
+
     // Stats for each process.
     repeated ProcessStatsProto process_stats = 8;
 
@@ -3269,6 +3421,21 @@
     repeated ProcessStatsPackageProto package_stats = 9;
 }
 
+message ProcessStatsAvailablePagesProto {
+    // Node these pages are in (as per /proc/pagetypeinfo)
+    optional int32 node = 1;
+
+    // Zone these pages are in (as per /proc/pagetypeinfo)
+    optional string zone = 2;
+
+    // Label for the type of these pages (as per /proc/pagetypeinfo)
+    optional string label = 3;
+
+    // Distribution of number of pages available by order size.  First entry in array is
+    // order 0, second is order 1, etc.  Each order increase is a doubling of page size.
+    repeated int32 pages_per_order = 4;
+}
+
 /**
  * Pulled from ProcessStatsService.java
  */
@@ -3859,3 +4026,105 @@
     // The rescue level of this reset. A value of 0 indicates missing or unknown level information.
     optional int32 rescue_level = 1;
 }
+
+/**
+ * Logs when signed config is received from an APK, and if that config was applied successfully.
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/signedconfig/SignedConfigService.java
+ */
+message SignedConfigReported {
+    enum Type {
+        UNKNOWN_TYPE = 0;
+        GLOBAL_SETTINGS = 1;
+    }
+    optional Type type = 1;
+
+    // The final status of the signed config received.
+    enum Status {
+        UNKNOWN_STATUS = 0;
+        APPLIED = 1;
+        BASE64_FAILURE_CONFIG = 2;
+        BASE64_FAILURE_SIGNATURE = 3;
+        SECURITY_EXCEPTION = 4;
+        INVALID_CONFIG = 5;
+        OLD_CONFIG = 6;
+        SIGNATURE_CHECK_FAILED = 7;
+        NOT_APPLICABLE = 8;
+        SIGNATURE_CHECK_FAILED_PROD_KEY_ABSENT = 9;
+    }
+    optional Status status = 2;
+
+    // The version of the signed config processed.
+    optional int32 version = 3;
+
+    // The package name that the config was extracted from.
+    optional string from_package = 4;
+
+    enum Key {
+        NO_KEY = 0;
+        DEBUG = 1;
+        PRODUCTION = 2;
+    }
+    // Which key was used to verify the config.
+    optional Key verified_with = 5;
+}
+
+/*
+ * Logs GNSS Network-Initiated (NI) location events.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/location/GnssLocationProvider.java
+ */
+message GnssNiEventReported {
+    // The type of GnssNiEvent.
+    enum EventType {
+        UNKNOWN = 0;
+        NI_REQUEST = 1;
+        NI_RESPONSE = 2;
+    }
+    optional EventType event_type = 1;
+
+    // An ID generated by HAL to associate NI notifications and UI responses.
+    optional int32 notification_id = 2;
+
+    // A type which distinguishes different categories of NI request, such as VOICE, UMTS_SUPL etc.
+    optional int32 ni_type = 3;
+
+    // NI requires notification.
+    optional bool need_notify = 4;
+
+    // NI requires verification.
+    optional bool need_verify = 5;
+
+    // NI requires privacy override, no notification/minimal trace.
+    optional bool privacy_override = 6;
+
+    // Timeout period to wait for user response. Set to 0 for no timeout limit. Specified in
+    // seconds.
+    optional int32 timeout = 7;
+
+    // Default response when timeout.
+    optional int32 default_response = 8;
+
+    // String representing the requester of the network inititated location request.
+    optional string requestor_id = 9;
+
+    // Notification message text string representing the service(for eg. SUPL-service) who sent the
+    // network initiated location request.
+    optional string text = 10;
+
+    // requestorId decoding scheme.
+    optional int32 requestor_id_encoding = 11;
+
+    // Notification message text decoding scheme.
+    optional int32 text_encoding = 12;
+
+    // True if SUPL ES is enabled.
+    optional bool is_supl_es_enabled = 13;
+
+    // True if GNSS location is enabled.
+    optional bool is_location_enabled = 14;
+
+    // GNSS NI responses which define the response in NI structures.
+    optional int32 user_response = 15;
+}
diff --git a/cmds/statsd/src/external/Perfetto.cpp b/cmds/statsd/src/external/Perfetto.cpp
index 42cc543..0c4c330 100644
--- a/cmds/statsd/src/external/Perfetto.cpp
+++ b/cmds/statsd/src/external/Perfetto.cpp
@@ -39,6 +39,7 @@
 namespace statsd {
 
 bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config,
+                                            int64_t subscription_id,
                                             int64_t alert_id,
                                             const ConfigKey& configKey) {
     VLOG("Starting trace collection through perfetto");
@@ -48,9 +49,11 @@
         return false;
     }
 
-    char alertId[20];
-    char configId[20];
-    char configUid[20];
+    char subscriptionId[25];
+    char alertId[25];
+    char configId[25];
+    char configUid[25];
+    snprintf(subscriptionId, sizeof(subscriptionId), "%" PRId64, subscription_id);
     snprintf(alertId, sizeof(alertId), "%" PRId64, alert_id);
     snprintf(configId, sizeof(configId), "%" PRId64, configKey.GetId());
     snprintf(configUid, sizeof(configUid), "%d", configKey.GetUid());
@@ -94,7 +97,7 @@
 
         execl("/system/bin/perfetto", "perfetto", "--background", "--config", "-", "--dropbox",
               kDropboxTag, "--alert-id", alertId, "--config-id", configId, "--config-uid",
-              configUid, nullptr);
+              configUid, "--subscription-id", subscriptionId, nullptr);
 
         // execl() doesn't return in case of success, if we get here something
         // failed.
diff --git a/cmds/statsd/src/external/Perfetto.h b/cmds/statsd/src/external/Perfetto.h
index 1e7f728..ab2c195 100644
--- a/cmds/statsd/src/external/Perfetto.h
+++ b/cmds/statsd/src/external/Perfetto.h
@@ -32,6 +32,7 @@
 // This method returns immediately after passing the config and does NOT wait
 // for the full duration of the trace.
 bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config,
+                                            int64_t subscription_id,
                                             int64_t alert_id,
                                             const ConfigKey& configKey);
 
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 4d3c5d1..02eff0b 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -1108,18 +1108,6 @@
 Landroid/os/UserManager;->mService:Landroid/os/IUserManager;
 Landroid/os/UserManager;->removeUser(I)Z
 Landroid/os/Vibrator;-><init>()V
-Landroid/os/VintfObject;->getHalNamesAndVersions()[Ljava/lang/String;
-Landroid/os/VintfObject;->getSepolicyVersion()Ljava/lang/String;
-Landroid/os/VintfObject;->getTargetFrameworkCompatibilityMatrixVersion()Ljava/lang/Long;
-Landroid/os/VintfObject;->getVndkSnapshots()Ljava/util/Map;
-Landroid/os/VintfObject;->report()[Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getCpuInfo()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getHardwareId()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getKernelVersion()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getNodeName()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getOsName()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getOsRelease()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getOsVersion()Ljava/lang/String;
 Landroid/os/WorkSource;-><init>(Landroid/os/Parcel;)V
 Landroid/os/WorkSource;->mNames:[Ljava/lang/String;
 Landroid/os/WorkSource;->mNum:I
@@ -1492,7 +1480,6 @@
 Landroid/test/AndroidTestCase;->getTestContext()Landroid/content/Context;
 Landroid/test/AndroidTestCase;->setTestContext(Landroid/content/Context;)V
 Landroid/test/InstrumentationTestCase;->runMethod(Ljava/lang/reflect/Method;I)V
-Landroid/test/RepetitiveTest;->numIterations()I
 Landroid/util/Singleton;-><init>()V
 Landroid/util/XmlPullAttributes;-><init>(Lorg/xmlpull/v1/XmlPullParser;)V
 Landroid/util/XmlPullAttributes;->mParser:Lorg/xmlpull/v1/XmlPullParser;
@@ -1825,22 +1812,10 @@
 Lcom/android/internal/os/RuntimeInit;->initialized:Z
 Lcom/android/internal/os/RuntimeInit;->main([Ljava/lang/String;)V
 Lcom/android/internal/os/RuntimeInit;->mApplicationObject:Landroid/os/IBinder;
-Lcom/android/internal/os/ZygoteConnection$Arguments;-><init>([Ljava/lang/String;)V
-Lcom/android/internal/os/ZygoteConnection$Arguments;->effectiveCapabilities:J
-Lcom/android/internal/os/ZygoteConnection$Arguments;->gid:I
-Lcom/android/internal/os/ZygoteConnection$Arguments;->gids:[I
-Lcom/android/internal/os/ZygoteConnection$Arguments;->permittedCapabilities:J
-Lcom/android/internal/os/ZygoteConnection$Arguments;->remainingArgs:[Ljava/lang/String;
-Lcom/android/internal/os/ZygoteConnection$Arguments;->rlimits:Ljava/util/ArrayList;
-Lcom/android/internal/os/ZygoteConnection$Arguments;->uid:I
-Lcom/android/internal/os/ZygoteConnection;->applyUidSecurityPolicy(Lcom/android/internal/os/ZygoteConnection$Arguments;Landroid/net/Credentials;)V
 Lcom/android/internal/os/ZygoteConnection;->closeSocket()V
-Lcom/android/internal/os/ZygoteConnection;->getFileDesciptor()Ljava/io/FileDescriptor;
-Lcom/android/internal/os/ZygoteConnection;->intArray2d:[[I
 Lcom/android/internal/os/ZygoteConnection;->mSocket:Landroid/net/LocalSocket;
 Lcom/android/internal/os/ZygoteConnection;->mSocketOutStream:Ljava/io/DataOutputStream;
 Lcom/android/internal/os/ZygoteConnection;->peer:Landroid/net/Credentials;
-Lcom/android/internal/os/ZygoteConnection;->readArgumentList()[Ljava/lang/String;
 Lcom/android/internal/os/ZygoteInit;->main([Ljava/lang/String;)V
 Lcom/android/internal/os/ZygoteInit;->mResources:Landroid/content/res/Resources;
 Lcom/android/internal/os/ZygoteSecurityException;-><init>(Ljava/lang/String;)V
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 98c5a0fb..836627e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.os.Process.myUid;
 
 import static java.lang.Character.MIN_VALUE;
 
@@ -123,6 +124,7 @@
 import android.view.autofill.IAutofillWindowPresenter;
 import android.view.contentcapture.ContentCaptureContext;
 import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.ContentCaptureSession;
 import android.widget.AdapterView;
 import android.widget.Toast;
 import android.widget.Toolbar;
@@ -1025,7 +1027,7 @@
      */
     @Nullable private ContentCaptureManager getContentCaptureManager() {
         // ContextCapture disabled for system apps
-        if (getApplicationInfo().isSystemApp()) return null;
+        if (!UserHandle.isApp(myUid())) return null;
         if (mContentCaptureManager == null) {
             mContentCaptureManager = getSystemService(ContentCaptureManager.class);
         }
@@ -1033,13 +1035,15 @@
     }
 
     /** @hide */ private static final int CONTENT_CAPTURE_START = 1;
-    /** @hide */ private static final int CONTENT_CAPTURE_FLUSH = 2;
-    /** @hide */ private static final int CONTENT_CAPTURE_STOP = 3;
+    /** @hide */ private static final int CONTENT_CAPTURE_PAUSE = 2;
+    /** @hide */ private static final int CONTENT_CAPTURE_RESUME = 3;
+    /** @hide */ private static final int CONTENT_CAPTURE_STOP = 4;
 
     /** @hide */
     @IntDef(prefix = { "CONTENT_CAPTURE_" }, value = {
             CONTENT_CAPTURE_START,
-            CONTENT_CAPTURE_FLUSH,
+            CONTENT_CAPTURE_PAUSE,
+            CONTENT_CAPTURE_RESUME,
             CONTENT_CAPTURE_STOP
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -1048,9 +1052,8 @@
 
     private void notifyContentCaptureManagerIfNeeded(@ContentCaptureNotificationType int type) {
         final ContentCaptureManager cm = getContentCaptureManager();
-        if (cm == null) {
-            return;
-        }
+        if (cm == null) return;
+
         switch (type) {
             case CONTENT_CAPTURE_START:
                 //TODO(b/111276913): decide whether the InteractionSessionId should be
@@ -1062,8 +1065,11 @@
                 }
                 cm.onActivityStarted(mToken, getComponentName(), flags);
                 break;
-            case CONTENT_CAPTURE_FLUSH:
-                cm.flush();
+            case CONTENT_CAPTURE_PAUSE:
+                cm.flush(ContentCaptureSession.FLUSH_REASON_ACTIVITY_PAUSED);
+                break;
+            case CONTENT_CAPTURE_RESUME:
+                cm.flush(ContentCaptureSession.FLUSH_REASON_ACTIVITY_RESUMED);
                 break;
             case CONTENT_CAPTURE_STOP:
                 cm.onActivityStopped();
@@ -1755,7 +1761,7 @@
             }
         }
         mCalled = true;
-        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_FLUSH);
+        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_RESUME);
     }
 
     /**
@@ -2149,7 +2155,7 @@
             }
         }
         mCalled = true;
-        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_FLUSH);
+        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_PAUSE);
     }
 
     /**
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d423260..e0b8d78 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3705,11 +3705,16 @@
      * Returns whether switching to provided user was successful.
      *
      * @param user the user to switch to.
+     *
+     * @throws IllegalArgumentException if the user is null.
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
-    public boolean switchUser(UserHandle user) {
+    public boolean switchUser(@NonNull UserHandle user) {
+        if (user == null) {
+            throw new IllegalArgumentException("UserHandle cannot be null.");
+        }
         return switchUser(user.getIdentifier());
     }
 
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index c90e404..5cac048 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -317,4 +317,13 @@
 
     /** Returns true if the given uid is the app in the foreground. */
     public abstract boolean isAppForeground(int uid);
+
+    /** Remove pending backup for the given userId. */
+    public abstract void clearPendingBackup(int userId);
+
+    /**
+     * When power button is very long pressed, call this interface to do some pre-shutdown work
+     * like persisting database etc.
+     */
+    public abstract void prepareForPossibleShutdown();
 }
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 57132a7..ab8f234 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -16,6 +16,10 @@
 
 package android.app;
 
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+
 import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager.StackInfo;
@@ -32,7 +36,6 @@
 import android.view.IWindowManager;
 import android.view.InputDevice;
 import android.view.MotionEvent;
-import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceHolder;
 import android.view.SurfaceSession;
@@ -82,7 +85,6 @@
     private boolean mOpened; // Protected by mGuard.
 
     private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
-    private Surface mTmpSurface = new Surface();
 
     /** The ActivityView is only allowed to contain one task. */
     private final boolean mSingleTaskInstance;
@@ -319,20 +321,20 @@
     private class SurfaceCallback implements SurfaceHolder.Callback {
         @Override
         public void surfaceCreated(SurfaceHolder surfaceHolder) {
-            mTmpSurface = new Surface();
             if (mVirtualDisplay == null) {
                 initVirtualDisplay(new SurfaceSession());
                 if (mVirtualDisplay != null && mActivityViewCallback != null) {
                     mActivityViewCallback.onActivityViewReady(ActivityView.this);
                 }
             } else {
-                // TODO (b/119209373): DisplayManager determines if a VirtualDisplay is on by
-                // whether it has a surface. Setting a fake surface here so DisplayManager will
-                // consider this display on.
-                mVirtualDisplay.setSurface(mTmpSurface);
                 mTmpTransaction.reparent(mRootSurfaceControl,
                         mSurfaceView.getSurfaceControl().getHandle()).apply();
             }
+
+            if (mVirtualDisplay != null) {
+                mVirtualDisplay.setDisplayState(true);
+            }
+
             updateLocation();
         }
 
@@ -346,10 +348,8 @@
 
         @Override
         public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
-            mTmpSurface.release();
-            mTmpSurface = null;
             if (mVirtualDisplay != null) {
-                mVirtualDisplay.setSurface(null);
+                mVirtualDisplay.setDisplayState(false);
             }
             cleanTapExcludeRegion();
         }
@@ -370,15 +370,11 @@
         final int height = mSurfaceView.getHeight();
         final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
 
-        // TODO (b/119209373): DisplayManager determines if a VirtualDisplay is on by
-        // whether it has a surface. Setting a fake surface here so DisplayManager will consider
-        // this display on.
         mVirtualDisplay = displayManager.createVirtualDisplay(
-                DISPLAY_NAME + "@" + System.identityHashCode(this),
-                width, height, getBaseDisplayDensity(), mTmpSurface,
-                DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
-                        | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
-                        | DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL);
+                DISPLAY_NAME + "@" + System.identityHashCode(this), width, height,
+                getBaseDisplayDensity(), null,
+                VIRTUAL_DISPLAY_FLAG_PUBLIC | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+                        | VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL);
         if (mVirtualDisplay == null) {
             Log.e(TAG, "Failed to initialize ActivityView");
             return;
@@ -443,11 +439,6 @@
             displayReleased = false;
         }
 
-        if (mTmpSurface != null) {
-            mTmpSurface.release();
-            mTmpSurface = null;
-        }
-
         if (displayReleased && mActivityViewCallback != null) {
             mActivityViewCallback.onActivityViewDestroyed(this);
         }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 347973e..fb65da1 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -317,7 +317,6 @@
      */
     void requestWifiBugReport(in String shareTitle, in String shareDescription);
 
-    void clearPendingBackup();
     Intent getIntentForIntentSender(in IIntentSender sender);
     // This is not public because you need to be very careful in how you
     // manage your activity to make sure it is always the uid you expect.
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 163be8e..199c133 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -65,9 +65,9 @@
     boolean areNotificationsEnabled(String pkg);
     int getPackageImportance(String pkg);
 
-    void setAppOverlaysAllowed(String pkg, int uid, boolean allowed);
-    boolean areAppOverlaysAllowed(String pkg);
-    boolean areAppOverlaysAllowedForPackage(String pkg, int uid);
+    void setBubblesAllowed(String pkg, int uid, boolean allowed);
+    boolean areBubblesAllowed(String pkg);
+    boolean areBubblesAllowedForPackage(String pkg, int uid);
 
     void createNotificationChannelGroups(String pkg, in ParceledListSlice channelGroupList);
     void createNotificationChannels(String pkg, in ParceledListSlice channelsList);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b657a91..72819cb 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1276,7 +1276,7 @@
     private String mShortcutId;
     private CharSequence mSettingsText;
 
-    private PendingIntent mAppOverlayIntent;
+    private BubbleMetadata mBubbleMetadata;
 
     /** @hide */
     @IntDef(prefix = { "GROUP_ALERT_" }, value = {
@@ -2278,7 +2278,7 @@
 
         mGroupAlertBehavior = parcel.readInt();
         if (parcel.readInt() != 0) {
-            mAppOverlayIntent = PendingIntent.CREATOR.createFromParcel(parcel);
+            mBubbleMetadata = BubbleMetadata.CREATOR.createFromParcel(parcel);
         }
 
         mAllowSystemGeneratedContextualActions = parcel.readBoolean();
@@ -2396,7 +2396,7 @@
         that.mBadgeIcon = this.mBadgeIcon;
         that.mSettingsText = this.mSettingsText;
         that.mGroupAlertBehavior = this.mGroupAlertBehavior;
-        that.mAppOverlayIntent = this.mAppOverlayIntent;
+        that.mBubbleMetadata = this.mBubbleMetadata;
         that.mAllowSystemGeneratedContextualActions = this.mAllowSystemGeneratedContextualActions;
 
         if (!heavy) {
@@ -2719,9 +2719,9 @@
 
         parcel.writeInt(mGroupAlertBehavior);
 
-        if (mAppOverlayIntent != null) {
+        if (mBubbleMetadata != null) {
             parcel.writeInt(1);
-            mAppOverlayIntent.writeToParcel(parcel, 0);
+            mBubbleMetadata.writeToParcel(parcel, 0);
         } else {
             parcel.writeInt(0);
         }
@@ -3141,11 +3141,11 @@
     }
 
     /**
-     * Returns the intent that will be used to display app content in a floating window over the
-     * existing foreground activity.
+     * Returns the bubble metadata that will be used to display app content in a floating window
+     * over the existing foreground activity.
      */
-    public PendingIntent getAppOverlayIntent() {
-        return mAppOverlayIntent;
+    public BubbleMetadata getBubbleMetadata() {
+        return mBubbleMetadata;
     }
 
     /**
@@ -3508,19 +3508,18 @@
         }
 
         /**
-         * Sets the intent that will be used to display app content in a floating window
-         * over the existing foreground activity.
+         * Sets the {@link BubbleMetadata} that will be used to display app content in a floating
+         * window over the existing foreground activity.
          *
-         * <p>This intent will be ignored unless this notification is posted to a channel that
-         * allows {@link NotificationChannel#canOverlayApps() app overlays}.</p>
+         * <p>This data will be ignored unless the notification is posted to a channel that
+         * allows {@link NotificationChannel#canBubble() bubbles}.</p>
          *
-         * <p>Notifications with a valid and allowed app overlay intent will be displayed as
-         * floating windows outside of the notification shade on unlocked devices. When a user
-         * interacts with one of these windows, this app overlay intent will be invoked and
-         * displayed.</p>
+         * <b>Notifications with a valid and allowed bubble metadata will display in collapsed state
+         * outside of the notification shade on unlocked devices. When a user interacts with the
+         * collapsed state, the bubble intent will be invoked and displayed.</b>
          */
-        public Builder setAppOverlayIntent(PendingIntent intent) {
-            mN.mAppOverlayIntent = intent;
+        public Builder setBubbleMetadata(BubbleMetadata data) {
+            mN.mBubbleMetadata = data;
             return this;
         }
 
@@ -8422,6 +8421,186 @@
         }
     }
 
+    /**
+     * Encapsulates the information needed to display a notification as a bubble.
+     *
+     * <p>A bubble is used to display app content in a floating window over the existing
+     * foreground activity. A bubble has a collapsed state represented by an icon,
+     * {@link BubbleMetadata.Builder#setIcon(Icon)} and an expanded state which is populated
+     * via {@link BubbleMetadata.Builder#setIntent(PendingIntent)}.</p>
+     *
+     * <b>Notifications with a valid and allowed bubble will display in collapsed state
+     * outside of the notification shade on unlocked devices. When a user interacts with the
+     * collapsed bubble, the bubble intent will be invoked and displayed.</b>
+     *
+     * @see Notification.Builder#setBubbleMetadata(BubbleMetadata)
+     */
+    public static final class BubbleMetadata implements Parcelable {
+
+        private PendingIntent mPendingIntent;
+        private CharSequence mTitle;
+        private Icon mIcon;
+        private int mDesiredHeight;
+
+        private BubbleMetadata(PendingIntent intent, CharSequence title, Icon icon, int height) {
+            mPendingIntent = intent;
+            mTitle = title;
+            mIcon = icon;
+            mDesiredHeight = height;
+        }
+
+        private BubbleMetadata(Parcel in) {
+            mPendingIntent = PendingIntent.CREATOR.createFromParcel(in);
+            mTitle = in.readCharSequence();
+            mIcon = Icon.CREATOR.createFromParcel(in);
+            mDesiredHeight = in.readInt();
+        }
+
+        /**
+         * @return the pending intent used to populate the floating window for this bubble.
+         */
+        public PendingIntent getIntent() {
+            return mPendingIntent;
+        }
+
+        /**
+         * @return the title that will appear along with the app content defined by
+         * {@link #getIntent()} for this bubble.
+         */
+        public CharSequence getTitle() {
+            return mTitle;
+        }
+
+        /**
+         * @return the icon that will be displayed for this bubble when it is collapsed.
+         */
+        public Icon getIcon() {
+            return mIcon;
+        }
+
+        /**
+         * @return the ideal height for the floating window that app content defined by
+         * {@link #getIntent()} for this bubble.
+         */
+        public int getDesiredHeight() {
+            return mDesiredHeight;
+        }
+
+        public static final Parcelable.Creator<BubbleMetadata> CREATOR =
+                new Parcelable.Creator<BubbleMetadata>() {
+
+                    @Override
+                    public BubbleMetadata createFromParcel(Parcel source) {
+                        return new BubbleMetadata(source);
+                    }
+
+                    @Override
+                    public BubbleMetadata[] newArray(int size) {
+                        return new BubbleMetadata[size];
+                    }
+                };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            mPendingIntent.writeToParcel(out, 0);
+            out.writeCharSequence(mTitle);
+            mIcon.writeToParcel(out, 0);
+            out.writeInt(mDesiredHeight);
+        }
+
+        /**
+         * Builder to construct a {@link BubbleMetadata} object.
+         */
+        public static class Builder {
+
+            private PendingIntent mPendingIntent;
+            private CharSequence mTitle;
+            private Icon mIcon;
+            private int mDesiredHeight;
+
+            /**
+             * Constructs a new builder object.
+             */
+            public Builder() {
+            }
+
+            /**
+             * Sets the intent that will be used when the bubble is expanded. This will display the
+             * app content in a floating window over the existing foreground activity.
+             */
+            public BubbleMetadata.Builder setIntent(PendingIntent intent) {
+                if (intent == null) {
+                    throw new IllegalArgumentException("Bubble requires non-null pending intent");
+                }
+                mPendingIntent = intent;
+                return this;
+            }
+
+            /**
+             * Sets the title that will appear along with the app content for this bubble.
+             *
+             * <p>A title is required and should expect to fit on a single line and make sense when
+             * shown with the content defined by {@link #setIntent(PendingIntent)}.</p>
+             */
+            public BubbleMetadata.Builder setTitle(CharSequence title) {
+                if (TextUtils.isEmpty(title)) {
+                    throw new IllegalArgumentException("Bubbles require non-null or empty title");
+                }
+                mTitle = title;
+                return this;
+            }
+
+            /**
+             * Sets the icon that will represent the bubble when it is collapsed.
+             *
+             * <p>An icon is required and should be representative of the content within the bubble.
+             * If your app produces multiple bubbles, the image should be unique for each of them.
+             * </p>
+             */
+            public BubbleMetadata.Builder setIcon(Icon icon) {
+                if (icon == null) {
+                    throw new IllegalArgumentException("Bubbles require non-null icon");
+                }
+                mIcon = icon;
+                return this;
+            }
+
+            /**
+             * Sets the desired height for the app content defined by
+             * {@link #setIntent(PendingIntent)}, this height may not be respected if there is not
+             * enough space on the screen or if the provided height is too small to be useful.
+             */
+            public BubbleMetadata.Builder setDesiredHeight(int height) {
+                mDesiredHeight = Math.max(height, 0);
+                return this;
+            }
+
+            /**
+             * Creates the {@link BubbleMetadata} defined by this builder.
+             * <p>Will throw {@link IllegalStateException} if required fields have not been set
+             * on this builder.</p>
+             */
+            public BubbleMetadata build() {
+                if (mPendingIntent == null) {
+                    throw new IllegalStateException("Must supply pending intent to bubble");
+                }
+                if (TextUtils.isEmpty(mTitle)) {
+                    throw new IllegalStateException("Must supply a title for the bubble");
+                }
+                if (mIcon == null) {
+                    throw new IllegalStateException("Must supply an icon for the bubble");
+                }
+                return new BubbleMetadata(mPendingIntent, mTitle, mIcon, mDesiredHeight);
+            }
+        }
+    }
+
+
     // When adding a new Style subclass here, don't forget to update
     // Builder.getNotificationStyleClass.
 
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 950e9aa..e95d62f 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -85,7 +85,7 @@
     private static final String ATT_FG_SERVICE_SHOWN = "fgservice";
     private static final String ATT_GROUP = "group";
     private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system";
-    private static final String ATT_ALLOW_APP_OVERLAY = "app_overlay";
+    private static final String ATT_ALLOW_BUBBLE = "allow_bubble";
     private static final String DELIMITER = ",";
 
     /**
@@ -121,7 +121,7 @@
     /**
      * @hide
      */
-    public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 0x00000100;
+    public static final int USER_LOCKED_ALLOW_BUBBLE = 0x00000100;
 
     /**
      * @hide
@@ -134,7 +134,7 @@
             USER_LOCKED_VIBRATION,
             USER_LOCKED_SOUND,
             USER_LOCKED_SHOW_BADGE,
-            USER_LOCKED_ALLOW_APP_OVERLAY
+            USER_LOCKED_ALLOW_BUBBLE
     };
 
     private static final int DEFAULT_LIGHT_COLOR = 0;
@@ -144,7 +144,7 @@
             NotificationManager.IMPORTANCE_UNSPECIFIED;
     private static final boolean DEFAULT_DELETED = false;
     private static final boolean DEFAULT_SHOW_BADGE = true;
-    private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true;
+    private static final boolean DEFAULT_ALLOW_BUBBLE = true;
 
     @UnsupportedAppUsage
     private final String mId;
@@ -168,7 +168,7 @@
     private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
     // If this is a blockable system notification channel.
     private boolean mBlockableSystem = false;
-    private boolean mAllowAppOverlay = DEFAULT_ALLOW_APP_OVERLAY;
+    private boolean mAllowBubbles = DEFAULT_ALLOW_BUBBLE;
     private boolean mImportanceLockedByOEM;
 
     /**
@@ -231,7 +231,7 @@
         mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null;
         mLightColor = in.readInt();
         mBlockableSystem = in.readBoolean();
-        mAllowAppOverlay = in.readBoolean();
+        mAllowBubbles = in.readBoolean();
         mImportanceLockedByOEM = in.readBoolean();
     }
 
@@ -285,7 +285,7 @@
         }
         dest.writeInt(mLightColor);
         dest.writeBoolean(mBlockableSystem);
-        dest.writeBoolean(mAllowAppOverlay);
+        dest.writeBoolean(mAllowBubbles);
         dest.writeBoolean(mImportanceLockedByOEM);
     }
 
@@ -480,7 +480,7 @@
 
     /**
      * Sets whether notifications posted to this channel can appear outside of the notification
-     * shade, floating over other apps' content.
+     * shade, floating over other apps' content as a bubble.
      *
      * <p>This value will be ignored for channels that aren't allowed to pop on screen (that is,
      * channels whose {@link #getImportance() importance} is <
@@ -488,10 +488,10 @@
      *
      * <p>Only modifiable before the channel is submitted to
      *      * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.</p>
-     * @see Notification#getAppOverlayIntent()
+     * @see Notification#getBubbleMetadata()
      */
-    public void setAllowAppOverlay(boolean allowAppOverlay) {
-        mAllowAppOverlay = allowAppOverlay;
+    public void setAllowBubbles(boolean allowBubbles) {
+        mAllowBubbles = allowBubbles;
     }
 
     /**
@@ -610,16 +610,16 @@
      * Returns whether notifications posted to this channel can display outside of the notification
      * shade, in a floating window on top of other apps.
      */
-    public boolean canOverlayApps() {
-        return isAppOverlayAllowed() && getImportance() >= IMPORTANCE_HIGH;
+    public boolean canBubble() {
+        return isBubbleAllowed() && getImportance() >= IMPORTANCE_HIGH;
     }
 
     /**
-     * Like {@link #canOverlayApps()}, but only checks the permission, not the importance.
+     * Like {@link #canBubble()}, but only checks the permission, not the importance.
      * @hide
      */
-    public boolean isAppOverlayAllowed() {
-        return mAllowAppOverlay;
+    public boolean isBubbleAllowed() {
+        return mAllowBubbles;
     }
 
     /**
@@ -719,7 +719,7 @@
         lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
         setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false));
         setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false));
-        setAllowAppOverlay(safeBool(parser, ATT_ALLOW_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY));
+        setAllowBubbles(safeBool(parser, ATT_ALLOW_BUBBLE, DEFAULT_ALLOW_BUBBLE));
     }
 
     @Nullable
@@ -838,8 +838,8 @@
         if (isBlockableSystem()) {
             out.attribute(null, ATT_BLOCKABLE_SYSTEM, Boolean.toString(isBlockableSystem()));
         }
-        if (canOverlayApps() != DEFAULT_ALLOW_APP_OVERLAY) {
-            out.attribute(null, ATT_ALLOW_APP_OVERLAY, Boolean.toString(canOverlayApps()));
+        if (canBubble() != DEFAULT_ALLOW_BUBBLE) {
+            out.attribute(null, ATT_ALLOW_BUBBLE, Boolean.toString(canBubble()));
         }
 
         out.endTag(null, TAG_CHANNEL);
@@ -883,7 +883,7 @@
         record.put(ATT_DELETED, Boolean.toString(isDeleted()));
         record.put(ATT_GROUP, getGroup());
         record.put(ATT_BLOCKABLE_SYSTEM, isBlockableSystem());
-        record.put(ATT_ALLOW_APP_OVERLAY, canOverlayApps());
+        record.put(ATT_ALLOW_BUBBLE, canBubble());
         return record;
     }
 
@@ -983,7 +983,7 @@
                 && mShowBadge == that.mShowBadge
                 && isDeleted() == that.isDeleted()
                 && isBlockableSystem() == that.isBlockableSystem()
-                && mAllowAppOverlay == that.mAllowAppOverlay
+                && mAllowBubbles == that.mAllowBubbles
                 && Objects.equals(getId(), that.getId())
                 && Objects.equals(getName(), that.getName())
                 && Objects.equals(mDesc, that.mDesc)
@@ -1000,7 +1000,7 @@
                 getLockscreenVisibility(), getSound(), mLights, getLightColor(),
                 getUserLockedFields(),
                 isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
-                getAudioAttributes(), isBlockableSystem(), mAllowAppOverlay,
+                getAudioAttributes(), isBlockableSystem(), mAllowBubbles,
                 mImportanceLockedByOEM);
         result = 31 * result + Arrays.hashCode(mVibration);
         return result;
@@ -1028,7 +1028,7 @@
                 + ", mGroup='" + mGroup + '\''
                 + ", mAudioAttributes=" + mAudioAttributes
                 + ", mBlockableSystem=" + mBlockableSystem
-                + ", mAllowAppOverlay=" + mAllowAppOverlay
+                + ", mAllowBubbles=" + mAllowBubbles
                 + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
                 + '}';
         pw.println(prefix + output);
@@ -1055,7 +1055,7 @@
                 + ", mGroup='" + mGroup + '\''
                 + ", mAudioAttributes=" + mAudioAttributes
                 + ", mBlockableSystem=" + mBlockableSystem
-                + ", mAllowAppOverlay=" + mAllowAppOverlay
+                + ", mAllowBubbles=" + mAllowBubbles
                 + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
                 + '}';
     }
@@ -1090,7 +1090,7 @@
             mAudioAttributes.writeToProto(proto, NotificationChannelProto.AUDIO_ATTRIBUTES);
         }
         proto.write(NotificationChannelProto.IS_BLOCKABLE_SYSTEM, mBlockableSystem);
-        proto.write(NotificationChannelProto.ALLOW_APP_OVERLAY, mAllowAppOverlay);
+        proto.write(NotificationChannelProto.ALLOW_APP_OVERLAY, mAllowBubbles);
 
         proto.end(token);
     }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index aad3253..43614fe 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1080,14 +1080,14 @@
      * notification shade, floating over other apps' content.
      *
      * <p>This value will be ignored for notifications that are posted to channels that do not
-     * allow app overlays ({@link NotificationChannel#canOverlayApps()}.
+     * allow bubbles ({@link NotificationChannel#canBubble()}.
      *
-     * @see Notification#getAppOverlayIntent()
+     * @see Notification#getBubbleMetadata()
      */
-    public boolean areAppOverlaysAllowed() {
+    public boolean areBubblesAllowed() {
         INotificationManager service = getService();
         try {
-            return service.areAppOverlaysAllowed(mContext.getPackageName());
+            return service.areBubblesAllowed(mContext.getPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9247486..6d7c547 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2168,6 +2168,74 @@
     public @interface SetPrivateDnsModeResultConstants {}
 
     /**
+     * Activity action: Starts the administrator to get the mode for the provisioning.
+     * This intent may contain the following extras:
+     * <ul>
+     *     <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}</li>
+     *     <li>{@link #EXTRA_PROVISIONING_IMEI}</li>
+     *     <li>{@link #EXTRA_PROVISIONING_SERIAL_NUMBER}</li>
+     * </ul>
+     *
+     * <p>The target activity should return one of the following values in
+     * {@link #EXTRA_PROVISIONING_MODE} as result:
+     * <ul>
+     *     <li>{@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE}</li>
+     *     <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE}</li>
+     *     <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE}</li>
+     * </ul>
+     *
+     * <p>The target activity may also return the account that needs to be migrated from primary
+     * user to managed profile in case of a profile owner provisioning in
+     * {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE} as result.
+     */
+    public static final String ACTION_GET_PROVISIONING_MODE =
+            "android.app.action.GET_PROVISIONING_MODE";
+
+    /**
+     * A string extra holding the IMEI (International Mobile Equipment Identity) of the device.
+     */
+    public static final String EXTRA_PROVISIONING_IMEI = "android.app.extra.PROVISIONING_IMEI";
+
+    /**
+     * A string extra holding the serial number of the device.
+     */
+    public static final String EXTRA_PROVISIONING_SERIAL_NUMBER =
+            "android.app.extra.PROVISIONING_SERIAL_NUMBER";
+
+    /**
+     * An intent extra holding the provisioning mode returned by the administrator.
+     * The value for this extra should be one of the following:
+     * <ul>
+     *     <li>{@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE}</li>
+     *     <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE}</li>
+     *     <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE}</li>
+     * </ul>
+     */
+    public static final String EXTRA_PROVISIONING_MODE =
+            "android.app.extra.PROVISIONING_MODE";
+
+    /**
+     * The provisioning mode for fully managed device.
+     */
+    public static final int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1;
+
+    /**
+     * The provisioning mode for managed profile.
+     */
+    public static final int PROVISIONING_MODE_MANAGED_PROFILE = 2;
+
+    /**
+     * The provisioning mode for managed profile on a fully managed device.
+     */
+    public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE = 3;
+
+    /**
+     * Activity action: Starts the administrator to show policy compliance for the provisioning.
+     */
+    public static final String ACTION_ADMIN_POLICY_COMPLIANCE =
+            "android.app.action.ADMIN_POLICY_COMPLIANCE";
+
+    /**
      * Return true if the given administrator component is currently active (enabled) in the system.
      *
      * @param admin The administrator component to check for.
diff --git a/core/java/android/app/usage/EventList.java b/core/java/android/app/usage/EventList.java
index a79ad2f..aaae57e5 100644
--- a/core/java/android/app/usage/EventList.java
+++ b/core/java/android/app/usage/EventList.java
@@ -103,21 +103,4 @@
         }
         return result;
     }
-
-    /**
-     * Remove events of certain type on or after a timestamp.
-     * @param type The type of event to remove.
-     * @param timeStamp the timeStamp on or after which to remove the event.
-     */
-    public void removeOnOrAfter(int type, long timeStamp) {
-        for (int i = mEvents.size() - 1; i >= 0; i--) {
-            UsageEvents.Event event = mEvents.get(i);
-            if (event.mTimeStamp < timeStamp) {
-                break;
-            }
-            if (event.mEventType == type) {
-                mEvents.remove(i);
-            }
-        }
-    }
 }
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index d7a5328..2c5fe04 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -245,10 +245,18 @@
         public static final int FLUSH_TO_DISK = 25;
 
         /**
+         * An event type denoting that the device underwent a shutdown process.
+         * A DEVICE_SHUTDOWN event should be treated as if all started activities and foreground
+         * services are now stopped and no explicit {@link #ACTIVITY_STOPPED} and
+         * {@link #FOREGROUND_SERVICE_STOP} events will be generated for them.
+         */
+        public static final int DEVICE_SHUTDOWN = 26;
+
+        /**
          * Keep in sync with the greatest event type value.
          * @hide
          */
-        public static final int MAX_EVENT_TYPE = 25;
+        public static final int MAX_EVENT_TYPE = 26;
 
         /** @hide */
         public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 308180b..94a2a3e 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -21,6 +21,7 @@
 import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
 import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED;
 import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE;
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
 import static android.app.usage.UsageEvents.Event.END_OF_DAY;
 import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK;
 import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START;
@@ -119,12 +120,9 @@
     public int mLastEvent;
 
     /**
-     * If an activity is visible(onStart(), onPause() states) or in foreground (onResume() state),
-     * it has one entry in this map. When an activity becomes invisible (onStop() or onDestroy()),
-     * it is removed from this map.
      * Key is instanceId of the activity (ActivityRecode appToken hashCode)..
-     * Value is this activity's last event, one of ACTIVITY_RESUMED or
-     * ACTIVITY_PAUSED.
+     * Value is this activity's last event, one of ACTIVITY_RESUMED, ACTIVITY_PAUSED or
+     * ACTIVITY_STOPPED.
      * {@hide}
      */
     public SparseIntArray mActivities = new SparseIntArray();
@@ -560,6 +558,7 @@
                 mLastTimeForegroundServiceUsed = timeStamp;
                 mForegroundServices.put(className, eventType);
                 break;
+            case DEVICE_SHUTDOWN:
             case FLUSH_TO_DISK:
                 // update usage of all active activities/services.
                 if (hasForegroundActivity()) {
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 2edad35..cc3ab00 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -98,6 +98,12 @@
     public abstract void prepareShutdown();
 
     /**
+     * When the device power button is long pressed for 3.5 seconds, prepareForPossibleShutdown()
+     * is called.
+     */
+    public abstract void prepareForPossibleShutdown();
+
+    /**
      * Returns true if the app has not been used for a certain amount of time. How much time?
      * Could be hours, could be days, who knows?
      *
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d27cce5..8497656 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -33,6 +33,7 @@
 import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
@@ -1954,6 +1955,17 @@
     public static final String EXTRA_LAUNCHER_EXTRAS = "android.intent.extra.LAUNCHER_EXTRAS";
 
     /**
+     * Intent extra: ID of the shortcut used to send the share intent.
+     *
+     * @see ShortcutInfo#getId()
+     *
+     * <p>
+     * Type: String
+     * </p>
+     */
+    public static final String EXTRA_SHORTCUT_ID = "android.intent.extra.shortcut.ID";
+
+    /**
      * Activity action: Launch UI to manage which apps have a given permission.
      * <p>
      * Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission group
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 03124be..c702b16 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -16,6 +16,7 @@
 package android.content.pm;
 
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ShortcutInfo;
@@ -72,4 +73,7 @@
     void applyRestore(in byte[] payload, int user);
 
     boolean isRequestPinItemSupported(int user, int requestType);
+
+    // System API used by framework's ShareSheet (ChooserActivity)
+    ParceledListSlice getShareTargets(String packageName, in IntentFilter filter, int userId);
 }
\ No newline at end of file
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 636a70f..b845673 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5555,26 +5555,24 @@
     }
 
     /**
-     * @deprecated This function no longer does anything; it was an old
-     * approach to managing preferred activities, which has been superseded
-     * by (and conflicts with) the modern activity-based preferences.
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     public abstract void addPackageToPreferred(String packageName);
 
     /**
-     * @deprecated This function no longer does anything; it was an old
-     * approach to managing preferred activities, which has been superseded
-     * by (and conflicts with) the modern activity-based preferences.
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     public abstract void removePackageFromPreferred(String packageName);
 
     /**
-     * @deprecated This function no longer does anything; it was an old
-     * approach to managing preferred activities, which has been superseded
-     * by (and conflicts with) the modern activity-based preferences.
-     *
      * Retrieve the list of all currently configured preferred packages. The
      * first package on the list is the most preferred, the last is the least
      * preferred.
@@ -5582,15 +5580,16 @@
      * @param flags Additional option flags to modify the data returned.
      * @return A List of PackageInfo objects, one for each preferred
      *         application, in order of preference.
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     public abstract List<PackageInfo> getPreferredPackages(@PackageInfoFlags int flags);
 
     /**
-     * @deprecated This is a protected API that should not have been available
-     * to third party applications.  It is the platform's responsibility for
-     * assigning preferred activities and this cannot be directly modified.
-     *
      * Add a new preferred activity mapping to the system.  This will be used
      * to automatically select the given activity component when
      * {@link Context#startActivity(Intent) Context.startActivity()} finds
@@ -5604,20 +5603,26 @@
      * this preference was made.
      * @param activity The component name of the activity that is to be
      * preferred.
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     public abstract void addPreferredActivity(IntentFilter filter, int match,
             ComponentName[] set, ComponentName activity);
 
     /**
-     * @deprecated This is a protected API that should not have been available
-     * to third party applications.  It is the platform's responsibility for
-     * assigning preferred activities and this cannot be directly modified.
-     *
      * Same as {@link #addPreferredActivity(IntentFilter, int,
             ComponentName[], ComponentName)}, but with a specific userId to apply the preference
             to.
      * @hide
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     @UnsupportedAppUsage
@@ -5627,10 +5632,6 @@
     }
 
     /**
-     * @deprecated This is a protected API that should not have been available
-     * to third party applications.  It is the platform's responsibility for
-     * assigning preferred activities and this cannot be directly modified.
-     *
      * Replaces an existing preferred activity mapping to the system, and if that were not present
      * adds a new preferred activity.  This will be used
      * to automatically select the given activity component when
@@ -5645,7 +5646,13 @@
      * this preference was made.
      * @param activity The component name of the activity that is to be
      * preferred.
+     *
      * @hide
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     @UnsupportedAppUsage
@@ -5653,10 +5660,6 @@
             ComponentName[] set, ComponentName activity);
 
     /**
-     * @deprecated This is a protected API that should not have been available
-     * to third party applications.  It is the platform's responsibility for
-     * assigning preferred activities and this cannot be directly modified.
-     *
      * Replaces an existing preferred activity mapping to the system, and if that were not present
      * adds a new preferred activity.  This will be used to automatically select the given activity
      * component when {@link Context#startActivity(Intent) Context.startActivity()} finds multiple
@@ -5671,6 +5674,11 @@
      * @param activity The component name of the activity that is to be preferred.
      *
      * @hide
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     @SystemApi
@@ -5681,6 +5689,11 @@
 
     /**
      * @hide
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     @UnsupportedAppUsage
@@ -5690,10 +5703,6 @@
     }
 
     /**
-     * @deprecated This function no longer does anything; it was an old
-     * approach to managing preferred activities, which has been superseded
-     * by (and conflicts with) the modern activity-based preferences.
-     *
      * Remove all preferred activity mappings, previously added with
      * {@link #addPreferredActivity}, from the
      * system whose activities are implemented in the given package name.
@@ -5701,15 +5710,16 @@
      *
      * @param packageName The name of the package whose preferred activity
      * mappings are to be removed.
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     public abstract void clearPackagePreferredActivities(String packageName);
 
     /**
-     * @deprecated This function no longer does anything; it was an old
-     * approach to managing preferred activities, which has been superseded
-     * by (and conflicts with) the modern activity-based preferences.
-     *
      * Retrieve all preferred activities, previously added with
      * {@link #addPreferredActivity}, that are
      * currently registered with the system.
@@ -5725,6 +5735,11 @@
      * @return Returns the total number of registered preferred activities
      * (the number of distinct IntentFilter records, not the number of unique
      * activity components) that were found.
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     public abstract int getPreferredActivities(@NonNull List<IntentFilter> outFilters,
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 83563d0..359adbd 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -55,6 +55,7 @@
     public static final int PACKAGE_PERMISSION_CONTROLLER = 6;
     public static final int PACKAGE_WELLBEING = 7;
     public static final int PACKAGE_DOCUMENTER = 8;
+    public static final int PACKAGE_CONFIGURATOR = 9;
     @IntDef(value = {
         PACKAGE_SYSTEM,
         PACKAGE_SETUP_WIZARD,
@@ -65,6 +66,7 @@
         PACKAGE_PERMISSION_CONTROLLER,
         PACKAGE_WELLBEING,
         PACKAGE_DOCUMENTER,
+        PACKAGE_CONFIGURATOR,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface KnownPackage {}
@@ -137,6 +139,12 @@
     public abstract void setLocationPackagesProvider(PackagesProvider provider);
 
     /**
+     * Set the location extra packages provider.
+     * @param provider The packages provider.
+     */
+    public abstract  void setLocationExtraPackagesProvider(PackagesProvider provider);
+
+    /**
      * Sets the voice interaction packages provider.
      * @param provider The packages provider.
      */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 0fc50c6..dbf3574 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2656,6 +2656,23 @@
     }
 
     /**
+     * Matches a given {@code targetCode} against a set of release codeNames. Target codes can
+     * either be of the form {@code [codename]}" (e.g {@code "Q"}) or of the form
+     * {@code [codename].[fingerprint]} (e.g {@code "Q.cafebc561"}).
+     */
+    private static boolean matchTargetCode(@NonNull String[] codeNames,
+            @NonNull String targetCode) {
+        final String targetCodeName;
+        final int targetCodeIdx = targetCode.indexOf('.');
+        if (targetCodeIdx == -1) {
+            targetCodeName = targetCode;
+        } else {
+            targetCodeName = targetCode.substring(0, targetCodeIdx);
+        }
+        return ArrayUtils.contains(codeNames, targetCodeName);
+    }
+
+    /**
      * Computes the targetSdkVersion to use at runtime. If the package is not
      * compatible with this platform, populates {@code outError[0]} with an
      * error message.
@@ -2698,7 +2715,7 @@
 
         // If it's a pre-release SDK and the codename matches this platform, it
         // definitely targets this SDK.
-        if (ArrayUtils.contains(platformSdkCodenames, targetCode) || forceCurrentDev) {
+        if (matchTargetCode(platformSdkCodenames, targetCode) || forceCurrentDev) {
             return Build.VERSION_CODES.CUR_DEVELOPMENT;
         }
 
@@ -2831,7 +2848,7 @@
 
         // If it's a pre-release SDK and the codename matches this platform, we
         // definitely meet the minimum SDK requirement.
-        if (ArrayUtils.contains(platformSdkCodenames, minCode)) {
+        if (matchTargetCode(platformSdkCodenames, minCode)) {
             return Build.VERSION_CODES.CUR_DEVELOPMENT;
         }
 
@@ -3760,9 +3777,11 @@
             ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
         }
 
+        final boolean extractNativeLibsDefault =
+                owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q;
         if (sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
-                true)) {
+                extractNativeLibsDefault)) {
             ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
         }
 
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index bb8c92d..5d2cf0a 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -158,6 +158,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int PROTECTION_FLAG_OEM = 0x4000;
 
     /**
@@ -202,6 +203,16 @@
     @TestApi
     public static final int PROTECTION_FLAG_DOCUMENTER = 0x40000;
 
+    /**
+     * Additional flag for {@link #protectionLevel}, corresponding to the
+     * {@code configurator} value of {@link android.R.attr#protectionLevel}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final int PROTECTION_FLAG_CONFIGURATOR = 0x80000;
+
 
     /** @hide */
     @IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = {
@@ -221,6 +232,7 @@
             PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER,
             PROTECTION_FLAG_WELLBEING,
             PROTECTION_FLAG_DOCUMENTER,
+            PROTECTION_FLAG_CONFIGURATOR,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ProtectionFlags {}
@@ -416,6 +428,9 @@
         if ((level & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0) {
             protLevel += "|documenter";
         }
+        if ((level & PROTECTION_FLAG_CONFIGURATOR) != 0) {
+            protLevel += "|configurator";
+        }
         return protLevel;
     }
 
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index ec2e2fd..fe68b8a 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -21,6 +21,7 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
+import android.app.Person;
 import android.app.TaskStackBuilder;
 import android.content.ComponentName;
 import android.content.Context;
@@ -111,6 +112,9 @@
     public static final int FLAG_SHADOW = 1 << 12;
 
     /** @hide */
+    public static final int FLAG_LONG_LIVED = 1 << 13;
+
+    /** @hide */
     @IntDef(flag = true, prefix = { "FLAG_" }, value = {
             FLAG_DYNAMIC,
             FLAG_PINNED,
@@ -124,6 +128,8 @@
             FLAG_ADAPTIVE_BITMAP,
             FLAG_RETURNED_BY_SERVICE,
             FLAG_ICON_FILE_PENDING_SAVE,
+            FLAG_SHADOW,
+            FLAG_LONG_LIVED,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ShortcutFlags {}
@@ -344,6 +350,9 @@
     @Nullable
     private PersistableBundle[] mIntentPersistableExtrases;
 
+    @Nullable
+    private Person[] mPersons;
+
     private int mRank;
 
     /**
@@ -399,6 +408,10 @@
         mCategories = cloneCategories(b.mCategories);
         mIntents = cloneIntents(b.mIntents);
         fixUpIntentExtras();
+        mPersons = clonePersons(b.mPersons);
+        if (b.mIsLongLived) {
+            setLongLived();
+        }
         mRank = b.mRank;
         mExtras = b.mExtras;
         updateTimestamp();
@@ -465,6 +478,20 @@
         return ret;
     }
 
+    private static Person[] clonePersons(Person[] persons) {
+        if (persons == null) {
+            return null;
+        }
+        final Person[] ret = new Person[persons.length];
+        for (int i = 0; i < ret.length; i++) {
+            if (persons[i] != null) {
+                // Don't need to keep the icon, remove it to save space
+                ret[i] = persons[i].toBuilder().setIcon(null).build();
+            }
+        }
+        return ret;
+    }
+
     /**
      * Throws if any of the mandatory fields is not set.
      *
@@ -511,6 +538,7 @@
             mDisabledMessage = source.mDisabledMessage;
             mDisabledMessageResId = source.mDisabledMessageResId;
             mCategories = cloneCategories(source.mCategories);
+            mPersons = clonePersons(source.mPersons);
             if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
                 mIntents = cloneIntents(source.mIntents);
                 mIntentPersistableExtrases =
@@ -833,6 +861,9 @@
         if (source.mCategories != null) {
             mCategories = cloneCategories(source.mCategories);
         }
+        if (source.mPersons != null) {
+            mPersons = clonePersons(source.mPersons);
+        }
         if (source.mIntents != null) {
             mIntents = cloneIntents(source.mIntents);
             mIntentPersistableExtrases =
@@ -901,6 +932,10 @@
 
         private Intent[] mIntents;
 
+        private Person[] mPersons;
+
+        private boolean mIsLongLived;
+
         private int mRank = RANK_NOT_SET;
 
         private PersistableBundle mExtras;
@@ -1165,6 +1200,53 @@
         }
 
         /**
+         * Add a person that is relevant to this shortcut. Alternatively,
+         * {@link #setPersons(Person[])} can be used to add multiple persons to a shortcut.
+         *
+         * <p> This is an optional field, but the addition of person may cause this shortcut to
+         * appear more prominently in the user interface (e.g. ShareSheet).
+         *
+         * <p> A person should usually contain a uri in order to benefit from the ranking boost.
+         * However, even if no uri is provided, it's beneficial to provide people in the shortcut,
+         * such that listeners and voice only devices can announce and handle them properly.
+         *
+         * @see Person
+         * @see #setPersons(Person[])
+         */
+        @NonNull
+        public Builder setPerson(@NonNull Person person) {
+            return setPersons(new Person[]{person});
+        }
+
+        /**
+         * Sets multiple persons instead of a single person.
+         *
+         * @see Person
+         * @see #setPerson(Person)
+         */
+        @NonNull
+        public Builder setPersons(@NonNull Person[] persons) {
+            Preconditions.checkNotNull(persons, "persons cannot be null");
+            Preconditions.checkNotNull(persons.length, "persons cannot be empty");
+            for (Person person : persons) {
+                Preconditions.checkNotNull(person, "persons cannot contain null");
+            }
+            mPersons = clonePersons(persons);
+            return this;
+        }
+
+        /**
+         * Sets if a shortcut would be valid even if it has been unpublished/invisible by the app
+         * (as a dynamic or pinned shortcut). If it is long lived, it can be cached by various
+         * system services even after it has been unpublished as a dynamic shortcut.
+         */
+        @NonNull
+        public Builder setLongLived() {
+            mIsLongLived = true;
+            return this;
+        }
+
+        /**
          * "Rank" of a shortcut, which is a non-negative value that's used by the launcher app
          * to sort shortcuts.
          *
@@ -1395,6 +1477,16 @@
     }
 
     /**
+     * Return the Persons set with {@link Builder#setPersons(Person[])}.
+     *
+     * @hide
+     */
+    @Nullable
+    public Person[] getPersons() {
+        return clonePersons(mPersons);
+    }
+
+    /**
      * The extras in the intents.  We convert extras into {@link PersistableBundle} so we can
      * persist them.
      * @hide
@@ -1525,6 +1617,16 @@
         addFlags(FLAG_RETURNED_BY_SERVICE);
     }
 
+    /** @hide */
+    public boolean isLongLived() {
+        return hasFlags(FLAG_LONG_LIVED);
+    }
+
+    /** @hide */
+    public void setLongLived() {
+        addFlags(FLAG_LONG_LIVED);
+    }
+
     /** Return whether a shortcut is dynamic. */
     public boolean isDynamic() {
         return hasFlags(FLAG_DYNAMIC);
@@ -1893,6 +1995,8 @@
                 mCategories.add(source.readString().intern());
             }
         }
+
+        mPersons = source.readParcelableArray(cl, Person.class);
     }
 
     @Override
@@ -1940,6 +2044,8 @@
         } else {
             dest.writeInt(0);
         }
+
+        dest.writeParcelableArray(mPersons, flags);
     }
 
     public static final Creator<ShortcutInfo> CREATOR =
@@ -2040,6 +2146,9 @@
         if (isReturnedByServer()) {
             sb.append("Rets");
         }
+        if (isLongLived()) {
+            sb.append("Liv");
+        }
         sb.append("]");
 
         addIndentOrComma(sb, indent);
@@ -2094,6 +2203,11 @@
 
         addIndentOrComma(sb, indent);
 
+        sb.append("persons=");
+        sb.append(mPersons);
+
+        addIndentOrComma(sb, indent);
+
         sb.append("icon=");
         sb.append(mIcon);
 
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 2d59003..4f7acd9 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -17,17 +17,22 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
 import android.app.usage.UsageStatsManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.os.Build;
 import android.os.Build.VERSION_CODES;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 
@@ -549,4 +554,85 @@
     protected int injectMyUserId() {
         return mContext.getUserId();
     }
+
+    /**
+     * Used by framework's ShareSheet (ChooserActivity.java) to retrieve all of the direct share
+     * targets that match the given IntentFilter.
+     *
+     * @param filter IntentFilter that will be used to retrieve the matching {@link ShortcutInfo}s.
+     * @return List of {@link ShareShortcutInfo}s that match the given IntentFilter.
+     * @hide
+     */
+    @NonNull
+    @SystemApi
+    public List<ShareShortcutInfo> getShareTargets(@NonNull IntentFilter filter) {
+        try {
+            return mService.getShareTargets(mContext.getPackageName(), filter,
+                    injectMyUserId()).getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Represents the result of a query return by {@link #getShareTargets(IntentFilter)}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class ShareShortcutInfo implements Parcelable {
+        private final ShortcutInfo mShortcutInfo;
+        private final ComponentName mTargetComponent;
+
+        /**
+         * @hide
+         */
+        public ShareShortcutInfo(@NonNull ShortcutInfo shortcutInfo,
+                @NonNull ComponentName targetComponent) {
+            if (shortcutInfo == null) {
+                throw new NullPointerException("shortcut info is null");
+            }
+            if (targetComponent == null) {
+                throw new NullPointerException("target component is null");
+            }
+
+            mShortcutInfo = shortcutInfo;
+            mTargetComponent = targetComponent;
+        }
+
+        private ShareShortcutInfo(Parcel in) {
+            mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader());
+            mTargetComponent = in.readParcelable(ComponentName.class.getClassLoader());
+        }
+
+        public ShortcutInfo getShortcutInfo() {
+            return mShortcutInfo;
+        }
+
+        public ComponentName getTargetComponent() {
+            return mTargetComponent;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeParcelable(mShortcutInfo, flags);
+            dest.writeParcelable(mTargetComponent, flags);
+        }
+
+        public static final Parcelable.Creator<ShareShortcutInfo> CREATOR =
+                new Parcelable.Creator<ShareShortcutInfo>() {
+                    public ShareShortcutInfo createFromParcel(Parcel in) {
+                        return new ShareShortcutInfo(in);
+                    }
+
+                    public ShareShortcutInfo[] newArray(int size) {
+                        return new ShareShortcutInfo[size];
+                    }
+                };
+    }
 }
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index f1a4db2..9e0a9ba 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -732,6 +732,38 @@
         }
     }
 
+    /**
+     * Enable resource resolution logging to track the steps taken to resolve the last resource
+     * entry retrieved. Stores the configuration and package names for each step.
+     *
+     * Default disabled.
+     *
+     * @param enabled Boolean indicating whether to enable or disable logging.
+     *
+     * @hide
+     */
+    public void setResourceResolutionLoggingEnabled(boolean enabled) {
+        synchronized (this) {
+            ensureValidLocked();
+            nativeSetResourceResolutionLoggingEnabled(mObject, enabled);
+        }
+    }
+
+    /**
+     * Retrieve the last resource resolution path logged.
+     *
+     * @return Formatted string containing last resource ID/name and steps taken to resolve final
+     * entry, including configuration and package names.
+     *
+     * @hide
+     */
+    public @Nullable String getLastResourceResolution() {
+        synchronized (this) {
+            ensureValidLocked();
+            return nativeGetLastResourceResolution(mObject);
+        }
+    }
+
     CharSequence getPooledStringForCookie(int cookie, int id) {
         // Cookies map to ApkAssets starting at 1.
         return getApkAssets()[cookie - 1].getStringFromPool(id);
@@ -1383,6 +1415,8 @@
     private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid);
     private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem);
     private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr);
+    private static native void nativeSetResourceResolutionLoggingEnabled(long ptr, boolean enabled);
+    private static native @Nullable String nativeGetLastResourceResolution(long ptr);
 
     // Style attribute retrieval native methods.
     private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr,
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 365ceac..dcd6e2e 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -98,6 +98,12 @@
  * href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.</p>
  */
 public class Resources {
+    /**
+     * The {@code null} resource ID. This denotes an invalid resource ID that is returned by the
+     * system when a resource is not found or the value is set to {@code @null} in XML.
+     */
+    public static final @AnyRes int ID_NULL = 0;
+
     static final String TAG = "Resources";
 
     private static final Object sSync = new Object();
@@ -2010,22 +2016,36 @@
     public String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
         return mResourcesImpl.getResourceTypeName(resid);
     }
-    
+
     /**
      * Return the entry name for a given resource identifier.
-     * 
+     *
      * @param resid The resource identifier whose entry name is to be
      * retrieved.
-     * 
+     *
      * @return A string holding the entry name of the resource.
-     * 
+     *
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
-     * 
+     *
      * @see #getResourceName
      */
     public String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
         return mResourcesImpl.getResourceEntryName(resid);
     }
+
+    /**
+     * Return formatted log of the last retrieved resource's resolution path.
+     *
+     * @return A string holding a formatted log of the steps taken to resolve the last resource.
+     *
+     * @throws NotFoundException Throws NotFoundException if there hasn't been a resource
+     * resolved yet.
+     *
+     * @hide
+     */
+    public String getLastResourceResolution() throws NotFoundException {
+        return mResourcesImpl.getLastResourceResolution();
+    }
     
     /**
      * Parse a series of {@link android.R.styleable#Extra &lt;extra&gt;} tags from
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 2ad4f62..77796d9 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -299,6 +299,13 @@
     }
 
     @NonNull
+    String getLastResourceResolution() throws NotFoundException {
+        String str = mAssets.getLastResourceResolution();
+        if (str != null) return str;
+        throw new NotFoundException("Associated AssetManager hasn't resolved a resource");
+    }
+
+    @NonNull
     CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException {
         PluralRules rule = getPluralRule();
         CharSequence res = mAssets.getResourceBagText(id,
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 508626b..d53834c 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -19,6 +19,7 @@
 import android.annotation.AnyRes;
 import android.annotation.ColorInt;
 import android.annotation.Nullable;
+import android.annotation.StyleRes;
 import android.annotation.StyleableRes;
 import android.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo;
@@ -63,13 +64,15 @@
     }
 
     // STYLE_ prefixed constants are offsets within the typed data array.
-    static final int STYLE_NUM_ENTRIES = 6;
+    // Keep this in sync with libs/androidfw/include/androidfw/AttributeResolution.h
+    static final int STYLE_NUM_ENTRIES = 7;
     static final int STYLE_TYPE = 0;
     static final int STYLE_DATA = 1;
     static final int STYLE_ASSET_COOKIE = 2;
     static final int STYLE_RESOURCE_ID = 3;
     static final int STYLE_CHANGING_CONFIGURATIONS = 4;
     static final int STYLE_DENSITY = 5;
+    static final int SYTLE_SOURCE_STYLE_RESOURCE_ID = 6;
 
     @UnsupportedAppUsage
     private final Resources mResources;
@@ -1098,6 +1101,31 @@
     }
 
     /**
+     * Returns the resource ID of the style against which the specified attribute was resolved,
+     * otherwise returns defValue.
+     *
+     * @param index Index of attribute whose source style to retrieve.
+     * @param defValue Value to return if the attribute is not defined or
+     *                 not a resource.
+     *
+     * @return Attribute source style resource ID or defValue if it was not resolved in any style.
+     * @throws RuntimeException if the TypedArray has already been recycled.
+     */
+    @StyleRes
+    public int getSourceStyleResourceId(@StyleableRes int index, @StyleRes int defValue) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
+        index *= STYLE_NUM_ENTRIES;
+        final int resid = mData[index + SYTLE_SOURCE_STYLE_RESOURCE_ID];
+        if (resid != 0) {
+            return resid;
+        }
+        return defValue;
+    }
+
+    /**
      * Determines whether there is an attribute at <var>index</var>.
      * <p>
      * <strong>Note:</strong> If the attribute was set to {@code @empty} or
@@ -1309,6 +1337,7 @@
                 data[index + STYLE_CHANGING_CONFIGURATIONS]);
         outValue.density = data[index + STYLE_DENSITY];
         outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null;
+        outValue.sourceStyleResourceId = data[index + SYTLE_SOURCE_STYLE_RESOURCE_ID];
         return true;
     }
 
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index eb3414d..8aac1bf 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -42,13 +42,13 @@
     /**
      * The hardware is unavailable. Try again later.
      */
-    public static final int BIOMETRIC_ERROR_UNAVAILABLE =
+    public static final int BIOMETRIC_ERROR_HW_UNAVAILABLE =
             BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE;
 
     /**
      * The user does not have any biometrics enrolled.
      */
-    public static final int BIOMETRIC_ERROR_NO_BIOMETRICS =
+    public static final int BIOMETRIC_ERROR_NONE_ENROLLED =
             BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS;
 
     /**
@@ -58,8 +58,8 @@
             BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT;
 
     @IntDef({BIOMETRIC_SUCCESS,
-            BIOMETRIC_ERROR_UNAVAILABLE,
-            BIOMETRIC_ERROR_NO_BIOMETRICS,
+            BIOMETRIC_ERROR_HW_UNAVAILABLE,
+            BIOMETRIC_ERROR_NONE_ENROLLED,
             BIOMETRIC_ERROR_NO_HARDWARE})
     @interface BiometricError {}
 
@@ -95,8 +95,8 @@
      * Determine if biometrics can be used. In other words, determine if {@link BiometricPrompt}
      * can be expected to be shown (hardware available, templates enrolled, user-enabled).
      *
-     * @return Returns {@link #BIOMETRIC_ERROR_NO_BIOMETRICS} if the user does not have any
-     *     enrolled, or {@link #BIOMETRIC_ERROR_UNAVAILABLE} if none are currently
+     * @return Returns {@link #BIOMETRIC_ERROR_NONE_ENROLLED} if the user does not have any
+     *     enrolled, or {@link #BIOMETRIC_ERROR_HW_UNAVAILABLE} if none are currently
      *     supported/enabled. Returns {@link #BIOMETRIC_SUCCESS} if a biometric can currently be
      *     used (enrolled and available).
      */
@@ -113,7 +113,7 @@
                 return BIOMETRIC_ERROR_NO_HARDWARE;
             } else {
                 Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
-                return BIOMETRIC_ERROR_UNAVAILABLE;
+                return BIOMETRIC_ERROR_HW_UNAVAILABLE;
             }
         }
     }
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index f652f85..c69b68e4 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -235,7 +235,6 @@
          * requiring confirmation.
          *
          * @param requireConfirmation
-         * @hide
          */
         public Builder setRequireConfirmation(boolean requireConfirmation) {
             mBundle.putBoolean(KEY_REQUIRE_CONFIRMATION, requireConfirmation);
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index be054297..8c74ddc 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -91,9 +91,7 @@
      *
      * @return The matching brightness correction, or null.
      *
-     * @hide
      */
-    @SystemApi
     @Nullable
     public BrightnessCorrection getCorrectionByPackageName(String packageName) {
         return mCorrectionsByPackageName.get(packageName);
@@ -106,10 +104,7 @@
      *      The app category.
      *
      * @return The matching brightness correction, or null.
-     *
-     * @hide
      */
-    @SystemApi
     @Nullable
     public BrightnessCorrection getCorrectionByCategory(int category) {
         return mCorrectionsByCategory.get(category);
@@ -416,9 +411,7 @@
          *
          * @return The maximum number of corrections by package name allowed.
          *
-         * @hide
          */
-        @SystemApi
         public int getMaxCorrectionsByPackageName() {
             return MAX_CORRECTIONS_BY_PACKAGE_NAME;
         }
@@ -428,9 +421,7 @@
          *
          * @return The maximum number of corrections by category allowed.
          *
-         * @hide
          */
-        @SystemApi
         public int getMaxCorrectionsByCategory() {
             return MAX_CORRECTIONS_BY_CATEGORY;
         }
@@ -451,9 +442,7 @@
          *      Maximum number of corrections by package name exceeded (see
          *      {@link #getMaxCorrectionsByPackageName}).
          *
-         * @hide
          */
-        @SystemApi
         public Builder addCorrectionByPackageName(String packageName,
                 BrightnessCorrection correction) {
             if (mCorrectionsByPackageName.size() >= getMaxCorrectionsByPackageName()) {
@@ -479,9 +468,7 @@
          *      Maximum number of corrections by category exceeded (see
          *      {@link #getMaxCorrectionsByCategory}).
          *
-         * @hide
          */
-        @SystemApi
         public Builder addCorrectionByCategory(@ApplicationInfo.Category int category,
                 BrightnessCorrection correction) {
             if (mCorrectionsByCategory.size() >= getMaxCorrectionsByCategory()) {
@@ -504,8 +491,6 @@
 
         /**
          * Builds the {@link BrightnessConfiguration}.
-         *
-         * A brightness curve <b>must</b> be set before calling this.
          */
         public BrightnessConfiguration build() {
             if (mCurveLux == null || mCurveNits == null) {
diff --git a/core/java/android/hardware/display/BrightnessCorrection.java b/core/java/android/hardware/display/BrightnessCorrection.java
index c4e0e3b..6a073ff 100644
--- a/core/java/android/hardware/display/BrightnessCorrection.java
+++ b/core/java/android/hardware/display/BrightnessCorrection.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.MathUtils;
@@ -41,6 +42,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public final class BrightnessCorrection implements Parcelable {
 
     private static final int SCALE_AND_TRANSLATE_LOG = 1;
@@ -98,6 +100,24 @@
         return mImplementation.toString();
     }
 
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (!(o instanceof BrightnessCorrection)) {
+            return false;
+        }
+        BrightnessCorrection other = (BrightnessCorrection) o;
+        return other.mImplementation.equals(mImplementation);
+    }
+
+    @Override
+    public int hashCode() {
+        return mImplementation.hashCode();
+    }
+
     public static final Creator<BrightnessCorrection> CREATOR =
             new Creator<BrightnessCorrection>() {
                 public BrightnessCorrection createFromParcel(Parcel in) {
@@ -215,6 +235,26 @@
         }
 
         @Override
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+            if (!(o instanceof ScaleAndTranslateLog)) {
+                return false;
+            }
+            ScaleAndTranslateLog other = (ScaleAndTranslateLog) o;
+            return other.mScale == mScale && other.mTranslate == mTranslate;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 1;
+            result = result * 31 + Float.hashCode(mScale);
+            result = result * 31 + Float.hashCode(mTranslate);
+            return result;
+        }
+
+        @Override
         public void writeToParcel(Parcel dest) {
             dest.writeInt(SCALE_AND_TRANSLATE_LOG);
             dest.writeFloat(mScale);
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index cda8498..7e45441 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -436,6 +436,7 @@
     public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) {
         try {
             mDm.setVirtualDisplaySurface(token, surface);
+            setVirtualDisplayState(token, surface != null);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
@@ -458,6 +459,14 @@
         }
     }
 
+    void setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn) {
+        try {
+            mDm.setVirtualDisplayState(token, isOn);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
     /**
      * Gets the stable device display size, in pixels.
      */
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 2d81cdf..aae8afb 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -82,6 +82,9 @@
     // No permissions required but must be same Uid as the creator.
     void releaseVirtualDisplay(in IVirtualDisplayCallback token);
 
+    // No permissions required but must be same Uid as the creator.
+    void setVirtualDisplayState(in IVirtualDisplayCallback token, boolean isOn);
+
     // Get a stable metric for the device's display size. No permissions required.
     Point getStableDisplaySize();
 
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
index d354666..bf62c95 100644
--- a/core/java/android/hardware/display/VirtualDisplay.java
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -104,6 +104,18 @@
         }
     }
 
+    /**
+     * Sets the on/off state for a virtual display.
+     *
+     * @param isOn Whether the display should be on or off.
+     * @hide
+     */
+    public void setDisplayState(boolean isOn) {
+        if (mToken != null) {
+            mGlobal.setVirtualDisplayState(mToken, isOn);
+        }
+    }
+
     @Override
     public String toString() {
         return "VirtualDisplay{display=" + mDisplay + ", token=" + mToken
diff --git a/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java b/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
index d382eb9..bdd5ab6 100644
--- a/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
+++ b/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
@@ -15,10 +15,12 @@
  */
 package android.hardware.hdmi;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -56,6 +58,21 @@
         mHandler = handler == null ? new Handler(Looper.getMainLooper()) : handler;
     }
 
+    /**
+     * Callback interface used to get the set System Audio Mode result.
+     *
+     * @hide
+     */
+    // TODO(b/110094868): unhide and add @SystemApi for Q
+    public interface SetSystemAudioModeCallback {
+        /**
+         * Called when the input was changed.
+         *
+         * @param result the result of the set System Audio Mode
+         */
+        void onComplete(int result);
+    }
+
     /** @hide */
     // TODO(b/110094868): unhide and add @SystemApi for Q
     @Override
@@ -117,4 +134,34 @@
             mPendingReportAudioStatus = true;
         }
     }
+
+    /**
+     * Set System Audio Mode on/off with audio system device.
+     *
+     * @param state true to set System Audio Mode on. False to set off.
+     * @param callback callback offer the setting result.
+     *
+     * @hide
+     */
+    // TODO(b/110094868): unhide and add @SystemApi for Q
+    public void setSystemAudioMode(boolean state, @NonNull SetSystemAudioModeCallback callback) {
+        // TODO(amyjojo): implement this when needed.
+    }
+
+    /**
+     * When device is switching to an audio only source, this method is called to broadcast
+     * a setSystemAudioMode on message to the HDMI CEC system without querying Active Source or
+     * TV supporting System Audio Control or not. This is to get volume control passthrough
+     * from STB even if TV does not support it.
+     *
+     * @hide
+     */
+    // TODO(b/110094868): unhide and add @SystemApi for Q
+    public void setSystemAudioModeOnForAudioOnlySource() {
+        try {
+            mService.setSystemAudioModeOnForAudioOnlySource();
+        } catch (RemoteException e) {
+            Log.d(TAG, "Failed to set System Audio Mode on for Audio Only source");
+        }
+    }
 }
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index f5d288e..a98b31a 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -33,6 +33,8 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
+import java.util.List;
+
 /**
  * The {@link HdmiControlManager} class is used to send HDMI control messages
  * to attached CEC devices.
@@ -53,6 +55,10 @@
 
     @Nullable private final IHdmiControlService mService;
 
+    private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
+
+    private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+
     /**
      * Broadcast Action: Display OSD message.
      * <p>Send when the service has a message to display on screen for events
@@ -404,6 +410,72 @@
     }
 
     /**
+     * Get a snapshot of the real-time status of the remote devices.
+     *
+     * @return a list of {@link HdmiDeviceInfo} of the devices connected to the current device.
+     *
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public List<HdmiDeviceInfo> getConnectedDevicesList() {
+        try {
+            return mService.getDeviceList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Power off the target device.
+     *
+     * @param deviceInfo HdmiDeviceInfo of the device to be powered off
+     *
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public void powerOffRemoteDevice(HdmiDeviceInfo deviceInfo) {
+        try {
+            mService.powerOffRemoteDevice(
+                    deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Power on the target device.
+     *
+     * @param deviceInfo HdmiDeviceInfo of the device to be powered on
+     *
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public void powerOnRemoteDevice(HdmiDeviceInfo deviceInfo) {
+        try {
+            mService.powerOnRemoteDevice(
+                    deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Ask the target device to be the new Active Source.
+     *
+     * @param deviceInfo HdmiDeviceInfo of the target device
+     *
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public void askRemoteDeviceToBecomeActiveSource(HdmiDeviceInfo deviceInfo) {
+        try {
+            mService.askRemoteDeviceToBecomeActiveSource(deviceInfo.getPhysicalAddress());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Controls standby mode of the system. It will also try to turn on/off the connected devices if
      * necessary.
      *
@@ -432,6 +504,46 @@
     }
 
     /**
+     * Get the physical address of the device.
+     *
+     * @hide
+     */
+    public int getPhysicalAddress() {
+        if (mPhysicalAddress != INVALID_PHYSICAL_ADDRESS) {
+            return mPhysicalAddress;
+        }
+        try {
+            mPhysicalAddress = mService.getPhysicalAddress();
+            return mPhysicalAddress;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Check if the target device is connected to the current device. The
+     * API also returns true if the current device is the target.
+     *
+     * @param targetDevice {@link HdmiDeviceInfo} of the target device.
+     * @return true if {@code device} is directly or indirectly connected to the
+     *
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public boolean isTargetDeviceConnected(HdmiDeviceInfo targetDevice) {
+        mPhysicalAddress = getPhysicalAddress();
+        if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
+            return false;
+        }
+        int targetPhysicalAddress = targetDevice.getPhysicalAddress();
+        if (targetPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
+            return false;
+        }
+        return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, mPhysicalAddress)
+            != HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE;
+    }
+
+    /**
      * Listener used to get hotplug event from HDMI port.
      */
     public interface HotplugEventListener {
diff --git a/core/java/android/hardware/hdmi/HdmiUtils.java b/core/java/android/hardware/hdmi/HdmiUtils.java
new file mode 100644
index 0000000..3081738
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiUtils.java
@@ -0,0 +1,81 @@
+/*
+ * 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.hardware.hdmi;
+
+/**
+ * Various utilities to handle HDMI CEC messages.
+ *
+ * TODO(b/110094868): unhide for Q
+ * @hide
+ */
+public class HdmiUtils {
+
+    /**
+     * Return value of {@link #getLocalPortFromPhysicalAddress(int, int)}
+     */
+    static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
+    static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;
+
+    private HdmiUtils() { /* cannot be instantiated */ }
+
+    /**
+     * Method to parse target physical address to the port number on the current device.
+     *
+     * <p>This check assumes target address is valid.
+     *
+     * @param targetPhysicalAddress is the physical address of the target device
+     * @param myPhysicalAddress is the physical address of the current device
+     * @return
+     * If the target device is under the current device, return the port number of current device
+     * that the target device is connected to. This also applies to the devices that are indirectly
+     * connected to the current device.
+     *
+     * <p>If the target device has the same physical address as the current device, return
+     * {@link #TARGET_SAME_PHYSICAL_ADDRESS}.
+     *
+     * <p>If the target device is not under the current device, return
+     * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}.
+     */
+    public static int getLocalPortFromPhysicalAddress(
+            int targetPhysicalAddress, int myPhysicalAddress) {
+        if (myPhysicalAddress == targetPhysicalAddress) {
+            return TARGET_SAME_PHYSICAL_ADDRESS;
+        }
+
+        int mask = 0xF000;
+        int finalMask = 0xF000;
+        int maskedAddress = myPhysicalAddress;
+
+        while (maskedAddress != 0) {
+            maskedAddress = myPhysicalAddress & mask;
+            finalMask |= mask;
+            mask >>= 4;
+        }
+
+        int portAddress = targetPhysicalAddress & finalMask;
+        if ((portAddress & (finalMask << 4)) != myPhysicalAddress) {
+            return TARGET_NOT_UNDER_LOCAL_DEVICE;
+        }
+
+        mask <<= 4;
+        int port = portAddress & mask;
+        while ((port >> 4) != 0) {
+            port >>= 4;
+        }
+        return port;
+    }
+}
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 2b8d00b..1cd9920 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -50,6 +50,7 @@
     List<HdmiPortInfo> getPortInfo();
     boolean canChangeSystemAudioMode();
     boolean getSystemAudioMode();
+    int getPhysicalAddress();
     void setSystemAudioMode(boolean enabled, IHdmiControlCallback callback);
     void addSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
     void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
@@ -60,6 +61,9 @@
     void setInputChangeListener(IHdmiInputChangeListener listener);
     List<HdmiDeviceInfo> getInputDevices();
     List<HdmiDeviceInfo> getDeviceList();
+    void powerOffRemoteDevice(int logicalAddress, int powerStatus);
+    void powerOnRemoteDevice(int logicalAddress, int powerStatus);
+    void askRemoteDeviceToBecomeActiveSource(int physicalAddress);
     void sendVendorCommand(int deviceType, int targetAddress, in byte[] params,
             boolean hasVendorId);
     void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType);
@@ -73,4 +77,5 @@
     void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener);
     void setStandbyMode(boolean isStandbyModeOn);
     void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute);
+    void setSystemAudioModeOnForAudioOnlySource();
 }
diff --git a/core/java/android/net/IpPrefixParcelable.aidl b/core/java/android/net/IpPrefixParcelable.aidl
new file mode 100644
index 0000000..93a8d41
--- /dev/null
+++ b/core/java/android/net/IpPrefixParcelable.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+parcelable IpPrefixParcelable {
+    String address;
+    int prefixLength;
+}
\ No newline at end of file
diff --git a/core/java/android/net/LinkAddressParcelable.aidl b/core/java/android/net/LinkAddressParcelable.aidl
new file mode 100644
index 0000000..af8e79b
--- /dev/null
+++ b/core/java/android/net/LinkAddressParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+parcelable LinkAddressParcelable {
+    String address;
+    int prefixLength;
+    int flags;
+    int scope;
+}
\ No newline at end of file
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 617125b3..c2963fd 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -191,6 +191,7 @@
             }
             setMtu(source.mMtu);
             mTcpBufferSizes = source.mTcpBufferSizes;
+            mNat64Prefix = source.mNat64Prefix;
         }
     }
 
diff --git a/core/java/android/net/LinkPropertiesParcelable.aidl b/core/java/android/net/LinkPropertiesParcelable.aidl
new file mode 100644
index 0000000..b153dc7
--- /dev/null
+++ b/core/java/android/net/LinkPropertiesParcelable.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddressParcelable;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfoParcelable;
+
+parcelable LinkPropertiesParcelable {
+    String ifaceName;
+    LinkAddressParcelable[] linkAddresses;
+    String[] dnses;
+    String[] pcscfs;
+    String[] validatedPrivateDnses;
+    boolean usePrivateDns;
+    String privateDnsServerName;
+    String domains;
+    RouteInfoParcelable[] routes;
+    ProxyInfoParcelable httpProxy;
+    int mtu;
+    String tcpBufferSizes;
+    IpPrefixParcelable nat64Prefix;
+    LinkPropertiesParcelable[] stackedLinks;
+}
\ No newline at end of file
diff --git a/core/java/android/net/ProxyInfoParcelable.aidl b/core/java/android/net/ProxyInfoParcelable.aidl
new file mode 100644
index 0000000..59fd846
--- /dev/null
+++ b/core/java/android/net/ProxyInfoParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+parcelable ProxyInfoParcelable {
+    String host;
+    int port;
+    String[] exclusionList;
+    String pacFileUrl;
+}
diff --git a/core/java/android/net/RouteInfoParcelable.aidl b/core/java/android/net/RouteInfoParcelable.aidl
new file mode 100644
index 0000000..15bcdcf
--- /dev/null
+++ b/core/java/android/net/RouteInfoParcelable.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+import android.net.IpPrefixParcelable;
+
+parcelable RouteInfoParcelable {
+    IpPrefixParcelable destination;
+    String gatewayAddr;
+    String ifaceName;
+    int type;
+}
diff --git a/core/java/android/net/ipmemorystore/NetworkAttributes.java b/core/java/android/net/ipmemorystore/NetworkAttributes.java
index d7e5b27..b932d21 100644
--- a/core/java/android/net/ipmemorystore/NetworkAttributes.java
+++ b/core/java/android/net/ipmemorystore/NetworkAttributes.java
@@ -28,6 +28,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.StringJoiner;
 
 /**
  * A POD object to represent attributes of a single L2 network entry.
@@ -207,4 +208,52 @@
     public int hashCode() {
         return Objects.hash(assignedV4Address, groupHint, dnsAddresses, mtu);
     }
+
+    /** Pretty print */
+    @Override
+    public String toString() {
+        final StringJoiner resultJoiner = new StringJoiner(" ", "{", "}");
+        final ArrayList<String> nullFields = new ArrayList<>();
+
+        if (null != assignedV4Address) {
+            resultJoiner.add("assignedV4Addr :");
+            resultJoiner.add(assignedV4Address.toString());
+        } else {
+            nullFields.add("assignedV4Addr");
+        }
+
+        if (null != groupHint) {
+            resultJoiner.add("groupHint :");
+            resultJoiner.add(groupHint);
+        } else {
+            nullFields.add("groupHint");
+        }
+
+        if (null != dnsAddresses) {
+            resultJoiner.add("dnsAddr : [");
+            for (final InetAddress addr : dnsAddresses) {
+                resultJoiner.add(addr.getHostAddress());
+            }
+            resultJoiner.add("]");
+        } else {
+            nullFields.add("dnsAddr");
+        }
+
+        if (null != mtu) {
+            resultJoiner.add("mtu :");
+            resultJoiner.add(mtu.toString());
+        } else {
+            nullFields.add("mtu");
+        }
+
+        if (!nullFields.isEmpty()) {
+            resultJoiner.add("; Null fields : [");
+            for (final String field : nullFields) {
+                resultJoiner.add(field);
+            }
+            resultJoiner.add("]");
+        }
+
+        return resultJoiner.toString();
+    }
 }
diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java b/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
index 0cb37e9..d040dcc 100644
--- a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
+++ b/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
@@ -128,4 +128,19 @@
     public int hashCode() {
         return Objects.hash(l2Key1, l2Key2, confidence);
     }
+
+    @Override
+    /** Pretty print */
+    public String toString() {
+        switch (getNetworkSameness()) {
+            case NETWORK_SAME:
+                return "\"" + l2Key1 + "\" same L3 network as \"" + l2Key2 + "\"";
+            case NETWORK_DIFFERENT:
+                return "\"" + l2Key1 + "\" different L3 network from \"" + l2Key2 + "\"";
+            case NETWORK_NEVER_CONNECTED:
+                return "\"" + l2Key1 + "\" can't be tested against \"" + l2Key2 + "\"";
+            default:
+                return "Buggy sameness value ? \"" + l2Key1 + "\", \"" + l2Key2 + "\"";
+        }
+    }
 }
diff --git a/core/java/android/net/ipmemorystore/Status.java b/core/java/android/net/ipmemorystore/Status.java
index 5b016ec..95e5042 100644
--- a/core/java/android/net/ipmemorystore/Status.java
+++ b/core/java/android/net/ipmemorystore/Status.java
@@ -26,6 +26,8 @@
 public class Status {
     public static final int SUCCESS = 0;
 
+    public static final int ERROR_DATABASE_CANNOT_BE_OPENED = -1;
+
     public final int resultCode;
 
     public Status(final int resultCode) {
@@ -47,4 +49,14 @@
     public boolean isSuccess() {
         return SUCCESS == resultCode;
     }
+
+    /** Pretty print */
+    @Override
+    public String toString() {
+        switch (resultCode) {
+            case SUCCESS: return "SUCCESS";
+            case ERROR_DATABASE_CANNOT_BE_OPENED: return "DATABASE CANNOT BE OPENED";
+            default: return "Unknown value ?!";
+        }
+    }
 }
diff --git a/core/java/android/net/ipmemorystore/Utils.java b/core/java/android/net/ipmemorystore/Utils.java
new file mode 100644
index 0000000..73d8c83
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/Utils.java
@@ -0,0 +1,44 @@
+/*
+ * 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.net.ipmemorystore;
+
+import android.annotation.NonNull;
+
+/** {@hide} */
+public class Utils {
+    /** Pretty print */
+    public static String blobToString(final Blob blob) {
+        final StringBuilder sb = new StringBuilder("Blob : [");
+        if (blob.data.length <= 24) {
+            appendByteArray(sb, blob.data, 0, blob.data.length);
+        } else {
+            appendByteArray(sb, blob.data, 0, 16);
+            sb.append("...");
+            appendByteArray(sb, blob.data, blob.data.length - 8, blob.data.length);
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    // Adds the hex representation of the array between the specified indices (inclusive, exclusive)
+    private static void appendByteArray(@NonNull final StringBuilder sb, @NonNull final byte[] ar,
+            final int from, final int to) {
+        for (int i = from; i < to; ++i) {
+            sb.append(String.format("%02X", ar[i]));
+        }
+    }
+}
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 1343d24..cbb3909 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -114,8 +114,6 @@
         }
     }
 
-
-    // TODO(b/111441001) Connect up with BugreportListener methods.
     private final class DumpstateListener extends IDumpstateListener.Stub
             implements DeathRecipient {
         private final BugreportListener mListener;
@@ -130,19 +128,36 @@
         }
 
         @Override
+        public void onProgress(int progress) throws RemoteException {
+            mListener.onProgress(progress);
+        }
+
+        @Override
+        public void onError(int errorCode) throws RemoteException {
+            mListener.onError(errorCode);
+        }
+
+        @Override
+        public void onFinished(long durationMs, String title, String description)
+                throws RemoteException {
+            mListener.onFinished(durationMs, title, description);
+        }
+
+        // Old methods; should go away
+        @Override
         public void onProgressUpdated(int progress) throws RemoteException {
-            // TODO(b/111441001): implement
+            // TODO(b/111441001): remove from interface
         }
 
         @Override
         public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
-            // TODO(b/111441001): implement
+            // TODO(b/111441001): remove from interface
         }
 
         @Override
         public void onSectionComplete(String title, int status, int size, int durationMs)
                 throws RemoteException {
-            // TODO(b/111441001): implement
+            // TODO(b/111441001): remove from interface
         }
     }
 }
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 9fea873..2d61a4e 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -289,6 +289,26 @@
                 "ro.build.version.preview_sdk", 0);
 
         /**
+         * The SDK fingerprint for a given prerelease SDK. This value will always be
+         * {@code REL} on production platform builds/devices.
+         *
+         * <p>When this value is not {@code REL}, it contains a string fingerprint of the API
+         * surface exposed by the preview SDK. Preview platforms with different API surfaces
+         * will have different {@code PREVIEW_SDK_FINGERPRINT}.
+         *
+         * <p>This attribute is intended for use by installers for finer grained targeting of
+         * packages. Applications targeting preview APIs should not use this field and should
+         * instead use {@code PREVIEW_SDK_INT} or use reflection or other runtime checks to
+         * detect the presence of an API or guard themselves against unexpected runtime
+         * behavior.
+         *
+         * @hide
+         */
+        @SystemApi
+        public static final String PREVIEW_SDK_FINGERPRINT = SystemProperties.get(
+                "ro.build.version.preview_sdk_fingerprint", "REL");
+
+        /**
          * The current development codename, or the string "REL" if this is
          * a release build.
          */
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index b0b8f49..f51ba9a 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -306,9 +306,18 @@
                                                 String packageName,
                                                 String paths,
                                                 String devOptIn) {
-        // Check for temporary rules if debuggable or root
-        if (!isDebuggable(context) && !(getCanLoadSystemLibraries() == 1)) {
-            Log.v(TAG, "Skipping loading temporary rules file");
+        /**
+         * We only want to load a temp rules file for:
+         *  - apps that are marked 'debuggable' in their manifest
+         *  - devices that are running a userdebug build (ro.debuggable) or can inject libraries for
+         *    debugging (PR_SET_DUMPABLE).
+         */
+        boolean appIsDebuggable = isDebuggable(context);
+        boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
+        if (!(appIsDebuggable || deviceIsDebuggable)) {
+            Log.v(TAG, "Skipping loading temporary rules file: "
+                    + "appIsDebuggable = " + appIsDebuggable + ", "
+                    + "adbRootEnabled = " + deviceIsDebuggable);
             return false;
         }
 
@@ -480,21 +489,36 @@
             return;
         }
 
-        if (getGlobalSettingsString(coreSettings, Settings.Global.GUP_DEV_OPT_OUT_APPS)
-                        .contains(ai.packageName)) {
+        // GUP_DEV_ALL_APPS
+        // 0: Default (Invalid values fallback to default as well)
+        // 1: All apps use Game Update Package
+        // 2: All apps use system graphics driver
+        int gupDevAllApps = coreSettings.getInt(Settings.Global.GUP_DEV_ALL_APPS, 0);
+        if (gupDevAllApps == 2) {
             if (DEBUG) {
-                Log.w(TAG, ai.packageName + " opts out from GUP.");
+                Log.w(TAG, "GUP is turned off on this device");
             }
             return;
         }
 
-        if (!getGlobalSettingsString(coreSettings, Settings.Global.GUP_DEV_OPT_IN_APPS)
-                        .contains(ai.packageName)
-                && !onWhitelist(context, driverPackageName, ai.packageName)) {
-            if (DEBUG) {
-                Log.w(TAG, ai.packageName + " is not on the whitelist.");
+        if (gupDevAllApps != 1) {
+            // GUP_DEV_OPT_OUT_APPS has higher priority than GUP_DEV_OPT_IN_APPS
+            if (getGlobalSettingsString(coreSettings, Settings.Global.GUP_DEV_OPT_OUT_APPS)
+                            .contains(ai.packageName)) {
+                if (DEBUG) {
+                    Log.w(TAG, ai.packageName + " opts out from GUP.");
+                }
+                return;
             }
-            return;
+
+            if (!getGlobalSettingsString(coreSettings, Settings.Global.GUP_DEV_OPT_IN_APPS)
+                            .contains(ai.packageName)
+                    && !onWhitelist(context, driverPackageName, ai.packageName)) {
+                if (DEBUG) {
+                    Log.w(TAG, ai.packageName + " is not on the whitelist.");
+                }
+                return;
+            }
         }
 
         ApplicationInfo driverInfo;
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index 3de3494..9e3e83e 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 
 import libcore.util.NativeAllocationRegistry;
 
@@ -24,6 +25,7 @@
 
 /** @hide */
 @SystemApi
+@TestApi
 public abstract class HwBinder implements IHwBinder {
     private static final String TAG = "HwBinder";
 
diff --git a/core/java/android/os/HwBlob.java b/core/java/android/os/HwBlob.java
index 6a5bb1c..0ec63b5 100644
--- a/core/java/android/os/HwBlob.java
+++ b/core/java/android/os/HwBlob.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 
 import libcore.util.NativeAllocationRegistry;
 
@@ -28,6 +29,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public class HwBlob {
     private static final String TAG = "HwBlob";
 
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index 7a51db2..7919a00 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 
 import libcore.util.NativeAllocationRegistry;
 
@@ -28,6 +29,7 @@
 
 /** @hide */
 @SystemApi
+@TestApi
 public class HwParcel {
     private static final String TAG = "HwParcel";
 
diff --git a/core/java/android/os/IHwBinder.java b/core/java/android/os/IHwBinder.java
index 249eb3a..46fa6ef 100644
--- a/core/java/android/os/IHwBinder.java
+++ b/core/java/android/os/IHwBinder.java
@@ -17,9 +17,11 @@
 package android.os;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 
 /** @hide */
 @SystemApi
+@TestApi
 public interface IHwBinder {
     /**
      * Process a hwbinder transaction.
diff --git a/core/java/android/os/IHwInterface.java b/core/java/android/os/IHwInterface.java
index f9edd5b..0a5a715 100644
--- a/core/java/android/os/IHwInterface.java
+++ b/core/java/android/os/IHwInterface.java
@@ -17,8 +17,11 @@
 package android.os;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
+
 /** @hide */
 @SystemApi
+@TestApi
 public interface IHwInterface {
     /**
      * @return the binder object that corresponds to this interface.
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index fdd7488..8ced722 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -356,16 +356,6 @@
     void removeVpnUidRanges(int netId, in UidRange[] ranges);
 
     /**
-     * Start the clatd (464xlat) service on the given interface.
-     */
-    void startClatd(String interfaceName);
-
-    /**
-     * Stop the clatd (464xlat) service on the given interface.
-     */
-    void stopClatd(String interfaceName);
-
-    /**
      * Start listening for mobile activity state changes.
      */
     void registerNetworkActivityListener(INetworkActivityListener listener);
diff --git a/core/java/android/os/NativeHandle.java b/core/java/android/os/NativeHandle.java
index f7ffc37..f13bf5f 100644
--- a/core/java/android/os/NativeHandle.java
+++ b/core/java/android/os/NativeHandle.java
@@ -20,6 +20,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.system.ErrnoException;
 import android.system.Os;
 
@@ -32,6 +33,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public final class NativeHandle implements Closeable {
     // whether this object owns mFds
     private boolean mOwn = false;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index ee56e3d..760fef7 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -208,30 +208,35 @@
      * First uid used for fully isolated sandboxed processes spawned from an app zygote
      * @hide
      */
+    @TestApi
     public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000;
 
     /**
      * Number of UIDs we allocate per application zygote
      * @hide
      */
+    @TestApi
     public static final int NUM_UIDS_PER_APP_ZYGOTE = 100;
 
     /**
      * Last uid used for fully isolated sandboxed processes spawned from an app zygote
      * @hide
      */
+    @TestApi
     public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999;
 
     /**
      * First uid used for fully isolated sandboxed processes (with no permissions of their own)
      * @hide
      */
+    @TestApi
     public static final int FIRST_ISOLATED_UID = 99000;
 
     /**
      * Last uid used for fully isolated sandboxed processes (with no permissions of their own)
      * @hide
      */
+    @TestApi
     public static final int LAST_ISOLATED_UID = 99999;
 
     /**
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index fb22194..23c54f4 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -16,23 +16,27 @@
 
 package android.os;
 
-import java.util.Map;
+import android.annotation.TestApi;
 
+import java.util.Map;
 
 /**
  * Java API for libvintf.
+ *
  * @hide
  */
+@TestApi
 public class VintfObject {
 
-    /// ---------- OTA
-
     /**
      * Slurps all device information (both manifests and both matrices)
      * and report them.
      * If any error in getting one of the manifests, it is not included in
      * the list.
+     *
+     * @hide
      */
+    @TestApi
     public static native String[] report();
 
     /**
@@ -44,6 +48,8 @@
      * @return = 0 if success (compatible)
      *         > 0 if incompatible
      *         < 0 if any error (mount partition fails, illformed XML, etc.)
+     *
+     * @hide
      */
     public static native int verify(String[] packageInfo);
 
@@ -55,22 +61,28 @@
      * @return = 0 if success (compatible)
      *         > 0 if incompatible
      *         < 0 if any error (mount partition fails, illformed XML, etc.)
+     *
+     * @hide
      */
     public static native int verifyWithoutAvb();
 
-    /// ---------- CTS Device Info
-
     /**
      * @return a list of HAL names and versions that is supported by this
      * device as stated in device and framework manifests. For example,
      * ["android.hidl.manager@1.0", "android.hardware.camera.device@1.0",
      *  "android.hardware.camera.device@3.2"]. There are no duplicates.
+     *
+     * @hide
      */
+    @TestApi
     public static native String[] getHalNamesAndVersions();
 
     /**
      * @return the BOARD_SEPOLICY_VERS build flag available in device manifest.
+     *
+     * @hide
      */
+    @TestApi
     public static native String getSepolicyVersion();
 
     /**
@@ -78,13 +90,22 @@
      * specified in framework manifest. For example,
      * [("27", ["libjpeg.so", "libbase.so"]),
      *  ("28", ["libjpeg.so", "libbase.so"])]
+     *
+     * @hide
      */
+    @TestApi
     public static native Map<String, String[]> getVndkSnapshots();
 
     /**
-     * @return target FCM version, a number specified in the device manifest
-     * indicating the FCM version that the device manifest implements. Null if
-     * device manifest doesn't specify this number (for legacy devices).
+     * @return Target Framework Compatibility Matrix (FCM) version, a number
+     * specified in the device manifest indicating the FCM version that the
+     * device manifest implements. Null if device manifest doesn't specify this
+     * number (for legacy devices).
+     *
+     * @hide
      */
+    @TestApi
     public static native Long getTargetFrameworkCompatibilityMatrixVersion();
+
+    private VintfObject() {}
 }
diff --git a/core/java/android/os/VintfRuntimeInfo.java b/core/java/android/os/VintfRuntimeInfo.java
index 29698b9..f17039b 100644
--- a/core/java/android/os/VintfRuntimeInfo.java
+++ b/core/java/android/os/VintfRuntimeInfo.java
@@ -16,55 +16,84 @@
 
 package android.os;
 
+import android.annotation.TestApi;
+
 /**
  * Java API for ::android::vintf::RuntimeInfo. Methods return null / 0 on any error.
  *
  * @hide
  */
+@TestApi
 public class VintfRuntimeInfo {
 
     private VintfRuntimeInfo() {}
 
     /**
      * @return /sys/fs/selinux/policyvers, via security_policyvers() native call
+     *
+     * @hide
      */
     public static native long getKernelSepolicyVersion();
     /**
      * @return content of /proc/cpuinfo
+     *
+     * @hide
      */
+    @TestApi
     public static native String getCpuInfo();
     /**
      * @return os name extracted from uname() native call
+     *
+     * @hide
      */
+    @TestApi
     public static native String getOsName();
     /**
      * @return node name extracted from uname() native call
+     *
+     * @hide
      */
+    @TestApi
     public static native String getNodeName();
     /**
      * @return os release extracted from uname() native call
+     *
+     * @hide
      */
+    @TestApi
     public static native String getOsRelease();
     /**
      * @return os version extracted from uname() native call
+     *
+     * @hide
      */
+    @TestApi
     public static native String getOsVersion();
     /**
      * @return hardware id extracted from uname() native call
+     *
+     * @hide
      */
+    @TestApi
     public static native String getHardwareId();
     /**
      * @return kernel version extracted from uname() native call. Format is
      * {@code x.y.z}.
+     *
+     * @hide
      */
+    @TestApi
     public static native String getKernelVersion();
     /**
      * @return libavb version in OS. Format is {@code x.y}.
+     *
+     * @hide
      */
     public static native String getBootAvbVersion();
     /**
      * @return libavb version in bootloader. Format is {@code x.y}.
+     *
+     * @hide
      */
     public static native String getBootVbmetaAvbVersion();
-
 }
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index 7a7bd83..249b622 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -18,6 +18,8 @@
 
 import android.os.RemoteCallback;
 import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
 
 /**
  * Interface for system apps to communication with the permission controller.
@@ -27,6 +29,7 @@
 oneway interface IPermissionController {
     void revokeRuntimePermissions(in Bundle request, boolean doDryRun, int reason,
             String callerPackageName, in RemoteCallback callback);
+    void getRuntimePermissionBackup(in UserHandle user, in ParcelFileDescriptor pipe);
     void getAppPermissions(String packageName, in RemoteCallback callback);
     void revokeRuntimePermission(String packageName, String permissionName);
     void countPermissionApps(in List<String> permissionNames, boolean countOnlyGranted,
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 0865b62..bfcca7c 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -36,10 +36,12 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -51,6 +53,11 @@
 import com.android.internal.infra.AbstractRemoteService;
 import com.android.internal.util.Preconditions;
 
+import libcore.io.IoUtils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -58,6 +65,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * Interface for communicating with the permission controller.
@@ -118,6 +126,20 @@
     }
 
     /**
+     * Callback for delivering the result of {@link #getRuntimePermissionBackup}.
+     *
+     * @hide
+     */
+    public interface OnGetRuntimePermissionBackupCallback {
+        /**
+         * The result for {@link #getRuntimePermissionBackup}.
+         *
+         * @param backup The backup file
+         */
+        void onGetRuntimePermissionsBackup(@NonNull byte[] backup);
+    }
+
+    /**
      * Callback for delivering the result of {@link #getAppPermissions}.
      *
      * @hide
@@ -219,6 +241,26 @@
     }
 
     /**
+     * Create a backup of the runtime permissions.
+     *
+     * @param user The user to be backed up
+     * @param executor Executor on which to invoke the callback
+     * @param callback Callback to receive the result
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
+    public void getRuntimePermissionBackup(@NonNull UserHandle user,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnGetRuntimePermissionBackupCallback callback) {
+        checkNotNull(executor);
+        checkNotNull(callback);
+
+        sRemoteService.scheduleRequest(new PendingGetRuntimePermissionBackup(sRemoteService,
+                user, executor, callback));
+    }
+
+    /**
      * Gets the runtime permissions for an app.
      *
      * @param packageName The package for which to query.
@@ -355,6 +397,89 @@
     }
 
     /**
+     * Task to read a large amount of data from a remote service.
+     */
+    private static class FileReaderTask<Callback extends Consumer<byte[]>>
+            extends AsyncTask<Void, Void, byte[]> {
+        private ParcelFileDescriptor mLocalPipe;
+        private ParcelFileDescriptor mRemotePipe;
+
+        private final @NonNull Callback mCallback;
+
+        FileReaderTask(@NonNull Callback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        protected void onPreExecute() {
+            ParcelFileDescriptor[] pipe;
+            try {
+                pipe = ParcelFileDescriptor.createPipe();
+            } catch (IOException e) {
+                Log.e(TAG, "Could not create pipe needed to get runtime permission backup", e);
+                return;
+            }
+
+            mLocalPipe = pipe[0];
+            mRemotePipe = pipe[1];
+        }
+
+        /**
+         * Get the file descriptor the remote service should write the data to.
+         *
+         * <p>Needs to be closed <u>locally</u> before the FileReader can finish.
+         *
+         * @return The file the data should be written to
+         */
+        ParcelFileDescriptor getRemotePipe() {
+            return mRemotePipe;
+        }
+
+        @Override
+        protected byte[] doInBackground(Void... ignored) {
+            ByteArrayOutputStream combinedBuffer = new ByteArrayOutputStream();
+
+            try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(mLocalPipe)) {
+                byte[] buffer = new byte[16 * 1024];
+
+                while (!isCancelled()) {
+                    int numRead = in.read(buffer);
+                    if (numRead == -1) {
+                        break;
+                    }
+
+                    combinedBuffer.write(buffer, 0, numRead);
+                }
+            } catch (IOException | NullPointerException e) {
+                Log.e(TAG, "Error reading runtime permission backup", e);
+                combinedBuffer.reset();
+            }
+
+            return combinedBuffer.toByteArray();
+        }
+
+        /**
+         * Interrupt the reading of the data.
+         *
+         * <p>Needs to be called when canceling this task as it might be hung.
+         */
+        void interruptRead() {
+            IoUtils.closeQuietly(mLocalPipe);
+        }
+
+        @Override
+        protected void onCancelled() {
+            onPostExecute(new byte[]{});
+        }
+
+        @Override
+        protected void onPostExecute(byte[] backup) {
+            IoUtils.closeQuietly(mLocalPipe);
+            mCallback.accept(backup);
+        }
+    }
+
+    /**
      * Request for {@link #revokeRuntimePermissions}
      */
     private static final class PendingRevokeRuntimePermissionRequest extends
@@ -441,6 +566,68 @@
     }
 
     /**
+     * Request for {@link #getRuntimePermissionBackup}
+     */
+    private static final class PendingGetRuntimePermissionBackup extends
+            AbstractRemoteService.PendingRequest<RemoteService, IPermissionController>
+            implements Consumer<byte[]> {
+        private final @NonNull FileReaderTask<PendingGetRuntimePermissionBackup> mBackupReader;
+        private final @NonNull Executor mExecutor;
+        private final @NonNull OnGetRuntimePermissionBackupCallback mCallback;
+        private final @NonNull UserHandle mUser;
+
+        private PendingGetRuntimePermissionBackup(@NonNull RemoteService service,
+                @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor,
+                @NonNull OnGetRuntimePermissionBackupCallback callback) {
+            super(service);
+
+            mUser = user;
+            mExecutor = executor;
+            mCallback = callback;
+
+            mBackupReader = new FileReaderTask<>(this);
+        }
+
+        @Override
+        protected void onTimeout(RemoteService remoteService) {
+            mBackupReader.cancel(true);
+            mBackupReader.interruptRead();
+        }
+
+        @Override
+        public void run() {
+            mBackupReader.execute();
+
+            ParcelFileDescriptor remotePipe = mBackupReader.getRemotePipe();
+            try {
+                getService().getServiceInterface().getRuntimePermissionBackup(mUser, remotePipe);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error getting runtime permission backup", e);
+            } finally {
+                // Remote pipe end is duped by binder call. Local copy is not needed anymore
+                IoUtils.closeQuietly(remotePipe);
+            }
+        }
+
+        /**
+         * Called when the {@link #mBackupReader} finished reading the file.
+         *
+         * @param backup The data read
+         */
+        @Override
+        public void accept(byte[] backup) {
+            long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onGetRuntimePermissionsBackup(backup));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+
+            finish();
+        }
+    }
+
+    /**
      * Request for {@link #getAppPermissions}
      */
     private static final class PendingGetAppPermissionRequest extends
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 75d61e6..10e8c8d 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -33,11 +33,16 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallback;
+import android.os.UserHandle;
 import android.util.ArrayMap;
+import android.util.Log;
 
 import com.android.internal.util.Preconditions;
 
+import java.io.IOException;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -51,6 +56,7 @@
  */
 @SystemApi
 public abstract class PermissionControllerService extends Service {
+    private static final String LOG_TAG = PermissionControllerService.class.getSimpleName();
 
     /**
      * The {@link Intent} action that must be declared as handled by a service
@@ -83,6 +89,15 @@
             @PermissionControllerManager.Reason int reason, @NonNull String callerPackageName);
 
     /**
+     * Create a backup of the runtime permissions.
+     *
+     * @param user The user to back up
+     * @param out The stream to write the backup to
+     */
+    public abstract void onGetRuntimePermissionsBackup(@NonNull UserHandle user,
+            @NonNull OutputStream out);
+
+    /**
      * Gets the runtime permissions for an app.
      *
      * @param packageName The package for which to query.
@@ -163,6 +178,18 @@
             }
 
             @Override
+            public void getRuntimePermissionBackup(UserHandle user, ParcelFileDescriptor pipe) {
+                checkNotNull(user);
+                checkNotNull(pipe);
+
+                enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+
+                mHandler.sendMessage(obtainMessage(
+                        PermissionControllerService::getRuntimePermissionsBackup,
+                        PermissionControllerService.this, user, pipe));
+            }
+
+            @Override
             public void getAppPermissions(String packageName, RemoteCallback callback) {
                 checkNotNull(packageName, "packageName");
                 checkNotNull(callback, "callback");
@@ -237,6 +264,15 @@
         callback.sendResult(result);
     }
 
+    private void getRuntimePermissionsBackup(@NonNull UserHandle user,
+            @NonNull ParcelFileDescriptor outFile) {
+        try (OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(outFile)) {
+            onGetRuntimePermissionsBackup(user, out);
+        } catch (IOException e) {
+            Log.e(LOG_TAG, "Could not open pipe to write backup tp", e);
+        }
+    }
+
     private void getAppPermissions(@NonNull String packageName, @NonNull RemoteCallback callback) {
         List<RuntimePermissionPresentationInfo> permissions = onGetAppPermissions(packageName);
         if (permissions != null && !permissions.isEmpty()) {
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index c795895..af8146e 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -16,9 +16,13 @@
 
 package android.provider;
 
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
+
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.app.ActivityThread;
 import android.content.ContentResolver;
@@ -49,6 +53,13 @@
     public static final Uri CONTENT_URI = Uri.parse("content://" + Settings.AUTHORITY + "/config");
 
     /**
+     * Namespace for all Game Driver features.
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_GAME_DRIVER = "game_driver";
+
+    /**
      * Namespace for all input-related features that are used at the native level.
      * These features are applied at reboot.
      *
@@ -78,6 +89,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(READ_DEVICE_CONFIG)
     public static String getProperty(String namespace, String name) {
         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
         String compositeName = createCompositeName(namespace, name);
@@ -105,6 +117,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(WRITE_DEVICE_CONFIG)
     public static boolean setProperty(
             String namespace, String name, String value, boolean makeDefault) {
         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
@@ -125,6 +138,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(WRITE_DEVICE_CONFIG)
     public static void resetToDefaults(@ResetMode int resetMode, @Nullable String namespace) {
         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
         Settings.Config.resetToDefaults(contentResolver, resetMode, namespace);
@@ -146,10 +160,12 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(READ_DEVICE_CONFIG)
     public static void addOnPropertyChangedListener(
             @NonNull String namespace,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull OnPropertyChangedListener onPropertyChangedListener) {
+        // TODO enforce READ_DEVICE_CONFIG permission
         synchronized (sLock) {
             Pair<String, Executor> oldNamespace = sListeners.get(onPropertyChangedListener);
             if (oldNamespace == null) {
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index 8e37559..e931826 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -34,6 +34,7 @@
 import android.graphics.fonts.FontStyle;
 import android.graphics.fonts.FontVariationAxis;
 import android.net.Uri;
+import android.os.Build.VERSION_CODES;
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -651,7 +652,16 @@
                 if (familyBuilder == null) {
                     familyBuilder = new FontFamily.Builder(font);
                 } else {
-                    familyBuilder.addFont(font);
+                    try {
+                        familyBuilder.addFont(font);
+                    } catch (IllegalArgumentException e) {
+                        if (context.getApplicationInfo().targetSdkVersion <= VERSION_CODES.P) {
+                            // Surpress the IllegalArgumentException for keeping the backward
+                            // compatibility.
+                            continue;
+                        }
+                        throw e;
+                    }
                 }
             } catch (IOException e) {
                 continue;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ef117ea..b39d871 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7391,6 +7391,14 @@
         private static final Validator DOZE_DOUBLE_TAP_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
+         * Whether the device should respond to the SLPI tap gesture.
+         * @hide
+         */
+        public static final String DOZE_TAP_SCREEN_GESTURE = "doze_tap_gesture";
+
+        private static final Validator DOZE_TAP_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
          * Gesture that wakes up the lock screen.
          * @hide
          */
@@ -7407,6 +7415,22 @@
         private static final Validator DOZE_WAKE_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
+         * Gesture that skips media.
+         * @hide
+         */
+        public static final String SKIP_GESTURE = "skip_gesture";
+
+        private static final Validator SKIP_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
+         * Gesture that silences sound (alarms, notification, calls).
+         * @hide
+         */
+        public static final String SILENCE_GESTURE = "silence_gesture";
+
+        private static final Validator SILENCE_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
          * The current night mode that has been selected by the user.  Owned
          * and controlled by UiModeManagerService.  Constants are as per
          * UiModeManager.
@@ -7708,6 +7732,23 @@
         public static final String TV_INPUT_CUSTOM_LABELS = "tv_input_custom_labels";
 
         /**
+         * Whether TV app uses non-system inputs.
+         *
+         * <p>
+         * The value is boolean (1 or 0), where 1 means non-system TV inputs are allowed,
+         * and 0 means non-system TV inputs are not allowed.
+         *
+         * <p>
+         * Devices such as sound bars may have changed the system property allow_third_party_inputs
+         * to false so the TV Application only uses HDMI and other built in inputs. This setting
+         * allows user to override the default and have the TV Application use third party TV inputs
+         * available on play store.
+         *
+         * @hide
+         */
+        public static final String TV_APP_USES_NON_SYSTEM_INPUTS = "tv_app_uses_non_system_inputs";
+
+        /**
          * Whether automatic routing of system audio to USB audio peripheral is disabled.
          * The value is boolean (1 or 0), where 1 means automatic routing is disabled,
          * and 0 means automatic routing is enabled.
@@ -8445,6 +8486,7 @@
             DOZE_ALWAYS_ON,
             DOZE_PICK_UP_GESTURE,
             DOZE_DOUBLE_TAP_GESTURE,
+            DOZE_TAP_SCREEN_GESTURE,
             DOZE_WAKE_LOCK_SCREEN_GESTURE,
             DOZE_WAKE_SCREEN_GESTURE,
             NFC_PAYMENT_DEFAULT_COMPONENT,
@@ -8483,6 +8525,8 @@
             NOTIFICATION_NEW_INTERRUPTION_MODEL,
             TRUST_AGENTS_EXTEND_UNLOCK,
             LOCK_SCREEN_WHEN_TRUST_LOST,
+            SKIP_GESTURE,
+            SILENCE_GESTURE,
         };
 
         /**
@@ -8599,6 +8643,7 @@
             VALIDATORS.put(DOZE_ALWAYS_ON, DOZE_ALWAYS_ON_VALIDATOR);
             VALIDATORS.put(DOZE_PICK_UP_GESTURE, DOZE_PICK_UP_GESTURE_VALIDATOR);
             VALIDATORS.put(DOZE_DOUBLE_TAP_GESTURE, DOZE_DOUBLE_TAP_GESTURE_VALIDATOR);
+            VALIDATORS.put(DOZE_TAP_SCREEN_GESTURE, DOZE_TAP_SCREEN_GESTURE_VALIDATOR);
             VALIDATORS.put(DOZE_WAKE_LOCK_SCREEN_GESTURE, DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR);
             VALIDATORS.put(DOZE_WAKE_SCREEN_GESTURE, DOZE_WAKE_SCREEN_GESTURE_VALIDATOR);
             VALIDATORS.put(NFC_PAYMENT_DEFAULT_COMPONENT, NFC_PAYMENT_DEFAULT_COMPONENT_VALIDATOR);
@@ -8650,6 +8695,8 @@
             VALIDATORS.put(TRUST_AGENTS_EXTEND_UNLOCK, TRUST_AGENTS_EXTEND_UNLOCK_VALIDATOR);
             VALIDATORS.put(LOCK_SCREEN_CUSTOM_CLOCK_FACE, LOCK_SCREEN_CUSTOM_CLOCK_FACE_VALIDATOR);
             VALIDATORS.put(LOCK_SCREEN_WHEN_TRUST_LOST, LOCK_SCREEN_WHEN_TRUST_LOST_VALIDATOR);
+            VALIDATORS.put(SKIP_GESTURE, SKIP_GESTURE_VALIDATOR);
+            VALIDATORS.put(SILENCE_GESTURE, SILENCE_GESTURE_VALIDATOR);
         }
 
         /**
@@ -8681,10 +8728,10 @@
             CLONE_TO_MANAGED_PROFILE.add(LOCATION_CHANGER);
             CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
             CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED);
-            CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
             if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
                 CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD);
                 CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
+                CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
                 CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER);
                 CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER_SUBTYPE);
             }
@@ -9361,6 +9408,15 @@
                 "hdmi_system_audio_control_enabled";
 
         /**
+         * Whether HDMI Routing Control feature is enabled. If enabled, the switch device will
+         * route to the correct input source on receiving Routing Control related messages. If
+         * disabled, you can only switch the input via controls on this device.
+         * @hide
+         */
+        public static final String HDMI_CEC_SWITCH_ENABLED =
+                "hdmi_cec_switch_enabled";
+
+        /**
          * Whether TV will automatically turn on upon reception of the CEC command
          * &lt;Text View On&gt; or &lt;Image View On&gt;. (0 = false, 1 = true)
          *
@@ -11062,6 +11118,31 @@
         /** {@hide} */
         public static final String
                 BLUETOOTH_HEARING_AID_PRIORITY_PREFIX = "bluetooth_hearing_aid_priority_";
+        /**
+         * Enable/disable radio bug detection
+         *
+         * {@hide}
+         */
+        public static final String
+                ENABLE_RADIO_BUG_DETECTION = "enable_radio_bug_detection";
+
+        /**
+         * Count threshold of RIL wakelock timeout for radio bug detection
+         *
+         * {@hide}
+         */
+        public static final String
+                RADIO_BUG_WAKELOCK_TIMEOUT_COUNT_THRESHOLD =
+                "radio_bug_wakelock_timeout_count_threshold";
+
+        /**
+         * Count threshold of RIL system error for radio bug detection
+         *
+         * {@hide}
+         */
+        public static final String
+                RADIO_BUG_SYSTEM_ERROR_COUNT_THRESHOLD =
+                "radio_bug_system_error_count_threshold";
 
         /**
          * Activity manager specific settings.
@@ -11552,6 +11633,7 @@
          * battery_level_collection_delay_ms (long)
          * max_history_files (int)
          * max_history_buffer_kb (int)
+         * battery_charged_delay_ms (int)
          * </pre>
          *
          * <p>
@@ -11937,22 +12019,33 @@
                 "angle_gl_driver_selection_values";
 
         /**
-         * List of Apps selected to use Game Update Packages.
+         * Game Update Package global preference for all Apps.
+         * 0 = Default
+         * 1 = All Apps use Game Update Package
+         * 2 = All Apps use system graphics driver
+         * @hide
+         */
+        public static final String GUP_DEV_ALL_APPS = "gup_dev_all_apps";
+
+        /**
+         * List of Apps selected to use Game Update Package.
+         * i.e. <pkg1>,<pkg2>,...,<pkgN>
          * @hide
          */
         public static final String GUP_DEV_OPT_IN_APPS = "gup_dev_opt_in_apps";
 
         /**
-         * List of Apps selected not to use Game Update Packages.
+         * List of Apps selected not to use Game Update Package.
+         * i.e. <pkg1>,<pkg2>,...,<pkgN>
          * @hide
          */
         public static final String GUP_DEV_OPT_OUT_APPS = "gup_dev_opt_out_apps";
 
         /**
-         * Apps on the black list that are forbidden to useGame Update Package.
+         * Apps on the blacklist that are forbidden to use Game Update Package.
          * @hide
          */
-        public static final String GUP_BLACK_LIST = "gup_black_list";
+        public static final String GUP_BLACKLIST = "gup_blacklist";
 
         /**
          * Ordered GPU debug layer list for Vulkan
@@ -14033,7 +14126,7 @@
          *
          * @hide
          */
-        // TODO(b/117663715): require a new read permission
+        @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
         static String getString(ContentResolver resolver, String name) {
             return sNameValueCache.getStringForUser(resolver, name, resolver.getUserId());
         }
@@ -14056,8 +14149,7 @@
          *
          * @hide
          */
-        // TODO(b/117663715): require a new write permission restricted to a single source
-        @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+        @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
         static boolean putString(@NonNull ContentResolver resolver, @NonNull String name,
                 @Nullable String value, boolean makeDefault) {
             return sNameValueCache.putStringForUser(resolver, name, value, null, makeDefault,
@@ -14079,7 +14171,7 @@
          * @hide
          */
         // TODO(b/117663715): require a new write permission restricted to a single source
-        @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+        @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
         static void resetToDefaults(@NonNull ContentResolver resolver, @ResetMode int resetMode,
                 @Nullable String prefix) {
             try {
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 0116961..aaba85b 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -42,6 +42,7 @@
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAugmentedAutofillManagerClient;
+import android.view.autofill.IAutofillWindowPresenter;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -95,10 +96,10 @@
         }
 
         @Override
-        public void onDestroyFillWindowRequest(int sessionId) {
+        public void onDestroyAllFillWindowsRequest() {
             mHandler.sendMessage(
-                    obtainMessage(AugmentedAutofillService::handleOnDestroyFillWindowRequest,
-                            AugmentedAutofillService.this, sessionId));
+                    obtainMessage(AugmentedAutofillService::handleOnDestroyAllFillWindowsRequest,
+                            AugmentedAutofillService.this));
         }
     };
 
@@ -185,18 +186,21 @@
                 new FillCallback(proxy));
     }
 
-    private void handleOnDestroyFillWindowRequest(@NonNull int sessionId) {
-        AutofillProxy proxy = null;
+    private void handleOnDestroyAllFillWindowsRequest() {
         if (mAutofillProxies != null) {
-            proxy = mAutofillProxies.get(sessionId);
+            final int size = mAutofillProxies.size();
+            for (int i = 0; i < size; i++) {
+                final int sessionId = mAutofillProxies.keyAt(i);
+                final AutofillProxy proxy = mAutofillProxies.valueAt(i);
+                if (proxy == null) {
+                    // TODO(b/111330312): this might be fine, in which case we should logv it
+                    Log.w(TAG, "No proxy for session " + sessionId);
+                    return;
+                }
+                proxy.destroy();
+            }
+            mAutofillProxies.clear();
         }
-        if (proxy == null) {
-            // TODO(b/111330312): this might be fine, in which case we should logv it
-            Log.w(TAG, "No proxy for session " + sessionId);
-            return;
-        }
-        proxy.destroy();
-        mAutofillProxies.remove(sessionId);
     }
 
     private void handleOnUnbind() {
@@ -350,6 +354,16 @@
             }
         }
 
+        public void requestShowFillUi(int width, int height, Rect anchorBounds,
+                IAutofillWindowPresenter presenter) throws RemoteException {
+            mClient.requestShowFillUi(mSessionId, mFocusedId, width, height, anchorBounds,
+                    presenter);
+        }
+
+        public void requestHideFillUi() throws RemoteException {
+            mClient.requestHideFillUi(mSessionId, mFocusedId);
+        }
+
         private void update(@NonNull AutofillId focusedId, @NonNull AutofillValue focusedValue) {
             synchronized (mLock) {
                 // TODO(b/111330312): should we close the popupwindow if the focused id changed?
diff --git a/core/java/android/service/autofill/augmented/FillWindow.java b/core/java/android/service/autofill/augmented/FillWindow.java
index 33b88e42..51b0f01 100644
--- a/core/java/android/service/autofill/augmented/FillWindow.java
+++ b/core/java/android/service/autofill/augmented/FillWindow.java
@@ -16,22 +16,25 @@
 package android.service.autofill.augmented;
 
 import static android.service.autofill.augmented.AugmentedAutofillService.DEBUG;
+import static android.service.autofill.augmented.AugmentedAutofillService.VERBOSE;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
 import android.annotation.LongDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.app.Dialog;
 import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
 import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
 import android.service.autofill.augmented.PresentationParams.Area;
 import android.util.Log;
-import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
 import android.view.WindowManager;
+import android.view.autofill.IAutofillWindowPresenter;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
@@ -71,7 +74,7 @@
     /** Indicates the data being shown is a physical address */
     public static final long FLAG_METADATA_ADDRESS = 0x1;
 
-    // TODO(b/111330312): add moar flags
+    // TODO(b/111330312): add more flags
 
     /** @hide */
     @LongDef(prefix = { "FLAG" }, value = {
@@ -83,8 +86,17 @@
     private final Object mLock = new Object();
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
+    private final @NonNull Handler mUiThreadHandler = new Handler(Looper.getMainLooper());
+    private final @NonNull FillWindowPresenter mFillWindowPresenter = new FillWindowPresenter();
+
     @GuardedBy("mLock")
-    private Dialog mDialog;
+    private WindowManager mWm;
+    @GuardedBy("mLock")
+    private View mFillView;
+    @GuardedBy("mLock")
+    private boolean mShowing;
+    @GuardedBy("mLock")
+    private Rect mBounds;
 
     @GuardedBy("mLock")
     private boolean mDestroyed;
@@ -140,51 +152,28 @@
             // window instead of destroying. In fact, it might be better to allocate a full window
             // initially, which is transparent (and let touches get through) everywhere but in the
             // rect boundaries.
-            destroy();
 
             // TODO(b/111330312): make sure all touch events are handled, window is always closed,
             // etc.
 
-            mDialog = new Dialog(rootView.getContext()) {
-                @Override
-                public boolean onTouchEvent(MotionEvent event) {
-                    if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
-                        FillWindow.this.destroy();
+            mWm = rootView.getContext().getSystemService(WindowManager.class);
+            mFillView = rootView;
+            // Listen to the touch outside to destroy the window when typing is detected.
+            mFillView.setOnTouchListener(
+                    (view, motionEvent) -> {
+                        if (motionEvent.getAction() == MotionEvent.ACTION_OUTSIDE) {
+                            if (VERBOSE) Log.v(TAG, "Outside touch detected, hiding the window");
+                            hide();
+                        }
+                        return false;
                     }
-                    return false;
-                }
-            };
-            mCloseGuard.open("destroy");
-            final Window window = mDialog.getWindow();
-            window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
-            // Makes sure touch outside the dialog is received by the window behind the dialog.
-            window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
-            // Makes sure the touch outside the dialog is received by the dialog to dismiss it.
-            window.addFlags(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
-            // Makes sure keyboard shows up.
-            window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
-
-            final int height = rect.bottom - rect.top;
-            final int width = rect.right - rect.left;
-            final WindowManager.LayoutParams windowParams = window.getAttributes();
-            windowParams.gravity = Gravity.TOP | Gravity.LEFT;
-            windowParams.y = rect.top + height;
-            windowParams.height = height;
-            windowParams.x = rect.left;
-            windowParams.width = width;
-
-            window.setAttributes(windowParams);
-            window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
-            window.setBackgroundDrawableResource(android.R.color.transparent);
-
-            mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
-            final ViewGroup.LayoutParams diagParams = new ViewGroup.LayoutParams(width, height);
-            mDialog.setContentView(rootView, diagParams);
-
+            );
+            mShowing = false;
+            mBounds = new Rect(area.getBounds());
             if (DEBUG) {
                 Log.d(TAG, "Created FillWindow: params= " + smartSuggestion + " view=" + rootView);
             }
-
+            mDestroyed = false;
             mProxy.setFillWindow(this);
             return true;
         }
@@ -194,36 +183,87 @@
     void show() {
         // TODO(b/111330312): check if updated first / throw exception
         if (DEBUG) Log.d(TAG, "show()");
-
         synchronized (mLock) {
             checkNotDestroyedLocked();
-            if (mDialog == null) {
+            if (mWm == null || mFillView == null) {
                 throw new IllegalStateException("update() not called yet, or already destroyed()");
             }
-
-            mDialog.show();
             if (mProxy != null) {
+                try {
+                    mProxy.requestShowFillUi(mBounds.right - mBounds.left,
+                            mBounds.bottom - mBounds.top,
+                            /*anchorBounds=*/ null, mFillWindowPresenter);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Error requesting to show fill window", e);
+                }
                 mProxy.report(AutofillProxy.REPORT_EVENT_UI_SHOWN);
             }
         }
     }
 
     /**
+     * Hides the window.
+     *
+     * <p>The window is not destroyed and can be shown again
+     */
+    private void hide() {
+        if (DEBUG) Log.d(TAG, "hide()");
+        synchronized (mLock) {
+            checkNotDestroyedLocked();
+            if (mWm == null || mFillView == null) {
+                throw new IllegalStateException("update() not called yet, or already destroyed()");
+            }
+            if (mProxy != null && mShowing) {
+                try {
+                    mProxy.requestHideFillUi();
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Error requesting to hide fill window", e);
+                }
+            }
+        }
+    }
+
+    private void handleShow(WindowManager.LayoutParams p) {
+        if (DEBUG) Log.d(TAG, "handleShow()");
+        synchronized (mLock) {
+            if (mWm != null && mFillView != null) {
+                p.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+                if (!mShowing) {
+                    mWm.addView(mFillView, p);
+                    mShowing = true;
+                } else {
+                    mWm.updateViewLayout(mFillView, p);
+                }
+            }
+        }
+    }
+
+    private void handleHide() {
+        if (DEBUG) Log.d(TAG, "handleHide()");
+        synchronized (mLock) {
+            if (mWm != null && mFillView != null && mShowing) {
+                mWm.removeView(mFillView);
+                mShowing = false;
+            }
+        }
+    }
+
+    /**
      * Destroys the window.
      *
      * <p>Once destroyed, this window cannot be used anymore
      */
     public void destroy() {
-        if (DEBUG) Log.d(TAG, "destroy(): mDestroyed=" + mDestroyed + " mDialog=" + mDialog);
-
-        synchronized (this) {
-            if (mDestroyed || mDialog == null) return;
-
-            mDialog.dismiss();
-            mDialog = null;
-            if (mProxy != null) {
-                mProxy.report(AutofillProxy.REPORT_EVENT_UI_DESTROYED);
-            }
+        if (DEBUG) {
+            Log.d(TAG,
+                    "destroy(): mDestroyed=" + mDestroyed + " mShowing=" + mShowing + " mFillView="
+                            + mFillView);
+        }
+        synchronized (mLock) {
+            if (mDestroyed) return;
+            hide();
+            mProxy.report(AutofillProxy.REPORT_EVENT_UI_DESTROYED);
+            mDestroyed = true;
             mCloseGuard.close();
         }
     }
@@ -250,11 +290,15 @@
     public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
         synchronized (this) {
             pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed);
-            if (mDialog != null) {
-                pw.print(prefix); pw.print("dialog: ");
-                pw.println(mDialog.isShowing() ? "shown" : "hidden");
-                pw.print(prefix); pw.print("window: ");
-                pw.println(mDialog.getWindow().getAttributes());
+            if (mFillView != null) {
+                pw.print(prefix); pw.print("fill window: ");
+                pw.println(mShowing ? "shown" : "hidden");
+                pw.print(prefix); pw.print("fill view: ");
+                pw.println(mFillView);
+                pw.print(prefix); pw.print("mBounds: ");
+                pw.println(mBounds);
+                pw.print(prefix); pw.print("mWm: ");
+                pw.println(mWm);
             }
         }
     }
@@ -264,4 +308,19 @@
     public void close() throws Exception {
         destroy();
     }
+
+    private final class FillWindowPresenter extends IAutofillWindowPresenter.Stub {
+        @Override
+        public void show(WindowManager.LayoutParams p, Rect transitionEpicenter,
+                boolean fitsSystemWindows, int layoutDirection) {
+            if (DEBUG) Log.d(TAG, "FillWindowPresenter.show()");
+            mUiThreadHandler.sendMessage(obtainMessage(FillWindow::handleShow, FillWindow.this, p));
+        }
+
+        @Override
+        public void hide(Rect transitionEpicenter) {
+            if (DEBUG) Log.d(TAG, "FillWindowPresenter.hide()");
+            mUiThreadHandler.sendMessage(obtainMessage(FillWindow::handleHide, FillWindow.this));
+        }
+    }
 }
diff --git a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
index b3ac2da..fb6912a 100644
--- a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
+++ b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
@@ -36,5 +36,5 @@
                        in ComponentName activityComponent, in AutofillId focusedId,
                        in AutofillValue focusedValue, long requestTime, in IFillCallback callback);
 
-    void onDestroyFillWindowRequest(int sessionId);
+    void onDestroyAllFillWindowsRequest();
 }
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index e5e028d..302e1a6 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -48,6 +48,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -77,6 +78,7 @@
             "android.service.contentcapture.ContentCaptureService";
 
     private Handler mHandler;
+    private IContentCaptureServiceCallback mCallback;
 
     /**
      * Binder that receives calls from the system server.
@@ -84,9 +86,15 @@
     private final IContentCaptureService mServerInterface = new IContentCaptureService.Stub() {
 
         @Override
-        public void onConnectedStateChanged(boolean state) {
-            mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnConnectedStateChanged,
-                    ContentCaptureService.this, state));
+        public void onConnected(IBinder callback) {
+            mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnConnected,
+                    ContentCaptureService.this, callback));
+        }
+
+        @Override
+        public void onDisconnected() {
+            mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnDisconnected,
+                    ContentCaptureService.this));
         }
 
         @Override
@@ -166,7 +174,16 @@
      */
     public final void setContentCaptureWhitelist(@Nullable List<String> packages,
             @Nullable List<ComponentName> activities) {
-        //TODO(b/122595322): implement
+        final IContentCaptureServiceCallback callback = mCallback;
+        if (callback == null) {
+            Log.w(TAG, "setContentCaptureWhitelist(): no server callback");
+            return;
+        }
+        try {
+            callback.setContentCaptureWhitelist(packages, activities);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -177,7 +194,16 @@
      */
     public final void setActivityContentCaptureEnabled(@NonNull ComponentName activity,
             boolean enabled) {
-        //TODO(b/122595322): implement
+        final IContentCaptureServiceCallback callback = mCallback;
+        if (callback == null) {
+            Log.w(TAG, "setActivityContentCaptureEnabled(): no server callback");
+            return;
+        }
+        try {
+            callback.setActivityContentCaptureEnabled(activity, enabled);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -188,7 +214,16 @@
      */
     public final void setPackageContentCaptureEnabled(@NonNull String packageName,
             boolean enabled) {
-        //TODO(b/122595322): implement
+        final IContentCaptureServiceCallback callback = mCallback;
+        if (callback == null) {
+            Log.w(TAG, "setPackageContentCaptureEnabled(): no server callback");
+            return;
+        }
+        try {
+            callback.setPackageContentCaptureEnabled(packageName, enabled);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -197,7 +232,12 @@
      */
     @NonNull
     public final Set<ComponentName> getContentCaptureDisabledActivities() {
-        //TODO(b/122595322): implement
+        final IContentCaptureServiceCallback callback = mCallback;
+        if (callback == null) {
+            Log.w(TAG, "getContentCaptureDisabledActivities(): no server callback");
+            return Collections.emptySet();
+        }
+        //TODO(b/122595322): implement (using SyncResultReceiver)
         return null;
     }
 
@@ -207,7 +247,12 @@
      */
     @NonNull
     public final Set<String> getContentCaptureDisabledPackages() {
-        //TODO(b/122595322): implement
+        final IContentCaptureServiceCallback callback = mCallback;
+        if (callback == null) {
+            Log.w(TAG, "getContentCaptureDisabledPackages(): no server callback");
+            return Collections.emptySet();
+        }
+        //TODO(b/122595322): implement (using SyncResultReceiver)
         return null;
     }
 
@@ -307,12 +352,14 @@
         }
     }
 
-    private void handleOnConnectedStateChanged(boolean state) {
-        if (state) {
-            onConnected();
-        } else {
-            onDisconnected();
-        }
+    private void handleOnConnected(@NonNull IBinder callback) {
+        mCallback = IContentCaptureServiceCallback.Stub.asInterface(callback);
+        onConnected();
+    }
+
+    private void handleOnDisconnected() {
+        onDisconnected();
+        mCallback = null;
     }
 
     //TODO(b/111276913): consider caching the InteractionSessionId for the lifetime of the session,
@@ -323,15 +370,21 @@
         mSessionUids.put(sessionId, uid);
         onCreateContentCaptureSession(context, new ContentCaptureSessionId(sessionId));
 
-        final int flags = context.getFlags();
-        if ((flags & ContentCaptureContext.FLAG_DISABLED_BY_FLAG_SECURE) != 0) {
-            setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED_BY_FLAG_SECURE,
-                    mClientInterface.asBinder());
-            return;
+        final int clientFlags = context.getFlags();
+        int stateFlags = 0;
+        if ((clientFlags & ContentCaptureContext.FLAG_DISABLED_BY_FLAG_SECURE) != 0) {
+            stateFlags |= ContentCaptureSession.STATE_FLAG_SECURE;
         }
+        if ((clientFlags & ContentCaptureContext.FLAG_DISABLED_BY_APP) != 0) {
+            stateFlags |= ContentCaptureSession.STATE_BY_APP;
+        }
+        if (stateFlags == 0) {
+            stateFlags = ContentCaptureSession.STATE_ACTIVE;
+        } else {
+            stateFlags |= ContentCaptureSession.STATE_DISABLED;
 
-        setClientState(clientReceiver, ContentCaptureSession.STATE_ACTIVE,
-                mClientInterface.asBinder());
+        }
+        setClientState(clientReceiver, stateFlags, mClientInterface.asBinder());
     }
 
     private void handleSendEvents(int uid,
diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl
index 1b4cccf..a8dd213 100644
--- a/core/java/android/service/contentcapture/IContentCaptureService.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl
@@ -16,6 +16,7 @@
 
 package android.service.contentcapture;
 
+import android.os.IBinder;
 import android.service.contentcapture.SnapshotData;
 import android.view.contentcapture.ContentCaptureContext;
 
@@ -29,7 +30,8 @@
  * @hide
  */
 oneway interface IContentCaptureService {
-    void onConnectedStateChanged(boolean state);
+    void onConnected(IBinder callback);
+    void onDisconnected();
     void onSessionStarted(in ContentCaptureContext context, String sessionId, int uid,
                           in IResultReceiver clientReceiver);
     void onSessionFinished(String sessionId);
diff --git a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
new file mode 100644
index 0000000..e84bd6f
--- /dev/null
+++ b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.contentcapture;
+
+import android.content.ComponentName;
+import com.android.internal.os.IResultReceiver;
+
+import java.util.List;
+
+/**
+ * Interface from the Content Capture service to the system.
+ *
+ * @hide
+ */
+oneway interface IContentCaptureServiceCallback {
+    void setContentCaptureWhitelist(in List<String> packages, in List<ComponentName> activities);
+    void setActivityContentCaptureEnabled(in ComponentName activity, boolean enabled);
+    void setPackageContentCaptureEnabled(in String packageName, boolean enabled);
+    void getContentCaptureDisabledActivities(in IResultReceiver receiver);
+    void getContentCaptureDisabledPackages(in IResultReceiver receiver);
+}
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 163e3d5..6f27447 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -121,6 +121,12 @@
      */
     public static final int SHOW_SOURCE_NOTIFICATION = 1 << 6;
 
+    /**
+     * Flag for use with {@link #onShow}: indicates that the voice interaction service was invoked
+     * from an Android automotive system Ui.
+     */
+    public static final int SHOW_SOURCE_AUTOMOTIVE_SYSTEM_UI = 1 << 7;
+
     final Context mContext;
     final HandlerCaller mHandlerCaller;
 
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 85b6b88..44353b1 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -33,8 +33,7 @@
 import android.icu.util.ULocale;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.SystemProperties;
-import android.provider.Settings;
+import android.sysprop.DisplayProperties;
 import android.text.style.AbsoluteSizeSpan;
 import android.text.style.AccessibilityClickableSpan;
 import android.text.style.AccessibilityURLSpan;
@@ -2059,7 +2058,7 @@
         return ((locale != null && !locale.equals(Locale.ROOT)
                         && ULocale.forLocale(locale).isRightToLeft())
                 // If forcing into RTL layout mode, return RTL as default
-                || SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false))
+                || DisplayProperties.debug_force_rtl().orElse(false))
             ? View.LAYOUT_DIRECTION_RTL
             : View.LAYOUT_DIRECTION_LTR;
     }
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index eef7ea2..50e7ec3 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -37,7 +37,6 @@
 import com.android.i18n.phonenumbers.PhoneNumberMatch;
 import com.android.i18n.phonenumbers.PhoneNumberUtil;
 import com.android.i18n.phonenumbers.PhoneNumberUtil.Leniency;
-import com.android.internal.annotations.GuardedBy;
 
 import libcore.util.EmptyArray;
 
@@ -49,6 +48,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Locale;
+import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -69,7 +69,6 @@
  *
  * @see MatchFilter
  * @see TransformFilter
- * @see UrlSpanFactory
  */
 
 public class Linkify {
@@ -228,44 +227,6 @@
     }
 
     /**
-     * Factory class to create {@link URLSpan}s. While adding spans to a {@link Spannable},
-     * {@link Linkify} will call {@link UrlSpanFactory#create(String)} function to create a
-     * {@link URLSpan}.
-     *
-     * @see #addLinks(Spannable, int, UrlSpanFactory)
-     * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter,
-     * UrlSpanFactory)
-     */
-    public static class UrlSpanFactory {
-        private static final Object sInstanceLock = new Object();
-
-        @GuardedBy("sInstanceLock")
-        private static volatile UrlSpanFactory sInstance = null;
-
-        private static synchronized UrlSpanFactory getInstance() {
-            if (sInstance == null) {
-                synchronized (sInstanceLock) {
-                    if (sInstance == null) {
-                        sInstance = new UrlSpanFactory();
-                    }
-                }
-            }
-            return sInstance;
-        }
-
-        /**
-         * Factory function that will called by {@link Linkify} in order to create a
-         * {@link URLSpan}.
-         *
-         * @param url URL found
-         * @return a URLSpan instance
-         */
-        public URLSpan create(final String url) {
-            return new URLSpan(url);
-        }
-    }
-
-    /**
      *  Scans the text of the provided Spannable and turns all occurrences
      *  of the link types indicated in the mask into clickable links.
      *  If the mask is nonzero, it also removes any existing URLSpans
@@ -277,7 +238,7 @@
      *
      *  @return True if at least one link is found and applied.
      *
-     * @see #addLinks(Spannable, int, UrlSpanFactory)
+     * @see #addLinks(Spannable, int, Function)
      */
     public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask) {
         return addLinks(text, mask, null, null);
@@ -292,11 +253,11 @@
      *
      *  @param text Spannable whose text is to be marked-up with links
      *  @param mask mask to define which kinds of links will be searched
-     *  @param urlSpanFactory factory class used to create {@link URLSpan}s
+     *  @param urlSpanFactory function used to create {@link URLSpan}s
      *  @return True if at least one link is found and applied.
      */
     public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask,
-            @Nullable UrlSpanFactory urlSpanFactory) {
+            @Nullable Function<String, URLSpan> urlSpanFactory) {
         return addLinks(text, mask, null, urlSpanFactory);
     }
 
@@ -309,11 +270,11 @@
      * @param text Spannable whose text is to be marked-up with links
      * @param mask mask to define which kinds of links will be searched
      * @param context Context to be used while identifying phone numbers
-     * @param urlSpanFactory factory class used to create {@link URLSpan}s
+     * @param urlSpanFactory function used to create {@link URLSpan}s
      * @return true if at least one link is found and applied.
      */
     private static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask,
-            @Nullable Context context, @Nullable UrlSpanFactory urlSpanFactory) {
+            @Nullable Context context, @Nullable Function<String, URLSpan> urlSpanFactory) {
         if (text != null && containsUnsupportedCharacters(text.toString())) {
             android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
             return false;
@@ -398,7 +359,7 @@
      *
      *  @return True if at least one link is found and applied.
      *
-     *  @see #addLinks(Spannable, int, UrlSpanFactory)
+     *  @see #addLinks(Spannable, int, Function)
      */
     public static final boolean addLinks(@NonNull TextView text, @LinkifyMask int mask) {
         if (mask == 0) {
@@ -512,8 +473,7 @@
      *  @param pattern      Regex pattern to be used for finding links
      *  @param scheme       URL scheme string (eg <code>http://</code>) to be
      *                      prepended to the links that do not start with this scheme.
-     * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter,
-     * UrlSpanFactory)
+     * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, Function)
      */
     public static final boolean addLinks(@NonNull Spannable text, @NonNull Pattern pattern,
             @Nullable String scheme) {
@@ -534,8 +494,7 @@
      * @param transformFilter Filter to allow the client code to update the link found.
      *
      * @return True if at least one link is found and applied.
-     * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter,
-     * UrlSpanFactory)
+     * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, Function)
      */
     public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
             @Nullable String scheme, @Nullable MatchFilter matchFilter,
@@ -560,8 +519,7 @@
      *
      * @return True if at least one link is found and applied.
      *
-     * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter,
-     * UrlSpanFactory)
+     * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, Function)
      */
     public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
             @Nullable String defaultScheme, @Nullable String[] schemes,
@@ -584,14 +542,14 @@
      * @param matchFilter     the filter that is used to allow the client code additional control
      *                        over which pattern matches are to be converted into links.
      * @param transformFilter filter to allow the client code to update the link found.
-     * @param urlSpanFactory  factory class used to create {@link URLSpan}s
+     * @param urlSpanFactory  function used to create {@link URLSpan}s
      *
      * @return True if at least one link is found and applied.
      */
     public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
             @Nullable String defaultScheme, @Nullable String[] schemes,
             @Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter,
-            @Nullable UrlSpanFactory urlSpanFactory) {
+            @Nullable Function<String, URLSpan> urlSpanFactory) {
         if (spannable != null && containsUnsupportedCharacters(spannable.toString())) {
             android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
             return false;
@@ -634,11 +592,11 @@
     }
 
     private static void applyLink(String url, int start, int end, Spannable text,
-            @Nullable UrlSpanFactory urlSpanFactory) {
+            @Nullable Function<String, URLSpan> urlSpanFactory) {
         if (urlSpanFactory == null) {
-            urlSpanFactory = UrlSpanFactory.getInstance();
+            urlSpanFactory = DEFAULT_SPAN_FACTORY;
         }
-        final URLSpan span = urlSpanFactory.create(url);
+        final URLSpan span = urlSpanFactory.apply(url);
         text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
     }
 
@@ -805,6 +763,13 @@
             i++;
         }
     }
+
+    /**
+     * Default factory function to create {@link URLSpan}s. While adding spans to a
+     * {@link Spannable}, {@link Linkify} will call this function to create a {@link URLSpan}.
+     */
+    private static final Function<String, URLSpan> DEFAULT_SPAN_FACTORY =
+            (String string) -> new URLSpan(string);
 }
 
 class LinkSpec {
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index ea4464d..99106be 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -216,6 +216,12 @@
      * */
     public int density;
 
+    /**
+     * If the Value came from a style resource, this holds the corresponding style resource id
+     * against which the attribute was resolved.
+     */
+    public int sourceStyleResourceId;
+
     /* ------------------------------------------------------------ */
 
     /** Return the data for this value as a float.  Only use for values
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index ffd4156..dc7c343 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -22,6 +22,7 @@
 import android.annotation.SystemService;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
@@ -29,6 +30,7 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
+import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -38,6 +40,9 @@
 
 import com.android.internal.R;
 
+import dalvik.system.PathClassLoader;
+import java.io.File;
+import java.lang.reflect.Method;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -72,6 +77,10 @@
     private static final String TAG = LayoutInflater.class.getSimpleName();
     private static final boolean DEBUG = false;
 
+    private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY
+        = "view.precompiled_layout_enabled";
+    private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex";
+
     /** Empty stack trace used to avoid log spam in re-throw exceptions. */
     private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
 
@@ -93,6 +102,13 @@
     private Factory2 mPrivateFactory;
     private Filter mFilter;
 
+    // Indicates whether we should try to inflate layouts using a precompiled layout instead of
+    // inflating from the XML resource.
+    private boolean mUseCompiledView;
+    // This variable holds the classloader that will be used to look for precompiled layouts. The
+    // The classloader includes the generated compiled_view.dex file.
+    private ClassLoader mPrecompiledClassLoader;
+
     @UnsupportedAppUsage
     final Object[] mConstructorArgs = new Object[2];
 
@@ -223,6 +239,7 @@
      */
     protected LayoutInflater(Context context) {
         mContext = context;
+        initPrecompiledViews();
     }
 
     /**
@@ -239,6 +256,7 @@
         mFactory2 = original.mFactory2;
         mPrivateFactory = original.mPrivateFactory;
         setFilter(original.mFilter);
+        initPrecompiledViews();
     }
 
     /**
@@ -380,6 +398,41 @@
         }
     }
 
+    private void initPrecompiledViews() {
+        // Check if precompiled layouts are enabled by a system property.
+        mUseCompiledView =
+            SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false);
+        if (!mUseCompiledView) {
+            return;
+        }
+
+        // Make sure the application allows code generation
+        ApplicationInfo appInfo = mContext.getApplicationInfo();
+        if ((appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PREFER_CODE_INTEGRITY) != 0
+            || appInfo.isPrivilegedApp()) {
+            mUseCompiledView = false;
+            return;
+        }
+
+        // Try to load the precompiled layout file.
+        try {
+            mPrecompiledClassLoader = mContext.getClassLoader();
+            String dexFile = mContext.getCodeCacheDir() + COMPILED_VIEW_DEX_FILE_NAME;
+            if (new File(dexFile).exists()) {
+                mPrecompiledClassLoader = new PathClassLoader(dexFile, mPrecompiledClassLoader);
+            } else {
+                // If the precompiled layout file doesn't exist, then disable precompiled
+                // layouts.
+                mUseCompiledView = false;
+            }
+        } catch (Throwable e) {
+            if (DEBUG) {
+                Log.e(TAG, "Failed to initialized precompiled views layouts", e);
+            }
+            mUseCompiledView = false;
+        }
+    }
+
     /**
      * Inflate a new view hierarchy from the specified xml resource. Throws
      * {@link InflateException} if there is an error.
@@ -436,10 +489,14 @@
         final Resources res = getContext().getResources();
         if (DEBUG) {
             Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
-                    + Integer.toHexString(resource) + ")");
+                  + Integer.toHexString(resource) + ")");
         }
 
-        final XmlResourceParser parser = res.getLayout(resource);
+        View view = tryInflatePrecompiled(resource, res, root, attachToRoot);
+        if (view != null) {
+            return view;
+        }
+        XmlResourceParser parser = res.getLayout(resource);
         try {
             return inflate(parser, root, attachToRoot);
         } finally {
@@ -447,6 +504,73 @@
         }
     }
 
+    private @Nullable
+    View tryInflatePrecompiled(@LayoutRes int resource, Resources res, @Nullable ViewGroup root,
+        boolean attachToRoot) {
+        if (!mUseCompiledView) {
+            return null;
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate (precompiled)");
+
+        // Try to inflate using a precompiled layout.
+        String pkg = res.getResourcePackageName(resource);
+        String layout = res.getResourceEntryName(resource);
+
+        try {
+            Class clazz = mPrecompiledClassLoader.loadClass("" + pkg + ".CompiledView");
+            Method inflater = clazz.getMethod(layout, Context.class, int.class);
+            View view = (View) inflater.invoke(null, mContext, resource);
+
+            if (view != null && root != null) {
+                // We were able to use the precompiled inflater, but now we need to do some work to
+                // attach the view to the root correctly.
+                XmlResourceParser parser = res.getLayout(resource);
+                try {
+                    AttributeSet attrs = Xml.asAttributeSet(parser);
+                    advanceToRootNode(parser);
+                    ViewGroup.LayoutParams params = root.generateLayoutParams(attrs);
+
+                    if (attachToRoot) {
+                        root.addView(view, params);
+                    } else {
+                        view.setLayoutParams(params);
+                    }
+                } finally {
+                    parser.close();
+                }
+            }
+
+            return view;
+        } catch (Throwable e) {
+            if (DEBUG) {
+                Log.e(TAG, "Failed to use precompiled view", e);
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
+        return null;
+    }
+
+    /**
+     * Advances the given parser to the first START_TAG. Throws InflateException if no start tag is
+     * found.
+     */
+    private void advanceToRootNode(XmlPullParser parser)
+        throws InflateException, IOException, XmlPullParserException {
+        // Look for the root node.
+        int type;
+        while ((type = parser.next()) != XmlPullParser.START_TAG &&
+            type != XmlPullParser.END_DOCUMENT) {
+            // Empty
+        }
+
+        if (type != XmlPullParser.START_TAG) {
+            throw new InflateException(parser.getPositionDescription()
+                + ": No start tag found!");
+        }
+    }
+
     /**
      * Inflate a new view hierarchy from the specified XML node. Throws
      * {@link InflateException} if there is an error.
@@ -480,18 +604,7 @@
             View result = root;
 
             try {
-                // Look for the root node.
-                int type;
-                while ((type = parser.next()) != XmlPullParser.START_TAG &&
-                        type != XmlPullParser.END_DOCUMENT) {
-                    // Empty
-                }
-
-                if (type != XmlPullParser.START_TAG) {
-                    throw new InflateException(parser.getPositionDescription()
-                            + ": No start tag found!");
-                }
-
+                advanceToRootNode(parser);
                 final String name = parser.getName();
 
                 if (DEBUG) {
@@ -994,82 +1107,85 @@
                 + "reference. The layout ID " + value + " is not valid.");
         }
 
-        final XmlResourceParser childParser = context.getResources().getLayout(layout);
+        final View precompiled = tryInflatePrecompiled(layout, context.getResources(),
+            (ViewGroup) parent, /*attachToRoot=*/true);
+        if (precompiled == null) {
+            final XmlResourceParser childParser = context.getResources().getLayout(layout);
 
-        try {
-            final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
+            try {
+                final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
 
-            while ((type = childParser.next()) != XmlPullParser.START_TAG &&
-                type != XmlPullParser.END_DOCUMENT) {
-                // Empty.
+                while ((type = childParser.next()) != XmlPullParser.START_TAG &&
+                    type != XmlPullParser.END_DOCUMENT) {
+                    // Empty.
+                }
+
+                if (type != XmlPullParser.START_TAG) {
+                    throw new InflateException(childParser.getPositionDescription() +
+                        ": No start tag found!");
+                }
+
+                final String childName = childParser.getName();
+
+                if (TAG_MERGE.equals(childName)) {
+                    // The <merge> tag doesn't support android:theme, so
+                    // nothing special to do here.
+                    rInflate(childParser, parent, context, childAttrs, false);
+                } else {
+                    final View view = createViewFromTag(parent, childName,
+                        context, childAttrs, hasThemeOverride);
+                    final ViewGroup group = (ViewGroup) parent;
+
+                    final TypedArray a = context.obtainStyledAttributes(
+                        attrs, R.styleable.Include);
+                    final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
+                    final int visibility = a.getInt(R.styleable.Include_visibility, -1);
+                    a.recycle();
+
+                    // We try to load the layout params set in the <include /> tag.
+                    // If the parent can't generate layout params (ex. missing width
+                    // or height for the framework ViewGroups, though this is not
+                    // necessarily true of all ViewGroups) then we expect it to throw
+                    // a runtime exception.
+                    // We catch this exception and set localParams accordingly: true
+                    // means we successfully loaded layout params from the <include>
+                    // tag, false means we need to rely on the included layout params.
+                    ViewGroup.LayoutParams params = null;
+                    try {
+                        params = group.generateLayoutParams(attrs);
+                    } catch (RuntimeException e) {
+                        // Ignore, just fail over to child attrs.
+                    }
+                    if (params == null) {
+                        params = group.generateLayoutParams(childAttrs);
+                    }
+                    view.setLayoutParams(params);
+
+                    // Inflate all children.
+                    rInflateChildren(childParser, view, childAttrs, true);
+
+                    if (id != View.NO_ID) {
+                        view.setId(id);
+                    }
+
+                    switch (visibility) {
+                        case 0:
+                            view.setVisibility(View.VISIBLE);
+                            break;
+                        case 1:
+                            view.setVisibility(View.INVISIBLE);
+                            break;
+                        case 2:
+                            view.setVisibility(View.GONE);
+                            break;
+                    }
+
+                    group.addView(view);
+                }
+            } finally {
+                childParser.close();
             }
-
-            if (type != XmlPullParser.START_TAG) {
-                throw new InflateException(childParser.getPositionDescription() +
-                    ": No start tag found!");
-            }
-
-            final String childName = childParser.getName();
-
-            if (TAG_MERGE.equals(childName)) {
-                // The <merge> tag doesn't support android:theme, so
-                // nothing special to do here.
-                rInflate(childParser, parent, context, childAttrs, false);
-            } else {
-                final View view = createViewFromTag(parent, childName,
-                    context, childAttrs, hasThemeOverride);
-                final ViewGroup group = (ViewGroup) parent;
-
-                final TypedArray a = context.obtainStyledAttributes(
-                    attrs, R.styleable.Include);
-                final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
-                final int visibility = a.getInt(R.styleable.Include_visibility, -1);
-                a.recycle();
-
-                // We try to load the layout params set in the <include /> tag.
-                // If the parent can't generate layout params (ex. missing width
-                // or height for the framework ViewGroups, though this is not
-                // necessarily true of all ViewGroups) then we expect it to throw
-                // a runtime exception.
-                // We catch this exception and set localParams accordingly: true
-                // means we successfully loaded layout params from the <include>
-                // tag, false means we need to rely on the included layout params.
-                ViewGroup.LayoutParams params = null;
-                try {
-                    params = group.generateLayoutParams(attrs);
-                } catch (RuntimeException e) {
-                    // Ignore, just fail over to child attrs.
-                }
-                if (params == null) {
-                    params = group.generateLayoutParams(childAttrs);
-                }
-                view.setLayoutParams(params);
-
-                // Inflate all children.
-                rInflateChildren(childParser, view, childAttrs, true);
-
-                if (id != View.NO_ID) {
-                    view.setId(id);
-                }
-
-                switch (visibility) {
-                    case 0:
-                        view.setVisibility(View.VISIBLE);
-                        break;
-                    case 1:
-                        view.setVisibility(View.INVISIBLE);
-                        break;
-                    case 2:
-                        view.setVisibility(View.GONE);
-                        break;
-                }
-
-                group.addView(view);
-            }
-        } finally {
-            childParser.close();
         }
-
         LayoutInflater.consumeChildElements(parser);
     }
 
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index cf11fd0..c3d13bd 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -31,6 +31,7 @@
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -144,7 +145,8 @@
     public static final int TYPE_DEFAULT = TYPE_ARROW;
 
     private static final PointerIcon gNullIcon = new PointerIcon(TYPE_NULL);
-    private static final SparseArray<PointerIcon> gSystemIcons = new SparseArray<PointerIcon>();
+    private static final SparseArray<SparseArray<PointerIcon>> gSystemIconsByDisplay =
+            new SparseArray<SparseArray<PointerIcon>>();
     private static boolean sUseLargeIcons = false;
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -163,6 +165,12 @@
     @UnsupportedAppUsage
     private int mDurationPerFrame;
 
+    /**
+     * Listener for displays lifecycle.
+     * @hide
+     */
+    private static DisplayManager.DisplayListener sDisplayListener;
+
     private PointerIcon(int type) {
         mType = type;
     }
@@ -211,7 +219,19 @@
             return gNullIcon;
         }
 
-        PointerIcon icon = gSystemIcons.get(type);
+        if (sDisplayListener == null) {
+            registerDisplayListener(context);
+        }
+
+        final int displayId = context.getDisplayId();
+        SparseArray<PointerIcon> systemIcons = gSystemIconsByDisplay.get(displayId);
+        if (systemIcons == null) {
+            systemIcons = new SparseArray<>();
+            gSystemIconsByDisplay.put(displayId, systemIcons);
+        }
+
+        PointerIcon icon = systemIcons.get(type);
+        // Reload if not in the same display.
         if (icon != null) {
             return icon;
         }
@@ -240,7 +260,7 @@
         } else {
             icon.loadResource(context, context.getResources(), resourceId);
         }
-        gSystemIcons.append(type, icon);
+        systemIcons.append(type, icon);
         return icon;
     }
 
@@ -250,7 +270,7 @@
      */
     public static void setUseLargeIcons(boolean use) {
         sUseLargeIcons = use;
-        gSystemIcons.clear();
+        gSystemIconsByDisplay.clear();
     }
 
     /**
@@ -576,4 +596,30 @@
                 return 0;
         }
     }
+
+    /**
+     * Manage system icon cache handled by display lifecycle.
+     * @param context The context.
+     */
+    private static void registerDisplayListener(@NonNull Context context) {
+        sDisplayListener = new DisplayManager.DisplayListener() {
+            @Override
+            public void onDisplayAdded(int displayId) {
+            }
+
+            @Override
+            public void onDisplayRemoved(int displayId) {
+                gSystemIconsByDisplay.remove(displayId);
+            }
+
+            @Override
+            public void onDisplayChanged(int displayId) {
+                gSystemIconsByDisplay.remove(displayId);
+            }
+        };
+
+        DisplayManager displayManager = context.getSystemService(DisplayManager.class);
+        displayManager.registerDisplayListener(sDisplayListener, null /* handler */);
+    }
+
 }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index ff5120d..5e98236 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -30,6 +30,7 @@
 import android.annotation.Size;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
 import android.graphics.GraphicBuffer;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
@@ -141,6 +142,7 @@
     private static native int nativeGetActiveConfig(IBinder displayToken);
     private static native boolean nativeSetActiveConfig(IBinder displayToken, int id);
     private static native int[] nativeGetDisplayColorModes(IBinder displayToken);
+    private static native int[] nativeGetCompositionDataspaces();
     private static native int nativeGetActiveColorMode(IBinder displayToken);
     private static native boolean nativeSetActiveColorMode(IBinder displayToken,
             int colorMode);
@@ -167,6 +169,7 @@
             InputWindowHandle handle);
     private static native void nativeTransferTouchFocus(long transactionObj, IBinder fromToken,
             IBinder toToken);
+    private static native boolean nativeGetProtectedContentSupport();
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
     private String mName;
@@ -374,6 +377,13 @@
      */
     public static final int WINDOW_TYPE_DONT_SCREENSHOT = 441731;
 
+    /**
+     * internal representation of how to interpret pixel value, used only to convert to ColorSpace.
+     */
+    private static final int INTERNAL_DATASPACE_SRGB = 142671872;
+    private static final int INTERNAL_DATASPACE_DISPLAY_P3 = 143261696;
+    private static final int INTERNAL_DATASPACE_SCRGB = 411107328;
+
     private void assignNativeObject(long nativeObject) {
         if (mNativeObject != 0) {
             release();
@@ -1516,6 +1526,35 @@
     }
 
     /**
+     * Returns an array of color spaces with 2 elements. The first color space is the
+     * default color space and second one is wide color gamut color space.
+     * @hide
+     */
+    public static ColorSpace[] getCompositionColorSpaces() {
+        int[] dataspaces = nativeGetCompositionDataspaces();
+        ColorSpace srgb = ColorSpace.get(ColorSpace.Named.SRGB);
+        ColorSpace[] colorSpaces = { srgb, srgb };
+        if (dataspaces.length == 2) {
+            for (int i = 0; i < 2; ++i) {
+                switch(dataspaces[i]) {
+                    case INTERNAL_DATASPACE_DISPLAY_P3:
+                        colorSpaces[i] = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
+                        break;
+                    case INTERNAL_DATASPACE_SCRGB:
+                        colorSpaces[i] = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
+                        break;
+                    case INTERNAL_DATASPACE_SRGB:
+                    // Other dataspace is not recognized, use SRGB color space instead,
+                    // the default value of the array is already SRGB, thus do nothing.
+                    default:
+                        break;
+                }
+            }
+        }
+        return colorSpaces;
+    }
+
+    /**
      * @hide
      */
     @UnsupportedAppUsage
@@ -1730,6 +1769,14 @@
     }
 
     /**
+     * Returns whether protected content is supported in GPU composition.
+     * @hide
+     */
+    public static boolean getProtectedContentSupport() {
+        return nativeGetProtectedContentSupport();
+    }
+
+    /**
      * @hide
      */
     public static class Transaction implements Closeable {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index abefd55..32974ac 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -76,8 +76,8 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.os.Trace;
+import android.sysprop.DisplayProperties;
 import android.text.InputType;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -812,14 +812,6 @@
     private static final String CONTENT_CAPTURE_LOG_TAG = "View.ContentCapture";
 
     /**
-     * When set to true, apps will draw debugging information about their layouts.
-     *
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout";
-
-    /**
      * When set to true, this view will save its attribute data.
      *
      * @hide
@@ -27833,7 +27825,7 @@
         /**
          * Show where the margins, bounds and layout bounds are for each view.
          */
-        boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false);
+        boolean mDebugLayout = DisplayProperties.debug_layout().orElse(false);
 
         /**
          * Point used to compute visible regions.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8e4dc67..27d4ea4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -75,6 +75,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
+import android.sysprop.DisplayProperties;
 import android.util.AndroidRuntimeException;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -7071,7 +7072,7 @@
                 }
 
                 // Layout debugging
-                boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
+                boolean layout = DisplayProperties.debug_layout().orElse(false);
                 if (layout != mAttachInfo.mDebugLayout) {
                     mAttachInfo.mDebugLayout = layout;
                     if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index c630177..dfd9a2e 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -187,6 +187,7 @@
     /**
      * An animation listener to be notified when the animation starts, ends or repeats.
      */
+    @UnsupportedAppUsage
     private AnimationListener mListener;
 
     /**
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 93941d0..888a4c5 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -2997,5 +2997,23 @@
                 afm.post(() -> afm.autofill(sessionId, ids, values));
             }
         }
+
+        @Override
+        public void requestShowFillUi(int sessionId, AutofillId id, int width, int height,
+                Rect anchorBounds, IAutofillWindowPresenter presenter) {
+            final AutofillManager afm = mAfm.get();
+            if (afm != null) {
+                afm.post(() -> afm.requestShowFillUi(sessionId, id, width, height, anchorBounds,
+                        presenter));
+            }
+        }
+
+        @Override
+        public void requestHideFillUi(int sessionId, AutofillId id) {
+            final AutofillManager afm = mAfm.get();
+            if (afm != null) {
+                afm.post(() -> afm.requestHideFillUi(id, false));
+            }
+        }
     }
 }
diff --git a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
index 67cd0bf..140507c 100644
--- a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
@@ -21,6 +21,7 @@
 import android.graphics.Rect;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
+import android.view.autofill.IAutofillWindowPresenter;
 
 /**
  * Object running in the application process and responsible to provide the functionalities
@@ -29,6 +30,24 @@
  * @hide
  */
 interface IAugmentedAutofillManagerClient {
-   Rect getViewCoordinates(in AutofillId id);
-   void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
+    /**
+      * Gets the coordinates of the input field view.
+      */
+    Rect getViewCoordinates(in AutofillId id);
+
+    /**
+     * Autofills the activity with the contents of the values.
+     */
+    void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
+
+    /**
+      * Requests showing the fill UI.
+      */
+    void requestShowFillUi(int sessionId, in AutofillId id, int width, int height,
+            in Rect anchorBounds, in IAutofillWindowPresenter presenter);
+
+    /**
+      * Requests hiding the fill UI.
+      */
+    void requestHideFillUi(int sessionId, in AutofillId id);
 }
diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
index 04e725e..0b39c3a 100644
--- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
@@ -68,8 +68,8 @@
     }
 
     @Override
-    void flush() {
-        mParent.flush();
+    void flush(@FlushReason int reason) {
+        mParent.flush(reason);
     }
 
     @Override
@@ -92,6 +92,7 @@
             int flags) {
         getMainCaptureSession().notifyViewTextChanged(mId, id, text, flags);
     }
+
     @Override
     boolean isContentCaptureEnabled() {
         return getMainCaptureSession().isContentCaptureEnabled();
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index ff45efd..413f1a5 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -24,17 +24,18 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.contentcapture.ContentCaptureSession.FlushReason;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.SyncResultReceiver;
 
 import java.io.PrintWriter;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 /*
  * NOTE: all methods in this class should return right away, or do the real work in a handler
@@ -51,8 +52,6 @@
 
     private static final String TAG = ContentCaptureManager.class.getSimpleName();
 
-    private static final String BG_THREAD_NAME = "intel_svc_streamer_thread";
-
     /**
      * Timeout for calls to system_server.
      */
@@ -62,8 +61,10 @@
     static final boolean VERBOSE = false;
     static final boolean DEBUG = true; // STOPSHIP if not set to false
 
-    @NonNull
-    private final AtomicBoolean mDisabled = new AtomicBoolean();
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private boolean mDisabled;
 
     @NonNull
     private final Context mContext;
@@ -71,35 +72,29 @@
     @Nullable
     private final IContentCaptureManager mService;
 
+    // Flags used for starting session.
+    @GuardedBy("mLock")
+    private int mFlags;
+
     // TODO(b/119220549): use UI Thread directly (as calls are one-way) or a shared thread / handler
     // held at the Application level
     @NonNull
     private final Handler mHandler;
 
+    @GuardedBy("mLock")
     private MainContentCaptureSession mMainSession;
 
     /** @hide */
     public ContentCaptureManager(@NonNull Context context,
             @Nullable IContentCaptureManager service) {
         mContext = Preconditions.checkNotNull(context, "context cannot be null");
-        if (VERBOSE) {
-            Log.v(TAG, "Constructor for " + context.getPackageName());
-        }
-        mService = service;
-        // TODO(b/119220549): use an existing bg thread instead...
-        final HandlerThread bgThread = new HandlerThread(BG_THREAD_NAME);
-        bgThread.start();
-        mHandler = Handler.createAsync(bgThread.getLooper());
-    }
+        if (VERBOSE) Log.v(TAG, "Constructor for " + context.getPackageName());
 
-    @NonNull
-    private static Handler newHandler() {
-        // TODO(b/119220549): use an existing bg thread instead...
-        // TODO(b/119220549): use UI Thread directly (as calls are one-way) or an existing bgThread
-        // or a shared thread / handler held at the Application level
-        final HandlerThread bgThread = new HandlerThread(BG_THREAD_NAME);
-        bgThread.start();
-        return Handler.createAsync(bgThread.getLooper());
+        mService = service;
+        // TODO(b/119220549): we might not even need a handler, as the IPCs are oneway. But if we
+        // do, then we should optimize it to run the tests after the Choreographer finishes the most
+        // important steps of the frame.
+        mHandler = Handler.createAsync(Looper.getMainLooper());
     }
 
     /**
@@ -114,20 +109,25 @@
     @NonNull
     @UiThread
     public MainContentCaptureSession getMainContentCaptureSession() {
-        if (mMainSession == null) {
-            mMainSession = new MainContentCaptureSession(mContext, mHandler, mService,
-                    mDisabled);
-            if (VERBOSE) {
-                Log.v(TAG, "getDefaultContentCaptureSession(): created " + mMainSession);
+        synchronized (mLock) {
+            if (mMainSession == null) {
+                mMainSession = new MainContentCaptureSession(mContext, mHandler, mService,
+                        mDisabled);
+                if (VERBOSE) {
+                    Log.v(TAG, "getDefaultContentCaptureSession(): created " + mMainSession);
+                }
             }
+            return mMainSession;
         }
-        return mMainSession;
     }
 
     /** @hide */
     public void onActivityStarted(@NonNull IBinder applicationToken,
             @NonNull ComponentName activityComponent, int flags) {
-        getMainContentCaptureSession().start(applicationToken, activityComponent, flags);
+        synchronized (mLock) {
+            mFlags |= flags;
+            getMainContentCaptureSession().start(applicationToken, activityComponent, mFlags);
+        }
     }
 
     /** @hide */
@@ -142,8 +142,8 @@
      *
      * @hide
      */
-    public void flush() {
-        getMainContentCaptureSession().flush();
+    public void flush(@FlushReason int reason) {
+        getMainContentCaptureSession().flush(reason);
     }
 
     /**
@@ -173,7 +173,9 @@
      * Checks whether content capture is enabled for this activity.
      */
     public boolean isContentCaptureEnabled() {
-        return mService != null && !mDisabled.get();
+        synchronized (mLock) {
+            return mService != null && !mDisabled;
+        }
     }
 
     /**
@@ -183,7 +185,9 @@
      * it on {@link android.app.Activity#onCreate(android.os.Bundle, android.os.PersistableBundle)}.
      */
     public void setContentCaptureEnabled(boolean enabled) {
-        //TODO(b/111276913): implement (need to finish / disable all sessions)
+        synchronized (mLock) {
+            mFlags |= enabled ? 0 : ContentCaptureContext.FLAG_DISABLED_BY_APP;
+        }
     }
 
     /**
@@ -198,20 +202,22 @@
 
     /** @hide */
     public void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.println("ContentCaptureManager");
-
-        pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled.get());
-        pw.print(prefix); pw.print("Context: "); pw.println(mContext);
-        pw.print(prefix); pw.print("User: "); pw.println(mContext.getUserId());
-        if (mService != null) {
-            pw.print(prefix); pw.print("Service: "); pw.println(mService);
-        }
-        if (mMainSession != null) {
-            final String prefix2 = prefix + "  ";
-            pw.print(prefix); pw.println("Main session:");
-            mMainSession.dump(prefix2, pw);
-        } else {
-            pw.print(prefix); pw.println("No sessions");
+        synchronized (mLock) {
+            pw.print(prefix); pw.println("ContentCaptureManager");
+            pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
+            pw.print(prefix); pw.print("Context: "); pw.println(mContext);
+            pw.print(prefix); pw.print("User: "); pw.println(mContext.getUserId());
+            if (mService != null) {
+                pw.print(prefix); pw.print("Service: "); pw.println(mService);
+            }
+            pw.print(prefix); pw.print("Flags: "); pw.println(mFlags);
+            if (mMainSession != null) {
+                final String prefix2 = prefix + "  ";
+                pw.print(prefix); pw.println("Main session:");
+                mMainSession.dump(prefix2, pw);
+            } else {
+                pw.print(prefix); pw.println("No sessions");
+            }
         }
     }
 
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index d9a8416..7fb1fdd 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -19,8 +19,10 @@
 import static android.view.contentcapture.ContentCaptureManager.VERBOSE;
 
 import android.annotation.CallSuper;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.util.DebugUtils;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewStructure;
@@ -29,11 +31,14 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 
 import dalvik.system.CloseGuard;
 
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.UUID;
 
@@ -56,45 +61,100 @@
      *
      * @hide
      */
-    public static final int STATE_UNKNOWN = 0;
+    // NOTE: not prefixed by STATE_ so it's not printed on getStateAsString()
+    public static final int UNKNWON_STATE = 0x0;
 
     /**
      * Service's startSession() was called, but server didn't confirm it was created yet.
      *
      * @hide
      */
-    public static final int STATE_WAITING_FOR_SERVER = 1;
+    public static final int STATE_WAITING_FOR_SERVER = 0x1;
 
     /**
      * Session is active.
      *
      * @hide
      */
-    public static final int STATE_ACTIVE = 2;
+    public static final int STATE_ACTIVE = 0x2;
 
     /**
      * Session is disabled because there is no service for this user.
      *
      * @hide
      */
-    public static final int STATE_DISABLED_NO_SERVICE = 3;
+    public static final int STATE_DISABLED = 0x4;
 
     /**
      * Session is disabled because its id already existed on server.
      *
      * @hide
      */
-    public static final int STATE_DISABLED_DUPLICATED_ID = 4;
+    public static final int STATE_DUPLICATED_ID = 0x8;
+
+    /**
+     * Session is disabled because service is not set for user.
+     *
+     * @hide
+     */
+    public static final int STATE_NO_SERVICE = 0x10;
 
     /**
      * Session is disabled by FLAG_SECURE
      *
      * @hide
      */
-    public static final int STATE_DISABLED_BY_FLAG_SECURE = 5;
+    public static final int STATE_FLAG_SECURE = 0x20;
+
+    /**
+     * Session is disabled manually by the specific app.
+     *
+     * @hide
+     */
+    public static final int STATE_BY_APP = 0x40;
+
+    /**
+     * Session is disabled because session start was never replied.
+     *
+     * @hide
+     */
+    public static final int STATE_NO_RESPONSE = 0x80;
+
+    /**
+     * Session is disabled because an internal error.
+     *
+     * @hide
+     */
+    public static final int STATE_INTERNAL_ERROR = 0x100;
 
     private static final int INITIAL_CHILDREN_CAPACITY = 5;
 
+    /** @hide */
+    public static final int FLUSH_REASON_FULL = 1;
+    /** @hide */
+    public static final int FLUSH_REASON_ACTIVITY_PAUSED = 2;
+    /** @hide */
+    public static final int FLUSH_REASON_ACTIVITY_RESUMED = 3;
+    /** @hide */
+    public static final int FLUSH_REASON_SESSION_STARTED = 4;
+    /** @hide */
+    public static final int FLUSH_REASON_SESSION_FINISHED = 5;
+    /** @hide */
+    public static final int FLUSH_REASON_IDLE_TIMEOUT = 6;
+
+    /** @hide */
+    @IntDef(prefix = { "FLUSH_REASON_" }, value = {
+            FLUSH_REASON_FULL,
+            FLUSH_REASON_ACTIVITY_PAUSED,
+            FLUSH_REASON_ACTIVITY_RESUMED,
+            FLUSH_REASON_SESSION_STARTED,
+            FLUSH_REASON_SESSION_FINISHED,
+            FLUSH_REASON_IDLE_TIMEOUT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface FlushReason{}
+
+
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
     private final Object mLock = new Object();
@@ -110,7 +170,7 @@
     @Nullable
     protected final String mId;
 
-    private int mState = STATE_UNKNOWN;
+    private int mState = UNKNWON_STATE;
 
     // Lazily created on demand.
     private ContentCaptureSessionId mContentCaptureSessionId;
@@ -182,7 +242,7 @@
     /**
      * Flushes the buffered events to the service.
      */
-    abstract void flush();
+    abstract void flush(@FlushReason int reason);
 
     /**
      * Destroys this session, flushing out all pending notifications to the service.
@@ -220,7 +280,7 @@
         }
 
         try {
-            flush();
+            flush(FLUSH_REASON_SESSION_FINISHED);
         } finally {
             onDestroy();
         }
@@ -286,6 +346,31 @@
     abstract void internalNotifyViewDisappeared(@NonNull AutofillId id);
 
     /**
+     * Notifies the Content Capture Service that many nodes has been removed from a virtual view
+     * structure.
+     *
+     * <p>Should only be called by views that handle their own virtual view hierarchy.
+     *
+     * @param hostId id of the view hosting the virtual hierarchy.
+     * @param virtualIds ids of the virtual children.
+     *
+     * @throws IllegalArgumentException if the {@code hostId} is an autofill id for a virtual view.
+     * @throws IllegalArgumentException if {@code virtualIds} is empty
+     */
+    public final void notifyViewsDisappeared(@NonNull AutofillId hostId,
+            @NonNull int[] virtualIds) {
+        Preconditions.checkArgument(!hostId.isVirtual(), "parent cannot be virtual");
+        Preconditions.checkArgument(!ArrayUtils.isEmpty(virtualIds), "virtual ids cannot be empty");
+        if (!isContentCaptureEnabled()) return;
+
+        // TODO(b/121050915): create a new VIEWS_DISAPPEARED event type, which could also be used
+        // to batch delete non-virtual views
+        for (int id : virtualIds) {
+            internalNotifyViewDisappeared(new AutofillId(hostId, id, getIdAsInt()));
+        }
+    }
+
+    /**
      * Notifies the Intelligence Service that the value of a text node has been changed.
      *
      * @param id of the node.
@@ -377,26 +462,31 @@
         return mId;
     }
 
-    /**
-     * @hide
-     */
+    /** @hide */
     @NonNull
     protected static String getStateAsString(int state) {
-        switch (state) {
-            case STATE_UNKNOWN:
-                return "UNKNOWN";
-            case STATE_WAITING_FOR_SERVER:
-                return "WAITING_FOR_SERVER";
-            case STATE_ACTIVE:
-                return "ACTIVE";
-            case STATE_DISABLED_NO_SERVICE:
-                return "DISABLED_NO_SERVICE";
-            case STATE_DISABLED_DUPLICATED_ID:
-                return "DISABLED_DUPLICATED_ID";
-            case STATE_DISABLED_BY_FLAG_SECURE:
-                return "DISABLED_FLAG_SECURE";
+        return state + " (" + (state == UNKNWON_STATE ? "UNKNOWN"
+                : DebugUtils.flagsToString(ContentCaptureSession.class, "STATE_", state)) + ")";
+    }
+
+    /** @hide */
+    @NonNull
+    static String getflushReasonAsString(@FlushReason int reason) {
+        switch (reason) {
+            case FLUSH_REASON_FULL:
+                return "FULL";
+            case FLUSH_REASON_ACTIVITY_PAUSED:
+                return "PAUSED";
+            case FLUSH_REASON_ACTIVITY_RESUMED:
+                return "RESUMED";
+            case FLUSH_REASON_SESSION_STARTED:
+                return "STARTED";
+            case FLUSH_REASON_SESSION_FINISHED:
+                return "FINISHED";
+            case FLUSH_REASON_IDLE_TIMEOUT:
+                return "IDLE";
             default:
-                return "INVALID:" + state;
+                return "UNKOWN-" + reason;
         }
     }
 }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index a29aaf0..f0778fa 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -35,7 +35,7 @@
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
 import android.os.RemoteException;
-import android.os.SystemClock;
+import android.util.LocalLog;
 import android.util.Log;
 import android.util.TimeUtils;
 import android.view.autofill.AutofillId;
@@ -88,6 +88,7 @@
      */
     public static final String EXTRA_BINDER = "binder";
 
+    // TODO(b/111276913): make sure disabled state is in sync with manager's disabled
     @NonNull
     private final AtomicBoolean mDisabled;
 
@@ -113,7 +114,7 @@
     @Nullable
     private DeathRecipient mDirectServiceVulture;
 
-    private int mState = STATE_UNKNOWN;
+    private int mState = UNKNWON_STATE;
 
     @Nullable
     private IBinder mApplicationToken;
@@ -130,14 +131,17 @@
     // Used just for debugging purposes (on dump)
     private long mNextFlush;
 
+    // TODO(b/121044064): use settings to set size
+    private final LocalLog mFlushHistory = new LocalLog(10);
+
     /** @hide */
     protected MainContentCaptureSession(@NonNull Context context, @NonNull Handler handler,
             @Nullable IContentCaptureManager systemServerInterface,
-            @NonNull AtomicBoolean disabled) {
+            @NonNull boolean disabled) {
         mContext = context;
         mHandler = handler;
         mSystemServerInterface = systemServerInterface;
-        mDisabled = disabled;
+        mDisabled = new AtomicBoolean(disabled);
     }
 
     @Override
@@ -171,8 +175,9 @@
     }
 
     @Override
-    void flush() {
-        mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleForceFlush, this));
+    void flush(@FlushReason int reason) {
+        mHandler.sendMessage(
+                obtainMessage(MainContentCaptureSession::handleForceFlush, this, reason));
     }
 
     @Override
@@ -184,10 +189,13 @@
 
     private void handleStartSession(@NonNull IBinder token, @NonNull ComponentName componentName,
             int flags) {
-        if (mState != STATE_UNKNOWN) {
-            // TODO(b/111276913): revisit this scenario
-            Log.w(TAG, "ignoring handleStartSession(" + token + ") while on state "
-                    + getStateAsString(mState));
+        if (handleHasStarted()) {
+            // TODO(b/122959591): make sure this is expected (and when), or use Log.w
+            if (DEBUG) {
+                Log.d(TAG, "ignoring handleStartSession(" + token + "/"
+                        + ComponentName.flattenToShortString(componentName) + " while on state "
+                        + getStateAsString(mState));
+            }
             return;
         }
         mState = STATE_WAITING_FOR_SERVER;
@@ -196,7 +204,7 @@
 
         if (VERBOSE) {
             Log.v(TAG, "handleStartSession(): token=" + token + ", act="
-                    + getActivityDebugName() + ", id=" + mId);
+                    + getDebugState() + ", id=" + mId);
         }
 
         try {
@@ -211,7 +219,7 @@
                                 binder = resultData.getBinder(EXTRA_BINDER);
                                 if (binder == null) {
                                     Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result");
-                                    handleResetState();
+                                    handleResetSession(STATE_DISABLED | STATE_INTERNAL_ERROR);
                                     return;
                                 }
                             }
@@ -233,7 +241,6 @@
      * @param binder handle to {@code IContentCaptureDirectManager}
      */
     private void handleSessionStarted(int resultCode, @Nullable IBinder binder) {
-        mState = resultCode;
         if (binder != null) {
             mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder);
             mDirectServiceVulture = () -> {
@@ -247,31 +254,39 @@
             }
         }
 
-        // TODO(b/111276913): change the resultCode to use flags so there's just one flag for
-        // disabled stuff
-        if (resultCode == STATE_DISABLED_NO_SERVICE || resultCode == STATE_DISABLED_DUPLICATED_ID
-                || resultCode == STATE_DISABLED_BY_FLAG_SECURE) {
-            mDisabled.set(true);
-            handleResetSession(/* resetState= */ false);
+        if ((resultCode & STATE_DISABLED) != 0) {
+            handleResetSession(resultCode);
         } else {
+            mState = resultCode;
             mDisabled.set(false);
         }
         if (VERBOSE) {
-            Log.v(TAG, "handleSessionStarted() result: code=" + resultCode + ", id=" + mId
+            Log.v(TAG, "handleSessionStarted() result: id=" + mId + " resultCode=" + resultCode
                     + ", state=" + getStateAsString(mState) + ", disabled=" + mDisabled.get()
                     + ", binder=" + binder + ", events=" + (mEvents == null ? 0 : mEvents.size()));
         }
     }
 
     private void handleSendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
+        final int eventType = event.getType();
+        if (!handleHasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED) {
+            // TODO(b/120494182): comment when this could happen (dialogs?)
+            Log.v(TAG, "handleSendEvent(" + getDebugState() + ", "
+                    + ContentCaptureEvent.getTypeAsString(eventType)
+                    + "): session not started yet");
+            return;
+        }
+        if (VERBOSE) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event);
         if (mEvents == null) {
             if (VERBOSE) {
-                Log.v(TAG, "Creating buffer for " + MAX_BUFFER_SIZE + " events");
+                Log.v(TAG, "handleSendEvent(" + getDebugState() + ", "
+                        + ContentCaptureEvent.getTypeAsString(eventType)
+                        + "): creating buffer for " + MAX_BUFFER_SIZE + " events");
             }
             mEvents = new ArrayList<>(MAX_BUFFER_SIZE);
         }
 
-        if (!mEvents.isEmpty() && event.getType() == TYPE_VIEW_TEXT_CHANGED) {
+        if (!mEvents.isEmpty() && eventType == TYPE_VIEW_TEXT_CHANGED) {
             final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1);
 
             // TODO(b/121045053): check if flags match
@@ -294,76 +309,104 @@
         final boolean bufferEvent = numberEvents < MAX_BUFFER_SIZE;
 
         if (bufferEvent && !forceFlush) {
-            handleScheduleFlush(/* checkExisting= */ true);
+            handleScheduleFlush(FLUSH_REASON_IDLE_TIMEOUT, /* checkExisting= */ true);
             return;
         }
 
         if (mState != STATE_ACTIVE && numberEvents >= MAX_BUFFER_SIZE) {
             // Callback from startSession hasn't been called yet - typically happens on system
             // apps that are started before the system service
-            // TODO(b/111276913): try to ignore session while system is not ready / boot
+            // TODO(b/122959591): try to ignore session while system is not ready / boot
             // not complete instead. Similarly, the manager service should return right away
             // when the user does not have a service set
             if (DEBUG) {
-                Log.d(TAG, "Closing session for " + getActivityDebugName()
-                        + " after " + numberEvents + " delayed events and state "
-                        + getStateAsString(mState));
+                Log.d(TAG, "Closing session for " + getDebugState()
+                        + " after " + numberEvents + " delayed events");
             }
-            handleResetState();
+            handleResetSession(STATE_DISABLED | STATE_NO_RESPONSE);
             // TODO(b/111276913): blacklist activity / use special flag to indicate that
             // when it's launched again
             return;
         }
+        final int flushReason;
+        switch (eventType) {
+            case ContentCaptureEvent.TYPE_SESSION_STARTED:
+                flushReason = FLUSH_REASON_SESSION_STARTED;
+                break;
+            case ContentCaptureEvent.TYPE_SESSION_FINISHED:
+                flushReason = FLUSH_REASON_SESSION_FINISHED;
+                break;
+            default:
+                flushReason = FLUSH_REASON_FULL;
+        }
 
-        handleForceFlush();
+        handleForceFlush(flushReason);
     }
 
-    private void handleScheduleFlush(boolean checkExisting) {
+    private boolean handleHasStarted() {
+        return mState != UNKNWON_STATE;
+    }
+
+    private void handleScheduleFlush(@FlushReason int reason, boolean checkExisting) {
+        if (!handleHasStarted()) {
+            Log.v(TAG, "handleScheduleFlush(" + getDebugState() + "): session not started yet");
+            return;
+        }
         if (checkExisting && mHandler.hasMessages(MSG_FLUSH)) {
             // "Renew" the flush message by removing the previous one
             mHandler.removeMessages(MSG_FLUSH);
         }
-        mNextFlush = SystemClock.elapsedRealtime() + FLUSHING_FREQUENCY_MS;
+        mNextFlush = System.currentTimeMillis() + FLUSHING_FREQUENCY_MS;
         if (VERBOSE) {
-            Log.v(TAG, "Scheduled to flush in " + FLUSHING_FREQUENCY_MS + "ms: " + mNextFlush);
+            Log.v(TAG, "handleScheduleFlush(" + getDebugState()
+                    + ", reason=" + getflushReasonAsString(reason) + "): scheduled to flush in "
+                    + FLUSHING_FREQUENCY_MS + "ms: " + TimeUtils.logTimeOfDay(mNextFlush));
         }
         mHandler.sendMessageDelayed(
-                obtainMessage(MainContentCaptureSession::handleFlushIfNeeded, this)
+                obtainMessage(MainContentCaptureSession::handleFlushIfNeeded, this, reason)
                 .setWhat(MSG_FLUSH), FLUSHING_FREQUENCY_MS);
     }
 
-    private void handleFlushIfNeeded() {
+    private void handleFlushIfNeeded(@FlushReason int reason) {
         if (mEvents.isEmpty()) {
             if (VERBOSE) Log.v(TAG, "Nothing to flush");
             return;
         }
-        handleForceFlush();
+        handleForceFlush(reason);
     }
 
-    private void handleForceFlush() {
+    private void handleForceFlush(@FlushReason int reason) {
         if (mEvents == null) return;
 
         if (mDirectServiceInterface == null) {
             if (VERBOSE) {
-                Log.v(TAG, "handleForceFlush(): hold your horses, client not ready: " + mEvents);
+                Log.v(TAG, "handleForceFlush(" + getDebugState()
+                        + ", reason=" + getflushReasonAsString(reason)
+                        + "): hold your horses, client not ready: " + mEvents);
             }
             if (!mHandler.hasMessages(MSG_FLUSH)) {
-                handleScheduleFlush(/* checkExisting= */ false);
+                handleScheduleFlush(reason, /* checkExisting= */ false);
             }
             return;
         }
 
         final int numberEvents = mEvents.size();
+        final String reasonString = getflushReasonAsString(reason);
+        if (DEBUG) {
+            Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState()
+                    + ". Reason: " + reasonString);
+        }
+        // Logs reason, size, max size, idle timeout
+        final String logRecord = "r=" + reasonString + " s=" + numberEvents
+                + " m=" + MAX_BUFFER_SIZE + " i=" + FLUSHING_FREQUENCY_MS;
         try {
-            if (DEBUG) {
-                Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getActivityDebugName());
-            }
+            mFlushHistory.log(logRecord);
             mHandler.removeMessages(MSG_FLUSH);
 
             final ParceledListSlice<ContentCaptureEvent> events = handleClearEvents();
             mDirectServiceInterface.sendEvents(events);
         } catch (RemoteException e) {
-            Log.w(TAG, "Error sending " + numberEvents + " for " + getActivityDebugName()
+            Log.w(TAG, "Error sending " + numberEvents + " for " + getDebugState()
                     + ": " + e);
         }
     }
@@ -386,7 +429,7 @@
         if (DEBUG) {
             Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
                     + (mEvents == null ? 0 : mEvents.size()) + " event(s) for "
-                    + getActivityDebugName());
+                    + getDebugState());
         }
 
         try {
@@ -395,21 +438,19 @@
             mSystemServerInterface.finishSession(mContext.getUserId(), mId);
         } catch (RemoteException e) {
             Log.e(TAG, "Error destroying system-service session " + mId + " for "
-                    + getActivityDebugName() + ": " + e);
+                    + getDebugState() + ": " + e);
         }
     }
 
-    private void handleResetState() {
-        handleResetSession(/* resetState= */ true);
-    }
-
     // TODO(b/122454205): once we support multiple sessions, we might need to move some of these
     // clearings out.
-    private void handleResetSession(boolean resetState) {
-        if (resetState) {
-            mState = STATE_UNKNOWN;
+    private void handleResetSession(int newState) {
+        if (VERBOSE) {
+            Log.v(TAG, "handleResetSession(" + getActivityName() + "): from "
+                    + getStateAsString(mState) + " to " + getStateAsString(newState));
         }
-
+        mState = newState;
+        mDisabled.set((newState & STATE_DISABLED) != 0);
         // TODO(b/122454205): must reset children (which currently is owned by superclass)
         mApplicationToken = null;
         mComponentName = null;
@@ -483,7 +524,6 @@
 
     @Override
     void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
-        pw.print(prefix); pw.print("id: "); pw.println(mId);
         pw.print(prefix); pw.print("mContext: "); pw.println(mContext);
         pw.print(prefix); pw.print("user: "); pw.println(mContext.getUserId());
         if (mSystemServerInterface != null) {
@@ -496,8 +536,7 @@
         }
         pw.print(prefix); pw.print("mDisabled: "); pw.println(mDisabled.get());
         pw.print(prefix); pw.print("isEnabled(): "); pw.println(isContentCaptureEnabled());
-        pw.print(prefix); pw.print("state: "); pw.print(mState); pw.print(" (");
-        pw.print(getStateAsString(mState)); pw.println(")");
+        pw.print(prefix); pw.print("state: "); pw.println(getStateAsString(mState));
         if (mApplicationToken != null) {
             pw.print(prefix); pw.print("app token: "); pw.println(mApplicationToken);
         }
@@ -519,16 +558,25 @@
             }
             pw.print(prefix); pw.print("flush frequency: "); pw.println(FLUSHING_FREQUENCY_MS);
             pw.print(prefix); pw.print("next flush: ");
-            TimeUtils.formatDuration(mNextFlush - SystemClock.elapsedRealtime(), pw); pw.println();
+            TimeUtils.formatDuration(mNextFlush - System.currentTimeMillis(), pw);
+            pw.print(" ("); pw.print(TimeUtils.logTimeOfDay(mNextFlush)); pw.println(")");
         }
+        pw.print(prefix); pw.println("flush history:");
+        mFlushHistory.reverseDump(/* fd= */ null, pw, /* args= */ null); pw.println();
+
         super.dump(prefix, pw);
     }
 
     /**
      * Gets a string that can be used to identify the activity on logging statements.
      */
-    private String getActivityDebugName() {
-        return mComponentName == null ? mContext.getPackageName()
-                : mComponentName.flattenToShortString();
+    private String getActivityName() {
+        return mComponentName == null
+                ? "pkg:" + mContext.getPackageName()
+                : "act:" + mComponentName.flattenToShortString();
+    }
+
+    private String getDebugState() {
+        return getActivityName() + " (state=" + getStateAsString(mState) + ")";
     }
 }
diff --git a/core/java/android/view/inspector/InspectableProperty.java b/core/java/android/view/inspector/InspectableProperty.java
index 5b957156..e2a763e 100644
--- a/core/java/android/view/inspector/InspectableProperty.java
+++ b/core/java/android/view/inspector/InspectableProperty.java
@@ -105,7 +105,6 @@
     /**
      * One entry in an enumeration packed into a primitive {int}.
      *
-     * @see IntEnumMapping
      * @hide
      */
     @Target({TYPE})
diff --git a/core/java/android/view/inspector/IntEnumMapping.java b/core/java/android/view/inspector/IntEnumMapping.java
deleted file mode 100644
index 69f6dce..0000000
--- a/core/java/android/view/inspector/IntEnumMapping.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.inspector;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import java.util.ArrayList;
-
-/**
- * Maps the values of an {int} property to string names for properties that encode enumerations.
- *
- * An {@link InspectionCompanion} may provide an instance of this class to a {@link PropertyMapper}
- * for enumerations packed into primitive {int} properties.
- *
- * This class is immutable, and must be constructed by a {@link Builder}.
- *
- * @see PropertyMapper#mapIntEnum(String, int, IntEnumMapping)
- */
-public final class IntEnumMapping {
-    private final Value[] mValues;
-
-    /**
-     * Map from a property value to a string name.
-     *
-     * @param value The value of a property
-     * @return The name of the enumeration value, null if the value is not mapped
-     */
-    @Nullable
-    public String nameOf(int value) {
-        for (Value valueTuple : mValues) {
-            if (valueTuple.mValue == value) {
-                return valueTuple.mName;
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * Create a new instance from a builder.
-     *
-     * This constructor is private, use {@link Builder#build()} instead.
-     *
-     * @param builder A builder to create from
-     */
-    private IntEnumMapping(Builder builder) {
-        mValues = builder.mValues.toArray(new Value[builder.mValues.size()]);
-    }
-
-    /**
-     * A builder for {@link IntEnumMapping}
-     */
-    public static final class Builder {
-        private final ArrayList<Value> mValues;
-
-        public Builder() {
-            mValues = new ArrayList<>();
-        }
-
-        /**
-         * Add a new entry to this mapping.
-         *
-         * @param name Name of the enumeration value
-         * @param value Int value of the enumeration value
-         * @return This builder
-         */
-        @NonNull
-        public Builder addValue(@NonNull String name, int value) {
-            mValues.add(new Value(name, value));
-            return this;
-        }
-
-        /**
-         * Clear the builder, allowing for recycling.
-         */
-        public void clear() {
-            mValues.clear();
-        }
-
-        /**
-         * Build a new {@link IntEnumMapping} from this builder
-         *
-         * @return A new mapping
-         */
-        @NonNull
-        public IntEnumMapping build() {
-            return new IntEnumMapping(this);
-        }
-    }
-
-    /**
-     * Inner class that holds the name and value of an enumeration value.
-     */
-    private static final class Value {
-        @NonNull private final String mName;
-        private final int mValue;
-
-        private Value(@NonNull String name, int value) {
-            mName = name;
-            mValue = value;
-        }
-    }
-}
diff --git a/core/java/android/view/inspector/IntFlagMapping.java b/core/java/android/view/inspector/IntFlagMapping.java
index dcb87e1..8f7dfd5 100644
--- a/core/java/android/view/inspector/IntFlagMapping.java
+++ b/core/java/android/view/inspector/IntFlagMapping.java
@@ -19,14 +19,20 @@
 import android.annotation.NonNull;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
- * Maps the values of an {int} property to arrays of string for properties that encode flags.
+ * Maps the values of an {@code int} property to arrays of string for properties that encode flags.
  *
  * An {@link InspectionCompanion} may provide an instance of this class to a {@link PropertyMapper}
- * for flag values packed into primitive {int} properties.
+ * for flag values packed into primitive {@code int} properties.
  *
- * Each flag has a
+ * Each flag has a mask and a target value, for non-exclusive flags, the target can also be used as
+ * the mask. A given integer value is compared against each flag to find what flags are active for
+ * it by bitwise anding it with the mask and comparing the result against the target, that is,
+ * {@code (value & mask) == target}.
  *
  * This class is immutable, and must be constructed by a {@link Builder}.
  *
@@ -42,8 +48,8 @@
      * @return The names of the enabled flags
      */
     @NonNull
-    public String[] namesOf(int value) {
-        ArrayList<String> enabledFlagNames = new ArrayList<>(mFlags.length);
+    public Set<String> get(int value) {
+        final Set<String> enabledFlagNames = new HashSet<>(mFlags.length);
 
         for (Flag flag : mFlags) {
             if (flag.isEnabledFor(value)) {
@@ -51,7 +57,7 @@
             }
         }
 
-        return enabledFlagNames.toArray(new String[enabledFlagNames.size()]);
+        return Collections.unmodifiableSet(enabledFlagNames);
     }
 
     /**
@@ -81,7 +87,7 @@
          * The target value will be used as a mask, to handle the common case where flag values
          * are not mutually exclusive. The flag will be considered enabled for a property value if
          * the result of bitwise anding the target and the value equals the target, that is:
-         * {(value & target) == target}.
+         * {@code (value & target) == target}.
          *
          * @param name The name of the flag
          * @param target The value to compare against
@@ -97,7 +103,7 @@
          * Add a new flag with a mask.
          *
          * The flag will be considered enabled for a property value if the result of bitwise anding
-         * the value and the mask equals the target, that is: {(value & mask) == target}.
+         * the value and the mask equals the target, that is: {@code (value & mask) == target}.
          *
          * @param name The name of the flag
          * @param target The value to compare against
@@ -111,13 +117,6 @@
         }
 
         /**
-         * Clear the builder, allowing for recycling.
-         */
-        public void clear() {
-            mFlags.clear();
-        }
-
-        /**
          * Build a new {@link IntFlagMapping} from this builder.
          *
          * @return A new mapping
@@ -143,7 +142,7 @@
         }
 
         /**
-         * Compare the supplied property value against the mask and taget.
+         * Compare the supplied property value against the mask and target.
          *
          * @param value The value to check
          * @return True if this flag is enabled
diff --git a/core/java/android/view/inspector/PropertyMapper.java b/core/java/android/view/inspector/PropertyMapper.java
index 5fb291b..e20582b 100644
--- a/core/java/android/view/inspector/PropertyMapper.java
+++ b/core/java/android/view/inspector/PropertyMapper.java
@@ -18,6 +18,7 @@
 
 import android.annotation.AttrRes;
 import android.annotation.NonNull;
+import android.util.SparseArray;
 
 /**
  * An interface for mapping the string names of inspectable properties to integer identifiers.
@@ -154,7 +155,7 @@
     int mapIntEnum(
             @NonNull String name,
             @AttrRes int attributeId,
-            @NonNull IntEnumMapping mapping);
+            @NonNull SparseArray<String> mapping);
 
     /**
      * Map a string name to an integer ID for a flag set packed into an int property.
diff --git a/core/java/android/view/inspector/PropertyReader.java b/core/java/android/view/inspector/PropertyReader.java
index fd83e8d..a8b7ecc 100644
--- a/core/java/android/view/inspector/PropertyReader.java
+++ b/core/java/android/view/inspector/PropertyReader.java
@@ -25,7 +25,13 @@
 /**
  * An interface for reading the properties of an inspectable object.
  *
- * Used as the parameter for {@link InspectionCompanion#readProperties(Object, PropertyReader)}.
+ * {@code PropertyReader} is defined as an interface that will be called by
+ * {@link InspectionCompanion#readProperties(Object, PropertyReader)}. This approach allows a
+ * client inspector to read the values of primitive properties without the overhead of
+ * instantiating a class to hold the property values for each inspection pass. If an inspectable
+ * remains unchanged between reading passes, it should be possible for a {@code PropertyReader} to
+ * avoid new allocations for subsequent reading passes.
+ *
  * It has separate methods for all primitive types to avoid autoboxing overhead if a concrete
  * implementation is able to work with primitives. Implementations should be prepared to accept
  * {null} as the value of {@link PropertyReader#readObject(int, Object)}.
@@ -38,7 +44,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {boolean}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code boolean}
      */
     void readBoolean(int id, boolean value);
 
@@ -47,7 +53,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {byte}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code byte}
      */
     void readByte(int id, byte value);
 
@@ -56,7 +62,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {char}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code char}
      */
     void readChar(int id, char value);
 
@@ -65,7 +71,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {double}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code double}
      */
     void readDouble(int id, double value);
 
@@ -74,7 +80,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {float}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code float}
      */
     void readFloat(int id, float value);
 
@@ -83,7 +89,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as an {int}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as an {@code int}
      */
     void readInt(int id, int value);
 
@@ -92,7 +98,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {long}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code long}
      */
     void readLong(int id, long value);
 
@@ -101,7 +107,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {short}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code short}
      */
     void readShort(int id, short value);
 
diff --git a/core/java/android/view/textclassifier/ConversationAction.java b/core/java/android/view/textclassifier/ConversationAction.java
new file mode 100644
index 0000000..1a6e5d8
--- /dev/null
+++ b/core/java/android/view/textclassifier/ConversationAction.java
@@ -0,0 +1,266 @@
+/*
+ * 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.textclassifier;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.app.RemoteAction;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+
+/** Represents the action suggested by a {@link TextClassifier} on a given conversation. */
+public final class ConversationAction implements Parcelable {
+
+    /** @hide */
+    @Retention(SOURCE)
+    @StringDef(
+            value = {
+                    TYPE_VIEW_CALENDAR,
+                    TYPE_VIEW_MAP,
+                    TYPE_TRACK_FLIGHT,
+                    TYPE_OPEN_URL,
+                    TYPE_SEND_SMS,
+                    TYPE_CALL_PHONE,
+                    TYPE_SEND_EMAIL,
+                    TYPE_TEXT_REPLY,
+                    TYPE_CREATE_REMINDER,
+                    TYPE_SHARE_LOCATION
+            },
+            prefix = "TYPE_")
+    public @interface ActionType {}
+
+    /**
+     * Indicates an action to view a calendar at a specified time.
+     */
+    public static final String TYPE_VIEW_CALENDAR = "view_calendar";
+    /**
+     * Indicates an action to view the map at a specified location.
+     */
+    public static final String TYPE_VIEW_MAP = "view_map";
+    /**
+     * Indicates an action to track a flight.
+     */
+    public static final String TYPE_TRACK_FLIGHT = "track_flight";
+    /**
+     * Indicates an action to open an URL.
+     */
+    public static final String TYPE_OPEN_URL = "open_url";
+    /**
+     * Indicates an action to send a SMS.
+     */
+    public static final String TYPE_SEND_SMS = "send_sms";
+    /**
+     * Indicates an action to call a phone number.
+     */
+    public static final String TYPE_CALL_PHONE = "call_phone";
+    /**
+     * Indicates an action to send an email.
+     */
+    public static final String TYPE_SEND_EMAIL = "send_email";
+    /**
+     * Indicates an action to reply with a text message.
+     */
+    public static final String TYPE_TEXT_REPLY = "text_reply";
+    /**
+     * Indicates an action to create a reminder.
+     */
+    public static final String TYPE_CREATE_REMINDER = "create_reminder";
+    /**
+     * Indicates an action to reply with a location.
+     */
+    public static final String TYPE_SHARE_LOCATION = "share_location";
+
+    public static final Creator<ConversationAction> CREATOR =
+            new Creator<ConversationAction>() {
+                @Override
+                public ConversationAction createFromParcel(Parcel in) {
+                    return new ConversationAction(in);
+                }
+
+                @Override
+                public ConversationAction[] newArray(int size) {
+                    return new ConversationAction[size];
+                }
+            };
+
+    @NonNull
+    @ActionType
+    private final String mType;
+    @NonNull
+    private final CharSequence mTextReply;
+    @Nullable
+    private final RemoteAction mAction;
+
+    @FloatRange(from = 0, to = 1)
+    private final float mScore;
+
+    @NonNull
+    private final Bundle mExtras;
+
+    private ConversationAction(
+            @NonNull String type,
+            @Nullable RemoteAction action,
+            @Nullable CharSequence textReply,
+            float score,
+            @NonNull Bundle extras) {
+        mType = Preconditions.checkNotNull(type);
+        mAction = action;
+        mTextReply = textReply;
+        mScore = score;
+        mExtras = Preconditions.checkNotNull(extras);
+    }
+
+    private ConversationAction(Parcel in) {
+        mType = in.readString();
+        mAction = in.readParcelable(null);
+        mTextReply = in.readCharSequence();
+        mScore = in.readFloat();
+        mExtras = in.readBundle();
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeString(mType);
+        parcel.writeParcelable(mAction, flags);
+        parcel.writeCharSequence(mTextReply);
+        parcel.writeFloat(mScore);
+        parcel.writeBundle(mExtras);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Returns the type of this action, for example, {@link #TYPE_VIEW_CALENDAR}. */
+    @NonNull
+    @ActionType
+    public String getType() {
+        return mType;
+    }
+
+    /**
+     * Returns a RemoteAction object, which contains the icon, label and a PendingIntent, for
+     * the specified action type.
+     */
+    @Nullable
+    public RemoteAction getAction() {
+        return mAction;
+    }
+
+    /**
+     * Returns the confidence score for the specified action. The value ranges from 0 (low
+     * confidence) to 1 (high confidence).
+     */
+    @FloatRange(from = 0, to = 1)
+    public float getConfidenceScore() {
+        return mScore;
+    }
+
+    /**
+     * Returns the text reply that could be sent as a reply to the given conversation.
+     * <p>
+     * This is only available when the type of the action is {@link #TYPE_TEXT_REPLY}.
+     */
+    @Nullable
+    public CharSequence getTextReply() {
+        return mTextReply;
+    }
+
+    /**
+     * Returns the extended data related to this conversation action.
+     *
+     * <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.
+     */
+    @NonNull
+    public Bundle getExtras() {
+        return mExtras.deepCopy();
+    }
+
+    /** Builder class to construct {@link ConversationAction}. */
+    public static final class Builder {
+        @Nullable
+        @ActionType
+        private String mType;
+        @Nullable
+        private RemoteAction mAction;
+        @Nullable
+        private CharSequence mTextReply;
+        private float mScore;
+        @Nullable
+        private Bundle mExtras;
+
+        public Builder(@NonNull @ActionType String actionType) {
+            mType = Preconditions.checkNotNull(actionType);
+        }
+
+        /**
+         * Sets an action that may be performed on the given conversation.
+         */
+        @NonNull
+        public Builder setAction(@Nullable RemoteAction action) {
+            mAction = action;
+            return this;
+        }
+
+        /**
+         * Sets a text reply that may be performed on the given conversation.
+         */
+        @NonNull
+        public Builder setTextReply(@Nullable CharSequence textReply) {
+            mTextReply = textReply;
+            return this;
+        }
+
+        /** Sets the confident score. */
+        @NonNull
+        public Builder setConfidenceScore(@FloatRange(from = 0, to = 1) float score) {
+            mScore = score;
+            return this;
+        }
+
+        /**
+         * Sets the extended data for the conversation action object.
+         */
+        @NonNull
+        public Builder setExtras(@Nullable Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /** Builds the {@link ConversationAction} object. */
+        @NonNull
+        public ConversationAction build() {
+            return new ConversationAction(
+                    mType,
+                    mAction,
+                    mTextReply,
+                    mScore,
+                    mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
+        }
+    }
+}
diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java
index 3f690f7..f7c1a26 100644
--- a/core/java/android/view/textclassifier/ConversationActions.java
+++ b/core/java/android/view/textclassifier/ConversationActions.java
@@ -17,18 +17,15 @@
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
-import android.annotation.FloatRange;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringDef;
 import android.app.Person;
-import android.app.RemoteAction;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.SpannedString;
-import android.util.ArraySet;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
@@ -37,10 +34,8 @@
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Set;
 
 /**
  * Represents a list of actions suggested by a {@link TextClassifier} on a given conversation.
@@ -62,83 +57,6 @@
                 }
             };
 
-    /** @hide */
-    @Retention(SOURCE)
-    @StringDef(
-            value = {
-                    TYPE_VIEW_CALENDAR,
-                    TYPE_VIEW_MAP,
-                    TYPE_TRACK_FLIGHT,
-                    TYPE_OPEN_URL,
-                    TYPE_SEND_SMS,
-                    TYPE_CALL_PHONE,
-                    TYPE_SEND_EMAIL,
-                    TYPE_TEXT_REPLY,
-                    TYPE_CREATE_REMINDER,
-                    TYPE_SHARE_LOCATION
-            },
-            prefix = "TYPE_")
-    public @interface ActionType {}
-
-    /**
-     * Indicates an action to view a calendar at a specified time.
-     */
-    public static final String TYPE_VIEW_CALENDAR = "view_calendar";
-    /**
-     * Indicates an action to view the map at a specified location.
-     */
-    public static final String TYPE_VIEW_MAP = "view_map";
-    /**
-     * Indicates an action to track a flight.
-     */
-    public static final String TYPE_TRACK_FLIGHT = "track_flight";
-    /**
-     * Indicates an action to open an URL.
-     */
-    public static final String TYPE_OPEN_URL = "open_url";
-    /**
-     * Indicates an action to send a SMS.
-     */
-    public static final String TYPE_SEND_SMS = "send_sms";
-    /**
-     * Indicates an action to call a phone number.
-     */
-    public static final String TYPE_CALL_PHONE = "call_phone";
-    /**
-     * Indicates an action to send an email.
-     */
-    public static final String TYPE_SEND_EMAIL = "send_email";
-    /**
-     * Indicates an action to reply with a text message.
-     */
-    public static final String TYPE_TEXT_REPLY = "text_reply";
-    /**
-     * Indicates an action to create a reminder.
-     */
-    public static final String TYPE_CREATE_REMINDER = "create_reminder";
-    /**
-     * Indicates an action to reply with a location.
-     */
-    public static final String TYPE_SHARE_LOCATION = "share_location";
-
-    /** @hide */
-    @Retention(SOURCE)
-    @StringDef(
-            value = {
-                    HINT_FOR_NOTIFICATION,
-                    HINT_FOR_IN_APP,
-            },
-            prefix = "HINT_")
-    public @interface Hint {}
-    /**
-     * To indicate the generated actions will be used within the app.
-     */
-    public static final String HINT_FOR_IN_APP = "in_app";
-    /**
-     * To indicate the generated actions will be used for notification.
-     */
-    public static final String HINT_FOR_NOTIFICATION = "notification";
-
     private final List<ConversationAction> mConversationActions;
     private final String mId;
 
@@ -184,182 +102,6 @@
         return mId;
     }
 
-    /** Represents the action suggested by a {@link TextClassifier} on a given conversation. */
-    public static final class ConversationAction implements Parcelable {
-
-        public static final Creator<ConversationAction> CREATOR =
-                new Creator<ConversationAction>() {
-                    @Override
-                    public ConversationAction createFromParcel(Parcel in) {
-                        return new ConversationAction(in);
-                    }
-
-                    @Override
-                    public ConversationAction[] newArray(int size) {
-                        return new ConversationAction[size];
-                    }
-                };
-
-        @NonNull
-        @ActionType
-        private final String mType;
-        @NonNull
-        private final CharSequence mTextReply;
-        @Nullable
-        private final RemoteAction mAction;
-
-        @FloatRange(from = 0, to = 1)
-        private final float mScore;
-
-        @NonNull
-        private final Bundle mExtras;
-
-        private ConversationAction(
-                @NonNull String type,
-                @Nullable RemoteAction action,
-                @Nullable CharSequence textReply,
-                float score,
-                @NonNull Bundle extras) {
-            mType = Preconditions.checkNotNull(type);
-            mAction = action;
-            mTextReply = textReply;
-            mScore = score;
-            mExtras = Preconditions.checkNotNull(extras);
-        }
-
-        private ConversationAction(Parcel in) {
-            mType = in.readString();
-            mAction = in.readParcelable(null);
-            mTextReply = in.readCharSequence();
-            mScore = in.readFloat();
-            mExtras = in.readBundle();
-        }
-
-        @Override
-        public void writeToParcel(Parcel parcel, int flags) {
-            parcel.writeString(mType);
-            parcel.writeParcelable(mAction, flags);
-            parcel.writeCharSequence(mTextReply);
-            parcel.writeFloat(mScore);
-            parcel.writeBundle(mExtras);
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @NonNull
-        @ActionType
-        /** Returns the type of this action, for example, {@link #TYPE_VIEW_CALENDAR}. */
-        public String getType() {
-            return mType;
-        }
-
-        @Nullable
-        /**
-         * Returns a RemoteAction object, which contains the icon, label and a PendingIntent, for
-         * the specified action type.
-         */
-        public RemoteAction getAction() {
-            return mAction;
-        }
-
-        /**
-         * Returns the confidence score for the specified action. The value ranges from 0 (low
-         * confidence) to 1 (high confidence).
-         */
-        @FloatRange(from = 0, to = 1)
-        public float getConfidenceScore() {
-            return mScore;
-        }
-
-        /**
-         * Returns the text reply that could be sent as a reply to the given conversation.
-         * <p>
-         * This is only available when the type of the action is {@link #TYPE_TEXT_REPLY}.
-         */
-        @Nullable
-        public CharSequence getTextReply() {
-            return mTextReply;
-        }
-
-        /**
-         * Returns the extended data related to this conversation action.
-         *
-         * <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.
-         */
-        @NonNull
-        public Bundle getExtras() {
-            return mExtras.deepCopy();
-        }
-
-        /** Builder class to construct {@link ConversationAction}. */
-        public static final class Builder {
-            @Nullable
-            @ActionType
-            private String mType;
-            @Nullable
-            private RemoteAction mAction;
-            @Nullable
-            private CharSequence mTextReply;
-            private float mScore;
-            @Nullable
-            private Bundle mExtras;
-
-            public Builder(@NonNull @ActionType String actionType) {
-                mType = Preconditions.checkNotNull(actionType);
-            }
-
-            /**
-             * Sets an action that may be performed on the given conversation.
-             */
-            @NonNull
-            public Builder setAction(@Nullable RemoteAction action) {
-                mAction = action;
-                return this;
-            }
-
-            /**
-             * Sets a text reply that may be performed on the given conversation.
-             */
-            @NonNull
-            public Builder setTextReply(@Nullable CharSequence textReply) {
-                mTextReply = textReply;
-                return this;
-            }
-
-            /** Sets the confident score. */
-            @NonNull
-            public Builder setConfidenceScore(@FloatRange(from = 0, to = 1) float score) {
-                mScore = score;
-                return this;
-            }
-
-            /**
-             * Sets the extended data for the conversation action object.
-             */
-            @NonNull
-            public Builder setExtras(@Nullable Bundle extras) {
-                mExtras = extras;
-                return this;
-            }
-
-            /** Builds the {@link ConversationAction} object. */
-            @NonNull
-            public ConversationAction build() {
-                return new ConversationAction(
-                        mType,
-                        mAction,
-                        mTextReply,
-                        mScore,
-                        mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
-            }
-        }
-    }
-
     /** Represents a message in the conversation. */
     public static final class Message implements Parcelable {
         /**
@@ -538,156 +280,36 @@
         }
     }
 
-    /** Configuration object for specifying what action types to identify. */
-    public static final class TypeConfig implements Parcelable {
-        @NonNull
-        @ActionType
-        private final Set<String> mExcludedTypes;
-        @NonNull
-        @ActionType
-        private final Set<String> mIncludedTypes;
-        private final boolean mIncludeTypesFromTextClassifier;
-
-        private TypeConfig(
-                @NonNull Set<String> includedTypes,
-                @NonNull Set<String> excludedTypes,
-                boolean includeTypesFromTextClassifier) {
-            mIncludedTypes = Preconditions.checkNotNull(includedTypes);
-            mExcludedTypes = Preconditions.checkNotNull(excludedTypes);
-            mIncludeTypesFromTextClassifier = includeTypesFromTextClassifier;
-        }
-
-        private TypeConfig(Parcel in) {
-            mIncludedTypes = new ArraySet<>(in.createStringArrayList());
-            mExcludedTypes = new ArraySet<>(in.createStringArrayList());
-            mIncludeTypesFromTextClassifier = in.readByte() != 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel parcel, int flags) {
-            parcel.writeStringList(new ArrayList<>(mIncludedTypes));
-            parcel.writeStringList(new ArrayList<>(mExcludedTypes));
-            parcel.writeByte((byte) (mIncludeTypesFromTextClassifier ? 1 : 0));
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        public static final Creator<TypeConfig> CREATOR =
-                new Creator<TypeConfig>() {
-                    @Override
-                    public TypeConfig createFromParcel(Parcel in) {
-                        return new TypeConfig(in);
-                    }
-
-                    @Override
-                    public TypeConfig[] newArray(int size) {
-                        return new TypeConfig[size];
-                    }
-                };
-
-        /**
-         * Returns a final list of types that the text classifier should look for.
-         *
-         * <p>NOTE: This method is intended for use by a text classifier.
-         *
-         * @param defaultTypes types the text classifier thinks should be included before factoring
-         *    in the included/excluded types given by the client.
-         */
-        @NonNull
-        public Collection<String> resolveTypes(@Nullable Collection<String> defaultTypes) {
-            Set<String> types = new ArraySet<>();
-            if (mIncludeTypesFromTextClassifier && defaultTypes != null) {
-                types.addAll(defaultTypes);
-            }
-            types.addAll(mIncludedTypes);
-            types.removeAll(mExcludedTypes);
-            return Collections.unmodifiableCollection(types);
-        }
-
-        /**
-         * Return whether the client allows the text classifier to include its own list of default
-         * types. If this function returns {@code true}, the text classifier can consider specifying
-         * a default list of entity types in {@link #resolveTypes(Collection)}.
-         *
-         * <p>NOTE: This method is intended for use by a text classifier.
-         *
-         * @see #resolveTypes(Collection)
-         */
-        public boolean shouldIncludeTypesFromTextClassifier() {
-            return mIncludeTypesFromTextClassifier;
-        }
-
-        /** Builder class to construct the {@link TypeConfig} object. */
-        public static final class Builder {
-            @Nullable
-            private Collection<String> mExcludedTypes;
-            @Nullable
-            private Collection<String> mIncludedTypes;
-            private boolean mIncludeTypesFromTextClassifier = true;
-
-            /**
-             * Sets a collection of types that are explicitly included, for example, {@link
-             * #TYPE_VIEW_CALENDAR}.
-             */
-            @NonNull
-            public Builder setIncludedTypes(
-                    @Nullable @ActionType Collection<String> includedTypes) {
-                mIncludedTypes = includedTypes;
-                return this;
-            }
-
-            /**
-             * Sets a collection of types that are explicitly excluded, for example, {@link
-             * #TYPE_VIEW_CALENDAR}.
-             */
-            @NonNull
-            public Builder setExcludedTypes(
-                    @Nullable @ActionType Collection<String> excludedTypes) {
-                mExcludedTypes = excludedTypes;
-                return this;
-            }
-
-            /**
-             * Specifies whether or not to include the types suggested by the text classifier. By
-             * default, it is included.
-             */
-            @NonNull
-            public Builder includeTypesFromTextClassifier(boolean includeTypesFromTextClassifier) {
-                mIncludeTypesFromTextClassifier = includeTypesFromTextClassifier;
-                return this;
-            }
-
-            /**
-             * Combines all of the options that have been set and returns a new {@link TypeConfig}
-             * object.
-             */
-            @NonNull
-            public TypeConfig build() {
-                return new TypeConfig(
-                        mIncludedTypes == null
-                                ? Collections.emptySet()
-                                : new ArraySet<>(mIncludedTypes),
-                        mExcludedTypes == null
-                                ? Collections.emptySet()
-                                : new ArraySet<>(mExcludedTypes),
-                        mIncludeTypesFromTextClassifier);
-            }
-        }
-    }
-
     /**
      * A request object for generating conversation action suggestions.
      *
      * @see TextClassifier#suggestConversationActions(Request)
      */
     public static final class Request implements Parcelable {
+
+        /** @hide */
+        @Retention(SOURCE)
+        @StringDef(
+                value = {
+                        HINT_FOR_NOTIFICATION,
+                        HINT_FOR_IN_APP,
+                },
+                prefix = "HINT_")
+        public @interface Hint {}
+
+        /**
+         * To indicate the generated actions will be used within the app.
+         */
+        public static final String HINT_FOR_IN_APP = "in_app";
+        /**
+         * To indicate the generated actions will be used for notification.
+         */
+        public static final String HINT_FOR_NOTIFICATION = "notification";
+
         @NonNull
         private final List<Message> mConversation;
         @NonNull
-        private final TypeConfig mTypeConfig;
+        private final TextClassifier.EntityConfig mTypeConfig;
         private final int mMaxSuggestions;
         @NonNull
         @Hint
@@ -699,7 +321,7 @@
 
         private Request(
                 @NonNull List<Message> conversation,
-                @NonNull TypeConfig typeConfig,
+                @NonNull TextClassifier.EntityConfig typeConfig,
                 int maxSuggestions,
                 String conversationId,
                 @Nullable @Hint List<String> hints) {
@@ -713,7 +335,7 @@
         private static Request readFromParcel(Parcel in) {
             List<Message> conversation = new ArrayList<>();
             in.readParcelableList(conversation, null);
-            TypeConfig typeConfig = in.readParcelable(null);
+            TextClassifier.EntityConfig typeConfig = in.readParcelable(null);
             int maxSuggestions = in.readInt();
             String conversationId = in.readString();
             List<String> hints = new ArrayList<>();
@@ -760,7 +382,7 @@
 
         /** Returns the type config. */
         @NonNull
-        public TypeConfig getTypeConfig() {
+        public TextClassifier.EntityConfig getTypeConfig() {
             return mTypeConfig;
         }
 
@@ -820,7 +442,7 @@
             @NonNull
             private List<Message> mConversation;
             @Nullable
-            private TypeConfig mTypeConfig;
+            private TextClassifier.EntityConfig mTypeConfig;
             private int mMaxSuggestions;
             @Nullable
             private String mConversationId;
@@ -849,7 +471,7 @@
 
             /** Sets the type config. */
             @NonNull
-            public Builder setTypeConfig(@Nullable TypeConfig typeConfig) {
+            public Builder setTypeConfig(@Nullable TextClassifier.EntityConfig typeConfig) {
                 mTypeConfig = typeConfig;
                 return this;
             }
@@ -879,7 +501,9 @@
             public Request build() {
                 return new Request(
                         Collections.unmodifiableList(mConversation),
-                        mTypeConfig == null ? new TypeConfig.Builder().build() : mTypeConfig,
+                        mTypeConfig == null
+                                ? new TextClassifier.EntityConfig.Builder().build()
+                                : mTypeConfig,
                         mMaxSuggestions,
                         mConversationId,
                         mHints == null
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index 50801a2..ce680ec 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -117,15 +117,15 @@
             .add(TextClassifier.TYPE_FLIGHT_NUMBER).toString();
     private static final String CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES =
             new StringJoiner(ENTITY_LIST_DELIMITER)
-                    .add(ConversationActions.TYPE_TEXT_REPLY)
-                    .add(ConversationActions.TYPE_CREATE_REMINDER)
-                    .add(ConversationActions.TYPE_CALL_PHONE)
-                    .add(ConversationActions.TYPE_OPEN_URL)
-                    .add(ConversationActions.TYPE_SEND_EMAIL)
-                    .add(ConversationActions.TYPE_SEND_SMS)
-                    .add(ConversationActions.TYPE_TRACK_FLIGHT)
-                    .add(ConversationActions.TYPE_VIEW_CALENDAR)
-                    .add(ConversationActions.TYPE_VIEW_MAP)
+                    .add(ConversationAction.TYPE_TEXT_REPLY)
+                    .add(ConversationAction.TYPE_CREATE_REMINDER)
+                    .add(ConversationAction.TYPE_CALL_PHONE)
+                    .add(ConversationAction.TYPE_OPEN_URL)
+                    .add(ConversationAction.TYPE_SEND_EMAIL)
+                    .add(ConversationAction.TYPE_SEND_SMS)
+                    .add(ConversationAction.TYPE_TRACK_FLIGHT)
+                    .add(ConversationAction.TYPE_VIEW_CALENDAR)
+                    .add(ConversationAction.TYPE_VIEW_MAP)
                     .toString();
 
     private final boolean mSystemTextClassifierEnabled;
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 8709e09..5a56136 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -32,7 +32,6 @@
 import android.text.util.Linkify;
 import android.text.util.Linkify.LinkifyMask;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -43,6 +42,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -324,7 +324,7 @@
     }
 
     /**
-     * Detects the language of the specified text.
+     * Detects the language of the text in the given request.
      *
      * <p><strong>NOTE: </strong>Call on a worker thread.
      *
@@ -403,42 +403,59 @@
     default void dump(@NonNull IndentingPrintWriter printWriter) {}
 
     /**
-     * Configuration object for specifying what entities to identify.
+     * Configuration object for specifying what entity types to identify.
      *
      * Configs are initially based on a predefined preset, and can be modified from there.
      */
     final class EntityConfig implements Parcelable {
-        private final Collection<String> mHints;
-        private final Collection<String> mExcludedEntityTypes;
-        private final Collection<String> mIncludedEntityTypes;
-        private final boolean mUseHints;
+        private final List<String> mIncludedTypes;
+        private final List<String> mExcludedTypes;
+        private final List<String> mHints;
+        private final boolean mIncludeTypesFromTextClassifier;
 
-        private EntityConfig(boolean useHints, Collection<String> hints,
-                Collection<String> includedEntityTypes, Collection<String> excludedEntityTypes) {
-            mHints = hints == null
-                    ? Collections.EMPTY_LIST
-                    : Collections.unmodifiableCollection(new ArraySet<>(hints));
-            mExcludedEntityTypes = excludedEntityTypes == null
-                    ? Collections.EMPTY_LIST : new ArraySet<>(excludedEntityTypes);
-            mIncludedEntityTypes = includedEntityTypes == null
-                    ? Collections.EMPTY_LIST : new ArraySet<>(includedEntityTypes);
-            mUseHints = useHints;
+        private EntityConfig(
+                List<String> includedEntityTypes,
+                List<String> excludedEntityTypes,
+                List<String> hints,
+                boolean includeTypesFromTextClassifier) {
+            mIncludedTypes = Preconditions.checkNotNull(includedEntityTypes);
+            mExcludedTypes = Preconditions.checkNotNull(excludedEntityTypes);
+            mHints = Preconditions.checkNotNull(hints);
+            mIncludeTypesFromTextClassifier = includeTypesFromTextClassifier;
+        }
+
+        private EntityConfig(Parcel in) {
+            mIncludedTypes = new ArrayList<>();
+            in.readStringList(mIncludedTypes);
+            mExcludedTypes = new ArrayList<>();
+            in.readStringList(mExcludedTypes);
+            List<String> tmpHints = new ArrayList<>();
+            in.readStringList(tmpHints);
+            mHints = Collections.unmodifiableList(tmpHints);
+            mIncludeTypesFromTextClassifier = in.readByte() != 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel parcel, int flags) {
+            parcel.writeStringList(mIncludedTypes);
+            parcel.writeStringList(mExcludedTypes);
+            parcel.writeStringList(mHints);
+            parcel.writeByte((byte) (mIncludeTypesFromTextClassifier ? 1 : 0));
         }
 
         /**
          * Creates an EntityConfig.
          *
          * @param hints Hints for the TextClassifier to determine what types of entities to find.
+         *
+         * @deprecated Use {@link Builder} instead.
          */
+        @Deprecated
         public static EntityConfig createWithHints(@Nullable Collection<String> hints) {
-            return new EntityConfig(/* useHints */ true, hints,
-                    /* includedEntityTypes */null, /* excludedEntityTypes */ null);
-        }
-
-        // TODO: Remove once apps can build against the latest sdk.
-        /** @hide */
-        public static EntityConfig create(@Nullable Collection<String> hints) {
-            return createWithHints(hints);
+            return new EntityConfig.Builder()
+                    .includeTypesFromTextClassifier(true)
+                    .setHints(hints)
+                    .build();
         }
 
         /**
@@ -450,12 +467,19 @@
          *
          *
          * Note that if an entity has been excluded, the exclusion will take precedence.
+         *
+         * @deprecated Use {@link Builder} instead.
          */
+        @Deprecated
         public static EntityConfig create(@Nullable Collection<String> hints,
                 @Nullable Collection<String> includedEntityTypes,
                 @Nullable Collection<String> excludedEntityTypes) {
-            return new EntityConfig(/* useHints */ true, hints,
-                    includedEntityTypes, excludedEntityTypes);
+            return new EntityConfig.Builder()
+                    .setIncludedTypes(includedEntityTypes)
+                    .setExcludedTypes(excludedEntityTypes)
+                    .setHints(hints)
+                    .includeTypesFromTextClassifier(true)
+                    .build();
         }
 
         /**
@@ -463,34 +487,33 @@
          *
          * @param entityTypes Complete set of entities, e.g. {@link #TYPE_URL} to find.
          *
+         * @deprecated Use {@link Builder} instead.
          */
+        @Deprecated
         public static EntityConfig createWithExplicitEntityList(
                 @Nullable Collection<String> entityTypes) {
-            return new EntityConfig(/* useHints */ false, /* hints */ null,
-                    /* includedEntityTypes */ entityTypes, /* excludedEntityTypes */ null);
-        }
-
-        // TODO: Remove once apps can build against the latest sdk.
-        /** @hide */
-        public static EntityConfig createWithEntityList(@Nullable Collection<String> entityTypes) {
-            return createWithExplicitEntityList(entityTypes);
+            return new EntityConfig.Builder()
+                    .setIncludedTypes(entityTypes)
+                    .includeTypesFromTextClassifier(false)
+                    .build();
         }
 
         /**
-         * Returns a list of the final set of entities to find.
+         * Returns a final list of entity types to find.
          *
-         * @param entities Entities we think should be found before factoring in includes/excludes
+         * @param entityTypes Entity types we think should be found before factoring in
+         *                    includes/excludes
          *
          * This method is intended for use by TextClassifier implementations.
          */
         public Collection<String> resolveEntityListModifications(
-                @NonNull Collection<String> entities) {
-            final Set<String> finalSet = new HashSet();
-            if (mUseHints) {
-                finalSet.addAll(entities);
+                @NonNull Collection<String> entityTypes) {
+            final Set<String> finalSet = new HashSet<>();
+            if (mIncludeTypesFromTextClassifier) {
+                finalSet.addAll(entityTypes);
             }
-            finalSet.addAll(mIncludedEntityTypes);
-            finalSet.removeAll(mExcludedEntityTypes);
+            finalSet.addAll(mIncludedTypes);
+            finalSet.removeAll(mExcludedTypes);
             return finalSet;
         }
 
@@ -503,17 +526,22 @@
             return mHints;
         }
 
-        @Override
-        public int describeContents() {
-            return 0;
+        /**
+         * Return whether the client allows the text classifier to include its own list of
+         * default types. If this function returns {@code true}, a default list of types suggested
+         * from a text classifier will be taking into account.
+         *
+         * <p>NOTE: This method is intended for use by a text classifier.
+         *
+         * @see #resolveEntityListModifications(Collection)
+         */
+        public boolean shouldIncludeTypesFromTextClassifier() {
+            return mIncludeTypesFromTextClassifier;
         }
 
         @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeStringList(new ArrayList<>(mHints));
-            dest.writeStringList(new ArrayList<>(mExcludedEntityTypes));
-            dest.writeStringList(new ArrayList<>(mIncludedEntityTypes));
-            dest.writeInt(mUseHints ? 1 : 0);
+        public int describeContents() {
+            return 0;
         }
 
         public static final Parcelable.Creator<EntityConfig> CREATOR =
@@ -529,11 +557,75 @@
                     }
                 };
 
-        private EntityConfig(Parcel in) {
-            mHints = new ArraySet<>(in.createStringArrayList());
-            mExcludedEntityTypes = new ArraySet<>(in.createStringArrayList());
-            mIncludedEntityTypes = new ArraySet<>(in.createStringArrayList());
-            mUseHints = in.readInt() == 1;
+
+
+        /** Builder class to construct the {@link EntityConfig} object. */
+        public static final class Builder {
+            @Nullable
+            private Collection<String> mIncludedTypes;
+            @Nullable
+            private Collection<String> mExcludedTypes;
+            @Nullable
+            private Collection<String> mHints;
+            private boolean mIncludeTypesFromTextClassifier = true;
+
+            /**
+             * Sets a collection of types that are explicitly included.
+             */
+            @NonNull
+            public Builder setIncludedTypes(@Nullable Collection<String> includedTypes) {
+                mIncludedTypes = includedTypes;
+                return this;
+            }
+
+            /**
+             * Sets a collection of types that are explicitly excluded.
+             */
+            @NonNull
+            public Builder setExcludedTypes(@Nullable Collection<String> excludedTypes) {
+                mExcludedTypes = excludedTypes;
+                return this;
+            }
+
+            /**
+             * Specifies whether or not to include the types suggested by the text classifier. By
+             * default, it is included.
+             */
+            @NonNull
+            public Builder includeTypesFromTextClassifier(boolean includeTypesFromTextClassifier) {
+                mIncludeTypesFromTextClassifier = includeTypesFromTextClassifier;
+                return this;
+            }
+
+
+            /**
+             * Sets the hints for the TextClassifier to determine what types of entities to find.
+             * These hints will only be used if {@link #includeTypesFromTextClassifier} is
+             * set to be true.
+             */
+            public Builder setHints(Collection<String> hints) {
+                mHints = hints;
+                return this;
+            }
+
+            /**
+             * Combines all of the options that have been set and returns a new {@link EntityConfig}
+             * object.
+             */
+            @NonNull
+            public EntityConfig build() {
+                return new EntityConfig(
+                        mIncludedTypes == null
+                                ? Collections.emptyList()
+                                : new ArrayList<>(mIncludedTypes),
+                        mExcludedTypes == null
+                                ? Collections.emptyList()
+                                : new ArrayList<>(mExcludedTypes),
+                        mHints == null
+                                ? Collections.emptyList()
+                                : Collections.unmodifiableList(new ArrayList<>(mHints)),
+                        mIncludeTypesFromTextClassifier);
+            }
         }
     }
 
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index d5b9eb1..9ab963e 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -393,7 +393,7 @@
                     actionsImpl.suggestActions(nativeConversation, null);
 
             Collection<String> expectedTypes = resolveActionTypesFromRequest(request);
-            List<ConversationActions.ConversationAction> conversationActions = new ArrayList<>();
+            List<ConversationAction> conversationActions = new ArrayList<>();
             int maxSuggestions = nativeSuggestions.length;
             if (request.getMaxSuggestions() > 0) {
                 maxSuggestions = Math.min(request.getMaxSuggestions(), nativeSuggestions.length);
@@ -405,7 +405,7 @@
                     continue;
                 }
                 conversationActions.add(
-                        new ConversationActions.ConversationAction.Builder(actionType)
+                        new ConversationAction.Builder(actionType)
                                 .setTextReply(nativeSuggestion.getResponseText())
                                 .setConfidenceScore(nativeSuggestion.getScore())
                                 .build());
@@ -445,10 +445,10 @@
 
     private Collection<String> resolveActionTypesFromRequest(ConversationActions.Request request) {
         List<String> defaultActionTypes =
-                request.getHints().contains(ConversationActions.HINT_FOR_NOTIFICATION)
+                request.getHints().contains(ConversationActions.Request.HINT_FOR_NOTIFICATION)
                         ? mSettings.getNotificationConversationActionTypes()
                         : mSettings.getInAppConversationActionTypes();
-        return request.getTypeConfig().resolveTypes(defaultActionTypes);
+        return request.getTypeConfig().resolveEntityListModifications(defaultActionTypes);
     }
 
     private AnnotatorModel getAnnotatorImpl(LocaleList localeList)
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index bad2dbf..6039350 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -69,6 +70,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Executor;
 
 /**
  * A View that displays web pages.
@@ -1688,6 +1690,84 @@
         return mProvider.getWebViewClient();
     }
 
+
+    /**
+     * Gets the WebView renderer associated with this WebView.
+     *
+     * <p>In {@link android.os.Build.VERSION_CODES#O} and above, WebView may
+     * run in "multiprocess" mode. In multiprocess mode, rendering of web
+     * content is performed by a sandboxed renderer process separate to the
+     * application process.  This renderer process may be shared with other
+     * WebViews in the application, but is not shared with other application
+     * processes.
+     *
+     * <p>If WebView is running in multiprocess mode, this method returns a
+     * handle to the renderer process associated with the WebView, which can
+     * be used to control the renderer process.
+     *
+     * @return the {@link WebViewRenderer} renderer handle associated
+     *         with this {@link WebView}, or {@code null} if
+     *         WebView is not runing in multiprocess mode.
+     */
+    @Nullable
+    public WebViewRenderer getWebViewRenderer() {
+        checkThread();
+        return mProvider.getWebViewRenderer();
+    }
+
+    /**
+     * Sets the renderer client object associated with this WebView.
+     *
+     * <p>The renderer client encapsulates callbacks relevant to WebView renderer
+     * state. See {@link WebViewRendererClient} for details.
+     *
+     * <p>Although many WebView instances may share a single underlying
+     * renderer, and renderers may live either in the application
+     * process, or in a sandboxed process that is isolated from the
+     * application process, instances of {@link WebViewRendererClient}
+     * are set per-WebView.  Callbacks represent renderer events from
+     * the perspective of this WebView, and may or may not be correlated
+     * with renderer events affecting other WebViews.
+     *
+     * @param executor the Executor on which {@link WebViewRendererClient} callbacks will execute.
+     * @param webViewRendererClient the {@link WebViewRendererClient} object.
+     */
+    public void setWebViewRendererClient(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull WebViewRendererClient webViewRendererClient) {
+        checkThread();
+        mProvider.setWebViewRendererClient(executor, webViewRendererClient);
+    }
+
+    /**
+     * Sets the renderer client object associated with this WebView.
+     *
+     * See {@link #setWebViewRendererClient(Executor,WebViewRendererClient)} for details.
+     *
+     * <p> {@link WebViewRendererClient} callbacks will run on the thread that this WebView was
+     * initialized on.
+     *
+     * @param webViewRendererClient the {@link WebViewRendererClient} object.
+     */
+    public void setWebViewRendererClient(
+            @Nullable WebViewRendererClient webViewRendererClient) {
+        checkThread();
+        mProvider.setWebViewRendererClient(null, webViewRendererClient);
+    }
+
+    /**
+     * Gets the renderer client object associated with this WebView.
+     *
+     * @return the {@link WebViewRendererClient} object associated with this WebView, if one has
+     * been set via {@link #setWebViewRendererClient(WebViewRendererClient)} or {@code null}
+     * otherwise.
+     */
+    @Nullable
+    public WebViewRendererClient getWebViewRendererClient() {
+        checkThread();
+        return mProvider.getWebViewRendererClient();
+    }
+
     /**
      * Registers the interface to be used when content can not be handled by
      * the rendering engine, and should be downloaded instead. This will replace
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 95e7a986..baf5826 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -54,6 +54,7 @@
 import java.io.BufferedWriter;
 import java.io.File;
 import java.util.Map;
+import java.util.concurrent.Executor;
 
 /**
  * WebView backend provider interface: this interface is the abstract backend to a WebView
@@ -237,6 +238,14 @@
 
     public WebViewClient getWebViewClient();
 
+    public WebViewRenderer getWebViewRenderer();
+
+    public void setWebViewRendererClient(
+            @Nullable Executor executor,
+            @Nullable WebViewRendererClient client);
+
+    public WebViewRendererClient getWebViewRendererClient();
+
     public void setDownloadListener(DownloadListener listener);
 
     public void setWebChromeClient(WebChromeClient client);
diff --git a/core/java/android/webkit/WebViewRenderer.java b/core/java/android/webkit/WebViewRenderer.java
new file mode 100644
index 0000000..5328254
--- /dev/null
+++ b/core/java/android/webkit/WebViewRenderer.java
@@ -0,0 +1,45 @@
+/*
+ * 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.webkit;
+
+/**
+ * WebViewRenderer provides an opaque handle to a {@link WebView} renderer.
+ */
+public abstract class WebViewRenderer {
+    /**
+     * Cause this renderer to terminate.
+     *
+     * <p>Calling this on a not yet started, or an already terminated renderer will have no effect.
+     *
+     * <p>Terminating a renderer process may have an effect on multiple {@link WebView} instances.
+     *
+     * <p>Renderer termination must be handled by properly overriding
+     * {@link WebViewClient#onRenderProcessGone} for every WebView that shares this
+     * renderer. If termination is not handled by all associated WebViews, then the application
+     * process will also be terminated.
+     *
+     * @return {@code true} if it was possible to terminate this renderer, {@code false} otherwise.
+     */
+    public abstract boolean terminate();
+
+    /**
+     * This class cannot be created by applications.
+     * @hide
+     */
+    public WebViewRenderer() {
+    }
+}
diff --git a/core/java/android/webkit/WebViewRendererClient.java b/core/java/android/webkit/WebViewRendererClient.java
new file mode 100644
index 0000000..2fadf54
--- /dev/null
+++ b/core/java/android/webkit/WebViewRendererClient.java
@@ -0,0 +1,77 @@
+/*
+ * 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.webkit;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * Used to receive callbacks on {@link WebView} renderer events.
+ *
+ * WebViewRendererClient instances may be set or retrieved via {@link
+ * WebView#setWebViewRendererClient(WebViewRendererClient)} and {@link
+ * WebView#getWebViewRendererClient()}.
+ *
+ * Instances may be attached to multiple WebViews, and thus a single renderer event may cause
+ * a callback to be called multiple times with different WebView parameters.
+ */
+public abstract class WebViewRendererClient {
+    /**
+     * Called when the renderer currently associated with {@code view} becomes unresponsive as a
+     * result of a long running blocking task such as the execution of JavaScript.
+     *
+     * <p>If a WebView fails to process an input event, or successfully navigate to a new URL within
+     * a reasonable time frame, the renderer is considered to be unresponsive, and this callback
+     * will be called.
+     *
+     * <p>This callback will continue to be called at regular intervals as long as the renderer
+     * remains unresponsive. If the renderer becomes responsive again, {@link
+     * WebViewRendererClient#onRendererResponsive} will be called once, and this method will not
+     * subsequently be called unless another period of unresponsiveness is detected.
+     *
+     * <p>No action is taken by WebView as a result of this method call. Applications may
+     * choose to terminate the associated renderer via the object that is passed to this callback,
+     * if in multiprocess mode, however this must be accompanied by correctly handling
+     * {@link WebViewClient#onRenderProcessGone} for this WebView, and all other WebViews associated
+     * with the same renderer. Failure to do so will result in application termination.
+     *
+     * @param view The {@link WebView} for which unresponsiveness was detected.
+     * @param renderer The {@link WebViewRenderer} that has become unresponsive,
+     * or {@code null} if WebView is running in single process mode.
+     */
+    public abstract void onRendererUnresponsive(
+            @NonNull WebView view, @Nullable WebViewRenderer renderer);
+
+    /**
+     * Called once when an unresponsive renderer currently associated with {@code view} becomes
+     * responsive.
+     *
+     * <p>After a WebView renderer becomes unresponsive, which is notified to the application by
+     * {@link WebViewRendererClient#onRendererUnresponsive}, it is possible for the blocking
+     * renderer task to complete, returning the renderer to a responsive state. In that case,
+     * this method is called once to indicate responsiveness.
+     *
+     * <p>No action is taken by WebView as a result of this method call.
+     *
+     * @param view The {@link WebView} for which responsiveness was detected.
+     *
+     * @param renderer The {@link WebViewRenderer} that has become responsive, or {@code null} if
+     * WebView is running in single process mode.
+     */
+    public abstract void onRendererResponsive(
+            @NonNull WebView view, @Nullable WebViewRenderer renderer);
+}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 4523d3b..b4d8322 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -21,19 +21,24 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
 import android.content.pm.LabeledIntent;
+import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
 import android.database.DataSetObserver;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
@@ -75,6 +80,7 @@
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
@@ -92,6 +98,15 @@
 
     private static final boolean DEBUG = false;
 
+    /**
+     * If set to true, use ShortcutManager to retrieve the matching direct share targets, instead of
+     * binding to every ChooserTargetService implementation.
+     */
+    // TODO(b/121287573): Replace with a system flag (setprop?)
+    private static final boolean USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS = false;
+    // TODO(b/121287224): Re-evaluate this limit
+    private static final int SHARE_TARGET_QUERY_PACKAGE_LIMIT = 20;
+
     private static final int QUERY_TARGET_SERVICE_LIMIT = 5;
     private static final int WATCHDOG_TIMEOUT_MILLIS = 2000;
 
@@ -120,6 +135,7 @@
 
     private static final int CHOOSER_TARGET_SERVICE_RESULT = 1;
     private static final int CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT = 2;
+    private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT = 3;
 
     private final Handler mChooserHandler = new Handler() {
         @Override
@@ -158,6 +174,18 @@
                     mChooserListAdapter.setShowServiceTargets(true);
                     break;
 
+                case SHORTCUT_MANAGER_SHARE_TARGET_RESULT:
+                    if (DEBUG) Log.d(TAG, "SHORTCUT_MANAGER_SHARE_TARGET_RESULT");
+                    if (isDestroyed()) break;
+                    final ServiceResultInfo resultInfo = (ServiceResultInfo) msg.obj;
+                    if (resultInfo.resultTargets != null) {
+                        mChooserListAdapter.addServiceResults(resultInfo.originalTarget,
+                                resultInfo.resultTargets);
+                    }
+                    sendVoiceChoicesIfNeeded();
+                    mChooserListAdapter.setShowServiceTargets(true);
+                    break;
+
                 default:
                     super.handleMessage(msg);
             }
@@ -552,6 +580,94 @@
         }
     }
 
+    private IntentFilter getTargetIntentFilter() {
+        try {
+            final Intent intent = getTargetIntent();
+            String dataString = intent.getDataString();
+            if (TextUtils.isEmpty(dataString)) {
+                dataString = intent.getType();
+            }
+            return new IntentFilter(intent.getAction(), dataString);
+        } catch (Exception e) {
+            Log.e(TAG, "failed to get target intent filter " + e);
+            return null;
+        }
+    }
+
+    private void queryDirectShareTargets(ChooserListAdapter adapter) {
+        final IntentFilter filter = getTargetIntentFilter();
+        if (filter == null) {
+            return;
+        }
+
+        // Need to keep the original DisplayResolveInfos to be able to reconstruct ServiceResultInfo
+        // and use the old code path. This Ugliness should go away when Sharesheet is refactored.
+        final List<DisplayResolveInfo> driList = new ArrayList<>();
+        int targetsToQuery = 0;
+        for (int i = 0, n = adapter.getDisplayResolveInfoCount(); i < n; i++) {
+            final DisplayResolveInfo dri = adapter.getDisplayResolveInfo(i);
+            if (adapter.getScore(dri) == 0) {
+                // A score of 0 means the app hasn't been used in some time;
+                // don't query it as it's not likely to be relevant.
+                continue;
+            }
+            driList.add(dri);
+            targetsToQuery++;
+            // TODO(b/121287224): Do we need this here? (similar to queryTargetServices)
+            if (targetsToQuery >= SHARE_TARGET_QUERY_PACKAGE_LIMIT) {
+                if (DEBUG) {
+                    Log.d(TAG, "queryTargets hit query target limit "
+                            + SHARE_TARGET_QUERY_PACKAGE_LIMIT);
+                }
+                break;
+            }
+        }
+
+        AsyncTask.execute(() -> {
+            ShortcutManager sm = (ShortcutManager) getSystemService(Context.SHORTCUT_SERVICE);
+            List<ShortcutManager.ShareShortcutInfo> resultList = sm.getShareTargets(filter);
+
+            // Match ShareShortcutInfos with DisplayResolveInfos to be able to use the old code path
+            // for direct share targets. After ShareSheet is refactored we should use the
+            // ShareShortcutInfos directly.
+            for (int i = 0; i < driList.size(); i++) {
+                List<ChooserTarget> chooserTargets = new ArrayList<>();
+                for (int j = 0; j < resultList.size(); j++) {
+                    if (driList.get(i).getResolvedComponentName().equals(
+                            resultList.get(j).getTargetComponent())) {
+                        chooserTargets.add(convertToChooserTarget(resultList.get(j)));
+                    }
+                }
+                if (chooserTargets.isEmpty()) {
+                    continue;
+                }
+
+                final Message msg = Message.obtain();
+                msg.what = SHORTCUT_MANAGER_SHARE_TARGET_RESULT;
+                msg.obj = new ServiceResultInfo(driList.get(i), chooserTargets, null);
+                mChooserHandler.sendMessage(msg);
+            }
+        });
+    }
+
+    private ChooserTarget convertToChooserTarget(ShortcutManager.ShareShortcutInfo shareShortcut) {
+        ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo();
+        Bundle extras = new Bundle();
+        extras.putString(Intent.EXTRA_SHORTCUT_ID, shortcutInfo.getId());
+        return new ChooserTarget(
+                // The name of this target.
+                shortcutInfo.getShortLabel(),
+                // Don't load the icon until it is selected to be shown
+                null,
+                // The ranking score for this target (0.0-1.0); the system will omit items with low
+                // scores when there are too many Direct Share items.
+                0.5f,
+                // The name of the component to be launched if this target is chosen.
+                shareShortcut.getTargetComponent().clone(),
+                // The extra values here will be merged into the Intent when this target is chosen.
+                extras);
+    }
+
     private String convertServiceName(String packageName, String serviceName) {
         if (TextUtils.isEmpty(serviceName)) {
             return null;
@@ -765,9 +881,8 @@
                     }
                 }
             }
-            final Icon icon = chooserTarget.getIcon();
-            // TODO do this in the background
-            mDisplayIcon = icon != null ? icon.loadDrawable(ChooserActivity.this) : null;
+            // TODO(b/121287224): do this in the background thread, and only for selected targets
+            mDisplayIcon = getChooserTargetIconDrawable(chooserTarget);
 
             if (sourceInfo != null) {
                 mBackupResolveInfo = null;
@@ -791,6 +906,39 @@
             mModifiedScore = other.mModifiedScore;
         }
 
+        /**
+         * Since ShortcutInfos are returned by ShortcutManager, we can cache the shortcuts and skip
+         * the call to LauncherApps#getShortcuts(ShortcutQuery).
+         */
+        // TODO(121287224): Refactor code to apply the suggestion above
+        private Drawable getChooserTargetIconDrawable(ChooserTarget target) {
+            final Icon icon = target.getIcon();
+            if (icon != null) {
+                return icon.loadDrawable(ChooserActivity.this);
+            }
+            if (!USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) {
+                return null;
+            }
+
+            Bundle extras = target.getIntentExtras();
+            if (extras == null || !extras.containsKey(Intent.EXTRA_SHORTCUT_ID)) {
+                return null;
+            }
+            CharSequence shortcutId = extras.getCharSequence(Intent.EXTRA_SHORTCUT_ID);
+            LauncherApps launcherApps = (LauncherApps) getSystemService(
+                    Context.LAUNCHER_APPS_SERVICE);
+            final LauncherApps.ShortcutQuery q = new LauncherApps.ShortcutQuery();
+            q.setPackage(target.getComponentName().getPackageName());
+            q.setShortcutIds(Arrays.asList(shortcutId.toString()));
+            q.setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC);
+            final List<ShortcutInfo> shortcuts = launcherApps.getShortcuts(q, getUser());
+            if (shortcuts != null && shortcuts.size() > 0) {
+                return launcherApps.getShortcutIconDrawable(shortcuts.get(0), 0);
+            }
+
+            return null;
+        }
+
         public float getModifiedScore() {
             return mModifiedScore;
         }
@@ -1030,8 +1178,15 @@
                     mTargetsNeedPruning = true;
                 }
             }
-            if (DEBUG) Log.d(TAG, "List built querying services");
-            queryTargetServices(this);
+            if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) {
+                if (DEBUG) {
+                    Log.d(TAG, "querying direct share targets from ShortcutManager");
+                }
+                queryDirectShareTargets(this);
+            } else {
+                if (DEBUG) Log.d(TAG, "List built querying services");
+                queryTargetServices(this);
+            }
         }
 
         @Override
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index 9b9b771..8e88c51 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -23,6 +23,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.service.procstats.ProcessStatsAvailablePagesProto;
 import android.service.procstats.ProcessStatsPackageProto;
 import android.service.procstats.ProcessStatsSectionProto;
 import android.text.format.DateFormat;
@@ -178,7 +179,7 @@
             {"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "all"};
 
     // Current version of the parcel format.
-    private static final int PARCEL_VERSION = 35;
+    private static final int PARCEL_VERSION = 36;
     // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
     private static final int MAGIC = 0x50535454;
 
@@ -237,10 +238,11 @@
     ArrayList<String> mIndexToCommonString;
 
     private static final Pattern sPageTypeRegex = Pattern.compile(
-            "^Node\\s+(\\d+),.*. type\\s+(\\w+)\\s+([\\s\\d]+?)\\s*$");
-    private final ArrayList<Integer> mPageTypeZones = new ArrayList<Integer>();
-    private final ArrayList<String> mPageTypeLabels = new ArrayList<String>();
-    private final ArrayList<int[]> mPageTypeSizes = new ArrayList<int[]>();
+            "^Node\\s+(\\d+),.* zone\\s+(\\w+),.* type\\s+(\\w+)\\s+([\\s\\d]+?)\\s*$");
+    private final ArrayList<Integer> mPageTypeNodes = new ArrayList<>();
+    private final ArrayList<String> mPageTypeZones = new ArrayList<>();
+    private final ArrayList<String> mPageTypeLabels = new ArrayList<>();
+    private final ArrayList<int[]> mPageTypeSizes = new ArrayList<>();
 
     public ProcessStats(boolean running) {
         mRunning = running;
@@ -621,6 +623,7 @@
         try {
             reader = new BufferedReader(new FileReader("/proc/pagetypeinfo"));
             final Matcher matcher = sPageTypeRegex.matcher("");
+            mPageTypeNodes.clear();
             mPageTypeZones.clear();
             mPageTypeLabels.clear();
             mPageTypeSizes.clear();
@@ -631,16 +634,18 @@
                 }
                 matcher.reset(line);
                 if (matcher.matches()) {
-                    final Integer zone = Integer.valueOf(matcher.group(1), 10);
-                    if (zone == null) {
+                    final Integer node = Integer.valueOf(matcher.group(1), 10);
+                    if (node == null) {
                         continue;
                     }
-                    mPageTypeZones.add(zone);
-                    mPageTypeLabels.add(matcher.group(2));
-                    mPageTypeSizes.add(splitAndParseNumbers(matcher.group(3)));
+                    mPageTypeNodes.add(node);
+                    mPageTypeZones.add(matcher.group(2));
+                    mPageTypeLabels.add(matcher.group(3));
+                    mPageTypeSizes.add(splitAndParseNumbers(matcher.group(4)));
                 }
             }
         } catch (IOException ex) {
+            mPageTypeNodes.clear();
             mPageTypeZones.clear();
             mPageTypeLabels.clear();
             mPageTypeSizes.clear();
@@ -935,7 +940,8 @@
         final int NPAGETYPES = mPageTypeLabels.size();
         out.writeInt(NPAGETYPES);
         for (int i=0; i<NPAGETYPES; i++) {
-            out.writeInt(mPageTypeZones.get(i));
+            out.writeInt(mPageTypeNodes.get(i));
+            out.writeString(mPageTypeZones.get(i));
             out.writeString(mPageTypeLabels.get(i));
             out.writeIntArray(mPageTypeSizes.get(i));
         }
@@ -1244,6 +1250,8 @@
 
         // Fragmentation info
         final int NPAGETYPES = in.readInt();
+        mPageTypeNodes.clear();
+        mPageTypeNodes.ensureCapacity(NPAGETYPES);
         mPageTypeZones.clear();
         mPageTypeZones.ensureCapacity(NPAGETYPES);
         mPageTypeLabels.clear();
@@ -1251,7 +1259,8 @@
         mPageTypeSizes.clear();
         mPageTypeSizes.ensureCapacity(NPAGETYPES);
         for (int i=0; i<NPAGETYPES; i++) {
-            mPageTypeZones.add(in.readInt());
+            mPageTypeNodes.add(in.readInt());
+            mPageTypeZones.add(in.readString());
             mPageTypeLabels.add(in.readString());
             mPageTypeSizes.add(in.createIntArray());
         }
@@ -1764,7 +1773,8 @@
         pw.println("Available pages by page size:");
         final int NPAGETYPES = mPageTypeLabels.size();
         for (int i=0; i<NPAGETYPES; i++) {
-            pw.format("Zone %3d  %14s ", mPageTypeZones.get(i), mPageTypeLabels.get(i));
+            pw.format("Node %3d Zone %7s  %14s ", mPageTypeNodes.get(i), mPageTypeZones.get(i),
+                    mPageTypeLabels.get(i));
             final int[] sizes = mPageTypeSizes.get(i);
             final int N = sizes == null ? 0 : sizes.length;
             for (int j=0; j<N; j++) {
@@ -2095,6 +2105,9 @@
             pw.print(",");
             pw.print(mPageTypeZones.get(i));
             pw.print(",");
+            // Wasn't included in original output.
+            //pw.print(mPageTypeNodes.get(i));
+            //pw.print(",");
             final int[] sizes = mPageTypeSizes.get(i);
             final int N = sizes == null ? 0 : sizes.length;
             for (int j=0; j<N; j++) {
@@ -2135,6 +2148,20 @@
             proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_PARTIAL);
         }
 
+        final int NPAGETYPES = mPageTypeLabels.size();
+        for (int i = 0; i < NPAGETYPES; i++) {
+            final long token = proto.start(ProcessStatsSectionProto.AVAILABLE_PAGES);
+            proto.write(ProcessStatsAvailablePagesProto.NODE, mPageTypeNodes.get(i));
+            proto.write(ProcessStatsAvailablePagesProto.ZONE, mPageTypeZones.get(i));
+            proto.write(ProcessStatsAvailablePagesProto.LABEL, mPageTypeLabels.get(i));
+            final int[] sizes = mPageTypeSizes.get(i);
+            final int N = sizes == null ? 0 : sizes.length;
+            for (int j = 0; j < N; j++) {
+                proto.write(ProcessStatsAvailablePagesProto.PAGES_PER_ORDER, sizes[j]);
+            }
+            proto.end(token);
+        }
+
         final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
         if ((section & REPORT_PROC_STATS) != 0) {
             for (int ip = 0; ip < procMap.size(); ip++) {
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
index 2995a8f..7a00a51 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -58,6 +58,15 @@
         return mContext.getResources().getBoolean(R.bool.config_dozePulsePickup);
     }
 
+    public boolean tapGestureEnabled(int user) {
+        return boolSettingDefaultOn(Settings.Secure.DOZE_TAP_SCREEN_GESTURE, user)
+                && tapSensorAvailable();
+    }
+
+    public boolean tapSensorAvailable() {
+        return !TextUtils.isEmpty(tapSensorType());
+    }
+
     public boolean doubleTapGestureEnabled(int user) {
         return boolSettingDefaultOn(Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, user)
                 && doubleTapSensorAvailable();
@@ -86,6 +95,10 @@
         return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType);
     }
 
+    public String tapSensorType() {
+        return mContext.getResources().getString(R.string.config_dozeTapSensorType);
+    }
+
     public String longPressSensorType() {
         return mContext.getResources().getString(R.string.config_dozeLongPressSensorType);
     }
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index 5945958..72c67d7 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -139,6 +139,14 @@
         return mDestroyed;
     }
 
+    /**
+     * Gets the name of the service.
+     */
+    @NonNull
+    public final ComponentName getComponentName() {
+        return mComponentName;
+    }
+
     private void handleOnConnectedStateChangedInternal(boolean connected) {
         if (connected) {
             handlePendingRequests();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index cc8da5c..17cc6af 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -30,6 +30,7 @@
 import android.database.ContentObserver;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
+import android.net.INetworkStatsService;
 import android.net.NetworkStats;
 import android.net.Uri;
 import android.net.wifi.WifiActivityEnergyInfo;
@@ -86,7 +87,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.location.gnssmetrics.GnssMetrics;
-import com.android.internal.net.NetworkStatsFactory;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FastXmlSerializer;
@@ -337,6 +337,25 @@
 
     private final PlatformIdleStateCallback mPlatformIdleStateCallback;
 
+    private final Runnable mDeferSetCharging = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (BatteryStatsImpl.this) {
+                if (mOnBattery) {
+                    // if the device gets unplugged in the time between this runnable being
+                    // executed and the lock being taken, we don't want to set charging state
+                    return;
+                }
+                boolean changed = setChargingLocked(true);
+                if (changed) {
+                    final long uptime = mClocks.uptimeMillis();
+                    final long elapsedRealtime = mClocks.elapsedRealtime();
+                    addHistoryRecordLocked(elapsedRealtime, uptime);
+                }
+            }
+        }
+    };
+
     /**
      * This handler is running on {@link BackgroundThread}.
      */
@@ -11012,7 +11031,6 @@
         }
     }
 
-    private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
     private final Pools.Pool<NetworkStats> mNetworkStatsPool = new Pools.SynchronizedPool<>(6);
 
     private final Object mWifiNetworkLock = new Object();
@@ -11034,11 +11052,16 @@
     private NetworkStats readNetworkStatsLocked(String[] ifaces) {
         try {
             if (!ArrayUtils.isEmpty(ifaces)) {
-                return mNetworkStatsFactory.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
-                        NetworkStats.TAG_NONE, mNetworkStatsPool.acquire());
+                INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
+                        ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+                if (statsService != null) {
+                    return statsService.getDetailedUidStats(ifaces);
+                } else {
+                    Slog.e(TAG, "Failed to get networkStatsService ");
+                }
             }
-        } catch (IOException e) {
-            Slog.e(TAG, "failed to read network stats for ifaces: " + Arrays.toString(ifaces));
+        } catch (RemoteException e) {
+            Slog.e(TAG, "failed to read network stats for ifaces: " + Arrays.toString(ifaces) + e);
         }
         return null;
     }
@@ -12336,6 +12359,14 @@
     }
 
     boolean setChargingLocked(boolean charging) {
+        // if the device is no longer charging, remove the callback
+        // if the device is now charging, it means that this is either called
+        // 1. directly when level >= 90
+        // 2. or from within the runnable that we deferred
+        // For 1. if we have an existing callback, remove it, since we will immediatelly send a
+        // ACTION_CHARGING
+        // For 2. we remove existing callback so we don't send multiple ACTION_CHARGING
+        mHandler.removeCallbacks(mDeferSetCharging);
         if (mCharging != charging) {
             mCharging = charging;
             if (charging) {
@@ -12674,12 +12705,23 @@
                     // charging even if it happens to go down a level.
                     changed |= setChargingLocked(true);
                     mLastChargeStepLevel = level;
-                } if (!mCharging) {
+                }
+                if (!mCharging) {
                     if (mLastChargeStepLevel < level) {
-                        // We have not reporting that we are charging, but the level has now
-                        // gone up, so consider the state to be charging.
-                        changed |= setChargingLocked(true);
+                        // We have not reported that we are charging, but the level has gone up,
+                        // but we would like to not have tons of activity from charging-constraint
+                        // jobs, so instead of reporting ACTION_CHARGING immediately, we defer it.
                         mLastChargeStepLevel = level;
+                        if (!mHandler.hasCallbacks(mDeferSetCharging)) {
+                            mHandler.postDelayed(
+                                    mDeferSetCharging,
+                                    mConstants.BATTERY_CHARGED_DELAY_MS);
+                        }
+                    } else if (mLastChargeStepLevel > level) {
+                        // if we had deferred a runnable due to charge level increasing, but then
+                        // later the charge level drops (could be due to thermal issues), we don't
+                        // want to trigger the deferred runnable, so remove it here
+                        mHandler.removeCallbacks(mDeferSetCharging);
                     }
                 } else {
                     if (mLastChargeStepLevel > level) {
@@ -13296,6 +13338,8 @@
                 = "battery_level_collection_delay_ms";
         public static final String KEY_MAX_HISTORY_FILES = "max_history_files";
         public static final String KEY_MAX_HISTORY_BUFFER_KB = "max_history_buffer_kb";
+        public static final String KEY_BATTERY_CHARGED_DELAY_MS =
+                "battery_charged_delay_ms";
 
         private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = false;
         private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
@@ -13308,6 +13352,7 @@
         private static final int DEFAULT_MAX_HISTORY_BUFFER_KB = 128; /*Kilo Bytes*/
         private static final int DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE = 64;
         private static final int DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB = 64; /*Kilo Bytes*/
+        private static final int DEFAULT_BATTERY_CHARGED_DELAY_MS = 900000; /* 15 min */
 
         public boolean TRACK_CPU_TIMES_BY_PROC_STATE = DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE;
         public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
@@ -13320,6 +13365,7 @@
                 = DEFAULT_BATTERY_LEVEL_COLLECTION_DELAY_MS;
         public int MAX_HISTORY_FILES;
         public int MAX_HISTORY_BUFFER; /*Bytes*/
+        public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS;
 
         private ContentResolver mResolver;
         private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -13388,6 +13434,9 @@
                                 DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB
                                 : DEFAULT_MAX_HISTORY_BUFFER_KB)
                         * 1024;
+                BATTERY_CHARGED_DELAY_MS = mParser.getInt(
+                        KEY_BATTERY_CHARGED_DELAY_MS,
+                        DEFAULT_BATTERY_CHARGED_DELAY_MS);
             }
         }
 
@@ -13445,6 +13494,8 @@
             pw.println(MAX_HISTORY_FILES);
             pw.print(KEY_MAX_HISTORY_BUFFER_KB); pw.print("=");
             pw.println(MAX_HISTORY_BUFFER/1024);
+            pw.print(KEY_BATTERY_CHARGED_DELAY_MS); pw.print("=");
+            pw.println(BATTERY_CHARGED_DELAY_MS);
         }
     }
 
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index c073466..876bd4f 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -8,7 +8,6 @@
 #include "SkImageInfo.h"
 #include "SkColor.h"
 #include "SkColorSpace.h"
-#include "SkMatrix44.h"
 #include "GraphicsJNI.h"
 #include "SkStream.h"
 
@@ -356,8 +355,8 @@
     if (xyzD50 == nullptr || transferParameters == nullptr) {
         colorSpace = SkColorSpace::MakeSRGB();
     } else {
-        SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
-        SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
+        skcms_TransferFunction p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
+        skcms_Matrix3x3 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
         colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix);
     }
 
@@ -549,8 +548,7 @@
     if (skbitmap.colorType() == kRGBA_F16_SkColorType) {
         // Convert to P3 before encoding. This matches SkAndroidCodec::computeOutputColorSpace
         // for wide gamuts.
-        auto cs = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
-                                        SkColorSpace::kDCIP3_D65_Gamut);
+        auto cs = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
         auto info = skbitmap.info().makeColorType(kRGBA_8888_SkColorType)
                                    .makeColorSpace(std::move(cs));
         SkBitmap p3;
@@ -568,11 +566,34 @@
     return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE;
 }
 
+static inline void bitmapErase(SkBitmap bitmap, const SkColor4f& color,
+        const sk_sp<SkColorSpace>& colorSpace) {
+    SkPaint p;
+    p.setColor4f(color, colorSpace.get());
+    p.setBlendMode(SkBlendMode::kSrc);
+    SkCanvas canvas(bitmap);
+    canvas.drawPaint(p);
+}
+
 static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
     LocalScopedBitmap bitmap(bitmapHandle);
     SkBitmap skBitmap;
     bitmap->getSkBitmap(&skBitmap);
-    skBitmap.eraseColor(color);
+    bitmapErase(skBitmap, SkColor4f::FromColor(color), SkColorSpace::MakeSRGB());
+}
+
+static void Bitmap_eraseLong(JNIEnv* env, jobject, jlong bitmapHandle, jobject jColorSpace,
+        jfloat r, jfloat g, jfloat b, jfloat a) {
+    sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(env, jColorSpace);
+    if (GraphicsJNI::hasException(env)) {
+        return;
+    }
+
+    LocalScopedBitmap bitmap(bitmapHandle);
+    SkBitmap skBitmap;
+    bitmap->getSkBitmap(&skBitmap);
+    SkColor4f color = SkColor4f{r, g, b, a};
+    bitmapErase(skBitmap, color, cs);
 }
 
 static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
@@ -910,32 +931,32 @@
     SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
     if (colorSpace == nullptr) return JNI_FALSE;
 
-    SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
+    skcms_Matrix3x3 xyzMatrix;
     if (!colorSpace->toXYZD50(&xyzMatrix)) return JNI_FALSE;
 
     jfloat* xyz = env->GetFloatArrayElements(xyzArray, NULL);
-    xyz[0] = xyzMatrix.getFloat(0, 0);
-    xyz[1] = xyzMatrix.getFloat(1, 0);
-    xyz[2] = xyzMatrix.getFloat(2, 0);
-    xyz[3] = xyzMatrix.getFloat(0, 1);
-    xyz[4] = xyzMatrix.getFloat(1, 1);
-    xyz[5] = xyzMatrix.getFloat(2, 1);
-    xyz[6] = xyzMatrix.getFloat(0, 2);
-    xyz[7] = xyzMatrix.getFloat(1, 2);
-    xyz[8] = xyzMatrix.getFloat(2, 2);
+    xyz[0] = xyzMatrix.vals[0][0];
+    xyz[1] = xyzMatrix.vals[1][0];
+    xyz[2] = xyzMatrix.vals[2][0];
+    xyz[3] = xyzMatrix.vals[0][1];
+    xyz[4] = xyzMatrix.vals[1][1];
+    xyz[5] = xyzMatrix.vals[2][1];
+    xyz[6] = xyzMatrix.vals[0][2];
+    xyz[7] = xyzMatrix.vals[1][2];
+    xyz[8] = xyzMatrix.vals[2][2];
     env->ReleaseFloatArrayElements(xyzArray, xyz, 0);
 
-    SkColorSpaceTransferFn transferParams;
+    skcms_TransferFunction transferParams;
     if (!colorSpace->isNumericalTransferFn(&transferParams)) return JNI_FALSE;
 
     jfloat* params = env->GetFloatArrayElements(paramsArray, NULL);
-    params[0] = transferParams.fA;
-    params[1] = transferParams.fB;
-    params[2] = transferParams.fC;
-    params[3] = transferParams.fD;
-    params[4] = transferParams.fE;
-    params[5] = transferParams.fF;
-    params[6] = transferParams.fG;
+    params[0] = transferParams.a;
+    params[1] = transferParams.b;
+    params[2] = transferParams.c;
+    params[3] = transferParams.d;
+    params[4] = transferParams.e;
+    params[5] = transferParams.f;
+    params[6] = transferParams.g;
     env->ReleaseFloatArrayElements(paramsArray, params, 0);
 
     return JNI_TRUE;
@@ -1121,8 +1142,8 @@
 
 static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject hardwareBuffer,
                                                jfloatArray xyzD50, jobject transferParameters) {
-    SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
-    SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
+    skcms_TransferFunction p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
+    skcms_Matrix3x3 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
     sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix);
     AHardwareBuffer* hwBuf = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env,
         hardwareBuffer);
@@ -1183,6 +1204,7 @@
     {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
         (void*)Bitmap_compress },
     {   "nativeErase",              "(JI)V", (void*)Bitmap_erase },
+    {   "nativeErase",              "(JLandroid/graphics/ColorSpace;FFFF)V", (void*)Bitmap_eraseLong },
     {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
     {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
     {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 67d0c8a..9e74b88 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -424,30 +424,30 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkColorSpaceTransferFn GraphicsJNI::getNativeTransferParameters(JNIEnv* env, jobject transferParams) {
-    SkColorSpaceTransferFn p;
-    p.fA = (float) env->GetDoubleField(transferParams, gTransferParams_aFieldID);
-    p.fB = (float) env->GetDoubleField(transferParams, gTransferParams_bFieldID);
-    p.fC = (float) env->GetDoubleField(transferParams, gTransferParams_cFieldID);
-    p.fD = (float) env->GetDoubleField(transferParams, gTransferParams_dFieldID);
-    p.fE = (float) env->GetDoubleField(transferParams, gTransferParams_eFieldID);
-    p.fF = (float) env->GetDoubleField(transferParams, gTransferParams_fFieldID);
-    p.fG = (float) env->GetDoubleField(transferParams, gTransferParams_gFieldID);
+skcms_TransferFunction GraphicsJNI::getNativeTransferParameters(JNIEnv* env, jobject transferParams) {
+    skcms_TransferFunction p;
+    p.a = (float) env->GetDoubleField(transferParams, gTransferParams_aFieldID);
+    p.b = (float) env->GetDoubleField(transferParams, gTransferParams_bFieldID);
+    p.c = (float) env->GetDoubleField(transferParams, gTransferParams_cFieldID);
+    p.d = (float) env->GetDoubleField(transferParams, gTransferParams_dFieldID);
+    p.e = (float) env->GetDoubleField(transferParams, gTransferParams_eFieldID);
+    p.f = (float) env->GetDoubleField(transferParams, gTransferParams_fFieldID);
+    p.g = (float) env->GetDoubleField(transferParams, gTransferParams_gFieldID);
     return p;
 }
 
-SkMatrix44 GraphicsJNI::getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50) {
-    SkMatrix44 xyzMatrix(SkMatrix44::kIdentity_Constructor);
+skcms_Matrix3x3 GraphicsJNI::getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50) {
+    skcms_Matrix3x3 xyzMatrix;
     jfloat* array = env->GetFloatArrayElements(xyzD50, NULL);
-    xyzMatrix.setFloat(0, 0, array[0]);
-    xyzMatrix.setFloat(1, 0, array[1]);
-    xyzMatrix.setFloat(2, 0, array[2]);
-    xyzMatrix.setFloat(0, 1, array[3]);
-    xyzMatrix.setFloat(1, 1, array[4]);
-    xyzMatrix.setFloat(2, 1, array[5]);
-    xyzMatrix.setFloat(0, 2, array[6]);
-    xyzMatrix.setFloat(1, 2, array[7]);
-    xyzMatrix.setFloat(2, 2, array[8]);
+    xyzMatrix.vals[0][0] = array[0];
+    xyzMatrix.vals[1][0] = array[1];
+    xyzMatrix.vals[2][0] = array[2];
+    xyzMatrix.vals[0][1] = array[3];
+    xyzMatrix.vals[1][1] = array[4];
+    xyzMatrix.vals[2][1] = array[5];
+    xyzMatrix.vals[0][2] = array[6];
+    xyzMatrix.vals[1][2] = array[7];
+    xyzMatrix.vals[2][2] = array[8];
     env->ReleaseFloatArrayElements(xyzD50, array, 0);
     return xyzMatrix;
 }
@@ -456,12 +456,14 @@
     if (colorSpace == nullptr) return nullptr;
     if (!env->IsInstanceOf(colorSpace, gColorSpaceRGB_class)) {
         doThrowIAE(env, "The color space must be an RGB color space");
+        return nullptr;
     }
 
     jobject transferParams = env->CallObjectMethod(colorSpace,
             gColorSpaceRGB_getTransferParametersMethodID);
     if (transferParams == nullptr) {
         doThrowIAE(env, "The color space must use an ICC parametric transfer function");
+        return nullptr;
     }
 
     jfloatArray illuminantD50 = (jfloatArray) env->GetStaticObjectField(gColorSpace_class,
@@ -472,8 +474,8 @@
     jfloatArray xyzD50 = (jfloatArray) env->CallObjectMethod(colorSpaceD50,
             gColorSpaceRGB_getTransformMethodID);
 
-    SkMatrix44 xyzMatrix = getNativeXYZMatrix(env, xyzD50);
-    SkColorSpaceTransferFn transferFunction = getNativeTransferParameters(env, transferParams);
+    skcms_Matrix3x3 xyzMatrix = getNativeXYZMatrix(env, xyzD50);
+    skcms_TransferFunction transferFunction = getNativeTransferParameters(env, transferParams);
 
     return SkColorSpace::MakeRGB(transferFunction, xyzMatrix);
 }
@@ -499,30 +501,30 @@
         } else if (decodeColorSpace.get() != nullptr) {
             // Try to match against known RGB color spaces using the CIE XYZ D50
             // conversion matrix and numerical transfer function parameters
-            SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
+            skcms_Matrix3x3 xyzMatrix;
             LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix));
 
-            SkColorSpaceTransferFn transferParams;
+            skcms_TransferFunction transferParams;
             // We can only handle numerical transfer functions at the moment
             LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams));
 
             jobject params = env->NewObject(gTransferParameters_class,
                     gTransferParameters_constructorMethodID,
-                    transferParams.fA, transferParams.fB, transferParams.fC,
-                    transferParams.fD, transferParams.fE, transferParams.fF,
-                    transferParams.fG);
+                    transferParams.a, transferParams.b, transferParams.c,
+                    transferParams.d, transferParams.e, transferParams.f,
+                    transferParams.g);
 
             jfloatArray xyzArray = env->NewFloatArray(9);
             jfloat xyz[9] = {
-                    xyzMatrix.getFloat(0, 0),
-                    xyzMatrix.getFloat(1, 0),
-                    xyzMatrix.getFloat(2, 0),
-                    xyzMatrix.getFloat(0, 1),
-                    xyzMatrix.getFloat(1, 1),
-                    xyzMatrix.getFloat(2, 1),
-                    xyzMatrix.getFloat(0, 2),
-                    xyzMatrix.getFloat(1, 2),
-                    xyzMatrix.getFloat(2, 2)
+                    xyzMatrix.vals[0][0],
+                    xyzMatrix.vals[1][0],
+                    xyzMatrix.vals[2][0],
+                    xyzMatrix.vals[0][1],
+                    xyzMatrix.vals[1][1],
+                    xyzMatrix.vals[2][1],
+                    xyzMatrix.vals[0][2],
+                    xyzMatrix.vals[1][2],
+                    xyzMatrix.vals[2][2]
             };
             env->SetFloatArrayRegion(xyzArray, 0, 9, xyz);
 
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index b0bd683..699d153 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -10,7 +10,6 @@
 #include "SkPoint.h"
 #include "SkRect.h"
 #include "SkColorSpace.h"
-#include "SkMatrix44.h"
 #include <jni.h>
 #include <hwui/Canvas.h>
 #include <hwui/Bitmap.h>
@@ -101,8 +100,8 @@
             int srcStride, int x, int y, int width, int height,
             SkBitmap* dstBitmap);
 
-    static SkColorSpaceTransferFn getNativeTransferParameters(JNIEnv* env, jobject transferParams);
-    static SkMatrix44 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50);
+    static skcms_TransferFunction getNativeTransferParameters(JNIEnv* env, jobject transferParams);
+    static skcms_Matrix3x3 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50);
     static sk_sp<SkColorSpace> getNativeColorSpace(JNIEnv* env, jobject colorSpace);
 
     static jobject getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColorSpace,
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index e97c9bc..bc49771 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -557,6 +557,38 @@
         return result;
     }
 
+    // FIXME: Should this be FastNative?
+    static void setColorLong(JNIEnv* env, jobject clazz, jlong paintHandle, jobject jColorSpace,
+            jfloat r, jfloat g, jfloat b, jfloat a) {
+        sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(env, jColorSpace);
+        if (GraphicsJNI::hasException(env)) {
+            return;
+        }
+
+        SkColor4f color = SkColor4f{r, g, b, a};
+        reinterpret_cast<Paint*>(paintHandle)->setColor4f(color, cs.get());
+    }
+
+    static void setShadowLayerLong(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat radius,
+                                   jfloat dx, jfloat dy, jobject jColorSpace,
+                                   jfloat r, jfloat g, jfloat b, jfloat a) {
+        sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(env, jColorSpace);
+        if (GraphicsJNI::hasException(env)) {
+            return;
+        }
+
+        SkColor4f color = SkColor4f{r, g, b, a};
+
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        if (radius <= 0) {
+            paint->setLooper(nullptr);
+        }
+        else {
+            SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
+            paint->setLooper(SkBlurDrawLooper::Make(color, cs.get(), sigma, dx, dy));
+        }
+    }
+
     // ------------------ @FastNative ---------------------------
 
     static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
@@ -1075,6 +1107,9 @@
     {"nGetRunAdvance", "(J[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F},
     {"nGetOffsetForAdvance", "(J[CIIIIZF)I",
             (void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I},
+    {"nSetColor","(JLandroid/graphics/ColorSpace;FFFF)V", (void*) PaintGlue::setColorLong},
+    {"nSetShadowLayer", "(JFFFLandroid/graphics/ColorSpace;FFFF)V",
+            (void*)PaintGlue::setShadowLayerLong},
 
     // --------------- @FastNative ----------------------
 
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 49a24a3..b2d3651 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -281,15 +281,18 @@
     std::unique_ptr<NativeCode> code;
     bool needs_native_bridge = false;
 
+    char* nativeloader_error_msg = nullptr;
     void* handle = OpenNativeLibrary(env,
                                      sdkVersion,
                                      pathStr.c_str(),
                                      classLoader,
                                      libraryPath,
                                      &needs_native_bridge,
-                                     &g_error_msg);
+                                     &nativeloader_error_msg);
 
     if (handle == nullptr) {
+        g_error_msg = nativeloader_error_msg;
+        NativeLoaderFreeErrorMessage(nativeloader_error_msg);
         ALOGW("NativeActivity LoadNativeLibrary(\"%s\") failed: %s",
               pathStr.c_str(),
               g_error_msg.c_str());
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 12a8343b4..67c3064 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -841,6 +841,43 @@
     return jStatus;
 }
 
+static int android_media_AudioRecord_set_microphone_direction(JNIEnv *env, jobject thiz,
+                                                              jint direction) {
+    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+    if (lpRecorder == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioRecord pointer for setMicrophoneDirection()");
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+
+    jint jStatus = AUDIO_JAVA_SUCCESS;
+    status_t status =
+        lpRecorder->setMicrophoneDirection(static_cast<audio_microphone_direction_t>(direction));
+    if (status != NO_ERROR) {
+        jStatus = nativeToJavaStatus(status);
+    }
+
+    return jStatus;
+}
+
+static int android_media_AudioRecord_set_microphone_field_dimension(JNIEnv *env, jobject thiz,
+                                                                    jfloat zoom) {
+    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+    if (lpRecorder == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioRecord pointer for setMicrophoneFieldDimension()");
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+
+    jint jStatus = AUDIO_JAVA_SUCCESS;
+    status_t status = lpRecorder->setMicrophoneFieldDimension(zoom);
+    if (status != NO_ERROR) {
+        jStatus = nativeToJavaStatus(status);
+    }
+
+    return jStatus;
+}
+
 // ----------------------------------------------------------------------------
 static jint android_media_AudioRecord_get_port_id(JNIEnv *env,  jobject thiz) {
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
@@ -896,6 +933,10 @@
     {"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
                                         (void *)android_media_AudioRecord_get_active_microphones},
     {"native_getPortId", "()I", (void *)android_media_AudioRecord_get_port_id},
+    {"native_set_microphone_direction", "(I)I",
+                                (void *)android_media_AudioRecord_set_microphone_direction},
+    {"native_set_microphone_field_dimension", "(F)I",
+                                (void *)android_media_AudioRecord_set_microphone_field_dimension},
 };
 
 // field names found in android/media/AudioRecord.java
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 7b564ae..4101c04 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -44,6 +44,8 @@
 #include "androidfw/MutexGuard.h"
 #include "androidfw/PosixUtils.h"
 #include "androidfw/ResourceTypes.h"
+#include "androidfw/ResourceUtils.h"
+
 #include "core_jni_helpers.h"
 #include "jni.h"
 #include "nativehelper/JNIHelp.h"
@@ -975,34 +977,7 @@
     return nullptr;
   }
 
-  std::string result;
-  if (name.package != nullptr) {
-    result.append(name.package, name.package_len);
-  }
-
-  if (name.type != nullptr || name.type16 != nullptr) {
-    if (!result.empty()) {
-      result += ":";
-    }
-
-    if (name.type != nullptr) {
-      result.append(name.type, name.type_len);
-    } else {
-      result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len));
-    }
-  }
-
-  if (name.entry != nullptr || name.entry16 != nullptr) {
-    if (!result.empty()) {
-      result += "/";
-    }
-
-    if (name.entry != nullptr) {
-      result.append(name.entry, name.entry_len);
-    } else {
-      result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len));
-    }
-  }
+  std::string result = ToFormattedResourceString(&name);
   return env->NewStringUTF(result.c_str());
 }
 
@@ -1049,6 +1024,26 @@
   return nullptr;
 }
 
+static void NativeSetResourceResolutionLoggingEnabled(JNIEnv* /*env*/,
+                                                      jclass /*clazz*/,
+                                                      jlong ptr,
+                                                      jboolean enabled) {
+  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+  assetmanager->SetResourceResolutionLoggingEnabled(enabled);
+}
+
+static jstring NativeGetLastResourceResolution(JNIEnv* env,
+                                               jclass /*clazz*/,
+                                               jlong ptr) {
+  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+  std::string resolution = assetmanager->GetLastResourceResolution();
+  if (resolution.empty()) {
+    return nullptr;
+  } else {
+    return env->NewStringUTF(resolution.c_str());
+  }
+}
+
 static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
                                      jboolean exclude_system) {
   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
@@ -1452,6 +1447,10 @@
     {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
     {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
     {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
+    {"nativeSetResourceResolutionLoggingEnabled", "(JZ)V",
+     (void*) NativeSetResourceResolutionLoggingEnabled},
+    {"nativeGetLastResourceResolution", "(J)Ljava/lang/String;",
+     (void*) NativeGetLastResourceResolution},
     {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
     {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
      (void*)NativeGetSizeConfigurations},
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index 10da892..aa10a2f 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -138,6 +138,7 @@
                 event->getDeviceId(), event->getSource(), event->getDisplayId(),
                 event->getAction(), event->getActionButton(), event->getFlags(),
                 event->getEdgeFlags(), event->getMetaState(), event->getButtonState(),
+                event->getClassification(),
                 event->getXOffset(), event->getYOffset(),
                 event->getXPrecision(), event->getYPrecision(),
                 event->getDownTime(), event->getHistoricalEventTime(i),
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 9ce6df1..897427f 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -642,6 +642,27 @@
     return static_cast<jint>(SurfaceComposerClient::getActiveColorMode(token));
 }
 
+static jintArray nativeGetCompositionDataspaces(JNIEnv* env, jclass) {
+    ui::Dataspace defaultDataspace, wcgDataspace;
+    ui::PixelFormat defaultPixelFormat, wcgPixelFormat;
+    if (SurfaceComposerClient::getCompositionPreference(&defaultDataspace,
+                                                        &defaultPixelFormat,
+                                                        &wcgDataspace,
+                                                        &wcgPixelFormat) != NO_ERROR) {
+        return nullptr;
+    }
+    jintArray array = env->NewIntArray(2);
+    if (array == nullptr) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
+        return nullptr;
+    }
+    jint* arrayValues = env->GetIntArrayElements(array, 0);
+    arrayValues[0] = static_cast<jint>(defaultDataspace);
+    arrayValues[1] = static_cast<jint>(wcgDataspace);
+    env->ReleaseIntArrayElements(array, arrayValues, 0);
+    return array;
+}
+
 static jboolean nativeSetActiveColorMode(JNIEnv* env, jclass,
         jobject tokenObj, jint colorMode) {
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
@@ -660,6 +681,10 @@
     if (t.duration() > 100ms) ALOGD("Excessive delay in setPowerMode()");
 }
 
+static jboolean nativeGetProtectedContentSupport(JNIEnv* env, jclass) {
+    return static_cast<jboolean>(SurfaceComposerClient::getProtectedContentSupport());
+}
+
 static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) {
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
     status_t err = ctrl->clearLayerFrameStats();
@@ -1016,6 +1041,8 @@
             (void*)nativeGetActiveColorMode},
     {"nativeSetActiveColorMode", "(Landroid/os/IBinder;I)Z",
             (void*)nativeSetActiveColorMode},
+    {"nativeGetCompositionDataspaces", "()[I",
+            (void*)nativeGetCompositionDataspaces},
     {"nativeGetHdrCapabilities", "(Landroid/os/IBinder;)Landroid/view/Display$HdrCapabilities;",
             (void*)nativeGetHdrCapabilities },
     {"nativeClearContentFrameStats", "(J)Z",
@@ -1028,6 +1055,8 @@
             (void*)nativeGetAnimationFrameStats },
     {"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V",
             (void*)nativeSetDisplayPowerMode },
+    {"nativeGetProtectedContentSupport", "()Z",
+            (void*)nativeGetProtectedContentSupport },
     {"nativeDeferTransactionUntil", "(JJLandroid/os/IBinder;J)V",
             (void*)nativeDeferTransactionUntil },
     {"nativeDeferTransactionUntilSurface", "(JJJJ)V",
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index a8e1427..9e449a2 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -14,6 +14,15 @@
  * limitations under the License.
  */
 
+/*
+ * Disable optimization of this file if we are compiling with the address
+ * sanitizer.  This is a mitigation for b/122921367 and can be removed once the
+ * bug is fixed.
+ */
+#if __has_feature(address_sanitizer)
+#pragma clang optimize off
+#endif
+
 #define LOG_TAG "Zygote"
 
 // sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index bd87dcc..41e00b9 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -33,6 +33,7 @@
 
 // Static whitelist of open paths that the zygote is allowed to keep open.
 static const char* kPathWhitelist[] = {
+  "/apex/com.android.conscrypt/javalib/conscrypt.jar",
   "/dev/null",
   "/dev/socket/zygote",
   "/dev/socket/zygote_secondary",
diff --git a/core/proto/Android.bp b/core/proto/Android.bp
new file mode 100644
index 0000000..80cc2d4
--- /dev/null
+++ b/core/proto/Android.bp
@@ -0,0 +1,27 @@
+// 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.
+
+// C++ library for Bluetooth platform wide protobuf definitions
+cc_library_static {
+    name: "libbt-platform-protos-lite",
+    host_supported: true,
+    proto: {
+        export_proto_headers: true,
+        type: "lite",
+    },
+    srcs: [
+        "android/bluetooth/enums.proto",
+        "android/bluetooth/hci/enums.proto",
+    ],
+}
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 2f2f623..4538508 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -27,9 +27,569 @@
     PAGE_VISIBLE = 1;
     PAGE_HIDE = 2;
 
+    // ACTION: Settings > Wi-Fi > [Long press network] > Connect to network
+    //   SUBTYPE: true if connecting to a saved network, false if not
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_WIFI_CONNECT = 135;
+
+    // ACTION: Settings > Wi-Fi > [Long press network] > Forget network
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_WIFI_FORGET = 137;
+
+    // ACTION: Settings > Wi-Fi > Toggle off
+    //   SUBTYPE: true if connected to network before toggle, false if not
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_WIFI_OFF = 138;
+
+    // ACTION: Settings > Wi-Fi > Toggle on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_WIFI_ON = 139;
+
+    // ACTION: Settings > Bluetooth > Overflow > Rename this device
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_BLUETOOTH_RENAME = 161;
+
+    // ACTION: Settings > Bluetooth > Overflow > Show received files
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_BLUETOOTH_FILES = 162;
+
+    // ACTION: DND Settings > Priority only allows > Reminder toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ZEN_ALLOW_REMINDERS = 167;
+
+    // ACTION: DND Settings > Priority only allows > Event toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ZEN_ALLOW_EVENTS = 168;
+
+    // ACTION: DND Settings > Priority only allows > Messages
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ZEN_ALLOW_MESSAGES = 169;
+
+    // ACTION: DND Settings > Priority only allows > Calls
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ZEN_ALLOW_CALLS = 170;
+
+    // ACTION: DND Settings > Priority only allows > Repeat callers toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ZEN_ALLOW_REPEAT_CALLS = 171;
+
+    // ACTION: DND Settings > Automatic rules > [Rule] > Delete rule > Delete
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ZEN_DELETE_RULE_OK = 175;
+
+    // ACTION: Settings > More > Airplane mode toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_AIRPLANE_TOGGLE = 177;
+
+    // ACTION: Settings > Data usage > Cellular data toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_CELL_DATA_TOGGLE = 178;
+
+    // ACTION: Settings > Display > When device is rotated
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ROTATION_LOCK = 203;
+
+    // OPEN: Settings > Search > Perform search
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_SEARCH_RESULTS = 226;
+
+    // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Delete
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_FINGERPRINT_DELETE = 253;
+
+    // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Rename
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_FINGERPRINT_RENAME = 254;
+
+    // ACTION: Settings -> Developer Options -> Take bug report -> Interactive report
+    // CATEGORY: SETTINGS
+    // OS: N
+    // Interactive bug report initiated from Settings.
+    ACTION_BUGREPORT_FROM_SETTINGS_INTERACTIVE = 294;
+
+    // ACTION: Settings -> Developer Options -> Take bug report -> Full report
+    // CATEGORY: SETTINGS
+    // OS: N
+    // Interactive bug report initiated from Settings.
+    ACTION_BUGREPORT_FROM_SETTINGS_FULL = 295;
+
+    // click on collapsed conditional or clicks expand button
+    ACTION_SETTINGS_CONDITION_EXPAND = 373;
+
+    // click main area of expanded conditional
+    ACTION_SETTINGS_CONDITION_CLICK = 375;
+
+    // click a direct button on expanded conditional
+    ACTION_SETTINGS_CONDITION_BUTTON = 376;
+
+    // Action: user enable / disabled data saver using Settings
+    // OPEN: Settings -> Data Usage -> Data saver -> On/off toggle
+    // VALUE: 1 for enabled, 0 for disabled
+    // CATEGORY: SETTINGS
+    // OS: N
+    ACTION_DATA_SAVER_MODE = 394;
+
+    // User whitelisted an app for Data Saver mode; action pass package name of app
+    // Action: user enable / disabled data saver using Settings
+    // OPEN: Settings -> Data Usage -> Data saver -> Unrestricted data access > APP toggle turned on
+    //       or
+    //       Settings -> Apps -> APP -> Data usage -> Unrestricted data usage toggle turned on
+    // VALUE: package name of APP
+    // CATEGORY: SETTINGS
+    // OS: N
+    ACTION_DATA_SAVER_WHITELIST = 395;
+
+    // User blacklisted an app for Data Saver mode; action pass package name of app
+    // OPEN: Settings -> Apps -> APP -> Data usage -> Background data toggle turned off
+    // VALUE: package name of APP
+    // CATEGORY: SETTINGS
+    // OS: N
+    ACTION_DATA_SAVER_BLACKLIST = 396;
+
+    // ACTION: Settings -> Storage -> Manage storage -> Click Storage Manager
+    //   SUBTYPE: false is off, true is on
+    ACTION_TOGGLE_STORAGE_MANAGER = 489;
+
+    // OPEN: Settings > Display -> Ambient Display
+    // CATEGORY: SETTINGS
+    ACTION_AMBIENT_DISPLAY = 495;
+
+    // ACTION: Allow Battery optimization for an app
+    APP_SPECIAL_PERMISSION_BATTERY_ALLOW = 764;
+
+    // ACTION: Deny Battery optimization for an app
+    APP_SPECIAL_PERMISSION_BATTERY_DENY = 765;
+
+    // ACTION: Enable Device Admin app
+    APP_SPECIAL_PERMISSION_ADMIN_ALLOW = 766;
+
+    // ACTION: Disable Device Admin app
+    APP_SPECIAL_PERMISSION_ADMIN_DENY = 767;
+
+    // ACTION: Allow "Do Not Disturb access" for an app
+    APP_SPECIAL_PERMISSION_DND_ALLOW = 768;
+
+    // ACTION: Deny "Do Not Disturb access" for an app
+    APP_SPECIAL_PERMISSION_DND_DENY = 769;
+
+    // ACTION: Allow "Draw over other apps" for an app
+    APP_SPECIAL_PERMISSION_APPDRAW_ALLOW = 770;
+
+    // ACTION: Deny "Display over other apps" for an app
+    APP_SPECIAL_PERMISSION_APPDRAW_DENY = 771;
+
+    // ACTION: Allow "VR helper services" for an app
+    APP_SPECIAL_PERMISSION_VRHELPER_ALLOW = 772;
+
+    // ACTION: Deny "VR helper services" for an app
+    APP_SPECIAL_PERMISSION_VRHELPER_DENY = 773;
+
+    // ACTION: Allow "Modify system settings" for an app
+    APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_ALLOW = 774;
+
+    // ACTION: Deny "Modify system settings" for an app
+    APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_DENY = 775;
+
+    // ACTION: Allow "Notification access" for an app
+    APP_SPECIAL_PERMISSION_NOTIVIEW_ALLOW = 776;
+
+    // ACTION: Deny "Notification access" for an app
+    APP_SPECIAL_PERMISSION_NOTIVIEW_DENY = 777;
+
+    // ACTION: "Premium SMS access" for an app - "ask user" option
+    APP_SPECIAL_PERMISSION_PREMIUM_SMS_ASK = 778;
+
+    // ACTION: "Premium SMS access" for an app - "never allow" option
+    APP_SPECIAL_PERMISSION_PREMIUM_SMS_DENY = 779;
+
+    // ACTION: "Premium SMS access" for an app - "always allow" option
+    APP_SPECIAL_PERMISSION_PREMIUM_SMS_ALWAYS_ALLOW = 780;
+
+    // ACTION: Allow "Unrestricted data access" for an app
+    APP_SPECIAL_PERMISSION_UNL_DATA_ALLOW = 781;
+
+    // ACTION: Deny "Unrestricted data access" for an app
+    APP_SPECIAL_PERMISSION_UNL_DATA_DENY = 782;
+
+    // ACTION: Allow "Usage access" for an app
+    APP_SPECIAL_PERMISSION_USAGE_VIEW_ALLOW = 783;
+
+    // ACTION: Deny "Usage access" for an app
+    APP_SPECIAL_PERMISSION_USAGE_VIEW_DENY = 784;
+
+    // ACTION: "Force stop" action on an app
+    ACTION_APP_FORCE_STOP = 807;
+
+    // ACTION: Allow "Enable picture-in-picture" for an app
+    APP_PICTURE_IN_PICTURE_ALLOW = 813;
+
+    // ACTION: Create a Settings shortcut item.
+    ACTION_SETTINGS_CREATE_SHORTCUT = 829;
+
+    // ACTION: Settings advanced button is expanded
+    ACTION_SETTINGS_ADVANCED_BUTTON_EXPAND = 834;
+
+    // ACTION: Deny "Enable picture-in-picture" for an app
+    APP_PICTURE_IN_PICTURE_DENY = 814;
+
+    // ACTION: Settings -> Display -> Theme
+    ACTION_THEME = 816;
+
+    // ACTION: Settings > About device > Build number
+    ACTION_SETTINGS_BUILD_NUMBER_PREF = 847;
+
+    // ACTION: Settings > Battery > Menu > Optimization
+    ACTION_SETTINGS_MENU_BATTERY_OPTIMIZATION = 851;
+
+    // ACTION: Settings > Battery > Menu > Apps Toggle
+    ACTION_SETTINGS_MENU_BATTERY_APPS_TOGGLE = 852;
+
     // ACTION: Settings > Any preference is changed
     ACTION_SETTINGS_PREFERENCE_CHANGE = 853;
 
+    // ACTION: Settings > Connected devices > Bluetooth -> Available devices
+    ACTION_SETTINGS_BLUETOOTH_PAIR = 866;
+
+    // ACTION: Settings > Connected devices > Bluetooth -> Paired devices
+    ACTION_SETTINGS_BLUETOOTH_CONNECT = 867;
+
+    // ACTION: Settings > Connected devices > Bluetooth -> Connected device
+    ACTION_SETTINGS_BLUETOOTH_DISCONNECT = 868;
+
+    // ACTION: Settings > Connected devices > Bluetooth -> Error dialog
+    ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR = 869;
+
+    // ACTION: Settings > Connected devices > Bluetooth master switch Toggle
+    ACTION_SETTINGS_MASTER_SWITCH_BLUETOOTH_TOGGLE = 870;
+
+    // ACTION: Settings > App detail > Uninstall
+    ACTION_SETTINGS_UNINSTALL_APP = 872;
+
+    // ACTION: Settings > App detail > Uninstall Device admin app
+    ACTION_SETTINGS_UNINSTALL_DEVICE_ADMIN = 873;
+
+    // ACTION: Settings > App detail > Disable app
+    ACTION_SETTINGS_DISABLE_APP = 874;
+
+    // ACTION: Settings > App detail > Enable app
+    ACTION_SETTINGS_ENABLE_APP = 875;
+
+    // ACTION: Settings > App detail > Clear data
+    ACTION_SETTINGS_CLEAR_APP_DATA = 876;
+
+    // ACTION: Settings > App detail > Clear cache
+    ACTION_SETTINGS_CLEAR_APP_CACHE = 877;
+
+    // ACTION: Logs pressing the "Clear app" button in the app info settings page for an instant
+    // app.
+    // VALUE: The package name of the app
+    ACTION_SETTINGS_CLEAR_INSTANT_APP = 923;
+
+    // OPEN: Assist Gesture training intro in Settings
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    SETTINGS_ASSIST_GESTURE_TRAINING_INTRO = 991;
+
+    // OPEN: Assist Gesture training enrolling in Settings
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    SETTINGS_ASSIST_GESTURE_TRAINING_ENROLLING = 992;
+
+    // OPEN: Assist Gesture training finished in Settings
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    SETTINGS_ASSIST_GESTURE_TRAINING_FINISHED = 993;
+
+    // ACTION: Update default app from Settings
+    ACTION_SETTINGS_UPDATE_DEFAULT_APP = 1000;
+
+    // ACTION: Settings > Wi-Fi > [Long press network] > Sign in to network
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    ACTION_WIFI_SIGNIN = 1008;
+
+    // ACTION: Settings > Notification Settings > Open application notification
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    ACTION_OPEN_APP_NOTIFICATION_SETTING = 1016;
+
+    // ACTION: Settings > App Info > Open app settings
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    ACTION_OPEN_APP_SETTING = 1017;
+
+    // ACTION: Collect PSD Signals
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    ACTION_PSD_LOADER = 1019;
+
+    // OPEN: Settings > Trampoline Intent > Settings page
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    TRAMPOLINE_SETTINGS_EVENT = 1033;
+
+    // ACTION: Logged when user tries to pair a Bluetooth device without name from Settings app
+    // CATEGORY: SETTINGS
+    // OS: O MR
+    ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES = 1096;
+
+    // ACTION: Settings > Network & Internet > Mobile network > Network
+    // CATEGORY: SETTINGS
+    ACTION_MOBILE_NETWORK_MANUAL_SELECT_NETWORK = 1210;
+
+    // ACTION: DND Settings > Priority only allows > Alarms toggle
+    // SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ALLOW_ALARMS = 1226;
+
+    // ACTION: DND Settings > Priority only allows > Media toggle
+    // SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ALLOW_MEDIA = 1227;
+
+    // ACTION: A private dns mode been selected by user
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_PRIVATE_DNS_MODE = 1249;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Select rule ("Event") > Rule name > OK
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK = 1267;
+
+    // OPEN: Settings > Sound > Do Not Disturb > TURN ON NOW/TURN OFF NOW
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_TOGGLE_DND_BUTTON = 1268;
+
+    // ACTION: DND Settings > What to block > full screen intents
+    //   SUBTYPE: false is allowed, true is blocked
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ZEN_BLOCK_FULL_SCREEN_INTENTS = 1332;
+
+    // ACTION: DND Settings > What to block
+    //   SUBTYPE: false is allowed, true is blocked
+    // OS: P
+    ACTION_ZEN_BLOCK_LIGHT = 1333;
+
+    // ACTION: DND Settings > What to block
+    //   SUBTYPE: false is allowed, true is blocked
+    // OS: P
+    ACTION_ZEN_BLOCK_PEEK = 1334;
+
+    // ACTION: DND Settings > What to block
+    //   SUBTYPE: false is allowed, true is blocked
+    // OS: P
+    ACTION_ZEN_BLOCK_STATUS = 1335;
+
+    // ACTION: DND Settings > What to block
+    //   SUBTYPE: false is allowed, true is blocked
+    // OS: P
+    ACTION_ZEN_BLOCK_BADGE = 1336;
+
+    // ACTION: DND Settings > What to block
+    //   SUBTYPE: false is allowed, true is blocked
+    // OS: P
+    ACTION_ZEN_BLOCK_AMBIENT = 1337;
+
+    // ACTION: DND Settings > What to block
+    //   SUBTYPE: false is allowed, true is blocked
+    // OS: P
+    ACTION_ZEN_BLOCK_NOTIFICATION_LIST = 1338;
+
+    // ACTION: DND Settings > Priority only allows > System toggle
+    // SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ALLOW_SYSTEM = 1340;
+
+    // ACTION: Settings > Battery settings > Battery tip > App restriction tip
+    // OS: P
+    ACTION_APP_RESTRICTION_TIP = 1347;
+
+    // ACTION: Settings > Battery settings > Battery tip > High usage tip
+    // OS: P
+    ACTION_HIGH_USAGE_TIP = 1348;
+
+    // ACTION: Settings > Battery settings > Battery tip > Summary tip
+    // OS: P
+    ACTION_SUMMARY_TIP = 1349;
+
+    // ACTION: Settings > Battery settings > Battery tip > Smart battery tip
+    // OS: P
+    ACTION_SMART_BATTERY_TIP = 1350;
+
+    // ACTION: Settings > Battery settings > Battery tip > Early warning tip
+    // OS: P
+    ACTION_EARLY_WARNING_TIP = 1351;
+
+    // ACTION: Settings > Battery settings > Battery tip > Low battery tip
+    // OS: P
+    ACTION_LOW_BATTERY_TIP = 1352;
+
+    // ACTION: Settings > Battery settings > Battery tip > App restriction list shown
+    // OS: P
+    ACTION_APP_RESTRICTION_TIP_LIST = 1353;
+
+    // ACTION: Settings > Battery settings > Battery tip > High usage list shown
+    // OS: P
+    ACTION_HIGH_USAGE_TIP_LIST = 1354;
+
+    // ACTION: Settings > Battery settings > Battery tip > Open app restriction page
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_TIP_OPEN_APP_RESTRICTION_PAGE = 1361;
+
+    // ACTION: Settings > Battery settings > Battery tip > Restrict app
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_TIP_RESTRICT_APP = 1362;
+
+    // ACTION: Settings > Battery settings > Battery tip > Unrestrict app
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_TIP_UNRESTRICT_APP = 1363;
+
+    // ACTION: Settings > Battery settings > Battery tip > Open smart battery page
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_TIP_OPEN_SMART_BATTERY = 1364;
+
+    // ACTION: Settings > Battery settings > Battery tip > Turn on battery saver
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_TIP_TURN_ON_BATTERY_SAVER = 1365;
+
+    // ACTION: Settings > Anomaly receiver > Anomaly received
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ANOMALY_TRIGGERED = 1367;
+
+    // ACTION: A Settings Slice is requested
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_SETTINGS_SLICE_REQUESTED = 1371;
+
+    // ACTION: A Settings Slice is updated with new value
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_SETTINGS_SLICE_CHANGED = 1372;
+
+    // OPEN: DND onboarding activity > Ok button
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ONBOARDING_OK = 1378;
+
+    // OPEN: DND onboarding activity > Settings link
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ONBOARDING_SETTINGS = 1379;
+
+    // ACTION: Settings > Anomaly receiver > Anomaly ignored, don't show up in battery settings
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ANOMALY_IGNORED = 1387;
+
+    // ACTION: Settings > Battery settings > Battery tip > Open battery saver page
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_TIP_OPEN_BATTERY_SAVER_PAGE = 1388;
+
+    // ACTION: DND Settings > What to block
+    // OS: P
+    ACTION_ZEN_SOUND_ONLY = 1396;
+
+    // ACTION: DND Settings > Notifications
+    // OS: P
+    ACTION_ZEN_SOUND_AND_VIS_EFFECTS = 1397;
+
+    // ACTION: DND Settings > Notifications
+    // OS: P
+    ACTION_ZEN_SHOW_CUSTOM = 1398;
+
+    // ACTION: DND Settings > Notifications
+    // OS: P
+    ACTION_ZEN_CUSTOM = 1399;
+
+    // OPEN: DND onboarding activity > don't update button
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ONBOARDING_KEEP_CURRENT_SETTINGS = 1406;
+
+    // ACTION: Storage initialization wizard initialization choice of external/portable
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_STORAGE_INIT_EXTERNAL = 1407;
+
+    // ACTION: Storage initialization wizard initialization choice of internal/adoptable
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_STORAGE_INIT_INTERNAL = 1408;
+
+    // ACTION: Storage initialization wizard benchmark fast choice of continue
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_STORAGE_BENCHMARK_FAST_CONTINUE = 1409;
+
+    // ACTION: Storage initialization wizard benchmark slow choice of continue
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_STORAGE_BENCHMARK_SLOW_CONTINUE = 1410;
+
+    // ACTION: Storage initialization wizard benchmark slow choice of abort
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_STORAGE_BENCHMARK_SLOW_ABORT = 1411;
+
+    // ACTION: Storage initialization wizard migration choice of now
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_STORAGE_MIGRATE_NOW = 1412;
+
+    // ACTION: Storage initialization wizard migration choice of later
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_STORAGE_MIGRATE_LATER = 1413;
+
+    // OPEN: Settings > Sound > Switch a2dp devices dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_SWITCH_A2DP_DEVICES = 1415;
+
+
+    // OPEN: Settings > Sound > Switch hfp devices dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_SWITCH_HFP_DEVICES = 1416;
+
     // ACTION: Tap & Pay -> Default Application Setting -> Use Forground
     ACTION_NFC_PAYMENT_FOREGROUND_SETTING = 1622;
 
@@ -44,15 +604,1454 @@
     // Unknown page. Should not be used in production code.
     PAGE_UNKNOWN = 0;
 
+    // OPEN: Settings > Accessibility
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCESSIBILITY = 2;
+
+    // OPEN: Settings > Accessibility > Captions
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCESSIBILITY_CAPTION_PROPERTIES = 3;
+
+    // OPEN: Settings > Accessibility > [Service]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCESSIBILITY_SERVICE = 4;
+
+    // OPEN: Settings > Accessibility > Color correction
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCESSIBILITY_TOGGLE_DALTONIZER = 5;
+
+    // OPEN: Settings > Accessibility > Accessibility shortcut
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE = 6;
+
+    // OPEN: Settings > Accessibility > Magnification gestures (Renamed in O)
+    // OPEN: Settings > Accessibility > Magnification > Magnify with triple-tap
+    // OPEN: Settings > Accessibility > Magnification > Magnify with button
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 7;
+
+    // OPEN: Settings > Accounts
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCOUNT = 8;
+
+    // OPEN: Settings > Accounts > [Single Account Sync Settings]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCOUNTS_ACCOUNT_SYNC = 9;
+
+    // OPEN: Settings > Accounts > Add an account
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10;
+
+    // OPEN: Settings > Cellular network settings > APNs
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APN = 12;
+
+    // OPEN: Settings > More > Cellular network settings > APNs > [Edit APN]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APN_EDITOR = 13;
+
+    // OPEN: Settings > Apps > Configure apps > App links > [App]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_APP_LAUNCH = 17;
+
+    // OPEN: Settings > Internal storage > Apps storage > [App]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_APP_STORAGE = 19;
+
+    // OPEN: Settings > Apps > [App info]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_INSTALLED_APP_DETAILS = 20;
+
+    // OPEN: Settings > Memory > App usage > [App Memory usage]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_PROCESS_STATS_DETAIL = 21;
+
+    // OPEN: Settings > Memory > App usage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_PROCESS_STATS_UI = 23;
+
+    // OPEN: Choose Bluetooth device (ex: when sharing)
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    BLUETOOTH_DEVICE_PICKER = 25;
+
+    // OPEN: Settings > Security > Choose screen lock
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    CHOOSE_LOCK_GENERIC = 27;
+
+    // OPEN: Settings > Security > Choose screen lock > Choose your password
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    CHOOSE_LOCK_PASSWORD = 28;
+
+    // OPEN: Settings > Security > Choose screen lock > Choose your pattern
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    CHOOSE_LOCK_PATTERN = 29;
+
+    // OPEN: Settings > Security > Choose screen lock > Confirm your password
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    CONFIRM_LOCK_PASSWORD = 30;
+
+    // OPEN: Settings > Security > Choose screen lock > Confirm your pattern
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    CONFIRM_LOCK_PATTERN = 31;
+
+    // OPEN: Settings > Security > Encrypt phone
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    CRYPT_KEEPER = 32;
+
+    // OPEN: Settings > Security > Encrypt phone > Confirm
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    CRYPT_KEEPER_CONFIRM = 33;
+
+    // OPEN: Settings (Root page)
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DASHBOARD_SUMMARY = 35;
+
+    // OPEN: Settings > Data usage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DATA_USAGE_SUMMARY = 37;
+
+    // OPEN: Settings > Date & time
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DATE_TIME = 38;
+
+    // OPEN: Settings > Developer options
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DEVELOPMENT = 39;
+
+    // OPEN: Settings > About phone
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DEVICEINFO = 40;
+
+    // OPEN: Settings > Internal storage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DEVICEINFO_STORAGE = 42;
+
+    // OPEN: Settings > Display
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DISPLAY = 46;
+
+    // OPEN: Settings > Display > Daydream
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DREAM = 47;
+
+    // OPEN: Settings > Security > Screen lock > Secure start-up
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ENCRYPTION = 48;
+
+    // OPEN: Settings > Security > Nexus Imprint
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT = 49;
+
+    // OPEN: Settings > Battery > History details
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FUELGAUGE_BATTERY_HISTORY_DETAIL = 51;
+
+    // OPEN: Settings > Battery > Battery saver
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FUELGAUGE_BATTERY_SAVER = 52;
+
+    // OPEN: Settings > Battery > [App Use details]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FUELGAUGE_POWER_USAGE_DETAIL = 53;
+
+    // OPEN: Settings > Security > SIM card lock settings
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ICC_LOCK = 56;
+
+    // OPEN: Settings > Language & input > Physical keyboard
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    INPUTMETHOD_KEYBOARD = 58;
+
+    // OPEN: Settings > Language & input > Spell checker
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    INPUTMETHOD_SPELL_CHECKERS = 59;
+
+    // OBSOLETE
+    INPUTMETHOD_SUBTYPE_ENABLER = 60;
+
+    // OPEN: Settings > Language & input > Personal dictionary
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    INPUTMETHOD_USER_DICTIONARY = 61;
+
+    // OPEN: Settings > Language & input > Add word
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62;
+
+    // OPEN: Settings > Location
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    LOCATION = 63;
+
+    // OPEN: Settings > Apps
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    MANAGE_APPLICATIONS = 65;
+
+    // OPEN: Settings > Backup & reset > Factory data reset
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    MASTER_CLEAR = 66;
+
+    // OPEN: Settings > Backup & reset > Factory data reset > Confirm
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    MASTER_CLEAR_CONFIRM = 67;
+
+    // OPEN: Settings > More > Android Beam
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NFC_BEAM = 69;
+
+    // OPEN: Settings > Tap & pay
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NFC_PAYMENT = 70;
+
+    // OPEN: Settings > Sound & notification > App notifications > [App]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_APP_NOTIFICATION = 72;
+
+    // OBSOLETE
+    NOTIFICATION_REDACTION = 74;
+
+    // OPEN: Settings Widget > Notification log
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_STATION = 75;
+
+    // OPEN: Settings > Sound & notification > Do not disturb
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_ZEN_MODE = 76;
+
+
+    // OPEN: Print job notification > Print job settings
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    PRINT_JOB_SETTINGS = 78;
+
+    // OPEN: Settings > Printing > [Print Service]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    PRINT_SERVICE_SETTINGS = 79;
+
+    // OPEN: Settings > Printing
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    PRINT_SETTINGS = 80;
+
+    // OPEN: Settings > Backup & reset
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    PRIVACY = 81;
+
+    //OBSOLETE
+    PROXY_SELECTOR = 82;
+
+    // OPEN: Settings > Backup & reset > Network settings reset
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    RESET_NETWORK = 83;
+
+    // OPEN: Settings > Backup & reset > Network settings reset > Confirm
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    RESET_NETWORK_CONFIRM = 84;
+
+    // OPEN: Settings > Developer Options > Running Services
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    RUNNING_SERVICE_DETAILS = 85;
+
+    // OPEN: Settings > Security > Screen pinning
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    SCREEN_PINNING = 86;
+
+    // OPEN: Settings > Security
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    SECURITY = 87;
+
+    // OPEN: Settings > SIM cards
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    SIM = 88;
+
+    // OBSOLETE
+    TESTING = 89;
+
+    // OPEN: Settings > More > Tethering & portable hotspot
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    TETHER = 90;
+
+    // OPEN: Settings > Security > Trust agents
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    TRUST_AGENT = 91;
+
+    // OPEN: Settings > Security > Trusted credentials
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    TRUSTED_CREDENTIALS = 92;
+
+    // OPEN: Settings > Language & input > TTS output > [Engine] > Settings
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    TTS_ENGINE_SETTINGS = 93;
+
+    // OPEN: Settings > Language & input > Text-to-speech output
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    TTS_TEXT_TO_SPEECH = 94;
+
+    // OPEN: Settings > Security > Apps with usage access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    USAGE_ACCESS = 95;
+
+    // OPEN: Settings > Users
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    USER = 96;
+
+    // OPEN: Settings > Users > [Restricted profile app & content access]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    USERS_APP_RESTRICTIONS = 97;
+
+    // OPEN: Settings > Users > [User settings]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    USER_DETAILS = 98;
+
+    // OPEN: Settings > More > VPN
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    VPN = 100;
+
+    // OPEN: Settings > Display > Choose wallpaper from
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    WALLPAPER_TYPE = 101;
+
+    // OPEN: Settings > Display > Cast
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    WFD_WIFI_DISPLAY = 102;
+
+    // OPEN: Settings > Wi-Fi
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    WIFI = 103;
+
+    // OPEN: Settings > More > Wi-Fi Calling
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    WIFI_CALLING = 105;
+
+    // OPEN: Settings > Wi-Fi > Saved networks
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    WIFI_SAVED_ACCESS_POINTS = 106;
+
+    // OPEN: Settings > Wi-Fi > Advanced Wi-Fi > Wi-Fi Direct
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    WIFI_P2P = 109;
+
+    // OPEN: Settings > Apps > Configure apps > App permissions
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_ADVANCED = 130;
+
+    // OPEN: Settings > Location > Scanning
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    LOCATION_SCANNING = 131;
+
+    // OPEN: Settings > Sound & notification > App notifications
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    MANAGE_APPLICATIONS_NOTIFICATIONS = 133;
+
+    // OPEN: Settings > Sound & notification > DND > Priority only allows
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_ZEN_MODE_PRIORITY = 141;
+
+    // OPEN: Settings > Sound & notification > DND > Automatic rules
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_ZEN_MODE_AUTOMATION = 142;
+
+    // OPEN: Settings > Sound & notification > DND > [Time based rule]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
+
+    // OPEN: Settings > Apps > Configure apps > App links
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    MANAGE_DOMAIN_URLS = 143;
+
+    // OPEN: Settings > Sound & notification > DND > [Event rule]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_ZEN_MODE_EVENT_RULE = 146;
+
+    // OPEN: Settings > Sound & notification > Notification access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_ACCESS = 179;
+
+    // OPEN: Settings > Sound & notification > Do Not Disturb access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_ZEN_MODE_ACCESS = 180;
+
+    // OPEN: Settings > Internal storage > Apps storage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_STORAGE_APPS = 182;
+
+    // OPEN: Settings > Security > Usage access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_USAGE_ACCESS_DETAIL = 183;
+
+    // OPEN: Settings > Battery > Battery optimization
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_HIGH_POWER_APPS = 184;
+
+    // OPEN: Settings > Apps > Configure > Default apps > Assist & voice input
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_MANAGE_ASSIST = 201;
+
+    // OPEN: Settings > Memory
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    PROCESS_STATS_SUMMARY = 202;
+
+    // OPEN: Settings > Apps > Configure Apps > Display over other apps
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    SYSTEM_ALERT_WINDOW_APPS = 221;
+
+    // OPEN: Settings > About phone > Legal information
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ABOUT_LEGAL_SETTINGS = 225;
+
+
+    // OPEN: Settings > Developer options > Inactive apps
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FUELGAUGE_INACTIVE_APPS = 238;
+
+    // OPEN: Settings > Security > Nexus Imprint > Add Fingerprint
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_ENROLLING = 240;
+    // OPEN: Fingerprint Enroll > Find Sensor
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_FIND_SENSOR = 241;
+
+    // OPEN: Fingerprint Enroll > Fingerprint Enrolled!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_ENROLL_FINISH = 242;
+
+    // OPEN: Fingerprint Enroll introduction
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_ENROLL_INTRO = 243;
+
+    // OPEN: Fingerprint Enroll > Let's Start!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_ENROLL_SIDECAR = 245;
+
+    // OPEN: Fingerprint Enroll SUW > Let's Start!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_ENROLLING_SETUP = 246;
+
+    // OPEN: Fingerprint Enroll SUW > Find Sensor
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_FIND_SENSOR_SETUP = 247;
+
+    // OPEN: Fingerprint Enroll SUW > Fingerprint Enrolled!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_ENROLL_FINISH_SETUP = 248;
+
+    // OPEN: Fingerprint Enroll SUW introduction
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_ENROLL_INTRO_SETUP = 249;
+
+    // OPEN: Settings > Developer Options > Background Check
+    // CATEGORY: SETTINGS
+    // OS: N
+    BACKGROUND_CHECK_SUMMARY = 258;
+
+    // OPEN: Settings > Notifications > [App] > Channel Notifications
+    // CATEGORY: SETTINGS
+    // OS: N
+    NOTIFICATION_TOPIC_NOTIFICATION = 265;
+
+    // OPEN: Settings > Security > User credentials
+    // CATEGORY: Settings
+    // OS: N
+    USER_CREDENTIALS = 285;
+
+    // Logs that the user has edited the enabled VR listeners.
+    // CATEGORY: SETTINGS
+    // OS: N
+    VR_MANAGE_LISTENERS = 334;
+
+    // Settings -> Accessibility -> Click after pointer stops moving
+    // CATEGORY: SETTINGS
+    // OS: N
+    ACCESSIBILITY_TOGGLE_AUTOCLICK = 335;
+
+    // Settings -> Sound
+    // CATEGORY: SETTINGS
+    // OS: N
+    SOUND = 336;
+
+    // Settings -> Notifications -> Gear
+    // CATEGORY: SETTINGS
+    // OS: N
+    CONFIGURE_NOTIFICATION = 337;
+
+    // Settings -> Wi-Fi -> Gear
+    // CATEGORY: SETTINGS
+    // OS: N
+    CONFIGURE_WIFI = 338;
+
+    // Settings -> Display -> Display size
+    // OS: N
+    DISPLAY_SCREEN_ZOOM = 339;
+
+    // Settings -> Display -> Font size
+    // CATEGORY: SETTINGS
+    // OS: N
+    ACCESSIBILITY_FONT_SIZE = 340;
+
+    // Settings -> Data usage -> Cellular/Wi-Fi data usage
+    // CATEGORY: SETTINGS
+    // OS: N
+    DATA_USAGE_LIST = 341;
+
+    // Settings -> Data usage -> Billing cycle or DATA_USAGE_LIST -> Gear
+    // CATEGORY: SETTINGS
+    // OS: N
+    BILLING_CYCLE = 342;
+
+    // DATA_USAGE_LIST -> Any item or App info -> Data usage
+    // CATEGORY: SETTINGS
+    // OS: N
+    APP_DATA_USAGE = 343;
+
+    // Settings -> Language & input -> Language
+    // CATEGORY: SETTINGS
+    // OS: N
+    USER_LOCALE_LIST = 344;
+
+    // Settings -> Language & input -> Virtual keyboard
+    // CATEGORY: SETTINGS
+    // OS: N
+    VIRTUAL_KEYBOARDS = 345;
+
+    // Settings -> Language & input -> Physical keyboard
+    // CATEGORY: SETTINGS
+    // OS: N
+    PHYSICAL_KEYBOARDS = 346;
+
+    // Settings -> Language & input -> Virtual keyboard -> Add a virtual keyboard
+    // CATEGORY: SETTINGS
+    // OS: N
+    ENABLE_VIRTUAL_KEYBOARDS = 347;
+
+    // Settings -> Data usage -> Data Saver
+    // CATEGORY: SETTINGS
+    // OS: N
+    DATA_SAVER_SUMMARY = 348;
+
+    // Settings -> Data usage -> Data Saver -> Unrestricted data access
+    // CATEGORY: SETTINGS
+    // OS: N
+    DATA_USAGE_UNRESTRICTED_ACCESS = 349;
+
+    // Settings -> Apps -> Gear -> Special access
+    SPECIAL_ACCESS = 351;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY = 367;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Magnification gestures (Renamed in O)
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Magnification -> Magnify with triple-tap
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Magnification -> Magnify with button
+    // ACTION: New magnification gesture configuration is chosen
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 368;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Font size
+    // ACTION: New font size is chosen
+    //  SUBTYPE: 0 is small, 1 is default, 2 is large, 3 is largest
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY_FONT_SIZE = 369;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Display size
+    // ACTION: New display size is chosen
+    //  SUBTYPE: 0 is small, 1 is default, 2 is large, 3 is larger, 4 is largest
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY_DISPLAY_SIZE = 370;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings -> TalkBack
+    // ACTION: New screen reader configuration is chosen
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY_TOGGLE_SCREEN_READER = 371;
+
+    // Airplane mode on
+    SETTINGS_CONDITION_AIRPLANE_MODE = 377;
+    // AKA Data saver on
+    SETTINGS_CONDITION_BACKGROUND_DATA = 378;
+    // Battery saver on
+    SETTINGS_CONDITION_BATTERY_SAVER = 379;
+    // Cellular data off
+    SETTINGS_CONDITION_CELLULAR_DATA = 380;
+    // Do not disturb on
+    SETTINGS_CONDITION_DND = 381;
+    // Hotspot on
+    SETTINGS_CONDITION_HOTSPOT = 382;
+    // Work profile off
+    SETTINGS_CONDITION_WORK_MODE = 383;
+
+    // Settings > Apps > Gear > Special Access > Premium SMS access
+    PREMIUM_SMS_ACCESS = 388;
+
+    // OPEN: Settings > Accounts > Work profile settings
+    // CATEGORY: SETTINGS
+    ACCOUNTS_WORK_PROFILE_SETTINGS = 401;
+
+    // Settings -> Dev options -> Convert to file encryption
+    CONVERT_FBE = 402;
+
+    // Settings -> Dev options -> Convert to file encryption -> WIPE AND CONVERT...
+    CONVERT_FBE_CONFIRM = 403;
+
+    // Settings -> Dev options -> Running services
+    RUNNING_SERVICES = 404;
+
+    // The dialog shown by 3P intent to change current webview implementation.
+    WEBVIEW_IMPLEMENTATION = 405;
+
+    // OPEN: Settings > Internal storage > Storage manager
+    // CATEGORY: SETTINGS
+    STORAGE_MANAGER_SETTINGS = 458;
+
+    // OPEN: Settings -> Gestures
+    // CATEGORY: SETTINGS
+    SETTINGS_GESTURES = 459;
+
+    // OPEN: Settings > Display > Night Light
+    // CATEGORY: SETTINGS
+    NIGHT_DISPLAY_SETTINGS = 488;
+
+    // Night Light on
+    SETTINGS_CONDITION_NIGHT_DISPLAY = 492;
+
+    // OPEN: Settings > Language & input > Personal dictionary (single locale)
+    USER_DICTIONARY_SETTINGS = 514;
+
+    // OPEN: Settings > Date & time > Select time zone
+    ZONE_PICKER = 515;
+
+    // OPEN: Settings > Security > Device administrators
+    DEVICE_ADMIN_SETTINGS = 516;
+
+    // OPEN: Settings > Security > Factory Reset Protection dialog
+    DIALOG_FRP = 528;
+
+    // OPEN: Settings > Custom list preference with confirmation message
+    DIALOG_CUSTOM_LIST_CONFIRMATION = 529;
+
+    // OPEN: Settings > APN Editor > Error dialog
+    DIALOG_APN_EDITOR_ERROR = 530;
+
+    // OPEN: Settings > Users > Edit owner info dialog
+    DIALOG_OWNER_INFO_SETTINGS = 531;
+
+    // OPEN: Settings > Security > Use one lock dialog
+    DIALOG_UNIFICATION_CONFIRMATION = 532;
+
+    // OPEN: Settings > Security > User Credential
+    DIALOG_USER_CREDENTIAL = 533;
+
+    // OPEN: Settings > Accounts > Remove account
+    DIALOG_REMOVE_USER = 534;
+
+    // OPEN: Settings > Accounts > Confirm auto sync dialog
+    DIALOG_CONFIRM_AUTO_SYNC_CHANGE = 535;
+
+    // OPEN: Settings > Apps > Dialog for running service details
+    DIALOG_RUNNIGN_SERVICE = 536;
+
+    // OPEN: Settings > Bluetooth > Rename this device
+    DIALOG_BLUETOOTH_RENAME = 538;
+
+    // OPEN: Settings > Battery optimization > details for app
+    DIALOG_HIGH_POWER_DETAILS = 540;
+
+    // OPEN: Settings > Keyboard > Show keyboard layout dialog
+    DIALOG_KEYBOARD_LAYOUT = 541;
+
+    // OPEN: Settings > WIFI Scan permission dialog
+    DIALOG_WIFI_SCAN_MODE = 543;
+
+    // OPEN: Settings > Wireless > VPN > Config dialog
+    DIALOG_LEGACY_VPN_CONFIG = 545;
+
+    // OPEN: Settings > Wireless > VPN > Config dialog for app
+    DIALOG_VPN_APP_CONFIG = 546;
+
+    // OPEN: Settings > Wireless > VPN > Cannot connect dialog
+    DIALOG_VPN_CANNOT_CONNECT = 547;
+
+    // OPEN: Settings > Wireless > VPN > Replace existing VPN dialog
+    DIALOG_VPN_REPLACE_EXISTING = 548;
+
+    // OPEN: Settings > Billing cycle > Edit billing cycle dates dialog
+    DIALOG_BILLING_CYCLE = 549;
+
+    // OPEN: Settings > Billing cycle > Edit data limit/warning dialog
+    DIALOG_BILLING_BYTE_LIMIT = 550;
+
+    // OPEN: Settings > Billing cycle > turn on data limit dialog
+    DIALOG_BILLING_CONFIRM_LIMIT = 551;
+
+    // OPEN: Settings > Service > Turn off notification access dialog
+    DIALOG_DISABLE_NOTIFICATION_ACCESS = 552;
+
+    // OPEN: Settings > Sound > Use personal sound for work profile dialog
+    DIALOG_UNIFY_SOUND_SETTINGS = 553;
+
+    // OPEN: Settings > Zen mode > Dialog warning about the zen access privileges being granted.
+    DIALOG_ZEN_ACCESS_GRANT = 554;
+
+    // OPEN: Settings > Zen mode > Dialog warning about the zen access privileges being revoked.
+    DIALOG_ZEN_ACCESS_REVOKE = 555;
+
+    // OPEN: Settings > Zen mode > Dialog that picks time for zen mode.
+    DIALOG_ZEN_TIMEPICKER = 556;
+
+    // OPEN: Settings > Apps > Dialog that informs user to allow service access for app.
+    DIALOG_SERVICE_ACCESS_WARNING = 557;
+
+    // OPEN: Settings > Apps > Dialog for app actions (such as force stop/clear data)
+    DIALOG_APP_INFO_ACTION = 558;
+
+    // OPEN: Settings > Storage > Dialog for forgetting a storage device
+    DIALOG_VOLUME_FORGET = 559;
+
+    // OPEN: Settings > Storage > Dialog for initializing a volume
+    DIALOG_VOLUME_INIT = 561;
+
+    // OPEN: Settings > Storage > Dialog for unmounting a volume
+    DIALOG_VOLUME_UNMOUNT = 562;
+
+    // OPEN: Settings > Storage > Dialog for renaming a volume
+    DIALOG_VOLUME_RENAME = 563;
+
+    // OPEN: Settings > Storage > Dialog for clear cache
+    DIALOG_STORAGE_CLEAR_CACHE = 564;
+
+    // OPEN: Settings > Storage > Dialog for system info
+    DIALOG_STORAGE_SYSTEM_INFO = 565;
+
+    // OPEN: Settings > Storage > Dialog for other info
+    DIALOG_STORAGE_OTHER_INFO = 566;
+
+    // OPEN: Settings > Storage > Dialog for user info
+    DIALOG_STORAGE_USER_INFO = 567;
+    // OPEN: Settings > Add fingerprint > Dialog when user touches fingerprint icon.
+    DIALOG_FINGERPRINT_ICON_TOUCH = 568;
+
+    // OPEN: Settings > Add fingerprint > Error dialog
+    DIALOG_FINGERPINT_ERROR = 569;
+
+    // OPEN: Settings > Fingerprint > Rename or delete dialog
+    DIALOG_FINGERPINT_EDIT = 570;
+
+    // OPEN: Settings > Fingerprint > Dialog for deleting last fingerprint
+    DIALOG_FINGERPINT_DELETE_LAST = 571;
+
+    // OPEN: SUW > Fingerprint > Dialog to confirm skip fingerprint setup entirely.
+    DIALOG_FINGERPRINT_SKIP_SETUP = 573;
+
+    // OPEN: Settings > Proxy Selector error dialog
+    DIALOG_PROXY_SELECTOR_ERROR = 574;
+
+    // OPEN: Settings > Wifi > P2P Settings > Disconnect dialog
+    DIALOG_WIFI_P2P_DISCONNECT = 575;
+
+    // OPEN: Settings > Wifi > P2P Settings > Cancel connection dialog
+    DIALOG_WIFI_P2P_CANCEL_CONNECT = 576;
+
+    // OPEN: Settings > Wifi > P2P Settings > Rename dialog
+    DIALOG_WIFI_P2P_RENAME = 577;
+
+    // OPEN: Settings > Wifi > P2P Settings > Forget group dialog
+    DIALOG_WIFI_P2P_DELETE_GROUP = 578;
+
+    // OPEN: Settings > APN > Restore default dialog
+    DIALOG_APN_RESTORE_DEFAULT = 579;
+
+    // OPEN: Settings > Encryption interstitial accessibility warning dialog
+    DIALOG_ENCRYPTION_INTERSTITIAL_ACCESSIBILITY = 581;
+
+    // OPEN: Settings > Acessibility > Enable accessiblity service dialog
+    DIALOG_ACCESSIBILITY_SERVICE_ENABLE = 583;
+
+    // OPEN: Settings > Acessibility > Disable accessiblity service dialog
+    DIALOG_ACCESSIBILITY_SERVICE_DISABLE = 584;
+
+    // OPEN: Settings > Account > Remove account dialog
+    DIALOG_ACCOUNT_SYNC_REMOVE = 585;
+
+    // OPEN: Settings > Account > Remove account failed dialog
+    DIALOG_ACCOUNT_SYNC_FAILED_REMOVAL = 586;
+
+    // OPEN: Settings > Account > Cannot do onetime sync dialog
+    DIALOG_ACCOUNT_SYNC_CANNOT_ONETIME_SYNC = 587;
+
+    // OPEN: Settings > Display > Night light > Set start time dialog
+    DIALOG_NIGHT_DISPLAY_SET_START_TIME = 588;
+
+    // OPEN: Settings > Display > Night light > Set end time dialog
+    DIALOG_NIGHT_DISPLAY_SET_END_TIME = 589;
+
+
+
+        // OPEN: Settings > User > Edit info dialog
+        DIALOG_USER_EDIT = 590;
+
+        // OPEN: Settings > User > Confirm remove dialog
+        DIALOG_USER_REMOVE = 591;
+
+        // OPEN: Settings > User > Enable calling dialog
+        DIALOG_USER_ENABLE_CALLING = 592;
+
+        // OPEN: Settings > User > Enable calling and sms dialog
+        DIALOG_USER_ENABLE_CALLING_AND_SMS = 593;
+
+        // OPEN: Settings > User > Cannot manage device message dialog
+        DIALOG_USER_CANNOT_MANAGE = 594;
+
+        // OPEN: Settings > User > Add user dialog
+        DIALOG_USER_ADD = 595;
+
+        // OPEN: Settings > User > Setup user dialog
+        DIALOG_USER_SETUP = 596;
+
+        // OPEN: Settings > User > Setup profile dialog
+        DIALOG_USER_SETUP_PROFILE = 597;
+
+        // OPEN: Settings > User > Choose user type dialog
+        DIALOG_USER_CHOOSE_TYPE = 598;
+
+        // OPEN: Settings > User > Need lockscreen dialog
+        DIALOG_USER_NEED_LOCKSCREEN = 599;
+
+        // OPEN: Settings > User > Confirm exit guest mode dialog
+        DIALOG_USER_CONFIRM_EXIT_GUEST = 600;
+
+        // OPEN: Settings > User > Edit user profile dialog
+        DIALOG_USER_EDIT_PROFILE = 601;
+
+
+    // OPEN: Settings > Wifi > Saved AP > Edit dialog
+    DIALOG_WIFI_SAVED_AP_EDIT = 602;
+
+    // OPEN: Settings > Wifi > Edit AP dialog
+    DIALOG_WIFI_AP_EDIT = 603;
+
+    // OPEN: Settings > Wifi > Write config to NFC dialog
+    DIALOG_WIFI_WRITE_NFC = 606;
+
+    // OPEN: Settings > Date > Date picker dialog
+    DIALOG_DATE_PICKER = 607;
+
+    // OPEN: Settings > Date > Time picker dialog
+    DIALOG_TIME_PICKER = 608;
+
+    // OPEN: Settings > Wireless > Manage wireless plan dialog
+    DIALOG_MANAGE_MOBILE_PLAN = 609;
+
+    // OPEN Settings > Bluetooth > Attempt to connect to device that shows dialog
+    BLUETOOTH_DIALOG_FRAGMENT = 613;
+
+    // OPEN: Settings > Security
+    // CATEGORY: SETTINGS
+    // OS: O
+    ENTERPRISE_PRIVACY_SETTINGS = 628;
+
+    // OPEN: Settings > System
+    SETTINGS_SYSTEM_CATEGORY = 744;
+
+    // OPEN: Settings > Storage
+    SETTINGS_STORAGE_CATEGORY = 745;
+
+    // OPEN: Settings > Network & Internet
+    SETTINGS_NETWORK_CATEGORY = 746;
+
+    // OPEN: Settings > Connected Device
+    SETTINGS_CONNECTED_DEVICE_CATEGORY = 747;
+
+    // OPEN: Settings > App & Notification
+    SETTINGS_APP_NOTIF_CATEGORY = 748;
+
+    // OPEN: Settings > System > Language & Region
+    SETTINGS_LANGUAGE_CATEGORY = 750;
+
+    // OPEN: Settings > System > Input & Gesture > Swipe to notification gesture
+    SETTINGS_GESTURE_SWIPE_TO_NOTIFICATION = 751;
+
+    // OPEN: Settings > System > Input & Gesture > Double tap power button gesture
+    SETTINGS_GESTURE_DOUBLE_TAP_POWER = 752;
+
+    // OPEN: Settings > System > Input & Gesture > Pick up gesture
+    SETTINGS_GESTURE_PICKUP = 753;
+
+    // OPEN: Settings > System > Input & Gesture > Double tap screen gesture
+    SETTINGS_GESTURE_DOUBLE_TAP_SCREEN = 754;
+
+    // OPEN: Settings > System > Input & Gesture > Double twist gesture
+    SETTINGS_GESTURE_DOUBLE_TWIST = 755;
+
+    // OPEN: Settings > Apps > Default Apps > Default browser
+    DEFAULT_BROWSER_PICKER = 785;
+    // OPEN: Settings > Apps > Default Apps > Default emergency app
+    DEFAULT_EMERGENCY_APP_PICKER = 786;
+
+    // OPEN: Settings > Apps > Default Apps > Default home
+    DEFAULT_HOME_PICKER = 787;
+
+    // OPEN: Settings > Apps > Default Apps > Default phone
+    DEFAULT_PHONE_PICKER = 788;
+
+    // OPEN: Settings > Apps > Default Apps > Default sms
+    DEFAULT_SMS_PICKER = 789;
+
+    // OPEN: Settings > Apps > Default Apps > Warning dialog to confirm selection
+    DEFAULT_APP_PICKER_CONFIRMATION_DIALOG = 791;
+
+    // OPEN: Settings > Apps > Default Apps > Default autofill app
+    DEFAULT_AUTOFILL_PICKER = 792;
+
+    // OPEN: Settings > Apps > Gear > Special Access > Install other apps
+    // CATEGORY: SETTINGS
+    // OS: 8.0
+    MANAGE_EXTERNAL_SOURCES = 808;
+
+    // Logs that the user has edited the picture-in-picture settings.
+    // CATEGORY: SETTINGS
+    SETTINGS_MANAGE_PICTURE_IN_PICTURE = 812;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Select to Speak
+    // ACTION: Select to Speak configuration is chosen
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY_TOGGLE_SELECT_TO_SPEAK = 817;
+
+    // OPEN: Settings > System > Backup
+    // CATEGORY: SETTINGS
+    // OS: O
+    BACKUP_SETTINGS = 818;
+
+    // OPEN: Settings > Storage > Games
+    // CATEGORY: SETTINGS
+    // OS: O
+    APPLICATIONS_STORAGE_GAMES = 838;
+
+    // OPEN: Settings > Storage > Audio and Music
+    // CATEGORY: SETTINGS
+    // OS: O
+    APPLICATIONS_STORAGE_MUSIC = 839;
+
+    // ACTION: Settings > Storage > Free Up Space to launch Deletion Helper
+    // CATEGORY: SETTINGS
+    // OS: O
+    STORAGE_FREE_UP_SPACE_NOW = 840;
+
+    // ACTION: Settings > Storage > Files to open the File Manager
+    // CATEGORY: SETTINGS
+    // OS: O
+    STORAGE_FILES = 841;
+
+    // OPEN: Settings > Apps > Default Apps > Assist >  Default assist
+    DEFAULT_ASSIST_PICKER = 843;
+
+    // OPEN: Settings > Apps > Default Apps > Assist >  Default voice input
+    DEFAULT_VOICE_INPUT_PICKER = 844;
+
+    // OPEN: Settings > Storage > [Profile]
+    SETTINGS_STORAGE_PROFILE = 845;
+
+    // OPEN: Settings > Security & screen lock -> Encryption & crendentials
+    // CATEGORY: SETTINGS
+    // OS: O
+    ENCRYPTION_AND_CREDENTIAL = 846;
+
+    // OPEN: Settings > Wi-Fi > Network Details (click on Access Point)
+    // CATEGORY: SETTINGS
+    // OS: O
+    WIFI_NETWORK_DETAILS = 849;
+
+    // OPEN: Settings > Wi-Fi > Wifi Preferences -> Advanced -> Network Scorer
+    // CATEGORY: SETTINGS
+    // OS: O
+    SETTINGS_NETWORK_SCORER = 861;
+
+    // OPEN: Settings > About device > Model > Hardware info dialog
+    DIALOG_SETTINGS_HARDWARE_INFO = 862;
+
+    // OPEN: Settings > Security & screen lock -> Lock screen preferences
+    // CATEGORY: SETTINGS
+    SETTINGS_LOCK_SCREEN_PREFERENCES = 882;
+
+
+    // OPEN: Settings -> Display -> When in VR Mode
+    VR_DISPLAY_PREFERENCE = 921;
+
+    // OPEN: Settings > Accessibility > Magnification
+    // CATEGORY: SETTINGS
+    // OS: O
+    ACCESSIBILITY_SCREEN_MAGNIFICATION_SETTINGS = 922;
+
+    // OPEN: Settings -> System -> Reset options
+    RESET_DASHBOARD = 924;
+
+     // OPEN: Settings > Security > Nexus Imprint > [Fingerprint] > Delete
+    // CATEGORY: SETTINGS
+    // OS: O
+    FINGERPRINT_REMOVE_SIDECAR = 934;
+
+    // OPEN: Settings > Storage > Movies & TV
+    // CATEGORY: SETTINGS
+    // OS: O
+    APPLICATIONS_STORAGE_MOVIES = 935;
+
+    // OPEN: Settings > Security > Managed Device Info > Apps installed
+    // CATEGORY: SETTINGS
+    // OS: O
+    ENTERPRISE_PRIVACY_INSTALLED_APPS = 938;
+
+    // OPEN: Settings > Security > Managed Device Info > nnn permissions
+    // CATEGORY: SETTINGS
+    // OS: O
+    ENTERPRISE_PRIVACY_PERMISSIONS = 939;
+
+
+    // OPEN: Settings > Security > Managed Device Info > Default apps
+    // CATEGORY: SETTINGS
+    // OS: O
+    ENTERPRISE_PRIVACY_DEFAULT_APPS = 940;
+
+    // OPEN: Choose screen lock dialog in Settings
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    SETTINGS_CHOOSE_LOCK_DIALOG = 990;
+
+    // OPEN: Settings > System > Languages & input > Assist gesture
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    SETTINGS_ASSIST_GESTURE = 996;
+
     // OPEN: Settings > Connected Devices > Bluetooth > (click on details link for a paired device)
     BLUETOOTH_DEVICE_DETAILS = 1009;
 
+    // OPEN: Settings > credential pages - prompt for key guard configuration confirmation
+    CONFIGURE_KEYGUARD_DIALOG = 1010;
+
+    // OPEN: Settings > Network > Tether > Wi-Fi hotspot
+    WIFI_TETHER_SETTINGS = 1014;
+
+    // OPEN: Settings->Connected Devices->Bluetooth->(click on details link for a paired device)
+    // -> Edit name button.
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    DIALOG_BLUETOOTH_PAIRED_DEVICE_RENAME = 1015;
+
     // OPEN: Settings > Connected devices > Bluetooth > Pair new device
+    // CATEGORY: SETTINGS
+    // OS: O DR
     BLUETOOTH_PAIRING = 1018;
 
+    // OPEN: Settings->Connected Devices->Bluetooth->(click on details link for a paired device)
+    // -> Forget button.
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    DIALOG_BLUETOOTH_PAIRED_DEVICE_FORGET = 1031;
+
+    // OPEN: Settings > Storage > Photos & Videos
+    // CATEGORY: SETTINGS
+    // OS: O MR
+    APPLICATIONS_STORAGE_PHOTOS = 1092;
+
+    // OPEN: Settings > Display > Colors
+    // CATEGORY: SETTINGS
+    // OS: O MR
+    COLOR_MODE_SETTINGS = 1143;
+
+    // OPEN: Settings > Developer Options > Experiment dashboard
+    // CATEGORY: SETTINGS
+    SETTINGS_FEATURE_FLAGS_DASHBOARD = 1217;
+
+    // OPEN: Settings > Notifications > [App] > Topic Notifications
+    // CATEGORY: SETTINGS
+    // OS: P
+    NOTIFICATION_CHANNEL_GROUP = 1218;
+
+    // OPEN: Settings > Developer options > Enable > Info dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_ENABLE_DEVELOPMENT_OPTIONS = 1219;
+
+    // OPEN: Settings > Developer options > OEM unlocking > Info dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_ENABLE_OEM_UNLOCKING = 1220;
+
+    // OPEN: Settings > Developer options > USB debugging > Info dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_ENABLE_ADB = 1222;
+
+    // OPEN: Settings > Security > Nexus Imprint > [Fingerprint]
+    // CATEGORY: SETTINGS
+    // OS: P
+    FINGERPRINT_AUTHENTICATE_SIDECAR = 1221;
+
+    // OPEN: Settings > Developer options > Revoke USB debugging authorizations > Info dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_CLEAR_ADB_KEYS = 1223;
+
+    // Open: Settings > Developer options > Quick setting tile config
+    // CATEGORY: SETTINGS
+    // OS: P
+    DEVELOPMENT_QS_TILE_CONFIG = 1224;
+
+    // OPEN: Settings > Developer options > Store logger data persistently on device > Info dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_LOG_PERSIST = 1225;
+
+    // OPEN: Settings > Network & Internet > Mobile network > Wi-Fi calling
+    // CATEGORY: SETTINGS
+    // OS: P
+    WIFI_CALLING_FOR_SUB = 1230;
+
+    // Open: Settings > Dev options > Oem unlock > lock it > warning dialog.
+    // OS: P
+    DIALOG_OEM_LOCK_INFO = 1238;
+
+    // Open: Settings > System > About phone > IMEI
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_IMEI_INFO = 1240;
+
+    // OPEN: Settings > System > About Phone > Sim status
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_SIM_STATUS = 1246;
+
+    // OPEN: Settings > System > About Phone > Android Version
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_FIRMWARE_VERSION = 1247;
+
+    // OPEN: Settings > Battery(version 2)
+    // CATEGORY: SETTINGS
+    // OS: P
+    FUELGAUGE_POWER_USAGE_SUMMARY_V2 = 1263;
+
+    // OPEN: Settings > Connected devices > Connection preferences
+    // CATEGORY: SETTINGS
+    // OS: P
+    CONNECTION_DEVICE_ADVANCED = 1264;
+
+    // OPEN: Settings > Security > Screen lock gear icon
+    // CATEGORY: SETTINGS
+    // OS: P
+    SCREEN_LOCK_SETTINGS = 1265;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Delete rule (trash can icon)
+    // CATEGORY: SETTINGS
+    // OS: P
+    NOTIFICATION_ZEN_MODE_DELETE_RULE_DIALOG = 1266;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Add rule > Event/Time
+    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Select rule ("Event") > Rule name
+    // CATEGORY: SETTINGS
+    // OS: P
+    NOTIFICATION_ZEN_MODE_RULE_NAME_DIALOG = 1269;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Add rule
+    // CATEGORY: SETTINGS
+    // OS: P
+    NOTIFICATION_ZEN_MODE_RULE_SELECTION_DIALOG = 1270;
+
+    // OPEN: Settings > Battery > Smart Battery
+    // CATEGORY: SETTINGS
+    // OS: P
+    FUELGAUGE_SMART_BATTERY = 1281;
+
+    // OPEN: Settings > Battery > Smart Battery > Restricted apps
+    // CATEGORY: SETTINGS
+    // OS: P
+    FUELGAUGE_RESTRICTED_APP_DETAILS = 1285;
+
+    // OPEN: Settings > Sound & notification > Do Not Disturb > Turn on now
+    // CATEGORY: SETTINGS
+    // OS: P
+    NOTIFICATION_ZEN_MODE_ENABLE_DIALOG = 1286;
+
+    // OPEN: Settings->Connected Devices->USB->(click on details link)
+    // CATEGORY: SETTINGS
+    // OS: P
+    USB_DEVICE_DETAILS = 1291;
+
+    // OPEN: Settings > Accessibility > Vibration
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACCESSIBILITY_VIBRATION = 1292;
+
+    // OPEN: Settings > Accessibility > Vibration > Notification vibration
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACCESSIBILITY_VIBRATION_NOTIFICATION = 1293;
+
+    // OPEN: Settings > Accessibility > Vibration > Touch vibration
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACCESSIBILITY_VIBRATION_TOUCH = 1294;
+
+    // OPEN: Settings->Developer Options->Default USB
+    // CATEGORY: SETTINGS
+    // OS: P
+    USB_DEFAULT = 1312;
+
+    // OPEN: Settings > Battery > Battery tip > Battery tip Dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    FUELGAUGE_BATTERY_TIP_DIALOG = 1323;
+
+    // OPEN: DND Settings > What to block
+    // OS: P
+    ZEN_WHAT_TO_BLOCK = 1339;
+
+    // OPEN: Settings > Sounds > Do Not Disturb > Duration
+    // CATEGORY: SETTINGS
+    // OS: P
+    NOTIFICATION_ZEN_MODE_DURATION_DIALOG = 1341;
+
+    // OPEN: Settings > Date & time > Select time zone -> Region
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_ZONE_PICKER_REGION = 1355;
+
+    // OPEN: Settings > Date & time > Select time zone -> Time Zone
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_ZONE_PICKER_TIME_ZONE = 1356;
+    // OPEN: Settings > Date & time > Select time zone -> Select UTC Offset
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_ZONE_PICKER_FIXED_OFFSET = 1357;
+
+    // OPEN: Settings > Gestures > Prevent Ringing
+    // OS: P
+    SETTINGS_PREVENT_RINGING = 1360;
+
+    // Settings > Condition > Device muted
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_CONDITION_DEVICE_MUTED = 1368;
+
+    // Settings > Condition > Device vibrate
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_CONDITION_DEVICE_VIBRATE = 1369;
+
+    // OPEN: Settings > Connected devices > previously connected devices
+    // CATEGORY: SETTINGS
+    // OS: P
+    PREVIOUSLY_CONNECTED_DEVICES = 1370;
+
+    // OPEN: Settings > Network & Internet > Wi-Fi > Wi-Fi Preferences > Turn on Wi-Fi automatically
+    //       note: Wifi Scanning must be off for this dialog to show
+    // CATEGORY: SETTINGS
+    // OS: P
+    WIFI_SCANNING_NEEDED_DIALOG = 1373;
+
+    // OPEN: Settings > System > Gestures > Swipe up gesture
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_GESTURE_SWIPE_UP = 1374;
+
+    // OPEN: Settings > Storage > Dialog to format a storage volume
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_VOLUME_FORMAT = 1375;
+
+    // OPEN: DND onboarding activity
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_ZEN_ONBOARDING = 1380;
+
+    // OPEN: Settings > Display > Auto brightness
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_AUTO_BRIGHTNESS = 1381;
+
+     // OPEN: Settings > Connected Devices > Bluetooth
+    // CATEGORY: SETTINGS
+    // OS: P
+    BLUETOOTH_FRAGMENT = 1390;
+
+    // Screen: DND Settings > Notifications
+    // OS: P
+    SETTINGS_ZEN_NOTIFICATIONS = 1400;
+
+    // An event category for slices.
+    // OPEN: Slice became visible.
+    // CLOSE: Slice became invisible.
+    // ACTION: Slice was tapped.
+    SLICE = 1401;
+
+    // OPEN: Settings -> Developer Options -> Disable Bluetooth A2DP hardware
+    // offload
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_BLUETOOTH_DISABLE_A2DP_HW_OFFLOAD = 1441;
+
     // OPEN: Settings homepage
     SETTINGS_HOMEPAGE = 1502;
 
+    // OPEN: Settings > Create shortcut(widget)
+    // CATEGORY: SETTINGS
+    // OS: Q
+    SETTINGS_CREATE_SHORTCUT = 1503;
+
+    // OPEN: Face Enroll introduction
+    // CATEGORY: SETTINGS
+    // OS: Q
+    FACE_ENROLL_INTRO = 1506;
+
+    // OPEN: Face Enroll introduction
+    // CATEGORY: SETTINGS
+    // OS: Q
+    FACE_ENROLL_ENROLLING = 1507;
+
+    // OPEN: Face Enroll introduction
+    // CATEGORY: SETTINGS
+    // OS: Q
+    FACE_ENROLL_FINISHED = 1508;
+
+    // OPEN: Face Enroll sidecar
+    // CATEGORY: SETTINGS
+    // OS: Q
+    FACE_ENROLL_SIDECAR = 1509;
+
+    // OPEN: Settings > Add face > Error dialog
+    // OS: Q
+    DIALOG_FACE_ERROR = 1510;
+
+    // OPEN: Settings > Security > Face
+    // CATEGORY: SETTINGS
+    // OS: Q
+    FACE = 1511;
+
+   // OPEN: Settings > Acessibility > HearingAid pairing instructions dialog
+    // CATEGORY: SETTINGS
+    // OS: Q
+    DIALOG_ACCESSIBILITY_HEARINGAID = 1512;
+
+    // OPEN: Settings > Add face
+    // OS: Q
+    FACE_ENROLL_PREVIEW = 1554;
+
+    // OPEN: Settings > Network & Internet > Wi-Fi > Add network
+    // CATEGORY: SETTINGS
+    // OS: Q
+    SETTINGS_WIFI_ADD_NETWORK = 1556;
+
+    // OPEN: Settings > System > Input & Gesture > Reach up gesture
+    // OS: Q
+    SETTINGS_GESTURE_WAKE_LOCK_SCREEN = 1557;
+
     // OPEN: Settings > System > Input & Gesture > Wake screen
     SETTINGS_GESTURE_WAKE_SCREEN = 1570;
 
@@ -80,6 +2079,19 @@
     // OPEN: Settings > Privacy
     TOP_LEVEL_PRIVACY = 1587;
 
+    // OPEN: Settings > Sound & notification > Do Not Disturb > See all exceptions >
+    // Allow apps to override
+    // CATEGORY: SETTINGS
+    // OS: Q
+    NOTIFICATION_ZEN_MODE_OVERRIDING_APPS = 1588;
+
+
+    // OPEN: Settings > Sound & notification > Do Not Disturb > See all exceptions >
+    // Allow apps to override > Choose app
+    // CATEGORY: SETTINGS
+    // OS: Q
+    NOTIFICATION_ZEN_MODE_OVERRIDING_APP = 1589;
+
     // OPEN: Settings > Developer options > Disable > Info dialog
     DIALOG_DISABLE_DEVELOPMENT_OPTIONS = 1591;
 
@@ -91,4 +2103,76 @@
 
     // OPEN: Settings > Apps & Notifications -> Special app access -> Financial Apps Sms Access
     SETTINGS_FINANCIAL_APPS_SMS_ACCESS = 1597;
+
+
+
+    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+    // > Do Not Disturb behavior
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_RULE_SETTINGS = 1604;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+    // > Do Not Disturb behavior > Custom
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_RULE_SOUND_SETTINGS = 1605;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_RULE_DEFAULT_SETTINGS = 1606;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+    // > Notification restriction
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_RULE_NOTIFICATION_RESTRICTIONS = 1608;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+    // > Notification restriction > Custom
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_RULE_VIS_EFFECTS = 1609;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+    // > Notification restriction > Custom > Allow messages
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_RULE_MESSAGES = 1610;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+    // > Notification restriction > Custom > Allow calls
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_RULE_CALLS = 1611;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Click footer link if custom settings applied
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_SETTINGS_DIALOG = 1612;
+
+    // OPEN: Settings > Developer Options > Game Update Packages
+    // CATEGORY: SETTINGS
+    // OS: Q
+    SETTINGS_GUP_DASHBOARD = 1613;
+
+    // OPEN: Settings > Accessibility > Vibration > Ring vibration
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ACCESSIBILITY_VIBRATION_RING = 1620;
+
+    // OPEN: Settings > System > Input & Gesture > Skip songs
+    SETTINGS_GESTURE_SKIP = 1624;
+
+    // OPEN: Settings > System > Input & Gesture > Silence alerts
+    SETTINGS_GESTURE_SILENCE = 1625;
+
+    // OPEN: Settings > System > Input & Gesture > Tap to check
+    SETTINGS_GESTURE_TAP_SCREEN = 1626;
 }
diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto
index d0c9226..76c240e 100644
--- a/core/proto/android/bluetooth/enums.proto
+++ b/core/proto/android/bluetooth/enums.proto
@@ -41,3 +41,18 @@
     ENABLE_DISABLE_REASON_USER_SWITCH = 8;
     ENABLE_DISABLE_REASON_RESTORE_USER_SETTING = 9;
 }
+
+enum DirectionEnum {
+    DIRECTION_UNKNOWN = 0;
+    DIRECTION_OUTGOING = 1;
+    DIRECTION_INCOMING = 2;
+}
+
+// First item is the default value, other values follow Bluetooth spec definition
+enum LinkTypeEnum {
+    // Link type is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
+    LINK_TYPE_UNKNOWN = 0xFFF;
+    LINK_TYPE_SCO = 0x00;
+    LINK_TYPE_ACL = 0x01;
+    LINK_TYPE_ESCO = 0x02;
+}
diff --git a/core/proto/android/bluetooth/hci/enums.proto b/core/proto/android/bluetooth/hci/enums.proto
new file mode 100644
index 0000000..e1d96bb
--- /dev/null
+++ b/core/proto/android/bluetooth/hci/enums.proto
@@ -0,0 +1,519 @@
+/*
+ * 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.hci;
+
+option java_outer_classname = "BluetoothHciProtoEnums";
+option java_multiple_files = true;
+
+// HCI command opcodes (OCF+OGF) from Bluetooth 5.0 specification Vol 2, Part E, Section 7
+// Original definition: system/bt/stack/include/hcidefs.h
+enum CommandEnum {
+    // Opcode is at most 2 bytes (0xFFFF), thus 0xFFFFF must not be a valid value
+    CMD_UNKNOWN = 0xFFFFF;
+    // Link control commands 0x0400
+    CMD_INQUIRY = 0x0401;
+    CMD_INQUIRY_CANCEL = 0x0402;
+    CMD_PERIODIC_INQUIRY_MODE = 0x0403;
+    CMD_EXIT_PERIODIC_INQUIRY_MODE = 0x0404;
+    CMD_CREATE_CONNECTION = 0x0405;
+    CMD_DISCONNECT = 0x0406;
+    CMD_ADD_SCO_CONNECTION = 0x0407; // Deprecated since Bluetooth 1.2
+    CMD_CREATE_CONNECTION_CANCEL = 0x0408;
+    CMD_ACCEPT_CONNECTION_REQUEST = 0x0409;
+    CMD_REJECT_CONNECTION_REQUEST = 0x040A;
+    CMD_LINK_KEY_REQUEST_REPLY = 0x040B;
+    CMD_LINK_KEY_REQUEST_NEG_REPLY = 0x040C;
+    CMD_PIN_CODE_REQUEST_REPLY = 0x040D;
+    CMD_PIN_CODE_REQUEST_NEG_REPLY = 0x040E;
+    CMD_CHANGE_CONN_PACKET_TYPE = 0x040F;
+    CMD_AUTHENTICATION_REQUESTED = 0x0411;
+    CMD_SET_CONN_ENCRYPTION = 0x0413;
+    CMD_CHANGE_CONN_LINK_KEY = 0x0415;
+    CMD_MASTER_LINK_KEY = 0x0417;
+    CMD_RMT_NAME_REQUEST = 0x0419;
+    CMD_RMT_NAME_REQUEST_CANCEL = 0x041A;
+    CMD_READ_RMT_FEATURES = 0x041B;
+    CMD_READ_RMT_EXT_FEATURES = 0x041C;
+    CMD_READ_RMT_VERSION_INFO = 0x041D;
+    CMD_READ_RMT_CLOCK_OFFSET = 0x041F;
+    CMD_READ_LMP_HANDLE = 0x0420;
+    CMD_SETUP_ESCO_CONNECTION = 0x0428;
+    CMD_ACCEPT_ESCO_CONNECTION = 0x0429;
+    CMD_REJECT_ESCO_CONNECTION = 0x042A;
+    CMD_IO_CAPABILITY_REQUEST_REPLY = 0x042B;
+    CMD_USER_CONF_REQUEST_REPLY = 0x042C;
+    CMD_USER_CONF_VALUE_NEG_REPLY = 0x042D;
+    CMD_USER_PASSKEY_REQ_REPLY = 0x042E;
+    CMD_USER_PASSKEY_REQ_NEG_REPLY = 0x042F;
+    CMD_REM_OOB_DATA_REQ_REPLY = 0x0430;
+    CMD_REM_OOB_DATA_REQ_NEG_REPLY = 0x0433;
+    CMD_IO_CAP_REQ_NEG_REPLY = 0x0434;
+    // BEGIN: AMP commands (not used in system/bt)
+    CMD_CREATE_PHYSICAL_LINK = 0x0435;
+    CMD_ACCEPT_PHYSICAL_LINK = 0x0436;
+    CMD_DISCONNECT_PHYSICAL_LINK = 0x0437;
+    CMD_CREATE_LOGICAL_LINK = 0x0438;
+    CMD_ACCEPT_LOGICAL_LINK = 0x0439;
+    CMD_DISCONNECT_LOGICAL_LINK = 0x043A;
+    CMD_LOGICAL_LINK_CANCEL = 0x043B;
+    CMD_FLOW_SPEC_MODIFY = 0x043C;
+    // END: AMP commands
+    CMD_ENH_SETUP_ESCO_CONNECTION = 0x043D;
+    CMD_ENH_ACCEPT_ESCO_CONNECTION = 0x043E;
+    CMD_TRUNCATED_PAGE = 0x043F;
+    CMD_TRUNCATED_PAGE_CANCEL = 0x0440;
+    CMD_SET_CLB = 0x0441;
+    CMD_RECEIVE_CLB = 0x0442;
+    CMD_START_SYNC_TRAIN = 0x0443;
+    CMD_RECEIVE_SYNC_TRAIN = 0x0444;
+    CMD_REM_OOB_EXTENDED_DATA_REQ_REPLY = 0x0445; // Not currently used in system/bt
+    // Link policy commands 0x0800
+    CMD_HOLD_MODE = 0x0801;
+    CMD_SNIFF_MODE = 0x0803;
+    CMD_EXIT_SNIFF_MODE = 0x0804;
+    CMD_PARK_MODE = 0x0805;
+    CMD_EXIT_PARK_MODE = 0x0806;
+    CMD_QOS_SETUP = 0x0807;
+    CMD_ROLE_DISCOVERY = 0x0809;
+    CMD_SWITCH_ROLE = 0x080B;
+    CMD_READ_POLICY_SETTINGS = 0x080C;
+    CMD_WRITE_POLICY_SETTINGS = 0x080D;
+    CMD_READ_DEF_POLICY_SETTINGS = 0x080E;
+    CMD_WRITE_DEF_POLICY_SETTINGS = 0x080F;
+    CMD_FLOW_SPECIFICATION = 0x0810;
+    CMD_SNIFF_SUB_RATE = 0x0811;
+    // Host controller baseband commands 0x0C00
+    CMD_SET_EVENT_MASK = 0x0C01;
+    CMD_RESET = 0x0C03;
+    CMD_SET_EVENT_FILTER = 0x0C05;
+    CMD_FLUSH = 0x0C08;
+    CMD_READ_PIN_TYPE = 0x0C09;
+    CMD_WRITE_PIN_TYPE = 0x0C0A;
+    CMD_CREATE_NEW_UNIT_KEY = 0x0C0B;
+    CMD_GET_MWS_TRANS_LAYER_CFG = 0x0C0C; // Deprecated (not used in spec)
+    CMD_READ_STORED_LINK_KEY = 0x0C0D;
+    CMD_WRITE_STORED_LINK_KEY = 0x0C11;
+    CMD_DELETE_STORED_LINK_KEY = 0x0C12;
+    CMD_CHANGE_LOCAL_NAME = 0x0C13;
+    CMD_READ_LOCAL_NAME = 0x0C14;
+    CMD_READ_CONN_ACCEPT_TOUT = 0x0C15;
+    CMD_WRITE_CONN_ACCEPT_TOUT = 0x0C16;
+    CMD_READ_PAGE_TOUT = 0x0C17;
+    CMD_WRITE_PAGE_TOUT = 0x0C18;
+    CMD_READ_SCAN_ENABLE = 0x0C19;
+    CMD_WRITE_SCAN_ENABLE = 0x0C1A;
+    CMD_READ_PAGESCAN_CFG = 0x0C1B;
+    CMD_WRITE_PAGESCAN_CFG = 0x0C1C;
+    CMD_READ_INQUIRYSCAN_CFG = 0x0C1D;
+    CMD_WRITE_INQUIRYSCAN_CFG = 0x0C1E;
+    CMD_READ_AUTHENTICATION_ENABLE = 0x0C1F;
+    CMD_WRITE_AUTHENTICATION_ENABLE = 0x0C20;
+    CMD_READ_ENCRYPTION_MODE = 0x0C21; // Deprecated
+    CMD_WRITE_ENCRYPTION_MODE = 0x0C22; // Deprecated
+    CMD_READ_CLASS_OF_DEVICE = 0x0C23;
+    CMD_WRITE_CLASS_OF_DEVICE = 0x0C24;
+    CMD_READ_VOICE_SETTINGS = 0x0C25;
+    CMD_WRITE_VOICE_SETTINGS = 0x0C26;
+    CMD_READ_AUTOMATIC_FLUSH_TIMEOUT = 0x0C27;
+    CMD_WRITE_AUTOMATIC_FLUSH_TIMEOUT = 0x0C28;
+    CMD_READ_NUM_BCAST_REXMITS = 0x0C29;
+    CMD_WRITE_NUM_BCAST_REXMITS = 0x0C2A;
+    CMD_READ_HOLD_MODE_ACTIVITY = 0x0C2B;
+    CMD_WRITE_HOLD_MODE_ACTIVITY = 0x0C2C;
+    CMD_READ_TRANSMIT_POWER_LEVEL = 0x0C2D;
+    CMD_READ_SCO_FLOW_CTRL_ENABLE = 0x0C2E;
+    CMD_WRITE_SCO_FLOW_CTRL_ENABLE = 0x0C2F;
+    CMD_SET_HC_TO_HOST_FLOW_CTRL = 0x0C31;
+    CMD_HOST_BUFFER_SIZE = 0x0C33;
+    CMD_HOST_NUM_PACKETS_DONE = 0x0C35;
+    CMD_READ_LINK_SUPER_TOUT = 0x0C36;
+    CMD_WRITE_LINK_SUPER_TOUT = 0x0C37;
+    CMD_READ_NUM_SUPPORTED_IAC = 0x0C38;
+    CMD_READ_CURRENT_IAC_LAP = 0x0C39;
+    CMD_WRITE_CURRENT_IAC_LAP = 0x0C3A;
+    CMD_READ_PAGESCAN_PERIOD_MODE = 0x0C3B; // Deprecated
+    CMD_WRITE_PAGESCAN_PERIOD_MODE = 0x0C3C; // Deprecated
+    CMD_READ_PAGESCAN_MODE = 0x0C3D; // Deprecated
+    CMD_WRITE_PAGESCAN_MODE = 0x0C3E; // Deprecated
+    CMD_SET_AFH_CHANNELS = 0x0C3F;
+    CMD_READ_INQSCAN_TYPE = 0x0C42;
+    CMD_WRITE_INQSCAN_TYPE = 0x0C43;
+    CMD_READ_INQUIRY_MODE = 0x0C44;
+    CMD_WRITE_INQUIRY_MODE = 0x0C45;
+    CMD_READ_PAGESCAN_TYPE = 0x0C46;
+    CMD_WRITE_PAGESCAN_TYPE = 0x0C47;
+    CMD_READ_AFH_ASSESSMENT_MODE = 0x0C48;
+    CMD_WRITE_AFH_ASSESSMENT_MODE = 0x0C49;
+    CMD_READ_EXT_INQ_RESPONSE = 0x0C51;
+    CMD_WRITE_EXT_INQ_RESPONSE = 0x0C52;
+    CMD_REFRESH_ENCRYPTION_KEY = 0x0C53;
+    CMD_READ_SIMPLE_PAIRING_MODE = 0x0C55;
+    CMD_WRITE_SIMPLE_PAIRING_MODE = 0x0C56;
+    CMD_READ_LOCAL_OOB_DATA = 0x0C57;
+    CMD_READ_INQ_TX_POWER_LEVEL = 0x0C58;
+    CMD_WRITE_INQ_TX_POWER_LEVEL = 0x0C59;
+    CMD_READ_ERRONEOUS_DATA_RPT = 0x0C5A;
+    CMD_WRITE_ERRONEOUS_DATA_RPT = 0x0C5B;
+    CMD_ENHANCED_FLUSH = 0x0C5F;
+    CMD_SEND_KEYPRESS_NOTIF = 0x0C60;
+    CMD_READ_LOGICAL_LINK_ACCEPT_TIMEOUT = 0x0C61;
+    CMD_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT = 0x0C62;
+    CMD_SET_EVENT_MASK_PAGE_2 = 0x0C63;
+    CMD_READ_LOCATION_DATA = 0x0C64;
+    CMD_WRITE_LOCATION_DATA = 0x0C65;
+    CMD_READ_FLOW_CONTROL_MODE = 0x0C66;
+    CMD_WRITE_FLOW_CONTROL_MODE = 0x0C67;
+    CMD_READ_ENHANCED_TX_PWR_LEVEL = 0x0C68; // Not currently used in system/bt
+    CMD_READ_BE_FLUSH_TOUT = 0x0C69;
+    CMD_WRITE_BE_FLUSH_TOUT = 0x0C6A;
+    CMD_SHORT_RANGE_MODE = 0x0C6B;
+    CMD_READ_BLE_HOST_SUPPORT = 0x0C6C;
+    CMD_WRITE_BLE_HOST_SUPPORT = 0x0C6D;
+    CMD_SET_MWS_CHANNEL_PARAMETERS = 0x0C6E;
+    CMD_SET_EXTERNAL_FRAME_CONFIGURATION = 0x0C6F;
+    CMD_SET_MWS_SIGNALING = 0x0C70;
+    CMD_SET_MWS_TRANSPORT_LAYER = 0x0C71;
+    CMD_SET_MWS_SCAN_FREQUENCY_TABLE = 0x0C72;
+    CMD_SET_MWS_PATTERN_CONFIGURATION = 0x0C73;
+    CMD_SET_RESERVED_LT_ADDR = 0x0C74;
+    CMD_DELETE_RESERVED_LT_ADDR = 0x0C75;
+    CMD_WRITE_CLB_DATA = 0x0C76;
+    CMD_READ_SYNC_TRAIN_PARAM = 0x0C77;
+    CMD_WRITE_SYNC_TRAIN_PARAM = 0x0C78;
+    CMD_READ_SECURE_CONNS_SUPPORT = 0x0C79;
+    CMD_WRITE_SECURE_CONNS_SUPPORT = 0x0C7A;
+    CMD_READ_AUTHED_PAYLOAD_TIMEOUT = 0x0C7B; // Not currently used in system/bt
+    CMD_WRITE_AUTHED_PAYLOAD_TIMEOUT = 0x0C7C; // Not currently used in system/bt
+    CMD_READ_LOCAL_OOB_EXTENDED_DATA = 0x0C7D; // Not currently used in system/bt
+    CMD_READ_EXTENDED_PAGE_TIMEOUT = 0x0C7E; // Not currently used in system/bt
+    CMD_WRITE_EXTENDED_PAGE_TIMEOUT = 0x0C7F; // Not currently used in system/bt
+    CMD_READ_EXTENDED_INQUIRY_LENGTH = 0x0C80; // Not currently used in system/bt
+    CMD_WRITE_EXTENDED_INQUIRY_LENGTH = 0x0C81; // Not currently used in system/bt
+    // Informational parameter commands 0x1000
+    CMD_READ_LOCAL_VERSION_INFO = 0x1001;
+    CMD_READ_LOCAL_SUPPORTED_CMDS = 0x1002;
+    CMD_READ_LOCAL_FEATURES = 0x1003;
+    CMD_READ_LOCAL_EXT_FEATURES = 0x1004;
+    CMD_READ_BUFFER_SIZE = 0x1005;
+    CMD_READ_COUNTRY_CODE = 0x1007; // Deprecated
+    CMD_READ_BD_ADDR = 0x1009;
+    CMD_READ_DATA_BLOCK_SIZE = 0x100A;
+    CMD_READ_LOCAL_SUPPORTED_CODECS = 0x100B;
+    // Status parameter commands 0x1400
+    CMD_READ_FAILED_CONTACT_COUNTER = 0x1401;
+    CMD_RESET_FAILED_CONTACT_COUNTER = 0x1402;
+    CMD_GET_LINK_QUALITY = 0x1403;
+    CMD_READ_RSSI = 0x1405;
+    CMD_READ_AFH_CH_MAP = 0x1406;
+    CMD_READ_CLOCK = 0x1407;
+    CMD_READ_ENCR_KEY_SIZE = 0x1408;
+    CMD_READ_LOCAL_AMP_INFO = 0x1409;
+    CMD_READ_LOCAL_AMP_ASSOC = 0x140A;
+    CMD_WRITE_REMOTE_AMP_ASSOC = 0x140B;
+    CMD_GET_MWS_TRANSPORT_CFG = 0x140C; // Not currently used in system/bt
+    CMD_SET_TRIGGERED_CLK_CAPTURE = 0x140D; // Not currently used in system/bt
+    // Testing commands 0x1800
+    CMD_READ_LOOPBACK_MODE = 0x1801;
+    CMD_WRITE_LOOPBACK_MODE = 0x1802;
+    CMD_ENABLE_DEV_UNDER_TEST_MODE = 0x1803;
+    CMD_WRITE_SIMP_PAIR_DEBUG_MODE = 0x1804;
+    CMD_ENABLE_AMP_RCVR_REPORTS = 0x1807;
+    CMD_AMP_TEST_END = 0x1808;
+    CMD_AMP_TEST = 0x1809;
+    CMD_WRITE_SECURE_CONN_TEST_MODE = 0x180A; // Not currently used in system/bt
+    // BLE commands 0x2000
+    CMD_BLE_SET_EVENT_MASK = 0x2001;
+    CMD_BLE_READ_BUFFER_SIZE = 0x2002;
+    CMD_BLE_READ_LOCAL_SPT_FEAT = 0x2003;
+    CMD_BLE_WRITE_LOCAL_SPT_FEAT = 0x2004;
+    CMD_BLE_WRITE_RANDOM_ADDR = 0x2005;
+    CMD_BLE_WRITE_ADV_PARAMS = 0x2006;
+    CMD_BLE_READ_ADV_CHNL_TX_POWER = 0x2007;
+    CMD_BLE_WRITE_ADV_DATA = 0x2008;
+    CMD_BLE_WRITE_SCAN_RSP_DATA = 0x2009;
+    CMD_BLE_WRITE_ADV_ENABLE = 0x200A;
+    CMD_BLE_WRITE_SCAN_PARAMS = 0x200B;
+    CMD_BLE_WRITE_SCAN_ENABLE = 0x200C;
+    CMD_BLE_CREATE_LL_CONN = 0x200D;
+    CMD_BLE_CREATE_CONN_CANCEL = 0x200E;
+    CMD_BLE_READ_WHITE_LIST_SIZE = 0x200F;
+    CMD_BLE_CLEAR_WHITE_LIST = 0x2010;
+    CMD_BLE_ADD_WHITE_LIST = 0x2011;
+    CMD_BLE_REMOVE_WHITE_LIST = 0x2012;
+    CMD_BLE_UPD_LL_CONN_PARAMS = 0x2013;
+    CMD_BLE_SET_HOST_CHNL_CLASS = 0x2014;
+    CMD_BLE_READ_CHNL_MAP = 0x2015;
+    CMD_BLE_READ_REMOTE_FEAT = 0x2016;
+    CMD_BLE_ENCRYPT = 0x2017;
+    CMD_BLE_RAND = 0x2018;
+    CMD_BLE_START_ENC = 0x2019;
+    CMD_BLE_LTK_REQ_REPLY = 0x201A;
+    CMD_BLE_LTK_REQ_NEG_REPLY = 0x201B;
+    CMD_BLE_READ_SUPPORTED_STATES = 0x201C;
+    CMD_BLE_RECEIVER_TEST = 0x201D;
+    CMD_BLE_TRANSMITTER_TEST = 0x201E;
+    CMD_BLE_TEST_END = 0x201F;
+    CMD_BLE_RC_PARAM_REQ_REPLY = 0x2020;
+    CMD_BLE_RC_PARAM_REQ_NEG_REPLY = 0x2021;
+    CMD_BLE_SET_DATA_LENGTH = 0x2022;
+    CMD_BLE_READ_DEFAULT_DATA_LENGTH = 0x2023;
+    CMD_BLE_WRITE_DEFAULT_DATA_LENGTH = 0x2024;
+    CMD_BLE_GENERATE_DHKEY = 0x2026; // Not currently used in system/bt
+    CMD_BLE_ADD_DEV_RESOLVING_LIST = 0x2027;
+    CMD_BLE_RM_DEV_RESOLVING_LIST = 0x2028;
+    CMD_BLE_CLEAR_RESOLVING_LIST = 0x2029;
+    CMD_BLE_READ_RESOLVING_LIST_SIZE = 0x202A;
+    CMD_BLE_READ_RESOLVABLE_ADDR_PEER = 0x202B;
+    CMD_BLE_READ_RESOLVABLE_ADDR_LOCAL = 0x202C;
+    CMD_BLE_SET_ADDR_RESOLUTION_ENABLE = 0x202D;
+    CMD_BLE_SET_RAND_PRIV_ADDR_TIMOUT = 0x202E;
+    CMD_BLE_READ_MAXIMUM_DATA_LENGTH = 0x202F;
+    CMD_BLE_READ_PHY = 0x2030;
+    CMD_BLE_SET_DEFAULT_PHY = 0x2031;
+    CMD_BLE_SET_PHY = 0x2032;
+    CMD_BLE_ENH_RECEIVER_TEST = 0x2033;
+    CMD_BLE_ENH_TRANSMITTER_TEST = 0x2034;
+    CMD_BLE_SET_EXT_ADVERTISING_RANDOM_ADDRESS = 0x2035;
+    CMD_BLE_SET_EXT_ADVERTISING_PARAM = 0x2036;
+    CMD_BLE_SET_EXT_ADVERTISING_DATA = 0x2037;
+    CMD_BLE_SET_EXT_ADVERTISING_SCAN_RESP = 0x2038;
+    CMD_BLE_SET_EXT_ADVERTISING_ENABLE = 0x2039;
+    CMD_BLE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH = 0x203A;
+    CMD_BLE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS = 0x203B;
+    CMD_BLE_REMOVE_ADVERTISING_SET = 0x203C;
+    CMD_BLE_CLEAR_ADVERTISING_SETS = 0x203D;
+    CMD_BLE_SET_PERIODIC_ADVERTISING_PARAM = 0x203E;
+    CMD_BLE_SET_PERIODIC_ADVERTISING_DATA = 0x203F;
+    CMD_BLE_SET_PERIODIC_ADVERTISING_ENABLE = 0x2040;
+    CMD_BLE_SET_EXTENDED_SCAN_PARAMETERS = 0x2041;
+    CMD_BLE_SET_EXTENDED_SCAN_ENABLE = 0x2042;
+    CMD_BLE_EXTENDED_CREATE_CONNECTION = 0x2043;
+    CMD_BLE_PERIODIC_ADVERTISING_CREATE_SYNC = 0x2044;
+    CMD_BLE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL = 0x2045;
+    CMD_BLE_PERIODIC_ADVERTISING_TERMINATE_SYNC = 0x2046;
+    CMD_BLE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST = 0x2047;
+    CMD_BLE_RM_DEVICE_FROM_PERIODIC_ADVERTISING_LIST = 0x2048;
+    CMD_BLE_CLEAR_PERIODIC_ADVERTISING_LIST = 0x2049;
+    CMD_BLE_READ_PERIODIC_ADVERTISING_LIST_SIZE = 0x204A;
+    CMD_BLE_READ_TRANSMIT_POWER = 0x204B;
+    CMD_BLE_READ_RF_COMPENS_POWER = 0x204C;
+    CMD_BLE_WRITE_RF_COMPENS_POWER = 0x204D;
+    CMD_BLE_SET_PRIVACY_MODE = 0x204E;
+    // Vendor specific commands 0xFC00 and above
+    // Android vendor specific commands defined in
+    // https://source.android.com/devices/bluetooth/hci_requirements#vendor-specific-capabilities
+    CMD_BLE_VENDOR_CAP = 0xFD53;
+    CMD_BLE_MULTI_ADV = 0xFD54;
+    CMD_BLE_BATCH_SCAN = 0xFD56;
+    CMD_BLE_ADV_FILTER = 0xFD57;
+    CMD_BLE_TRACK_ADV = 0xFD58;
+    CMD_BLE_ENERGY_INFO = 0xFD59;
+    CMD_BLE_EXTENDED_SCAN_PARAMS = 0xFD5A;
+    CMD_CONTROLLER_DEBUG_INFO = 0xFD5B;
+    CMD_CONTROLLER_A2DP_OPCODE = 0xFD5D;
+    CMD_BRCM_SET_ACL_PRIORITY = 0xFC57;
+    // Other vendor specific commands below here
+}
+
+// HCI event codes from the Bluetooth 5.0 specification Vol 2, Part 7, Section 7
+// Original definition: system/bt/stack/include/hcidefs.h
+enum EventEnum {
+    // Event is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
+    EVT_UNKNOWN = 0xFFF;
+    EVT_INQUIRY_COMP = 0x01;
+    EVT_INQUIRY_RESULT = 0x02;
+    EVT_CONNECTION_COMP = 0x03;
+    EVT_CONNECTION_REQUEST = 0x04;
+    EVT_DISCONNECTION_COMP = 0x05;
+    EVT_AUTHENTICATION_COMP = 0x06;
+    EVT_RMT_NAME_REQUEST_COMP = 0x07;
+    EVT_ENCRYPTION_CHANGE = 0x08;
+    EVT_CHANGE_CONN_LINK_KEY = 0x09;
+    EVT_MASTER_LINK_KEY_COMP = 0x0A;
+    EVT_READ_RMT_FEATURES_COMP = 0x0B;
+    EVT_READ_RMT_VERSION_COMP = 0x0C;
+    EVT_QOS_SETUP_COMP = 0x0D;
+    EVT_COMMAND_COMPLETE = 0x0E;
+    EVT_COMMAND_STATUS = 0x0F;
+    EVT_HARDWARE_ERROR = 0x10;
+    EVT_FLUSH_OCCURED = 0x11;
+    EVT_ROLE_CHANGE = 0x12;
+    EVT_NUM_COMPL_DATA_PKTS = 0x13;
+    EVT_MODE_CHANGE = 0x14;
+    EVT_RETURN_LINK_KEYS = 0x15;
+    EVT_PIN_CODE_REQUEST = 0x16;
+    EVT_LINK_KEY_REQUEST = 0x17;
+    EVT_LINK_KEY_NOTIFICATION = 0x18;
+    EVT_LOOPBACK_COMMAND = 0x19;
+    EVT_DATA_BUF_OVERFLOW = 0x1A;
+    EVT_MAX_SLOTS_CHANGED = 0x1B;
+    EVT_READ_CLOCK_OFF_COMP = 0x1C;
+    EVT_CONN_PKT_TYPE_CHANGE = 0x1D;
+    EVT_QOS_VIOLATION = 0x1E;
+    EVT_PAGE_SCAN_MODE_CHANGE = 0x1F; // Deprecated
+    EVT_PAGE_SCAN_REP_MODE_CHNG = 0x20;
+    EVT_FLOW_SPECIFICATION_COMP = 0x21;
+    EVT_INQUIRY_RSSI_RESULT = 0x22;
+    EVT_READ_RMT_EXT_FEATURES_COMP = 0x23;
+    EVT_ESCO_CONNECTION_COMP = 0x2C;
+    EVT_ESCO_CONNECTION_CHANGED = 0x2D;
+    EVT_SNIFF_SUB_RATE = 0x2E;
+    EVT_EXTENDED_INQUIRY_RESULT = 0x2F;
+    EVT_ENCRYPTION_KEY_REFRESH_COMP = 0x30;
+    EVT_IO_CAPABILITY_REQUEST = 0x31;
+    EVT_IO_CAPABILITY_RESPONSE = 0x32;
+    EVT_USER_CONFIRMATION_REQUEST = 0x33;
+    EVT_USER_PASSKEY_REQUEST = 0x34;
+    EVT_REMOTE_OOB_DATA_REQUEST = 0x35;
+    EVT_SIMPLE_PAIRING_COMPLETE = 0x36;
+    EVT_LINK_SUPER_TOUT_CHANGED = 0x38;
+    EVT_ENHANCED_FLUSH_COMPLETE = 0x39;
+    EVT_USER_PASSKEY_NOTIFY = 0x3B;
+    EVT_KEYPRESS_NOTIFY = 0x3C;
+    EVT_RMT_HOST_SUP_FEAT_NOTIFY = 0x3D;
+    EVT_BLE_META = 0x3E;
+    EVT_PHYSICAL_LINK_COMP = 0x40;
+    EVT_CHANNEL_SELECTED = 0x41;
+    EVT_DISC_PHYSICAL_LINK_COMP = 0x42;
+    EVT_PHY_LINK_LOSS_EARLY_WARNING = 0x43;
+    EVT_PHY_LINK_RECOVERY = 0x44;
+    EVT_LOGICAL_LINK_COMP = 0x45;
+    EVT_DISC_LOGICAL_LINK_COMP = 0x46;
+    EVT_FLOW_SPEC_MODIFY_COMP = 0x47;
+    EVT_NUM_COMPL_DATA_BLOCKS = 0x48;
+    EVT_AMP_TEST_START = 0x49; // Not currently used in system/bt
+    EVT_AMP_TEST_END = 0x4A; // Not currently used in system/bt
+    EVT_AMP_RECEIVER_RPT = 0x4B; // Not currently used in system/bt
+    EVT_SHORT_RANGE_MODE_COMPLETE = 0x4C;
+    EVT_AMP_STATUS_CHANGE = 0x4D;
+    EVT_SET_TRIGGERED_CLOCK_CAPTURE = 0x4E;
+    EVT_SYNC_TRAIN_CMPL = 0x4F; // Not currently used in system/bt
+    EVT_SYNC_TRAIN_RCVD = 0x50; // Not currently used in system/bt
+    EVT_CONNLESS_SLAVE_BROADCAST_RCVD = 0x51; // Not currently used in system/bt
+    EVT_CONNLESS_SLAVE_BROADCAST_TIMEOUT = 0x52; // Not currently used in system/bt
+    EVT_TRUNCATED_PAGE_CMPL = 0x53; // Not currently used in system/bt
+    EVT_SLAVE_PAGE_RES_TIMEOUT = 0x54; // Not currently used in system/bt
+    EVT_CONNLESS_SLAVE_BROADCAST_CHNL_MAP_CHANGE = 0x55; // Not currently used in system/bt
+    EVT_INQUIRY_RES_NOTIFICATION = 0x56; // Not currently used in system/bt
+    EVT_AUTHED_PAYLOAD_TIMEOUT = 0x57; // Not currently used in system/bt
+    EVT_SAM_STATUS_CHANGE = 0x58; // Not currently used in system/bt
+}
+
+// Bluetooth low energy related meta event codes
+// from the Bluetooth 5.0 specification Vol 2, Part E, Section 7.7.65
+// Original definition: system/bt/stack/include/hcidefs.h
+enum BleMetaEventEnum {
+    // BLE meta event code is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
+    BLE_EVT_UNKNOWN = 0xFFF;
+    BLE_EVT_CONN_COMPLETE_EVT = 0x01;
+    BLE_EVT_ADV_PKT_RPT_EVT = 0x02;
+    BLE_EVT_LL_CONN_PARAM_UPD_EVT = 0x03;
+    BLE_EVT_READ_REMOTE_FEAT_CMPL_EVT = 0x04;
+    BLE_EVT_LTK_REQ_EVT = 0x05;
+    BLE_EVT_RC_PARAM_REQ_EVT = 0x06;
+    BLE_EVT_DATA_LENGTH_CHANGE_EVT = 0x07;
+    BLE_EVT_READ_LOCAL_P256_PUB_KEY = 0x08; // Not currently used in system/bt
+    BLE_EVT_GEN_DHKEY_CMPL = 0x09; // Not currently used in system/bt
+    BLE_EVT_ENHANCED_CONN_COMPLETE_EVT = 0x0a;
+    BLE_EVT_DIRECT_ADV_EVT = 0x0b;
+    BLE_EVT_PHY_UPDATE_COMPLETE_EVT = 0x0c;
+    BLE_EVT_EXTENDED_ADVERTISING_REPORT_EVT = 0x0D;
+    BLE_EVT_PERIODIC_ADV_SYNC_EST_EVT = 0x0E;
+    BLE_EVT_PERIODIC_ADV_REPORT_EVT = 0x0F;
+    BLE_EVT_PERIODIC_ADV_SYNC_LOST_EVT = 0x10;
+    BLE_EVT_SCAN_TIMEOUT_EVT = 0x11;
+    BLE_EVT_ADVERTISING_SET_TERMINATED_EVT = 0x12;
+    BLE_EVT_SCAN_REQ_RX_EVT = 0x13;
+    BLE_EVT_CHNL_SELECTION_ALGORITHM = 0x14; // Not currently used in system/bt
+}
+
+// HCI status code from the Bluetooth 5.0 specification Vol 2, Part D.
+// Original definition: system/bt/stack/include/hcidefs.h
+enum StatusEnum {
+    // Status is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
+    STATUS_UNKNOWN = 0xFFF;
+    STATUS_SUCCESS = 0x00;
+    STATUS_ILLEGAL_COMMAND = 0x01;
+    STATUS_NO_CONNECTION = 0x02;
+    STATUS_HW_FAILURE = 0x03;
+    STATUS_PAGE_TIMEOUT = 0x04;
+    STATUS_AUTH_FAILURE = 0x05;
+    STATUS_KEY_MISSING = 0x06;
+    STATUS_MEMORY_FULL = 0x07;
+    STATUS_CONNECTION_TOUT = 0x08;
+    STATUS_MAX_NUM_OF_CONNECTIONS = 0x09;
+    STATUS_MAX_NUM_OF_SCOS = 0x0A;
+    STATUS_CONNECTION_EXISTS = 0x0B;
+    STATUS_COMMAND_DISALLOWED = 0x0C;
+    STATUS_HOST_REJECT_RESOURCES = 0x0D;
+    STATUS_HOST_REJECT_SECURITY = 0x0E;
+    STATUS_HOST_REJECT_DEVICE = 0x0F;
+    STATUS_HOST_TIMEOUT = 0x10;
+    STATUS_UNSUPPORTED_VALUE = 0x11;
+    STATUS_ILLEGAL_PARAMETER_FMT = 0x12;
+    STATUS_PEER_USER = 0x13;
+    STATUS_PEER_LOW_RESOURCES = 0x14;
+    STATUS_PEER_POWER_OFF = 0x15;
+    STATUS_CONN_CAUSE_LOCAL_HOST = 0x16;
+    STATUS_REPEATED_ATTEMPTS = 0x17;
+    STATUS_PAIRING_NOT_ALLOWED = 0x18;
+    STATUS_UNKNOWN_LMP_PDU = 0x19;
+    STATUS_UNSUPPORTED_REM_FEATURE = 0x1A;
+    STATUS_SCO_OFFSET_REJECTED = 0x1B;
+    STATUS_SCO_INTERVAL_REJECTED = 0x1C;
+    STATUS_SCO_AIR_MODE = 0x1D;
+    STATUS_INVALID_LMP_PARAM = 0x1E;
+    STATUS_UNSPECIFIED = 0x1F;
+    STATUS_UNSUPPORTED_LMP_FEATURE = 0x20;
+    STATUS_ROLE_CHANGE_NOT_ALLOWED = 0x21;
+    STATUS_LMP_RESPONSE_TIMEOUT = 0x22;
+    STATUS_LMP_STATUS_TRANS_COLLISION = 0x23;
+    STATUS_LMP_PDU_NOT_ALLOWED = 0x24;
+    STATUS_ENCRY_MODE_NOT_ACCEPTABLE = 0x25;
+    STATUS_UNIT_KEY_USED = 0x26;
+    STATUS_QOS_NOT_SUPPORTED = 0x27;
+    STATUS_INSTANT_PASSED = 0x28;
+    STATUS_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED = 0x29;
+    STATUS_DIFF_TRANSACTION_COLLISION = 0x2A;
+    STATUS_UNDEFINED_0x2B = 0x2B; // Not used
+    STATUS_QOS_UNACCEPTABLE_PARAM = 0x2C;
+    STATUS_QOS_REJECTED = 0x2D;
+    STATUS_CHAN_CLASSIF_NOT_SUPPORTED = 0x2E;
+    STATUS_INSUFFCIENT_SECURITY = 0x2F;
+    STATUS_PARAM_OUT_OF_RANGE = 0x30;
+    STATUS_UNDEFINED_0x31 = 0x31; // Not used
+    STATUS_ROLE_SWITCH_PENDING = 0x32;
+    STATUS_UNDEFINED_0x33 = 0x33;
+    STATUS_RESERVED_SLOT_VIOLATION = 0x34;
+    STATUS_ROLE_SWITCH_FAILED = 0x35;
+    STATUS_INQ_RSP_DATA_TOO_LARGE = 0x36;
+    STATUS_SIMPLE_PAIRING_NOT_SUPPORTED = 0x37;
+    STATUS_HOST_BUSY_PAIRING = 0x38;
+    STATUS_REJ_NO_SUITABLE_CHANNEL = 0x39;
+    STATUS_CONTROLLER_BUSY = 0x3A;
+    STATUS_UNACCEPT_CONN_INTERVAL = 0x3B;
+    STATUS_ADVERTISING_TIMEOUT = 0x3C;
+    STATUS_CONN_TOUT_DUE_TO_MIC_FAILURE = 0x3D;
+    STATUS_CONN_FAILED_ESTABLISHMENT = 0x3E;
+    STATUS_MAC_CONNECTION_FAILED = 0x3F;
+    STATUS_LT_ADDR_ALREADY_IN_USE = 0x40;
+    STATUS_LT_ADDR_NOT_ALLOCATED = 0x41;
+    STATUS_CLB_NOT_ENABLED = 0x42;
+    STATUS_CLB_DATA_TOO_BIG = 0x43;
+    STATUS_OPERATION_CANCELED_BY_HOST = 0x44; // Not currently used in system/bt
+}
diff --git a/core/proto/android/bluetooth/hfp/enums.proto b/core/proto/android/bluetooth/hfp/enums.proto
new file mode 100644
index 0000000..d286e4b
--- /dev/null
+++ b/core/proto/android/bluetooth/hfp/enums.proto
@@ -0,0 +1,28 @@
+/*
+ * 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.hfp;
+
+option java_outer_classname = "BluetoothHfpProtoEnums";
+option java_multiple_files = true;
+
+enum ScoCodec {
+    SCO_CODEC_UNKNOWN = 0;
+    SCO_CODEC_CVSD = 1;
+    // Default codec behind Wide Band Speech
+    SCO_CODEC_MSBC = 2;
+}
\ No newline at end of file
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index cc5aa20..4158577 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -436,12 +436,19 @@
         // Ordered GPU debug layer list for GLES
         // i.e. <layer1>:<layer2>:...:<layerN>
         optional SettingProto debug_layers_gles = 7;
-        // GUP - List of Apps selected to use Game Update Packages
-        optional SettingProto gup_dev_opt_in_apps = 8;
-        // GUP - List of Apps selected not to use Game Update Packages
-        optional SettingProto gup_dev_opt_out_apps = 9;
-        // GUP - List of Apps that are forbidden to use Game Update Packages
-        optional SettingProto gup_black_list = 10;
+        // GUP - Game Update Package global preference for all Apps
+        // 0 = Default
+        // 1 = All Apps use Game Update Package
+        // 2 = All Apps use system graphics driver
+        optional SettingProto gup_dev_all_apps = 8;
+        // GUP - List of Apps selected to use Game Update Package
+        // i.e. <pkg1>,<pkg2>,...,<pkgN>
+        optional SettingProto gup_dev_opt_in_apps = 9;
+        // GUP - List of Apps selected not to use Game Update Package
+        // i.e. <pkg1>,<pkg2>,...,<pkgN>
+        optional SettingProto gup_dev_opt_out_apps = 10;
+        // GUP - List of Apps that are forbidden to use Game Update Package
+        optional SettingProto gup_blacklist = 11;
     }
     optional Gpu gpu = 59;
 
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 0e052fe..4bfd4d2 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -182,6 +182,7 @@
         optional SettingProto pulse_on_pick_up = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto pulse_on_long_press = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto pulse_on_double_tap = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto pulse_on_tap = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Doze doze = 21;
 
@@ -525,7 +526,10 @@
     }
     optional Zen zen = 71;
 
+    optional SettingProto skip_gesture_enabled = 74 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto silence_gesture_enabled = 75 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 74;
+    // Next tag = 76;
 }
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 0ec8c1a..7f3ea7a 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -403,18 +403,23 @@
         optional bool is_charging = 1;
         optional bool is_in_parole = 2;
 
+        // List of UIDs currently in the foreground.
+        repeated int32 foreground_uids = 3;
+
         message TrackedJob {
             option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
             optional JobStatusShortInfoProto info = 1;
             optional int32 source_uid = 2;
             optional JobStatusDumpProto.Bucket effective_standby_bucket = 3;
-            optional bool has_quota = 4;
+            // If the job started while the app was in the TOP state.
+            optional bool is_top_started_job = 4;
+            optional bool has_quota = 5;
             // The amount of time that this job has remaining in its quota. This
             // can be negative if the job is out of quota.
-            optional int64 remaining_quota_ms = 5;
+            optional int64 remaining_quota_ms = 6;
         }
-        repeated TrackedJob tracked_jobs = 3;
+        repeated TrackedJob tracked_jobs = 4;
 
         message Package {
             option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -456,7 +461,7 @@
 
             repeated TimingSession saved_sessions = 3;
         }
-        repeated PackageStats package_stats = 4;
+        repeated PackageStats package_stats = 5;
     }
     message StorageController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/proto/android/service/procstats.proto b/core/proto/android/service/procstats.proto
index 71ebcc1..da801ff 100644
--- a/core/proto/android/service/procstats.proto
+++ b/core/proto/android/service/procstats.proto
@@ -43,7 +43,7 @@
  * Data model from /frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
  * This proto is defined based on the writeToParcel method.
  *
- * Next Tag: 10
+ * Next Tag: 11
  */
 message ProcessStatsSectionProto {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -76,6 +76,9 @@
     }
     repeated Status status = 7;
 
+    // Number of pages available of various types and sizes, representation fragmentation.
+    repeated ProcessStatsAvailablePagesProto available_pages = 10;
+
     // Stats for each process.
     repeated ProcessStatsProto process_stats = 8;
 
@@ -83,6 +86,24 @@
     repeated ProcessStatsPackageProto package_stats = 9;
 }
 
+// Next Tag: 5
+message ProcessStatsAvailablePagesProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Node these pages are in (as per /proc/pagetypeinfo)
+    optional int32 node = 1;
+
+    // Zone these pages are in (as per /proc/pagetypeinfo)
+    optional string zone = 2;
+
+    // Label for the type of these pages (as per /proc/pagetypeinfo)
+    optional string label = 3;
+
+    // Distribution of number of pages available by order size.  First entry in array is
+    // order 0, second is order 1, etc.  Each order increase is a doubling of page size.
+    repeated int32 pages_per_order = 4;
+}
+
 // Next Tag: 10
 message ProcessStatsStateProto {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 506d7f2..f3e3241 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1186,6 +1186,7 @@
     <!-- Used for permissions that are associated with activity recognition.
          TODO(zezeozue). STOPSHIP: Add icon -->
     <permission-group android:name="android.permission-group.ACTIVITY_RECOGNITION"
+        android:icon="@drawable/perm_group_activity_recognition"
         android:label="@string/permgrouplab_activityRecognition"
         android:description="@string/permgroupdesc_activityRecognition"
         android:request="@string/permgrouprequest_activityRecognition"
@@ -2269,6 +2270,11 @@
     <permission android:name="android.permission.START_ANY_ACTIVITY"
         android:protectionLevel="signature" />
 
+    <!-- Allows an application to start activities from background
+         @hide -->
+    <permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"
+        android:protectionLevel="signature|privileged|vendorPrivileged|oem" />
+
     <!-- @SystemApi Must be required by activities that handle the intent action
          {@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
          hold {@link Manifest.permission#SUSPEND_APPS} to interact with the system.
@@ -2527,6 +2533,16 @@
     <permission android:name="android.permission.WRITE_GSERVICES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi @hide Allows an application to modify config settings.
+    <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.WRITE_DEVICE_CONFIG"
+        android:protectionLevel="signature|configurator"/>
+
+    <!-- @SystemApi @hide Allows an application to read config settings.
+    <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.READ_DEVICE_CONFIG"
+        android:protectionLevel="signature|preinstalled" />
+
     <!-- @SystemApi @TestApi Allows an application to call
         {@link android.app.ActivityManager#forceStopPackage}.
         @hide -->
@@ -3191,9 +3207,10 @@
 
     <!-- @SystemApi Required to add or remove another application as a device admin.
          <p>Not for use by third-party applications.
-         @hide -->
+         @hide
+         @removed -->
     <permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an app to reset the device password.
          <p>Not for use by third-party applications.
@@ -3515,19 +3532,25 @@
     <permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to provide remote displays.
+         <p>Not for use by third-party applications.</p>
+         @hide -->
+    <permission android:name="android.permission.REMOTE_DISPLAY_PROVIDER"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Allows an application to capture video output.
          <p>Not for use by third-party applications.</p>
           @hide
           @removed -->
     <permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to capture secure video output.
          <p>Not for use by third-party applications.</p>
           @hide
           @removed -->
     <permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to know what content is playing and control its playback.
          <p>Not for use by third-party applications due to privacy of media consumption</p>  -->
diff --git a/core/res/res/drawable/perm_group_activity_recognition.xml b/core/res/res/drawable/perm_group_activity_recognition.xml
new file mode 100644
index 0000000..0ade6c6
--- /dev/null
+++ b/core/res/res/drawable/perm_group_activity_recognition.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2019 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#000000"
+        android:pathData="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1
+2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9
+0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5 .1 -.8 .1 l-5.2
+2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z" />
+</vector>
diff --git a/core/res/res/drawable/perm_group_sensors.xml b/core/res/res/drawable/perm_group_sensors.xml
index ce36c13..e4663d7 100644
--- a/core/res/res/drawable/perm_group_sensors.xml
+++ b/core/res/res/drawable/perm_group_sensors.xml
@@ -19,11 +19,11 @@
     android:height="24dp"
     android:viewportWidth="24"
     android:viewportHeight="24">
-
-    <path
-        android:fillColor="#000000"
-        android:pathData="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1
-2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9
-0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5 .1 -.8 .1 l-5.2
-2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z" />
-</vector>
\ No newline at end of file
+  <path
+      android:fillColor="#000000"
+      android:pathData="M16.5,3c-1.74,0 -3.41,0.81 -4.5,2.09C10.91,3.81 9.24,3 7.5,3C4.42,3 2,5.42 2,
+                        8.5c0,3.78 3.4,6.86 8.55,11.54L12,21.35l1.45,-1.32C18.6,15.36 22,12.28 22,8.5C22,
+                        5.42 19.58,3 16.5,3zM12.1,18.55l-0.1,0.1l-0.1,-0.1C7.14,14.24 4,11.39 4,8.5C4,6.5 5.5,
+                        5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5C20,
+                        11.39 16.86,14.24 12.1,18.55z"/>
+</vector>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 18a42bc..b15f72e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -274,6 +274,9 @@
         <!-- Additional flag from base permission type: this permission can be automatically
             granted to the document manager -->
         <flag name="documenter" value="0x40000" />
+        <!-- Additional flag from base permission type: this permission automatically
+            granted to device configurator -->
+        <flag name="configurator" value="0x80000" />
     </attr>
 
     <!-- Flags indicating more context for a permission group. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1feb59a..64fdc02 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -618,15 +618,6 @@
     <!-- Integer indicating wpa_supplicant scan interval when p2p is connected in milliseconds -->
     <integer translatable="false" name="config_wifi_scan_interval_p2p_connected">60000</integer>
 
-    <!-- Integer indicating the framework scan interval in milliseconds. This is used in the scenario
-         where the chipset does not support background scanning (config_wifi_background_scan_suport
-         is false) to set up a periodic wake up scan so that the device can connect to a new access
-         point on the move. A value of 0 means no periodic scans will be used in the framework. -->
-    <integer translatable="false" name="config_wifi_framework_scan_interval">300000</integer>
-
-    <!-- Integer indicating the framework no networks periodic scan interval in milliseconds. -->
-    <integer translatable="false" name="config_wifi_no_network_periodic_scan_interval">300000</integer>
-
     <!-- Integer indicating disconnect mode short scan interval in milliseconds -->
     <integer translatable="false" name="config_wifi_disconnected_short_scan_interval">15000</integer>
 
@@ -692,6 +683,11 @@
     <!-- Wifi driver supports Automatic channel selection (ACS) for softap -->
     <bool translatable="false" name="config_wifi_softap_acs_supported">false</bool>
 
+    <!-- Channel list restriction to Automatic channel selection (ACS) for softap. If the device
+         doesn't want to restrict channels this should be empty. Value is a comma separated channel
+         string and/or channel range string like '1-6,11' -->
+    <string translatable="false" name="config_wifi_softap_acs_supported_channel_list"></string>
+
     <!-- Wifi driver supports IEEE80211AC for softap -->
     <bool translatable="false" name="config_wifi_softap_ieee80211ac_supported">false</bool>
 
@@ -699,6 +695,9 @@
          for automotive builds only (the one that have PackageManager#FEATURE_AUTOMOTIVE) -->
     <bool translatable="false" name="config_wifi_local_only_hotspot_5ghz">false</bool>
 
+    <!-- Indicates that connected MAC randomization is supported on this device -->
+    <bool translatable="false" name="config_wifi_connected_mac_randomization_supported">false</bool>
+
     <!-- Flag indicating whether we should enable the automatic brightness.
          Software implementation will be used if config_hardware_auto_brightness_available is not set -->
     <bool name="config_automatic_brightness_available">false</bool>
@@ -929,9 +928,6 @@
          in hardware. -->
     <bool name="config_setColorTransformAccelerated">false</bool>
 
-    <!-- Boolean indicating whether display white balance is supported. -->
-    <bool name="config_displayWhiteBalanceAvailable">false</bool>
-
     <!-- Control whether Night display is available. This should only be enabled on devices
          that have a HWC implementation that can apply the matrix passed to setColorTransform
          without impacting power, performance, and app compatibility (e.g. protected content). -->
@@ -987,6 +983,44 @@
         <!-- B y-intercept --> <item>-0.198650895</item>
     </string-array>
 
+    <!-- Boolean indicating whether display white balance is supported. -->
+    <bool name="config_displayWhiteBalanceAvailable">false</bool>
+
+    <!-- Minimum color temperature, in Kelvin, supported by display white balance. -->
+    <integer name="config_displayWhiteBalanceColorTemperatureMin">4000</integer>
+
+    <!-- Maximum color temperature, in Kelvin, supported by display white balance. -->
+    <integer name="config_displayWhiteBalanceColorTemperatureMax">8000</integer>
+
+    <!-- Default color temperature, in Kelvin, used by display white balance. -->
+    <integer name="config_displayWhiteBalanceColorTemperatureDefault">6500</integer>
+
+    <!-- The display primaries, in CIE1931 XYZ color space, for display
+         white balance to use in its calculations. -->
+    <string-array name="config_displayWhiteBalanceDisplayPrimaries">
+        <!-- Red X -->   <item>0.412315</item>
+        <!-- Red Y -->   <item>0.212600</item>
+        <!-- Red Z -->   <item>0.019327</item>
+        <!-- Green X --> <item>0.357600</item>
+        <!-- Green Y --> <item>0.715200</item>
+        <!-- Green Z --> <item>0.119200</item>
+        <!-- Blue X -->  <item>0.180500</item>
+        <!-- Blue Y -->  <item>0.072200</item>
+        <!-- Blue Z -->  <item>0.950633</item>
+        <!-- White X --> <item>0.950456</item>
+        <!-- White Y --> <item>1.000000</item>
+        <!-- White Z --> <item>1.089058</item>
+    </string-array>
+
+    <!-- The nominal white coordinates, in CIE1931 XYZ color space, for Display White Balance to
+         use in its calculations. AWB will adapt this white point to the target ambient white
+         point. -->
+    <string-array name="config_displayWhiteBalanceDisplayNominalWhite">
+        <!-- Nominal White X --> <item>0.950456</item>
+        <!-- Nominal White Y --> <item>1.000000</item>
+        <!-- Nominal White Z --> <item>1.089058</item>
+    </string-array>
+
 
     <!-- Indicate available ColorDisplayController.COLOR_MODE_xxx. -->
     <integer-array name="config_availableColorModes">
@@ -1654,6 +1688,8 @@
          config_enableFusedLocationOverlay is false. -->
     <string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string>
 
+    <string-array name="config_locationExtraPackageNames" translatable="false"></string-array>
+
     <!-- The package name of the default network recommendation app.
          A network recommendation provider must:
              * Be granted the SCORE_NETWORKS permission.
@@ -1855,6 +1891,8 @@
                cell broadcasting sms, and MMS. -->
     <bool name="config_sms_capable">true</bool>
 
+    <!-- TODO: STOPSHIP(b/110557011): Remove this from framework and overlays as we use
+         config_defaultRoleHolders now. -->
     <!-- Default SMS Application. This will be the default SMS application when
          the phone first boots. The user can then change the default app to one
          of their choosing.
@@ -1873,6 +1911,12 @@
          the behavior will be as though no app was named as an explicit default. -->
     <string name="default_browser" translatable="false"></string>
 
+    <!-- Default role holders. This will be an array of roles and package names of their default
+         holders, with each item in the format of "ROLE_NAME: PACKAGE_NAME_1, PACKAGE_NAME_2". -->
+    <string-array name="config_defaultRoleHolders" translatable="false">
+        <item>android.app.role.SMS: com.android.messaging</item>
+    </string-array>
+
     <!-- Enable/disable default bluetooth profiles:
         HSP_AG, ObexObjectPush, Audio, NAP -->
     <bool name="config_bluetooth_default_profiles">true</bool>
@@ -2168,6 +2212,9 @@
     <!-- Type of the double tap sensor. Empty if double tap is not supported. -->
     <string name="config_dozeDoubleTapSensorType" translatable="false"></string>
 
+    <!-- Type of the tap sensor. Empty if tap is not supported. -->
+    <string name="config_dozeTapSensorType" translatable="false"></string>
+
     <!-- Type of the long press sensor. Empty if long press is not supported. -->
     <string name="config_dozeLongPressSensorType" translatable="false"></string>
 
@@ -2765,6 +2812,9 @@
     <!-- Flag indicating which package name can access the persistent data partition -->
     <string name="config_persistentDataPackageName" translatable="false"></string>
 
+    <!-- Flag indicating which package name can access DeviceConfig table -->
+    <string name="config_deviceConfiguratorPackageName" translatable="false"></string>
+
     <!-- Flag indicating apps will skip sending hold request before merge. In this case
         IMS service implementation will do both.i.e.hold followed by merge. -->
     <bool name="skipHoldBeforeMerge">true</bool>
@@ -3661,7 +3711,7 @@
     <string name="config_inputEventCompatProcessorOverrideClassName" translatable="false"></string>
 
     <!-- Component name for the default module metadata provider on this device -->
-    <string name="config_defaultModuleMetadataProvider">com.android.modulemetadata</string>
+    <string name="config_defaultModuleMetadataProvider" translatable="false">com.android.modulemetadata</string>
 
     <!-- This is the default launcher component to use on secondary displays that support system
          decorations.
@@ -3673,4 +3723,10 @@
     <!-- If device supports corner radius on windows.
          This should be turned off on low-end devices to improve animation performance. -->
     <bool name="config_supportsRoundedCornersOnWindows">true</bool>
+
+    <!-- If the sensor that skips media is available or not. -->
+    <bool name="config_skipSensorAvailable">false</bool>
+
+    <!-- If the sensor that silences alerts is available or not. -->
+    <bool name="config_silenceSensorAvailable">false</bool>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b3b30e9..777886a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2985,6 +2985,11 @@
         <public name="system_notification_accent_color" />
     </public-group>
 
+    <public-group type="array" first-id="0x01070006">
+      <!-- @hide @SystemApi -->
+      <public name="config_defaultRoleHolders" />
+    </public-group>
+
   <!-- ===============================================================
        DO NOT ADD UN-GROUPED ITEMS HERE
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 010accf..9317cff 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -325,6 +325,7 @@
   <java-symbol type="bool" name="config_forceDefaultOrientation" />
   <java-symbol type="bool" name="config_wifi_batched_scan_supported" />
   <java-symbol type="bool" name="config_wifi_softap_acs_supported" />
+  <java-symbol type="string" name="config_wifi_softap_acs_supported_channel_list" />
   <java-symbol type="bool" name="config_wifi_softap_ieee80211ac_supported" />
   <java-symbol type="bool" name="config_enableMultiUserUI"/>
   <java-symbol type="bool" name="config_enableNewAutoSelectNetworkUI"/>
@@ -458,9 +459,7 @@
   <java-symbol type="integer" name="config_toastDefaultGravity" />
   <java-symbol type="integer" name="config_triplePressOnPowerBehavior" />
   <java-symbol type="integer" name="config_shortPressOnSleepBehavior" />
-  <java-symbol type="integer" name="config_wifi_framework_scan_interval" />
   <java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
-  <java-symbol type="integer" name="config_wifi_no_network_periodic_scan_interval" />
   <java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
   <java-symbol type="integer" name="config_windowOutsetBottom" />
   <java-symbol type="integer" name="db_connection_pool_size" />
@@ -1840,6 +1839,7 @@
   <java-symbol type="array" name="radioAttributes" />
   <java-symbol type="array" name="config_oemUsbModeOverride" />
   <java-symbol type="array" name="config_locationProviderPackageNames" />
+  <java-symbol type="array" name="config_locationExtraPackageNames" />
   <java-symbol type="array" name="config_testLocationProviders" />
   <java-symbol type="array" name="config_defaultNotificationVibePattern" />
   <java-symbol type="array" name="config_notificationFallbackVibePattern" />
@@ -1879,6 +1879,7 @@
   <java-symbol type="bool" name="config_wifi_dual_band_support" />
   <java-symbol type="bool" name="config_wifi_convert_apband_5ghz_to_any" />
   <java-symbol type="bool" name="config_wifi_local_only_hotspot_5ghz" />
+  <java-symbol type="bool" name="config_wifi_connected_mac_randomization_supported" />
   <java-symbol type="bool" name="config_wifi_fast_bss_transition_enabled" />
   <java-symbol type="bool" name="config_wimaxEnabled" />
   <java-symbol type="bool" name="show_ongoing_ime_switcher" />
@@ -2139,6 +2140,7 @@
   <java-symbol type="string" name="config_carrierAppInstallDialogComponent" />
   <java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
   <java-symbol type="string" name="config_persistentDataPackageName" />
+  <java-symbol type="string" name="config_deviceConfiguratorPackageName" />
 
   <java-symbol type="layout" name="resolver_list" />
   <java-symbol type="id" name="resolver_list" />
@@ -3001,6 +3003,7 @@
   <java-symbol type="array" name="config_emergency_mcc_codes" />
 
   <java-symbol type="string" name="config_dozeDoubleTapSensorType" />
+  <java-symbol type="string" name="config_dozeTapSensorType" />
   <java-symbol type="bool" name="config_dozePulsePickup" />
 
   <!-- Used for MimeIconUtils. -->
@@ -3042,6 +3045,13 @@
   <java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficientsNative" />
   <java-symbol type="array" name="config_availableColorModes" />
 
+  <java-symbol type="bool" name="config_displayWhiteBalanceAvailable" />
+  <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMin" />
+  <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMax" />
+  <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureDefault" />
+  <java-symbol type="array" name="config_displayWhiteBalanceDisplayPrimaries" />
+  <java-symbol type="array" name="config_displayWhiteBalanceDisplayNominalWhite" />
+
   <!-- Default first user restrictions -->
   <java-symbol type="array" name="config_defaultFirstUserRestrictions" />
 
@@ -3529,4 +3539,7 @@
   <java-symbol type="string" name="dynamic_mode_notification_title" />
   <java-symbol type="string" name="dynamic_mode_notification_summary" />
   <java-symbol type="drawable" name="ic_battery" />
+
+  <java-symbol type="bool" name="config_skipSensorAvailable" />
+  <java-symbol type="bool" name="config_silenceSensorAvailable" />
 </resources>
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 74943c7..0fc3bd2 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -36,12 +36,12 @@
     frameworks-core-util-lib \
     mockwebserver \
     guava \
-    android-support-test \
+    androidx.test.runner \
+    androidx.test.rules \
     mockito-target-minus-junit4 \
     espresso-core \
     ub-uiautomator \
     platform-test-annotations \
-    compatibility-device-util \
     truth-prebuilt \
     print-test-util-lib \
     testng # TODO: remove once Android migrates to JUnit 4.12, which provide assertThrows
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 46d4a47..86818c6 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -56,6 +56,7 @@
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.READ_DREAM_STATE" />
     <uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
     <uses-permission android:name="android.permission.READ_LOGS"/>
@@ -65,6 +66,7 @@
     <uses-permission android:name="android.permission.USE_CREDENTIALS" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
@@ -1425,7 +1427,7 @@
 
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
             android:targetPackage="com.android.frameworks.coretests"
             android:label="Frameworks Core Tests" />
     <key-sets>
diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml
index 68ef34b..b40aa87 100644
--- a/core/tests/coretests/AndroidTest.xml
+++ b/core/tests/coretests/AndroidTest.xml
@@ -25,6 +25,7 @@
     <option name="test-tag" value="FrameworksCoreTests" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.frameworks.coretests" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
 </configuration>
diff --git a/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java b/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
index e26bdf5..be1d44c 100644
--- a/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
@@ -13,17 +13,17 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
+
 package android.animation;
 
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase2;
 
+import androidx.test.filters.LargeTest;
+
+import com.android.frameworks.coretests.R;
+
 import java.util.HashSet;
 import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import com.android.frameworks.coretests.R;
 
 @LargeTest
 public class AnimatorInflaterTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity>  {
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetActivity.java b/core/tests/coretests/src/android/animation/AnimatorSetActivity.java
index 501ea48..af265af 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetActivity.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetActivity.java
@@ -1,10 +1,26 @@
-package android.animation;
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
-import com.android.frameworks.coretests.R;
+package android.animation;
 
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 public class AnimatorSetActivity extends Activity {
     @Override
     public void onCreate(Bundle savedBundleInstance) {
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java b/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
index 922bc59..55837ba 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
@@ -1,12 +1,29 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.animation;
 
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.View;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.SmallTest;
+
+import com.android.frameworks.coretests.R;
+
 import java.util.ArrayList;
 
 public class AnimatorSetActivityTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> {
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
index 7eb32ee..4e90d1a 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
@@ -13,12 +13,14 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
+
 package android.animation;
 
 import android.os.Handler;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.widget.Button;
+
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.util.concurrent.TimeUnit;
diff --git a/core/tests/coretests/src/android/animation/AutoCancelTest.java b/core/tests/coretests/src/android/animation/AutoCancelTest.java
index b1f88db..b3ec92c 100644
--- a/core/tests/coretests/src/android/animation/AutoCancelTest.java
+++ b/core/tests/coretests/src/android/animation/AutoCancelTest.java
@@ -13,11 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.animation;
 
 import android.os.Handler;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import java.util.HashMap;
 import java.util.concurrent.TimeUnit;
diff --git a/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
index 0e1e6ac..2b9866d 100644
--- a/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
+++ b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
@@ -13,14 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.animation;
 
-import com.android.frameworks.coretests.R;
+package android.animation;
 
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.Button;
 
+import com.android.frameworks.coretests.R;
+
 public class BasicAnimatorActivity extends Activity {
     public Button mAnimatingButton;
     @Override
diff --git a/core/tests/coretests/src/android/animation/EventsTest.java b/core/tests/coretests/src/android/animation/EventsTest.java
index 28cfe3d..ba7413a 100644
--- a/core/tests/coretests/src/android/animation/EventsTest.java
+++ b/core/tests/coretests/src/android/animation/EventsTest.java
@@ -13,13 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.animation;
 
 import android.os.Handler;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
 
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
diff --git a/core/tests/coretests/src/android/animation/FutureWaiter.java b/core/tests/coretests/src/android/animation/FutureWaiter.java
index 0c65e20..0c09a4a 100644
--- a/core/tests/coretests/src/android/animation/FutureWaiter.java
+++ b/core/tests/coretests/src/android/animation/FutureWaiter.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.animation;
 
 import com.google.common.util.concurrent.AbstractFuture;
diff --git a/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java b/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
index 606a939..53f9472 100644
--- a/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
+++ b/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
@@ -13,9 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.animation;
 
 import android.widget.Button;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/animation/StateListAnimatorTest.java b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
index a9961e1..e755b89 100644
--- a/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
+++ b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
@@ -14,16 +14,16 @@
 * limitations under the License.
 */
 
-
 package android.animation;
 
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
 import android.util.StateSet;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.util.concurrent.atomic.AtomicInteger;
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java b/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
index c25d050..f6d71b8 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.animation;
 
 /**
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
index 4facf77..dee0a3e 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -13,8 +13,11 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
+
 package android.animation;
 
+import static android.test.MoreAsserts.assertNotEqual;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
@@ -24,23 +27,20 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.SystemClock;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.Choreographer;
 import android.view.animation.LinearInterpolator;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 
-import static android.test.MoreAsserts.assertNotEqual;
-
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class ValueAnimatorTests {
diff --git a/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java b/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
index 30ec182..997af00 100644
--- a/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
+++ b/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
@@ -13,15 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.animation;
 
 import android.os.Handler;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.ViewPropertyAnimator;
 import android.widget.Button;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.util.concurrent.TimeUnit;
diff --git a/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java b/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java
index 19a390a..8dc5ad6 100644
--- a/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java
+++ b/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java
@@ -16,16 +16,17 @@
 
 package android.app;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import android.app.ApplicationErrorReport.CrashInfo;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.app.ApplicationErrorReport.CrashInfo;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class ApplicationErrorReportTest {
diff --git a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
index 063bef7..4b0ed65 100644
--- a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
+++ b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
@@ -16,13 +16,17 @@
 
 package android.app;
 
+import static android.os.storage.VolumeInfo.STATE_MOUNTED;
+import static android.os.storage.VolumeInfo.STATE_UNMOUNTED;
+
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
 
@@ -32,9 +36,6 @@
 import java.util.Arrays;
 import java.util.List;
 
-import static android.os.storage.VolumeInfo.STATE_MOUNTED;
-import static android.os.storage.VolumeInfo.STATE_UNMOUNTED;
-
 @LargeTest
 public class ApplicationPackageManagerTest extends TestCase {
     private static final String sInternalVolPath = "/data";
diff --git a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
index c1d4be0..33e0402 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
@@ -22,7 +22,8 @@
 import android.net.Uri;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import com.google.mockwebserver.MockResponse;
 
diff --git a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
index 39d9a8e..adfe76f 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
@@ -23,10 +23,11 @@
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.os.StatFs;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
diff --git a/core/tests/coretests/src/android/app/InstrumentationTest.java b/core/tests/coretests/src/android/app/InstrumentationTest.java
index 9b59da4..93b5aec 100644
--- a/core/tests/coretests/src/android/app/InstrumentationTest.java
+++ b/core/tests/coretests/src/android/app/InstrumentationTest.java
@@ -17,9 +17,10 @@
 package android.app;
 
 import android.os.Bundle;
-import android.support.test.filters.LargeTest;
 import android.test.InstrumentationTestCase;
 
+import androidx.test.filters.LargeTest;
+
 @LargeTest
 public class InstrumentationTest extends InstrumentationTestCase {
 
diff --git a/core/tests/coretests/src/android/app/LoaderLifecycleTest.java b/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
index c83e798..e343383 100644
--- a/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
+++ b/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 package android.app;
 
 import static junit.framework.TestCase.assertNotNull;
@@ -27,11 +26,12 @@
 import android.content.Context;
 import android.os.Handler;
 import android.os.Parcelable;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index e89a4d3..c17aa92 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -33,11 +33,12 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.widget.RemoteViews;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/SearchManagerTest.java b/core/tests/coretests/src/android/app/SearchManagerTest.java
index 08b7f60..14370c8 100644
--- a/core/tests/coretests/src/android/app/SearchManagerTest.java
+++ b/core/tests/coretests/src/android/app/SearchManagerTest.java
@@ -17,17 +17,13 @@
 package android.app;
 
 import android.app.activity.LocalActivity;
-
-import android.app.Activity;
-import android.app.ISearchManager;
-import android.app.SearchManager;
-import android.app.SearchableInfo;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.ServiceManager;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 /**
  * To launch this test from the command line:
diff --git a/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java b/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
index 61d73bc..bbd442d 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
@@ -21,8 +21,9 @@
 import android.content.pm.ConfigurationInfo;
 import android.content.res.Configuration;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
 
 import java.util.Iterator;
 import java.util.List;
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 0f83a29..9cb3489 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -36,13 +36,14 @@
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.IBinder;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.MergedConfiguration;
 import android.view.Display;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/app/activity/BroadcastTest.java b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
index 13e70eb..0f81896 100644
--- a/core/tests/coretests/src/android/app/activity/BroadcastTest.java
+++ b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
@@ -27,11 +27,10 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.UserHandle;
-import android.support.test.filters.LargeTest;
-import android.test.FlakyTest;
 import android.util.Log;
 
-import java.util.Arrays;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.LargeTest;
 
 @LargeTest
 public class BroadcastTest extends ActivityTestsBase {
@@ -231,7 +230,7 @@
     };
 
     // Mark flaky until http://b/issue?id=1191607 is resolved.
-    @FlakyTest(tolerance=2)
+    @FlakyTest
     public void testRegistered() throws Exception {
         runLaunchpad(LaunchpadActivity.BROADCAST_REGISTERED);
     }
@@ -248,12 +247,12 @@
         runLaunchpad(LaunchpadActivity.BROADCAST_ABORT);
     }
 
-    @FlakyTest(tolerance=2)
+    @FlakyTest
     public void testAll() throws Exception {
         runLaunchpad(LaunchpadActivity.BROADCAST_ALL);
     }
 
-    @FlakyTest(tolerance=2)
+    @FlakyTest
     public void testMulti() throws Exception {
         runLaunchpad(LaunchpadActivity.BROADCAST_MULTI);
     }
@@ -348,7 +347,7 @@
     }
 
     // Marking flaky until http://b/issue?id=1191337 is resolved
-    @FlakyTest(tolerance=2)
+    @FlakyTest
     public void testReceiveSticky() throws Exception {
         Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
         intent.putExtra("test", LaunchpadActivity.DATA_1);
@@ -358,7 +357,7 @@
     }
 
     // Marking flaky until http://b/issue?id=1191337 is resolved
-    @FlakyTest(tolerance=2)
+    @FlakyTest
     public void testReceive2Sticky() throws Exception {
         Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
         intent.putExtra("test", LaunchpadActivity.DATA_1);
diff --git a/core/tests/coretests/src/android/app/activity/IntentSenderTest.java b/core/tests/coretests/src/android/app/activity/IntentSenderTest.java
index 8c1d79b..19ddb52 100644
--- a/core/tests/coretests/src/android/app/activity/IntentSenderTest.java
+++ b/core/tests/coretests/src/android/app/activity/IntentSenderTest.java
@@ -21,7 +21,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 @LargeTest
 public class IntentSenderTest extends BroadcastTest {
diff --git a/core/tests/coretests/src/android/app/activity/LaunchTest.java b/core/tests/coretests/src/android/app/activity/LaunchTest.java
index 5b86dce..6846ea7 100644
--- a/core/tests/coretests/src/android/app/activity/LaunchTest.java
+++ b/core/tests/coretests/src/android/app/activity/LaunchTest.java
@@ -17,8 +17,9 @@
 package android.app.activity;
 
 import android.content.ComponentName;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
 
 @Suppress  // Flaky.
 public class LaunchTest extends ActivityTestsBase {
diff --git a/core/tests/coretests/src/android/app/activity/LifecycleTest.java b/core/tests/coretests/src/android/app/activity/LifecycleTest.java
index ed01fac..5aa0380 100644
--- a/core/tests/coretests/src/android/app/activity/LifecycleTest.java
+++ b/core/tests/coretests/src/android/app/activity/LifecycleTest.java
@@ -18,8 +18,9 @@
 
 import android.content.ComponentName;
 import android.content.Intent;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 public class LifecycleTest extends ActivityTestsBase {
     private Intent mTopIntent;
diff --git a/core/tests/coretests/src/android/app/activity/MetaDataTest.java b/core/tests/coretests/src/android/app/activity/MetaDataTest.java
index 5b9c0e9..cf27878 100644
--- a/core/tests/coretests/src/android/app/activity/MetaDataTest.java
+++ b/core/tests/coretests/src/android/app/activity/MetaDataTest.java
@@ -27,8 +27,11 @@
 import android.content.res.XmlResourceParser;
 import android.os.Bundle;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
diff --git a/core/tests/coretests/src/android/app/activity/RemoteSubActivityScreen.java b/core/tests/coretests/src/android/app/activity/RemoteSubActivityScreen.java
index 9f402a5..8184627 100644
--- a/core/tests/coretests/src/android/app/activity/RemoteSubActivityScreen.java
+++ b/core/tests/coretests/src/android/app/activity/RemoteSubActivityScreen.java
@@ -1,19 +1,18 @@
-/* //device/apps/AndroidTests/src/com.android.unit_tests/activity/TestedScreen.java
-**
-** Copyright 2006, 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.
-*/
+/*
+ * Copyright (C) 2006 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.activity;
 
@@ -21,7 +20,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Process;
-import android.util.Log;
+
+//device/apps/AndroidTests/src/com.android.unit_tests/activity/TestedScreen.java
 
 public class RemoteSubActivityScreen extends SubActivityScreen {
     Handler mHandler = new Handler();
diff --git a/core/tests/coretests/src/android/app/activity/ServiceTest.java b/core/tests/coretests/src/android/app/activity/ServiceTest.java
index d3ae415..9d2aebd 100644
--- a/core/tests/coretests/src/android/app/activity/ServiceTest.java
+++ b/core/tests/coretests/src/android/app/activity/ServiceTest.java
@@ -22,13 +22,12 @@
 import android.content.ServiceConnection;
 import android.os.Binder;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.Parcel;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.util.Log;
+import android.os.RemoteException;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 // These test binders purport to support an interface whose canonical
 // interface name is ServiceTest.SERVICE_LOCAL
diff --git a/core/tests/coretests/src/android/app/activity/SetTimeZonePermissionsTest.java b/core/tests/coretests/src/android/app/activity/SetTimeZonePermissionsTest.java
index 41b9547..8e17295 100644
--- a/core/tests/coretests/src/android/app/activity/SetTimeZonePermissionsTest.java
+++ b/core/tests/coretests/src/android/app/activity/SetTimeZonePermissionsTest.java
@@ -19,7 +19,8 @@
 import android.app.AlarmManager;
 import android.content.Context;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import java.util.TimeZone;
 
diff --git a/core/tests/coretests/src/android/app/activity/SubActivityTest.java b/core/tests/coretests/src/android/app/activity/SubActivityTest.java
index 35dde8a..53f89fe 100644
--- a/core/tests/coretests/src/android/app/activity/SubActivityTest.java
+++ b/core/tests/coretests/src/android/app/activity/SubActivityTest.java
@@ -16,9 +16,10 @@
 
 package android.app.activity;
 
-import android.test.suitebuilder.annotation.Suppress;
 import android.content.ComponentName;
 
+import androidx.test.filters.Suppress;
+
 @Suppress
 public class SubActivityTest extends ActivityTestsBase {
 
diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
index 9b5b725..8d42c74 100644
--- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
+++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
@@ -27,8 +27,9 @@
 
 import android.app.admin.PasswordMetrics.PasswordComplexityBucket;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
index 689e683..1f4e5df 100644
--- a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
+++ b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.app.assist;
 
 import static android.view.View.AUTOFILL_TYPE_TEXT;
@@ -22,13 +23,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.app.assist.AssistStructure.ViewNode;
-import android.content.ComponentName;
 import android.content.Context;
 import android.os.Parcel;
 import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.InputFilter;
 import android.util.Log;
 import android.view.autofill.AutofillId;
@@ -37,6 +34,10 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/assist/EmptyLayoutActivity.java b/core/tests/coretests/src/android/app/assist/EmptyLayoutActivity.java
index f4b6bed..defec43 100644
--- a/core/tests/coretests/src/android/app/assist/EmptyLayoutActivity.java
+++ b/core/tests/coretests/src/android/app/assist/EmptyLayoutActivity.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.app.assist;
 
 import android.app.Activity;
diff --git a/core/tests/coretests/src/android/app/backup/BackupDataTest.java b/core/tests/coretests/src/android/app/backup/BackupDataTest.java
index 5b8e481..18ff54f 100644
--- a/core/tests/coretests/src/android/app/backup/BackupDataTest.java
+++ b/core/tests/coretests/src/android/app/backup/BackupDataTest.java
@@ -16,31 +16,22 @@
 
 package android.app.backup;
 
-import android.app.backup.BackupDataInput;
-import android.app.backup.BackupDataOutput;
-import android.content.res.AssetFileDescriptor;
 import android.content.res.AssetManager;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
-import android.test.InstrumentationTestCase;
 import android.util.Base64;
-import android.util.Log;
-import org.json.JSONObject;
+
+import androidx.test.filters.LargeTest;
 
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
-import java.io.FileReader;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.lang.Exception;
-import java.nio.ByteBuffer;
 
 @LargeTest
 public class BackupDataTest extends AndroidTestCase {
diff --git a/core/tests/coretests/src/android/app/backup/FullBackupTest.java b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
index 5db416b..08edb4e 100644
--- a/core/tests/coretests/src/android/app/backup/FullBackupTest.java
+++ b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
@@ -18,11 +18,12 @@
 
 import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags;
 import android.content.Context;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
+import androidx.test.filters.LargeTest;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlPullParserFactory;
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
index b1f8552..52b2658 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
@@ -23,8 +23,9 @@
 import android.app.ClientTransactionHandler;
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index fb0f534..ad28d13 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -35,8 +35,9 @@
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
index a788a93..f730a24 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
@@ -45,10 +45,11 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 2801f324..8604b0c 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -50,8 +50,9 @@
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.app.IVoiceInteractor;
 
diff --git a/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java b/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
index e20645c..0efc0ab 100644
--- a/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
+++ b/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
@@ -21,7 +21,8 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.Test;
 
diff --git a/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java b/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
index b69054c..b519bf8 100644
--- a/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
+++ b/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
@@ -21,7 +21,8 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.Test;
 
diff --git a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
index dd46240..bb535b6 100644
--- a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
+++ b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
@@ -16,14 +16,13 @@
 
 package android.app.timezone;
 
-import static junit.framework.Assert.fail;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.Test;
 
diff --git a/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java b/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
index 4004086..df9ddea 100644
--- a/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
+++ b/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
@@ -25,7 +25,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.UserHandle;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
diff --git a/core/tests/coretests/src/android/app/usage/EventListTest.java b/core/tests/coretests/src/android/app/usage/EventListTest.java
index 9dc0d43..685fcae 100644
--- a/core/tests/coretests/src/android/app/usage/EventListTest.java
+++ b/core/tests/coretests/src/android/app/usage/EventListTest.java
@@ -20,10 +20,11 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
index 28aaf1e..1633e1a 100644
--- a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
+++ b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
@@ -21,6 +21,7 @@
 import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
 import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED;
 import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE;
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
 import static android.app.usage.UsageEvents.Event.END_OF_DAY;
 import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK;
 import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START;
@@ -33,8 +34,9 @@
 
 import android.app.usage.UsageEvents.Event;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -528,6 +530,11 @@
     }
 
     @Test
+    public void testEvent_DEVICE_SHUTDOWN() {
+        testClosingEvent(DEVICE_SHUTDOWN);
+    }
+
+    @Test
     public void testEvent_FLUSH_TO_DISK() {
         testClosingEvent(FLUSH_TO_DISK);
     }
@@ -535,8 +542,9 @@
     private void testClosingEvent(int eventType) {
         // When these three closing events are received, all open activities/services need to be
         // closed and usage stats are updated.
-        if (eventType != FLUSH_TO_DISK) {
-            fail("Closing eventType must be one of FLUSH_TO_DISK");
+        if (eventType != DEVICE_SHUTDOWN
+                && eventType != FLUSH_TO_DISK) {
+            fail("Closing eventType must be one of DEVICE_SHUTDOWN, FLUSH_TO_DISK");
         }
 
         left.mPackageName = "com.test";
diff --git a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
index 978ea7a..c307e64 100644
--- a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
@@ -16,7 +16,6 @@
 
 package android.content;
 
-
 import static org.junit.Assert.fail;
 
 import android.app.ActivityManager;
@@ -30,9 +29,10 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/content/AssetTest.java b/core/tests/coretests/src/android/content/AssetTest.java
index b66574c..8e55e8a 100644
--- a/core/tests/coretests/src/android/content/AssetTest.java
+++ b/core/tests/coretests/src/android/content/AssetTest.java
@@ -18,7 +18,8 @@
 
 import android.content.res.AssetManager;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/core/tests/coretests/src/android/content/BrickDeniedTest.java b/core/tests/coretests/src/android/content/BrickDeniedTest.java
index 3d246b4..d8c9baa 100644
--- a/core/tests/coretests/src/android/content/BrickDeniedTest.java
+++ b/core/tests/coretests/src/android/content/BrickDeniedTest.java
@@ -17,7 +17,8 @@
 package android.content;
 
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 /** Test to make sure brick intents <b>don't</b> work without permission. */
 public class BrickDeniedTest extends AndroidTestCase {
diff --git a/core/tests/coretests/src/android/content/BroadcastReceiverTests.java b/core/tests/coretests/src/android/content/BroadcastReceiverTests.java
index 8deccb7..1509ff9 100644
--- a/core/tests/coretests/src/android/content/BroadcastReceiverTests.java
+++ b/core/tests/coretests/src/android/content/BroadcastReceiverTests.java
@@ -18,9 +18,9 @@
 
 import static org.junit.Assert.fail;
 
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/content/ContentProviderOperationTest.java b/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
index aea124b..b142761 100644
--- a/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
+++ b/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
@@ -16,22 +16,23 @@
 
 package android.content;
 
-import android.content.ContentValues;
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.net.Uri;
 import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.text.TextUtils;
+
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.util.HashMap;
-import java.util.Set;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 
 @SmallTest
 public class ContentProviderOperationTest extends TestCase {
diff --git a/core/tests/coretests/src/android/content/ContentProviderTest.java b/core/tests/coretests/src/android/content/ContentProviderTest.java
index 2142f27..8895f9b 100644
--- a/core/tests/coretests/src/android/content/ContentProviderTest.java
+++ b/core/tests/coretests/src/android/content/ContentProviderTest.java
@@ -23,7 +23,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ProviderInfo;
 import android.net.Uri;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/content/ContentQueryMapTest.java b/core/tests/coretests/src/android/content/ContentQueryMapTest.java
index f47bfdb..7106234 100644
--- a/core/tests/coretests/src/android/content/ContentQueryMapTest.java
+++ b/core/tests/coretests/src/android/content/ContentQueryMapTest.java
@@ -16,16 +16,14 @@
 
 package android.content;
 
-import android.content.ContentQueryMap;
-import android.content.ContentResolver;
-import android.content.ContentValues;
 import android.database.Cursor;
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.Settings;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 import java.util.Observable;
 import java.util.Observer;
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 9940bf7..f14f289 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -31,10 +31,11 @@
 import android.net.Uri;
 import android.os.MemoryFile;
 import android.os.ParcelFileDescriptor;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Size;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/content/ContentValuesTest.java b/core/tests/coretests/src/android/content/ContentValuesTest.java
index 7b39939..0ab79e7 100644
--- a/core/tests/coretests/src/android/content/ContentValuesTest.java
+++ b/core/tests/coretests/src/android/content/ContentValuesTest.java
@@ -17,8 +17,8 @@
 package android.content;
 
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 
 /*
   runtest -c android.content.ContentValuesTest frameworks-core
@@ -29,7 +29,7 @@
     adb shell pm uninstall -k com.android.frameworks.coretests && \
     adb install out/target/product/bullhead/testcases/FrameworksCoreTests/FrameworksCoreTests.apk && \
     adb shell am instrument -w -e package android.content \
-      com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+      com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
 */
 public class ContentValuesTest extends AndroidTestCase {
 
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index c8a3098..2f442c3 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -19,11 +19,12 @@
 import static org.junit.Assert.assertEquals;
 
 import android.app.ActivityThread;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.WindowManager;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java b/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
index 4362ec3..22b2314 100644
--- a/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
@@ -19,7 +19,8 @@
 import android.content.pm.UserInfo;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * To run the tests, use
@@ -32,7 +33,7 @@
  * Install: adb install -r \
  *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
  * Run: adb shell am instrument -e class android.content.ManagedUserContentResolverTest -w \
- *     com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ *     com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  */
 @LargeTest
 public class ManagedUserContentResolverTest extends AbstractCrossUserContentResolverTest {
diff --git a/core/tests/coretests/src/android/content/MemoryFileProviderTest.java b/core/tests/coretests/src/android/content/MemoryFileProviderTest.java
index bbe7c10..7cd4862 100644
--- a/core/tests/coretests/src/android/content/MemoryFileProviderTest.java
+++ b/core/tests/coretests/src/android/content/MemoryFileProviderTest.java
@@ -18,9 +18,10 @@
 
 import android.net.Uri;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
 
 import java.io.InputStream;
 import java.util.Arrays;
diff --git a/core/tests/coretests/src/android/content/RestrictionsManagerTest.java b/core/tests/coretests/src/android/content/RestrictionsManagerTest.java
index 10d74f7..fd5de32 100644
--- a/core/tests/coretests/src/android/content/RestrictionsManagerTest.java
+++ b/core/tests/coretests/src/android/content/RestrictionsManagerTest.java
@@ -13,13 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License
  */
+
 package android.content;
 
 import android.os.Bundle;
 import android.os.Parcelable;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 
+import androidx.test.filters.LargeTest;
+
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
diff --git a/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java b/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
index f8b13f0..dbe0278 100644
--- a/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
@@ -18,7 +18,8 @@
 
 import android.content.pm.UserInfo;
 import android.os.RemoteException;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * To run the tests, use
@@ -31,7 +32,7 @@
  * Install: adb install -r \
  *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
  * Run: adb shell am instrument -e class android.content.SecondaryUserContentResolverTest -w \
- *     com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ *     com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  */
 @LargeTest
 public class SecondaryUserContentResolverTest extends AbstractCrossUserContentResolverTest {
diff --git a/core/tests/coretests/src/android/content/UriMatcherTest.java b/core/tests/coretests/src/android/content/UriMatcherTest.java
index f3b9e76..6cef46b 100644
--- a/core/tests/coretests/src/android/content/UriMatcherTest.java
+++ b/core/tests/coretests/src/android/content/UriMatcherTest.java
@@ -17,14 +17,14 @@
 package android.content;
 
 import android.net.Uri;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
 
-
 public class UriMatcherTest extends TestCase {
 
     static final int ROOT = 0;
diff --git a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
index 2acb08d..9b360db 100644
--- a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.pm;
 
 import static android.content.pm.PackageBuilder.builder;
@@ -20,7 +21,8 @@
 import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
 
 import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
index dce22ce..0ed76dc 100644
--- a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
@@ -13,13 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.pm;
 
 import static android.content.pm.PackageBuilder.builder;
 import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
 
 import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
index 866de93..7f817d6 100644
--- a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.pm;
 
 import static android.content.pm.PackageBuilder.builder;
@@ -20,7 +21,8 @@
 import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
 
 import android.content.pm.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/ComponentTest.java b/core/tests/coretests/src/android/content/pm/ComponentTest.java
index cc75641..f31f0b5 100644
--- a/core/tests/coretests/src/android/content/pm/ComponentTest.java
+++ b/core/tests/coretests/src/android/content/pm/ComponentTest.java
@@ -21,7 +21,14 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 import static android.content.pm.PackageManager.GET_DISABLED_COMPONENTS;
 
-import android.test.suitebuilder.annotation.Suppress;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+
 import com.android.frameworks.coretests.enabled_app.DisabledActivity;
 import com.android.frameworks.coretests.enabled_app.DisabledProvider;
 import com.android.frameworks.coretests.enabled_app.DisabledReceiver;
@@ -31,12 +38,6 @@
 import com.android.frameworks.coretests.enabled_app.EnabledReceiver;
 import com.android.frameworks.coretests.enabled_app.EnabledService;
 
-import android.content.ComponentName;
-import android.content.Intent;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-
 import java.util.List;
 
 /**
diff --git a/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java b/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java
index 1f762fd..1c703ab 100644
--- a/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java
+++ b/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java
@@ -17,7 +17,8 @@
 package android.content.pm;
 
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
diff --git a/core/tests/coretests/src/android/content/pm/MacAuthenticatedInputStreamTest.java b/core/tests/coretests/src/android/content/pm/MacAuthenticatedInputStreamTest.java
index 659f9ea..1ddd753 100644
--- a/core/tests/coretests/src/android/content/pm/MacAuthenticatedInputStreamTest.java
+++ b/core/tests/coretests/src/android/content/pm/MacAuthenticatedInputStreamTest.java
@@ -16,9 +16,12 @@
 
 package android.content.pm;
 
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 
+import androidx.test.filters.LargeTest;
+
+import libcore.io.Streams;
+
 import java.io.ByteArrayInputStream;
 import java.util.Arrays;
 
@@ -26,8 +29,6 @@
 import javax.crypto.SecretKey;
 import javax.crypto.spec.SecretKeySpec;
 
-import libcore.io.Streams;
-
 @LargeTest
 public class MacAuthenticatedInputStreamTest extends AndroidTestCase {
 
diff --git a/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java b/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java
index 91697c0..05db8ee 100644
--- a/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java
+++ b/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.pm;
 
 import org.junit.Assume;
diff --git a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java b/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
index dcd2707..834a0bb 100644
--- a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
@@ -13,13 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.pm;
 
 import static android.content.pm.PackageBuilder.builder;
 import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
 
 import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
index c64d520..3d7aab0 100644
--- a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
@@ -24,7 +24,8 @@
 
 import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
 import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Assume;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/content/pm/PackageBuilder.java b/core/tests/coretests/src/android/content/pm/PackageBuilder.java
index 4ceed83..c5db962 100644
--- a/core/tests/coretests/src/android/content/pm/PackageBuilder.java
+++ b/core/tests/coretests/src/android/content/pm/PackageBuilder.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.pm;
 
 import static org.junit.Assert.assertEquals;
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 8ac9451d..0ab5367 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -54,11 +54,12 @@
 import android.system.Os;
 import android.system.StructStat;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+
 import com.android.frameworks.coretests.R;
 import com.android.internal.content.PackageHelper;
 
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserCacheHelperTest.java b/core/tests/coretests/src/android/content/pm/PackageParserCacheHelperTest.java
index 00be822..e852f98 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserCacheHelperTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserCacheHelperTest.java
@@ -22,8 +22,9 @@
 import android.content.pm.PackageParserCacheHelper.WriteHelper;
 import android.os.Bundle;
 import android.os.Parcel;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 267267e..be1b1ce 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -29,9 +29,10 @@
 import android.os.Bundle;
 import android.os.FileUtils;
 import android.os.SystemProperties;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
 
@@ -51,6 +52,12 @@
     private static final String PRE_RELEASE = "B";
     private static final String NEWER_PRE_RELEASE = "C";
 
+    // Codenames with a fingerprint attached to them. These may only be present in the apps
+    // declared min SDK and not as platform codenames.
+    private static final String OLDER_PRE_RELEASE_WITH_FINGERPRINT = "A.fingerprint";
+    private static final String PRE_RELEASE_WITH_FINGERPRINT = "B.fingerprint";
+    private static final String NEWER_PRE_RELEASE_WITH_FINGERPRINT = "C.fingerprint";
+
     private static final String[] CODENAMES_RELEASED = { /* empty */ };
     private static final String[] CODENAMES_PRE_RELEASE = { PRE_RELEASE };
 
@@ -68,7 +75,7 @@
                 isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
                 outError);
 
-        assertEquals(result, expectedMinSdk);
+        assertEquals("Error msg: " + outError[0], expectedMinSdk, result);
 
         if (expectedMinSdk == -1) {
             assertNotNull(outError[0]);
@@ -98,6 +105,7 @@
         // APP: Pre-release API 10
         // DEV: Pre-release API 20
         verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1);
+        verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, -1);
 
         // Do allow same pre-release minSdkVersion on pre-release platform,
         // but overwrite the specified version with CUR_DEVELOPMENT.
@@ -105,11 +113,15 @@
         // DEV: Pre-release API 20
         verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false,
                 Build.VERSION_CODES.CUR_DEVELOPMENT);
+        verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, false,
+                Build.VERSION_CODES.CUR_DEVELOPMENT);
+
 
         // Don't allow newer pre-release minSdkVersion on pre-release platform.
         // APP: Pre-release API 30
         // DEV: Pre-release API 20
         verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1);
+        verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, -1);
     }
 
     @Test
@@ -133,16 +145,20 @@
         // APP: Pre-release API 10
         // DEV: Released API 20
         verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1);
+        verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, -1);
 
         // Don't allow same pre-release minSdkVersion on released platform.
         // APP: Pre-release API 20
         // DEV: Released API 20
         verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1);
+        verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, -1);
+
 
         // Don't allow newer pre-release minSdkVersion on released platform.
         // APP: Pre-release API 30
         // DEV: Released API 20
         verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1);
+        verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, -1);
     }
 
     private void verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename,
@@ -189,6 +205,9 @@
         // DEV: Pre-release API 20
         verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1,
                 false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, -1,
+                false /* forceCurrentDev */);
+
 
         // Do allow same pre-release targetSdkVersion on pre-release platform,
         // but overwrite the specified version with CUR_DEVELOPMENT.
@@ -196,18 +215,26 @@
         // DEV: Pre-release API 20
         verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false,
                 Build.VERSION_CODES.CUR_DEVELOPMENT, false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, false,
+                Build.VERSION_CODES.CUR_DEVELOPMENT, false /* forceCurrentDev */);
+
 
         // Don't allow newer pre-release targetSdkVersion on pre-release platform.
         // APP: Pre-release API 30
         // DEV: Pre-release API 20
         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1,
                 false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, -1,
+                false /* forceCurrentDev */);
+
 
         // Force newer pre-release targetSdkVersion to current pre-release platform.
         // APP: Pre-release API 30
         // DEV: Pre-release API 20
         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false,
                 Build.VERSION_CODES.CUR_DEVELOPMENT, true /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false,
+                Build.VERSION_CODES.CUR_DEVELOPMENT, true /* forceCurrentDev */);
     }
 
     @Test
@@ -235,18 +262,25 @@
         // DEV: Released API 20
         verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1,
                 false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, -1,
+                false /* forceCurrentDev */);
 
         // Don't allow same pre-release targetSdkVersion on released platform.
         // APP: Pre-release API 20
         // DEV: Released API 20
         verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1,
                 false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, -1,
+                false /* forceCurrentDev */);
+
 
         // Don't allow newer pre-release targetSdkVersion on released platform.
         // APP: Pre-release API 30
         // DEV: Released API 20
         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1,
                 false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, -1,
+                false /* forceCurrentDev */);
     }
 
     /**
diff --git a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java b/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
index d5d3d7a..71a0e5e 100644
--- a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.pm;
 
 import java.util.function.Supplier;
diff --git a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
index 952bb55..8874525 100644
--- a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
+++ b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
@@ -1,8 +1,25 @@
+/*
+ * 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.content.pm;
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
index d3d1f22a..365e97d 100644
--- a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
+++ b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
@@ -21,11 +21,12 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
 import android.util.SparseArray;
 
+import androidx.test.filters.LargeTest;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
index 3dba440..216b0c8 100644
--- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
+++ b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.pm;
 
 import static android.content.pm.PackageBuilder.builder;
@@ -20,7 +21,8 @@
 
 import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
 import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
index 15b27d7..fc60980 100644
--- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
+++ b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.pm;
 
 import static android.content.pm.PackageBuilder.builder;
@@ -20,7 +21,8 @@
 
 import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
 import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/SignatureTest.java b/core/tests/coretests/src/android/content/pm/SignatureTest.java
index a3fa1a9..f0b4af6 100644
--- a/core/tests/coretests/src/android/content/pm/SignatureTest.java
+++ b/core/tests/coretests/src/android/content/pm/SignatureTest.java
@@ -16,7 +16,7 @@
 
 package android.content.pm;
 
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
index 68942cb..f6527da 100644
--- a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
+++ b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
@@ -16,12 +16,12 @@
 
 package android.content.pm;
 
-import android.content.pm.VerificationParams;
 import android.net.Uri;
 import android.os.Parcel;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 
+import androidx.test.filters.LargeTest;
+
 /**
  * Tests the android.content.pm.VerificationParams class
  *
diff --git a/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java b/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java
index 88d7a59..e7cd02d 100644
--- a/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java
+++ b/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java
@@ -17,7 +17,8 @@
 package android.content.pm;
 
 import android.os.Parcel;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import java.util.Random;
 
diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
index e248a77..1ca879c 100644
--- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
+++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
@@ -29,12 +29,21 @@
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
 
+import libcore.testing.io.TestIoUtils;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -45,14 +54,6 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
-import libcore.testing.io.TestIoUtils;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DexMetadataHelperTest {
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
index 47554a6..47b14bb 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
@@ -17,9 +17,10 @@
 package android.content.res;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.TypedValue;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.lang.reflect.InvocationTargetException;
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationTest.java b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
index 72b9197..2fc3e36 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
@@ -13,19 +13,18 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package android.content.res;
 
-import org.junit.runner.RunWith;
-import org.junit.Test;
-import org.junit.runners.JUnit4;
-
-import android.content.res.Configuration;
-import android.support.test.filters.SmallTest;
 import android.platform.test.annotations.Presubmit;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
-import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Build/install/run: bit FrameworksCoreTests:android.content.res.ConfigurationTest
diff --git a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
index 42ff2e9..7ab9d7f 100644
--- a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
+++ b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.res;
 
 import static android.content.res.FontResourcesParser.FamilyResourceEntry;
@@ -26,9 +27,10 @@
 import static org.junit.Assert.assertNotNull;
 
 import android.app.Instrumentation;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java b/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java
index e85666e..aa1a534 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java
@@ -13,14 +13,15 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package android.content.res;
 
 import android.os.FileUtils;
 import android.os.LocaleList;
-import android.support.test.filters.SmallTest;
 import android.test.AndroidTestCase;
 import android.util.DisplayMetrics;
-import android.view.Display;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index b2ff927..a2dab99 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -13,18 +13,20 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package android.content.res;
 
 import android.annotation.NonNull;
 import android.app.ResourcesManager;
 import android.os.Binder;
 import android.os.LocaleList;
-import android.support.test.filters.SmallTest;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
 import android.view.Display;
 import android.view.DisplayAdjustments;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 public class ResourcesManagerTest extends TestCase {
diff --git a/core/tests/coretests/src/android/database/CursorWindowTest.java b/core/tests/coretests/src/android/database/CursorWindowTest.java
index 075f5b7..123da3e 100644
--- a/core/tests/coretests/src/android/database/CursorWindowTest.java
+++ b/core/tests/coretests/src/android/database/CursorWindowTest.java
@@ -16,14 +16,14 @@
 
 package android.database;
 
-import android.test.suitebuilder.annotation.SmallTest;
-import android.database.CursorWindow;
 import android.test.PerformanceTestCase;
 
-import java.util.Arrays;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
+import java.util.Arrays;
+
 public class CursorWindowTest extends TestCase implements PerformanceTestCase {
     public boolean isPerformanceOnly() {
         return false;
diff --git a/core/tests/coretests/src/android/database/DatabaseCursorTest.java b/core/tests/coretests/src/android/database/DatabaseCursorTest.java
index 3507223..eb4fd70 100644
--- a/core/tests/coretests/src/android/database/DatabaseCursorTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseCursorTest.java
@@ -18,10 +18,6 @@
 
 import android.content.ContentValues;
 import android.content.Context;
-import android.database.Cursor;
-import android.database.CursorIndexOutOfBoundsException;
-import android.database.DataSetObserver;
-import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteCursor;
 import android.database.sqlite.SQLiteCursorDriver;
 import android.database.sqlite.SQLiteDatabase;
@@ -29,11 +25,12 @@
 import android.os.Looper;
 import android.test.AndroidTestCase;
 import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
index 9d75c78..49fb75b 100644
--- a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
@@ -25,16 +25,17 @@
 import android.database.sqlite.SQLiteDebug;
 import android.database.sqlite.SQLiteException;
 import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.uiautomator.UiDevice;
 import android.test.AndroidTestCase;
 import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 import android.util.Pair;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
 import junit.framework.Assert;
 
 import java.io.File;
diff --git a/core/tests/coretests/src/android/database/DatabaseLocaleTest.java b/core/tests/coretests/src/android/database/DatabaseLocaleTest.java
index b3282941..ee7936f 100644
--- a/core/tests/coretests/src/android/database/DatabaseLocaleTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseLocaleTest.java
@@ -17,17 +17,17 @@
 package android.database;
 
 import android.database.sqlite.SQLiteDatabase;
-import android.database.Cursor;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
 import android.test.MoreAsserts;
+import android.util.Log;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
+import junit.framework.TestCase;
 
 import java.util.ArrayList;
 import java.util.Locale;
 
-import junit.framework.TestCase;
-
 public class DatabaseLocaleTest extends TestCase {
 
     private SQLiteDatabase mDatabase;
diff --git a/core/tests/coretests/src/android/database/DatabaseLockTest.java b/core/tests/coretests/src/android/database/DatabaseLockTest.java
index 8d3cf5a..e8936c9 100644
--- a/core/tests/coretests/src/android/database/DatabaseLockTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseLockTest.java
@@ -17,11 +17,13 @@
 package android.database;
 
 import android.database.sqlite.SQLiteDatabase;
-import android.test.suitebuilder.annotation.Suppress;
+import android.test.AndroidTestCase;
 import android.util.Log;
+
+import androidx.test.filters.Suppress;
+
 import java.io.File;
 import java.util.concurrent.atomic.AtomicInteger;
-import android.test.AndroidTestCase;
 
 /* 
  * This is a series of unit tests for database locks.
diff --git a/core/tests/coretests/src/android/database/DatabaseStatementTest.java b/core/tests/coretests/src/android/database/DatabaseStatementTest.java
index 895d715..4b34650 100644
--- a/core/tests/coretests/src/android/database/DatabaseStatementTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseStatementTest.java
@@ -17,14 +17,14 @@
 package android.database;
 
 import android.content.Context;
-import android.database.Cursor;
 import android.database.sqlite.SQLiteConstraintException;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteDoneException;
 import android.database.sqlite.SQLiteStatement;
 import android.test.AndroidTestCase;
 import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
 
 import java.io.File;
 
diff --git a/core/tests/coretests/src/android/database/DatabaseStressTest.java b/core/tests/coretests/src/android/database/DatabaseStressTest.java
index 30e46e7..bfea1fc 100644
--- a/core/tests/coretests/src/android/database/DatabaseStressTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseStressTest.java
@@ -17,11 +17,11 @@
 package android.database;
 
 import android.content.Context;
-import android.database.sqlite.*;
+import android.database.sqlite.SQLiteDatabase;
+import android.test.AndroidTestCase;
 import android.util.Log;
 
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.Suppress;
+import androidx.test.filters.Suppress;
 
 import java.io.File;
 
diff --git a/core/tests/coretests/src/android/database/DatabaseUtilsTest.java b/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
index 7c206d7..be156c8 100644
--- a/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
@@ -20,7 +20,7 @@
 
 import static org.junit.Assert.assertEquals;
 
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/database/RedactingCursorTest.java b/core/tests/coretests/src/android/database/RedactingCursorTest.java
index 93998f3..e2d2bae 100644
--- a/core/tests/coretests/src/android/database/RedactingCursorTest.java
+++ b/core/tests/coretests/src/android/database/RedactingCursorTest.java
@@ -22,8 +22,9 @@
 
 import android.content.Context;
 import android.net.Uri;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java b/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java
index 9ed3f11b..730a3cb 100644
--- a/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java
+++ b/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java
@@ -26,11 +26,12 @@
 import android.database.sqlite.SQLiteDatabaseConfiguration;
 import android.database.sqlite.SQLiteDebug;
 import android.database.sqlite.SQLiteOpenHelper;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/database/run_newdb_perf_test.sh b/core/tests/coretests/src/android/database/run_newdb_perf_test.sh
index c5b2c97..95f1f83 100755
--- a/core/tests/coretests/src/android/database/run_newdb_perf_test.sh
+++ b/core/tests/coretests/src/android/database/run_newdb_perf_test.sh
@@ -23,7 +23,7 @@
 
 for (( i=0; i<$RUN_N; i++ ))
 do
-    adb  shell am instrument -e class 'android.database.NewDatabasePerformanceTestSuite' -w 'com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner'
+    adb  shell am instrument -e class 'android.database.NewDatabasePerformanceTestSuite' -w 'com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner'
 done
 
 adb logcat -d > /tmp/testlogcat.txt
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
index 551a58e..5dbcb3c 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
@@ -22,9 +22,10 @@
 
 import android.content.Context;
 import android.database.DatabaseUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java
index ed14a53..f1d27d4 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java
@@ -21,11 +21,12 @@
 
 import android.content.Context;
 import android.os.HandlerThread;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
index c52cf6e..78d3c41 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
@@ -23,7 +23,8 @@
 import android.database.CursorWindow;
 import android.platform.test.annotations.Presubmit;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import java.io.File;
 import java.util.Arrays;
diff --git a/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java b/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java
index e9e2a4d..564460e 100644
--- a/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java
+++ b/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java
@@ -17,14 +17,14 @@
 package android.graphics;
 
 import android.os.ParcelFileDescriptor;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
 import java.io.ByteArrayOutputStream;
 import java.io.FileDescriptor;
 
-
 public class BitmapFactoryTest extends TestCase {
 
     // tests that we can decode bitmaps from MemoryFiles
diff --git a/core/tests/coretests/src/android/graphics/BitmapTest.java b/core/tests/coretests/src/android/graphics/BitmapTest.java
index 3666ddd..e79d2ae 100644
--- a/core/tests/coretests/src/android/graphics/BitmapTest.java
+++ b/core/tests/coretests/src/android/graphics/BitmapTest.java
@@ -16,11 +16,10 @@
 
 package android.graphics;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
-
 public class BitmapTest extends TestCase {
 
     @SmallTest
diff --git a/core/tests/coretests/src/android/graphics/ColorSpaceRendererTest.java b/core/tests/coretests/src/android/graphics/ColorSpaceRendererTest.java
index 6e38fb6..8e9b38c 100644
--- a/core/tests/coretests/src/android/graphics/ColorSpaceRendererTest.java
+++ b/core/tests/coretests/src/android/graphics/ColorSpaceRendererTest.java
@@ -19,8 +19,8 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/graphics/ColorStateListTest.java b/core/tests/coretests/src/android/graphics/ColorStateListTest.java
index 374d142..1d34f93 100644
--- a/core/tests/coretests/src/android/graphics/ColorStateListTest.java
+++ b/core/tests/coretests/src/android/graphics/ColorStateListTest.java
@@ -19,7 +19,8 @@
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/graphics/FontFileUtilTest.java b/core/tests/coretests/src/android/graphics/FontFileUtilTest.java
index 76267b2..1771671 100644
--- a/core/tests/coretests/src/android/graphics/FontFileUtilTest.java
+++ b/core/tests/coretests/src/android/graphics/FontFileUtilTest.java
@@ -22,11 +22,12 @@
 import android.content.res.AssetManager;
 import android.graphics.fonts.FontFileUtil;
 import android.graphics.fonts.FontVariationAxis;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
 import android.util.Log;
 import android.util.Pair;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 
 import java.io.File;
diff --git a/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java b/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java
index 164c1aa..3cfeb25 100644
--- a/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java
+++ b/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java
@@ -20,7 +20,8 @@
 import android.content.res.Resources;
 import android.test.AndroidTestCase;
 import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.Suppress;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/graphics/PaintTest.java b/core/tests/coretests/src/android/graphics/PaintTest.java
index b5ed01f..bf56df1 100644
--- a/core/tests/coretests/src/android/graphics/PaintTest.java
+++ b/core/tests/coretests/src/android/graphics/PaintTest.java
@@ -18,9 +18,9 @@
 
 import static org.junit.Assert.assertNotEquals;
 
-import android.graphics.Paint;
 import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import java.util.Arrays;
 import java.util.HashSet;
diff --git a/core/tests/coretests/src/android/graphics/PathOffsetTest.java b/core/tests/coretests/src/android/graphics/PathOffsetTest.java
index 950f873..6cc42f6 100644
--- a/core/tests/coretests/src/android/graphics/PathOffsetTest.java
+++ b/core/tests/coretests/src/android/graphics/PathOffsetTest.java
@@ -16,13 +16,13 @@
 
 package android.graphics;
 
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap.Config;
 import android.graphics.Path.Direction;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 
-import static org.junit.Assert.assertTrue;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/graphics/PathTest.java b/core/tests/coretests/src/android/graphics/PathTest.java
index 78e4959..c6d6d1f 100644
--- a/core/tests/coretests/src/android/graphics/PathTest.java
+++ b/core/tests/coretests/src/android/graphics/PathTest.java
@@ -16,11 +16,10 @@
 
 package android.graphics;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
-
 public class PathTest extends TestCase {
 
     @SmallTest
diff --git a/core/tests/coretests/src/android/graphics/RectTest.java b/core/tests/coretests/src/android/graphics/RectTest.java
index d31d7d5..2918f44 100644
--- a/core/tests/coretests/src/android/graphics/RectTest.java
+++ b/core/tests/coretests/src/android/graphics/RectTest.java
@@ -23,8 +23,9 @@
 import static org.junit.Assert.assertNull;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java b/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java
index 909a8d9..e1ca7df 100644
--- a/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java
+++ b/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java
@@ -16,7 +16,7 @@
 
 package android.graphics;
 
-import android.test.suitebuilder.annotation.LargeTest;
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
index 6fdb71f..c66bac6 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
@@ -27,12 +27,13 @@
 import android.graphics.fonts.FontCustomizationParser;
 import android.graphics.fonts.FontFamily;
 import android.graphics.fonts.SystemFonts;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.FontConfig;
 import android.util.ArrayMap;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java
index b0c7976..2d16f82 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java
@@ -22,13 +22,12 @@
 import android.content.Context;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
-import android.graphics.Paint;
-import android.graphics.Typeface;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java b/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
index 781e343..3dc9987 100644
--- a/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.graphics.drawable;
 
 import android.content.res.Resources;
@@ -11,11 +27,12 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 import android.util.Log;
 import android.util.PathParser;
 
+import androidx.test.filters.LargeTest;
+
 import org.junit.Test;
 
 import java.io.File;
diff --git a/core/tests/coretests/src/android/graphics/drawable/DrawableWrapperTest.java b/core/tests/coretests/src/android/graphics/drawable/DrawableWrapperTest.java
index 655efb5..d0a6ff9 100644
--- a/core/tests/coretests/src/android/graphics/drawable/DrawableWrapperTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/DrawableWrapperTest.java
@@ -24,8 +24,9 @@
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Xfermode;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/graphics/drawable/IconTest.java b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
index 64fadc0..2bdcc28 100644
--- a/core/tests/coretests/src/android/graphics/drawable/IconTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
@@ -25,9 +25,10 @@
 import android.os.HandlerThread;
 import android.os.Parcel;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.io.ByteArrayOutputStream;
diff --git a/core/tests/coretests/src/android/hardware/display/AmbientBrightnessDayStatsTest.java b/core/tests/coretests/src/android/hardware/display/AmbientBrightnessDayStatsTest.java
index f90ae34..0a25bd7 100644
--- a/core/tests/coretests/src/android/hardware/display/AmbientBrightnessDayStatsTest.java
+++ b/core/tests/coretests/src/android/hardware/display/AmbientBrightnessDayStatsTest.java
@@ -23,8 +23,9 @@
 import static org.junit.Assert.fail;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
index dcc51e1..823fca5 100644
--- a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
+++ b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
@@ -22,10 +22,11 @@
 import static org.junit.Assert.fail;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Pair;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
index f30b1a2..daf6139 100644
--- a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
+++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
@@ -22,15 +22,12 @@
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.drawable.ColorDrawable;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.VirtualDisplay;
 import android.media.Image;
 import android.media.ImageReader;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -40,6 +37,8 @@
 import android.view.WindowManager;
 import android.widget.ImageView;
 
+import androidx.test.filters.LargeTest;
+
 import java.nio.ByteBuffer;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
diff --git a/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
new file mode 100644
index 0000000..16be0b0
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.hardware.hdmi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/** Tests for {@link HdmiUtils} class. */
+public class HdmiUtilsTest {
+
+    @Test
+    public void pathToPort_isMe() {
+        int targetPhysicalAddress = 0x1000;
+        int myPhysicalAddress = 0x1000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                HdmiUtils.TARGET_SAME_PHYSICAL_ADDRESS);
+    }
+
+    @Test
+    public void pathToPort_isDirectlyBelow() {
+        int targetPhysicalAddress = 0x1100;
+        int myPhysicalAddress = 0x1000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+            targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+    }
+
+    @Test
+    public void pathToPort_isBelow() {
+        int targetPhysicalAddress = 0x1110;
+        int myPhysicalAddress = 0x1000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+            targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+    }
+
+    @Test
+    public void pathToPort_neitherMeNorBelow() {
+        int targetPhysicalAddress = 0x3000;
+        int myPhysicalAddress = 0x2000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+        targetPhysicalAddress = 0x2200;
+        myPhysicalAddress = 0x3300;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+        targetPhysicalAddress = 0x2213;
+        myPhysicalAddress = 0x2212;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+        targetPhysicalAddress = 0x2340;
+        myPhysicalAddress = 0x2310;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+    }
+}
diff --git a/core/tests/coretests/src/android/metrics/LogMakerTest.java b/core/tests/coretests/src/android/metrics/LogMakerTest.java
index 3be776d..aabfc28 100644
--- a/core/tests/coretests/src/android/metrics/LogMakerTest.java
+++ b/core/tests/coretests/src/android/metrics/LogMakerTest.java
@@ -13,9 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.metrics;
 
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
diff --git a/core/tests/coretests/src/android/metrics/MetricsReaderTest.java b/core/tests/coretests/src/android/metrics/MetricsReaderTest.java
index 784a12f..96dac64 100644
--- a/core/tests/coretests/src/android/metrics/MetricsReaderTest.java
+++ b/core/tests/coretests/src/android/metrics/MetricsReaderTest.java
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.metrics;
 
 import android.metrics.MetricsReader.Event;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
diff --git a/core/tests/coretests/src/android/net/LocalSocketTest.java b/core/tests/coretests/src/android/net/LocalSocketTest.java
index 1286b13..9172237 100644
--- a/core/tests/coretests/src/android/net/LocalSocketTest.java
+++ b/core/tests/coretests/src/android/net/LocalSocketTest.java
@@ -16,12 +16,9 @@
 
 package android.net;
 
-import android.net.Credentials;
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
 import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/net/NetworkKeyTest.java b/core/tests/coretests/src/android/net/NetworkKeyTest.java
index fff23a0..0f1c71d 100644
--- a/core/tests/coretests/src/android/net/NetworkKeyTest.java
+++ b/core/tests/coretests/src/android/net/NetworkKeyTest.java
@@ -1,3 +1,19 @@
+/*
+ * 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;
 
 import static org.junit.Assert.assertEquals;
@@ -7,7 +23,8 @@
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiSsid;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java b/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
index c6758ce..29e212f 100644
--- a/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.net;
 
 import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
diff --git a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
index ff9816a..3e45a79 100644
--- a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
+++ b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
@@ -1,3 +1,19 @@
+/*
+ * 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.
+ */
+
 package android.net;
 
 import static junit.framework.Assert.assertFalse;
@@ -9,7 +25,8 @@
 
 import android.Manifest.permission;
 import android.content.Context;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java b/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java
index 5cbf02a..bc12e72 100644
--- a/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java
+++ b/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java
@@ -19,7 +19,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/net/SSLSessionCacheTest.java b/core/tests/coretests/src/android/net/SSLSessionCacheTest.java
index 11d066b..eec09e6 100644
--- a/core/tests/coretests/src/android/net/SSLSessionCacheTest.java
+++ b/core/tests/coretests/src/android/net/SSLSessionCacheTest.java
@@ -19,10 +19,10 @@
 import com.android.org.conscrypt.ClientSessionContext;
 import com.android.org.conscrypt.SSLClientSessionCache;
 
-import org.mockito.Mockito;
-
 import junit.framework.TestCase;
 
+import org.mockito.Mockito;
+
 import java.security.KeyManagementException;
 import java.security.SecureRandom;
 
diff --git a/core/tests/coretests/src/android/net/ScoredNetworkTest.java b/core/tests/coretests/src/android/net/ScoredNetworkTest.java
index 109f32e..d984d86 100644
--- a/core/tests/coretests/src/android/net/ScoredNetworkTest.java
+++ b/core/tests/coretests/src/android/net/ScoredNetworkTest.java
@@ -16,11 +16,17 @@
 
 package android.net;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.os.Bundle;
 import android.os.Parcel;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/net/SntpClientTest.java b/core/tests/coretests/src/android/net/SntpClientTest.java
index d72738c..87edb6e 100644
--- a/core/tests/coretests/src/android/net/SntpClientTest.java
+++ b/core/tests/coretests/src/android/net/SntpClientTest.java
@@ -20,9 +20,10 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import libcore.util.HexEncoding;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index ea0347d..a33de7b 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -18,7 +18,8 @@
 
 import android.content.ContentUris;
 import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/net/WebAddressTest.java b/core/tests/coretests/src/android/net/WebAddressTest.java
index 6fcb97e..70a6253 100644
--- a/core/tests/coretests/src/android/net/WebAddressTest.java
+++ b/core/tests/coretests/src/android/net/WebAddressTest.java
@@ -16,8 +16,8 @@
 
 package android.net;
 
-import android.net.WebAddress;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 public class WebAddressTest extends TestCase {
diff --git a/core/tests/coretests/src/android/net/http/SslCertificateTest.java b/core/tests/coretests/src/android/net/http/SslCertificateTest.java
index 6a30c6c..1beb1de 100644
--- a/core/tests/coretests/src/android/net/http/SslCertificateTest.java
+++ b/core/tests/coretests/src/android/net/http/SslCertificateTest.java
@@ -17,12 +17,13 @@
 
 package android.net.http;
 
-import android.net.http.SslCertificate;
-import android.test.suitebuilder.annotation.LargeTest;
+import androidx.test.filters.LargeTest;
+
+import junit.framework.TestCase;
+
 import java.io.ByteArrayInputStream;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
-import junit.framework.TestCase;
 
 public class SslCertificateTest extends TestCase {
 
diff --git a/core/tests/coretests/src/android/os/AidlTest.java b/core/tests/coretests/src/android/os/AidlTest.java
index bf11d56..4c51415 100644
--- a/core/tests/coretests/src/android/os/AidlTest.java
+++ b/core/tests/coretests/src/android/os/AidlTest.java
@@ -16,11 +16,10 @@
 
 package android.os;
 
-import android.os.IInterface;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
 import com.google.android.collect.Lists;
+
 import junit.framework.TestCase;
 
 import java.util.List;
diff --git a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
index 6cdb35ab..ce6ad87 100644
--- a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
+++ b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 package android.os;
 
 import static org.junit.Assert.assertEquals;
@@ -25,12 +24,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.support.test.uiautomator.UiDevice;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.frameworks.coretests.aidl.IBpcCallbackObserver;
 import com.android.frameworks.coretests.aidl.IBpcTestAppCmdService;
 import com.android.frameworks.coretests.aidl.IBpcTestServiceCmdService;
@@ -63,7 +63,7 @@
  * Install: adb install -r \
  * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
  * Run: adb shell am instrument -e class android.os.BinderProxyCountingTest -w \
- * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ * com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  *
  * or
  *
diff --git a/core/tests/coretests/src/android/os/BinderProxyTest.java b/core/tests/coretests/src/android/os/BinderProxyTest.java
index 4c36b5c..aceda2d 100644
--- a/core/tests/coretests/src/android/os/BinderProxyTest.java
+++ b/core/tests/coretests/src/android/os/BinderProxyTest.java
@@ -19,7 +19,8 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
 
 public class BinderProxyTest extends AndroidTestCase {
     private static class CountingListener implements Binder.ProxyTransactListener {
diff --git a/core/tests/coretests/src/android/os/BinderTest.java b/core/tests/coretests/src/android/os/BinderTest.java
index 6c9c3c1..a354195 100644
--- a/core/tests/coretests/src/android/os/BinderTest.java
+++ b/core/tests/coretests/src/android/os/BinderTest.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/os/BinderThreadPriorityService.java b/core/tests/coretests/src/android/os/BinderThreadPriorityService.java
index 47a4483..ed42058 100644
--- a/core/tests/coretests/src/android/os/BinderThreadPriorityService.java
+++ b/core/tests/coretests/src/android/os/BinderThreadPriorityService.java
@@ -18,7 +18,6 @@
 
 import android.app.Service;
 import android.content.Intent;
-import android.text.TextUtils;
 import android.util.Log;
 
 /**
diff --git a/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java b/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
index 56e977c..48c9df6 100644
--- a/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
+++ b/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
@@ -21,7 +21,6 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 
 import java.io.File;
diff --git a/core/tests/coretests/src/android/os/BinderWorkSourceTest.java b/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
index 5664df6..e16a3db 100644
--- a/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
+++ b/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
@@ -24,9 +24,10 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/os/BrightnessLimit.java b/core/tests/coretests/src/android/os/BrightnessLimit.java
index fabcf3d..5a3724f 100644
--- a/core/tests/coretests/src/android/os/BrightnessLimit.java
+++ b/core/tests/coretests/src/android/os/BrightnessLimit.java
@@ -18,7 +18,6 @@
 
 import android.app.Activity;
 import android.hardware.display.DisplayManager;
-import android.os.Bundle;
 import android.provider.Settings;
 import android.view.View;
 import android.view.View.OnClickListener;
diff --git a/core/tests/coretests/src/android/os/BroadcasterTest.java b/core/tests/coretests/src/android/os/BroadcasterTest.java
index 551ea8d..b4c47af9 100644
--- a/core/tests/coretests/src/android/os/BroadcasterTest.java
+++ b/core/tests/coretests/src/android/os/BroadcasterTest.java
@@ -16,11 +16,8 @@
 
 package android.os;
 
-import android.os.Broadcaster;
-import android.os.Handler;
-import android.os.Message;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.MediumTest;
+
 import junit.framework.TestCase;
 
 public class BroadcasterTest extends TestCase {
diff --git a/core/tests/coretests/src/android/os/BuildTest.java b/core/tests/coretests/src/android/os/BuildTest.java
index 3758627..decc768 100644
--- a/core/tests/coretests/src/android/os/BuildTest.java
+++ b/core/tests/coretests/src/android/os/BuildTest.java
@@ -16,9 +16,8 @@
 
 package android.os;
 
-import android.os.Build;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
+import androidx.test.filters.SmallTest;
+
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java
index 9fcf96d..e4dc993 100644
--- a/core/tests/coretests/src/android/os/BundleTest.java
+++ b/core/tests/coretests/src/android/os/BundleTest.java
@@ -20,8 +20,8 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/os/EnvironmentTest.java b/core/tests/coretests/src/android/os/EnvironmentTest.java
index 5189df5..d98ceaf 100644
--- a/core/tests/coretests/src/android/os/EnvironmentTest.java
+++ b/core/tests/coretests/src/android/os/EnvironmentTest.java
@@ -25,8 +25,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/os/FileObserverTest.java b/core/tests/coretests/src/android/os/FileObserverTest.java
index 93e27af..ece7645 100644
--- a/core/tests/coretests/src/android/os/FileObserverTest.java
+++ b/core/tests/coretests/src/android/os/FileObserverTest.java
@@ -16,13 +16,14 @@
 
 package android.os;
 
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import androidx.test.filters.MediumTest;
+
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.util.Log;
-
 import java.io.File;
 import java.io.FileOutputStream;
 import java.util.Iterator;
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 514ea0c..5bce227c 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -51,8 +51,9 @@
 import android.content.Context;
 import android.os.FileUtils.MemoryPipe;
 import android.provider.DocumentsContract.Document;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 
 import libcore.io.Streams;
 
diff --git a/core/tests/coretests/src/android/os/HandlerTester.java b/core/tests/coretests/src/android/os/HandlerTester.java
index a216a0b..fa442f4 100644
--- a/core/tests/coretests/src/android/os/HandlerTester.java
+++ b/core/tests/coretests/src/android/os/HandlerTester.java
@@ -16,10 +16,6 @@
 
 package android.os;
 
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-
 public abstract class HandlerTester extends Thread {
     public abstract void go();
     public abstract void handleMessage(Message msg);
diff --git a/core/tests/coretests/src/android/os/HandlerThreadTest.java b/core/tests/coretests/src/android/os/HandlerThreadTest.java
index 9772aa4..93cfc40 100644
--- a/core/tests/coretests/src/android/os/HandlerThreadTest.java
+++ b/core/tests/coretests/src/android/os/HandlerThreadTest.java
@@ -16,13 +16,9 @@
 
 package android.os;
 
+import androidx.test.filters.MediumTest;
+
 import junit.framework.TestCase;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Message;
-import android.os.Process;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
 
 public class HandlerThreadTest extends TestCase {
     private static final int TEST_WHAT = 1;
diff --git a/core/tests/coretests/src/android/os/IdleHandlerTest.java b/core/tests/coretests/src/android/os/IdleHandlerTest.java
index 6c0a862..d8886c9 100644
--- a/core/tests/coretests/src/android/os/IdleHandlerTest.java
+++ b/core/tests/coretests/src/android/os/IdleHandlerTest.java
@@ -16,11 +16,10 @@
 
 package android.os;
 
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
 import android.os.MessageQueue.IdleHandler;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
+
 import junit.framework.TestCase;
 
 public class IdleHandlerTest extends TestCase {
diff --git a/core/tests/coretests/src/android/os/LocaleListTest.java b/core/tests/coretests/src/android/os/LocaleListTest.java
index 17ef773..1f00a7a 100644
--- a/core/tests/coretests/src/android/os/LocaleListTest.java
+++ b/core/tests/coretests/src/android/os/LocaleListTest.java
@@ -13,14 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.os;
 
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.util.Locale;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
+import java.util.Locale;
+
 public class LocaleListTest extends TestCase {
     @SmallTest
     public void testConstructor() throws Exception {
diff --git a/core/tests/coretests/src/android/os/MemoryFileTest.java b/core/tests/coretests/src/android/os/MemoryFileTest.java
index 20b298d..05c2995 100644
--- a/core/tests/coretests/src/android/os/MemoryFileTest.java
+++ b/core/tests/coretests/src/android/os/MemoryFileTest.java
@@ -17,8 +17,9 @@
 package android.os;
 
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/core/tests/coretests/src/android/os/MessageQueueTest.java b/core/tests/coretests/src/android/os/MessageQueueTest.java
index 1cd1020..2c5588e 100644
--- a/core/tests/coretests/src/android/os/MessageQueueTest.java
+++ b/core/tests/coretests/src/android/os/MessageQueueTest.java
@@ -16,11 +16,9 @@
 
 package android.os;
 
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 import junit.framework.TestCase;
 
 @Suppress  // Failing.
diff --git a/core/tests/coretests/src/android/os/MessengerService.java b/core/tests/coretests/src/android/os/MessengerService.java
index f15e134..db33471 100644
--- a/core/tests/coretests/src/android/os/MessengerService.java
+++ b/core/tests/coretests/src/android/os/MessengerService.java
@@ -18,11 +18,6 @@
 
 import android.app.Service;
 import android.content.Intent;
-import android.os.RemoteException;
-import android.os.IBinder;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
 
 public class MessengerService extends Service {
     private final Handler mHandler = new Handler() {
diff --git a/core/tests/coretests/src/android/os/MessengerTest.java b/core/tests/coretests/src/android/os/MessengerTest.java
index 473ffe2..9143ff1 100644
--- a/core/tests/coretests/src/android/os/MessengerTest.java
+++ b/core/tests/coretests/src/android/os/MessengerTest.java
@@ -20,13 +20,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.os.RemoteException;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
 
 public class MessengerTest extends AndroidTestCase {
     private Messenger mServiceMessenger;
diff --git a/core/tests/coretests/src/android/os/OsTests.java b/core/tests/coretests/src/android/os/OsTests.java
index 2b84126..08fb945 100644
--- a/core/tests/coretests/src/android/os/OsTests.java
+++ b/core/tests/coretests/src/android/os/OsTests.java
@@ -16,12 +16,8 @@
 
 package android.os;
 
-import com.google.android.collect.Lists;
 import junit.framework.TestSuite;
 
-import java.util.Enumeration;
-import java.util.List;
-
 public class OsTests {
     public static TestSuite suite() {
         TestSuite suite = new TestSuite(OsTests.class.getName());
diff --git a/core/tests/coretests/src/android/os/ParcelNullabilityTest.java b/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
index 516dc0a..a6b296d 100644
--- a/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
+++ b/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
@@ -20,10 +20,11 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArrayMap;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/os/PatternMatcherTest.java b/core/tests/coretests/src/android/os/PatternMatcherTest.java
index 9645ccc..82350cd 100644
--- a/core/tests/coretests/src/android/os/PatternMatcherTest.java
+++ b/core/tests/coretests/src/android/os/PatternMatcherTest.java
@@ -1,9 +1,27 @@
+/*
+ * 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.
+ */
+
 package android.os;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
-import org.junit.runner.RunWith;
+
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 @RunWith(JUnit4.class)
diff --git a/core/tests/coretests/src/android/os/PerformanceCollectorTest.java b/core/tests/coretests/src/android/os/PerformanceCollectorTest.java
index 7533c84..38ad90f 100644
--- a/core/tests/coretests/src/android/os/PerformanceCollectorTest.java
+++ b/core/tests/coretests/src/android/os/PerformanceCollectorTest.java
@@ -17,15 +17,16 @@
 package android.os;
 
 import android.os.PerformanceCollector.PerformanceResultsWriter;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
+import junit.framework.TestCase;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Random;
 
-import junit.framework.TestCase;
-
 public class PerformanceCollectorTest extends TestCase {
 
     private PerformanceCollector mPerfCollector;
diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java
index a828f44..1b587dd 100644
--- a/core/tests/coretests/src/android/os/PowerManagerTest.java
+++ b/core/tests/coretests/src/android/os/PowerManagerTest.java
@@ -21,10 +21,11 @@
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.uiautomator.UiDevice;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 
 import org.junit.After;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/os/PowerManagerVrTest.java b/core/tests/coretests/src/android/os/PowerManagerVrTest.java
index e01e5fa..5d2c65b 100644
--- a/core/tests/coretests/src/android/os/PowerManagerVrTest.java
+++ b/core/tests/coretests/src/android/os/PowerManagerVrTest.java
@@ -19,16 +19,14 @@
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.provider.Settings;
-import android.service.dreams.IDreamManager;
 import android.service.dreams.DreamService;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
+import android.service.dreams.IDreamManager;
 import android.test.ActivityInstrumentationTestCase2;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
 /**
  * Tests dream aspects of PowerManager.
  */
diff --git a/core/tests/coretests/src/android/os/ProcessTest.java b/core/tests/coretests/src/android/os/ProcessTest.java
index 1f5b7c8..b749e71 100644
--- a/core/tests/coretests/src/android/os/ProcessTest.java
+++ b/core/tests/coretests/src/android/os/ProcessTest.java
@@ -17,14 +17,10 @@
 
 package android.os;
 
-import android.os.Process;
-import android.os.UserHandle;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.MediumTest;
 
 import junit.framework.TestCase;
 
-
 public class ProcessTest extends TestCase {
 
     @MediumTest
diff --git a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
index 9e15231..d5163e1 100644
--- a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
+++ b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
@@ -24,10 +24,11 @@
 import static org.junit.Assert.assertEquals;
 
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
 import android.system.Os;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java b/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java
index 9e44554..8085993 100644
--- a/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java
+++ b/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.os;
 
 import android.app.ActivityManager;
@@ -20,10 +21,10 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.os.Process;
 import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 /**
  * Tests ActivityManager#setPersistentVrThread and ActivityManager#setVrThread's
diff --git a/core/tests/coretests/src/android/os/TestHandlerThread.java b/core/tests/coretests/src/android/os/TestHandlerThread.java
index 7e84af3..8c0330b 100644
--- a/core/tests/coretests/src/android/os/TestHandlerThread.java
+++ b/core/tests/coretests/src/android/os/TestHandlerThread.java
@@ -16,11 +16,6 @@
 
 package android.os;
 
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.MessageQueue.IdleHandler;
-
 abstract class TestHandlerThread {
     private boolean mDone = false;
     private boolean mSuccess = false;
diff --git a/core/tests/coretests/src/android/os/TestVrActivity.java b/core/tests/coretests/src/android/os/TestVrActivity.java
index 33ff164..75df7c2 100644
--- a/core/tests/coretests/src/android/os/TestVrActivity.java
+++ b/core/tests/coretests/src/android/os/TestVrActivity.java
@@ -17,7 +17,6 @@
 package android.os;
 
 import android.app.Activity;
-import android.os.Bundle;
 import android.service.vr.VrListenerService;
 
 import java.util.concurrent.CountDownLatch;
diff --git a/core/tests/coretests/src/android/os/TraceTest.java b/core/tests/coretests/src/android/os/TraceTest.java
index 1541553..5cad549 100644
--- a/core/tests/coretests/src/android/os/TraceTest.java
+++ b/core/tests/coretests/src/android/os/TraceTest.java
@@ -16,13 +16,13 @@
 
 package android.os;
 
-import android.os.Debug;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+
 /**
  * This class is used to test the native tracing support.  Run this test
  * while tracing on the emulator and then run traceview to view the trace.
diff --git a/core/tests/coretests/src/android/os/UserHandleTest.java b/core/tests/coretests/src/android/os/UserHandleTest.java
index af559fd..4a1cdbf 100644
--- a/core/tests/coretests/src/android/os/UserHandleTest.java
+++ b/core/tests/coretests/src/android/os/UserHandleTest.java
@@ -25,7 +25,7 @@
 
 import static org.junit.Assert.assertEquals;
 
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/os/VintfObjectTest.java b/core/tests/coretests/src/android/os/VintfObjectTest.java
index 44510c2..af3660a 100644
--- a/core/tests/coretests/src/android/os/VintfObjectTest.java
+++ b/core/tests/coretests/src/android/os/VintfObjectTest.java
@@ -16,7 +16,6 @@
 
 package android.os;
 
-import junit.framework.Assert;
 import junit.framework.TestCase;
 
 public class VintfObjectTest extends TestCase {
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
index 3ec297c..62f2ac2 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
@@ -19,7 +19,8 @@
 import android.os.ParcelFileDescriptor;
 import android.os.ProxyFileDescriptorCallback;
 import android.system.ErrnoException;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/preference/ListPreferenceTest.java b/core/tests/coretests/src/android/preference/ListPreferenceTest.java
index 72f62f1..51dbb64 100644
--- a/core/tests/coretests/src/android/preference/ListPreferenceTest.java
+++ b/core/tests/coretests/src/android/preference/ListPreferenceTest.java
@@ -16,10 +16,10 @@
 
 package android.preference;
 
-import android.preference.ListPreference;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 
+import androidx.test.filters.LargeTest;
+
 @LargeTest
 public class ListPreferenceTest extends AndroidTestCase {
     public void testListPreferenceSummaryFromEntries() {
diff --git a/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java b/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java
index 654474c..0deb77e 100644
--- a/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java
+++ b/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java
@@ -16,20 +16,20 @@
 
 package android.preference;
 
-
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
index 5d12f7e..94d85e6 100644
--- a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
+++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
@@ -41,9 +41,10 @@
 import android.print.test.services.PrinterDiscoverySessionCallbacks;
 import android.print.test.services.StubbablePrinterDiscoverySession;
 import android.printservice.recommendation.IRecommendationsChangeListener;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index 800b864..17e9654 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -28,9 +28,10 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/provider/DocumentsProviderTest.java b/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
index 1465d0a9..02a9adf 100644
--- a/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
@@ -20,9 +20,10 @@
 import android.content.ContentResolver;
 import android.net.Uri;
 import android.provider.DocumentsContract.Path;
-import android.support.test.filters.SmallTest;
 import android.test.ProviderTestCase2;
 
+import androidx.test.filters.SmallTest;
+
 import java.util.Arrays;
 
 /**
diff --git a/core/tests/coretests/src/android/provider/FontsContractE2ETest.java b/core/tests/coretests/src/android/provider/FontsContractE2ETest.java
index 2955869..7e02be8 100644
--- a/core/tests/coretests/src/android/provider/FontsContractE2ETest.java
+++ b/core/tests/coretests/src/android/provider/FontsContractE2ETest.java
@@ -25,25 +25,25 @@
 import android.app.Instrumentation;
 import android.content.Context;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.Signature;
 import android.graphics.Typeface;
 import android.os.Handler;
-import android.provider.FontsContract.Columns;
 import android.provider.FontsContract.FontFamilyResult;
-import android.provider.FontsContract.FontInfo;
-import android.provider.FontsContract;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import java.util.ArrayList;
-import java.util.List;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class FontsContractE2ETest {
diff --git a/core/tests/coretests/src/android/provider/FontsContractTest.java b/core/tests/coretests/src/android/provider/FontsContractTest.java
index d42d79e..c5d6f7f 100644
--- a/core/tests/coretests/src/android/provider/FontsContractTest.java
+++ b/core/tests/coretests/src/android/provider/FontsContractTest.java
@@ -13,31 +13,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.provider;
 
+import static android.provider.FontsContract.Columns.RESULT_CODE_FONT_NOT_FOUND;
+import static android.provider.FontsContract.Columns.RESULT_CODE_FONT_UNAVAILABLE;
+import static android.provider.FontsContract.Columns.RESULT_CODE_MALFORMED_QUERY;
+import static android.provider.FontsContract.Columns.RESULT_CODE_OK;
+
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import static android.provider.FontsContract.Columns.RESULT_CODE_OK;
-import static android.provider.FontsContract.Columns.RESULT_CODE_FONT_NOT_FOUND;
-import static android.provider.FontsContract.Columns.RESULT_CODE_FONT_UNAVAILABLE;
-import static android.provider.FontsContract.Columns.RESULT_CODE_MALFORMED_QUERY;
-
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ProviderInfo;
 import android.content.pm.Signature;
 import android.database.MatrixCursor;
 import android.graphics.fonts.FontVariationAxis;
 import android.provider.FontsContract.FontInfo;
-import android.support.test.filters.SmallTest;
 import android.test.ProviderTestCase2;
 import android.util.Base64;
 
+import androidx.test.filters.SmallTest;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
diff --git a/core/tests/coretests/src/android/provider/MockFontProvider.java b/core/tests/coretests/src/android/provider/MockFontProvider.java
index ad5b130..e527dec 100644
--- a/core/tests/coretests/src/android/provider/MockFontProvider.java
+++ b/core/tests/coretests/src/android/provider/MockFontProvider.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.provider;
 
 import static android.provider.FontsContract.Columns;
@@ -21,16 +22,13 @@
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
-import android.content.res.AssetFileDescriptor;
 import android.content.res.AssetManager;
 import android.database.Cursor;
 import android.database.MatrixCursor;
-import android.graphics.fonts.FontVariationAxis;
 import android.net.Uri;
-import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
-import android.util.ArraySet;
-import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -46,8 +44,6 @@
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
-import com.android.internal.annotations.GuardedBy;
-
 public class MockFontProvider extends ContentProvider {
     final static String AUTHORITY = "android.provider.fonts.font";
 
diff --git a/core/tests/coretests/src/android/provider/SearchRecentSuggestionsProviderTest.java b/core/tests/coretests/src/android/provider/SearchRecentSuggestionsProviderTest.java
index 7458de5..f84355f 100644
--- a/core/tests/coretests/src/android/provider/SearchRecentSuggestionsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SearchRecentSuggestionsProviderTest.java
@@ -21,9 +21,9 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.test.ProviderTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 /**
  * ProviderTestCase that performs unit tests of SearchRecentSuggestionsProvider.
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 1ed5ce4..93af013 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -27,9 +27,9 @@
 import static java.lang.reflect.Modifier.isStatic;
 
 import android.platform.test.annotations.Presubmit;
-import android.provider.Settings.Global;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -270,6 +270,7 @@
                     Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS,
                     Settings.Global.GNSS_SATELLITE_BLACKLIST,
                     Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
+                    Settings.Global.HDMI_CEC_SWITCH_ENABLED,
                     Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
                     Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
                     Settings.Global.HDMI_CONTROL_ENABLED,
@@ -477,9 +478,10 @@
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
+                    Settings.Global.GUP_DEV_ALL_APPS,
                     Settings.Global.GUP_DEV_OPT_IN_APPS,
                     Settings.Global.GUP_DEV_OPT_OUT_APPS,
-                    Settings.Global.GUP_BLACK_LIST,
+                    Settings.Global.GUP_BLACKLIST,
                     Settings.Global.GPU_DEBUG_LAYER_APP,
                     Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
                     Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
@@ -554,8 +556,10 @@
                     Settings.Global.APPOP_HISTORY_PARAMETERS,
                     Settings.Global.APPOP_HISTORY_MODE,
                     Settings.Global.APPOP_HISTORY_INTERVAL_MULTIPLIER,
-                    Settings.Global.APPOP_HISTORY_BASE_INTERVAL_MILLIS);
-
+                    Settings.Global.APPOP_HISTORY_BASE_INTERVAL_MILLIS,
+                    Settings.Global.ENABLE_RADIO_BUG_DETECTION,
+                    Settings.Global.RADIO_BUG_WAKELOCK_TIMEOUT_COUNT_THRESHOLD,
+                    Settings.Global.RADIO_BUG_SYSTEM_ERROR_COUNT_THRESHOLD);
     private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
              newHashSet(
                  Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
@@ -664,6 +668,7 @@
                  Settings.Secure.SMS_DEFAULT_APPLICATION,
                  Settings.Secure.SPELL_CHECKER_ENABLED,  // Intentionally removed in Q
                  Settings.Secure.TRUST_AGENTS_INITIALIZED,
+                 Settings.Secure.TV_APP_USES_NON_SYSTEM_INPUTS,
                  Settings.Secure.TV_INPUT_CUSTOM_LABELS,
                  Settings.Secure.TV_INPUT_HIDDEN_INPUTS,
                  Settings.Secure.TV_USER_SETUP_COMPLETE,
diff --git a/core/tests/coretests/src/android/provider/SettingsProviderTest.java b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
index cb6f0e6..a5f5f67 100644
--- a/core/tests/coretests/src/android/provider/SettingsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
@@ -34,9 +34,10 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
 
 import java.util.HashMap;
 import java.util.List;
diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
index b0d29bd..08f9de6 100644
--- a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
@@ -22,8 +22,9 @@
 
 import android.platform.test.annotations.Presubmit;
 import android.provider.SettingsValidators.Validator;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/provider/SmsProviderTest.java b/core/tests/coretests/src/android/provider/SmsProviderTest.java
index af4d1a6..67ac8ea 100644
--- a/core/tests/coretests/src/android/provider/SmsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SmsProviderTest.java
@@ -22,8 +22,9 @@
 import android.net.Uri;
 import android.provider.Telephony.Sms;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
 
 import java.util.GregorianCalendar;
 
diff --git a/core/tests/coretests/src/android/provider/TestFontsProvider.java b/core/tests/coretests/src/android/provider/TestFontsProvider.java
index 46906df..c3457fa 100644
--- a/core/tests/coretests/src/android/provider/TestFontsProvider.java
+++ b/core/tests/coretests/src/android/provider/TestFontsProvider.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.provider;
 
 import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
@@ -23,7 +24,6 @@
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.database.MatrixCursor;
-import android.graphics.Typeface;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/KeyChainProtectionParamsTest.java b/core/tests/coretests/src/android/security/keystore/recovery/KeyChainProtectionParamsTest.java
index 0c9c4c1..ce0bf30 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/KeyChainProtectionParamsTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/KeyChainProtectionParamsTest.java
@@ -20,8 +20,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/KeyChainSnapshotTest.java b/core/tests/coretests/src/android/security/keystore/recovery/KeyChainSnapshotTest.java
index 61ab152..2a962c2 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/KeyChainSnapshotTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/KeyChainSnapshotTest.java
@@ -20,8 +20,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.google.common.collect.Lists;
 
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/KeyDerivationParamsTest.java b/core/tests/coretests/src/android/security/keystore/recovery/KeyDerivationParamsTest.java
index b6af9bb..2b37b52 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/KeyDerivationParamsTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/KeyDerivationParamsTest.java
@@ -20,8 +20,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/RecoveryCertPathTest.java b/core/tests/coretests/src/android/security/keystore/recovery/RecoveryCertPathTest.java
index dd8cd8d..3b8f715 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/RecoveryCertPathTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/RecoveryCertPathTest.java
@@ -20,8 +20,9 @@
 import static org.junit.Assert.fail;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java b/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
index a5a3ca9..2b15d73 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
@@ -20,8 +20,8 @@
 
 import static org.junit.Assert.assertTrue;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/WrappedApplicationKeyTest.java b/core/tests/coretests/src/android/security/keystore/recovery/WrappedApplicationKeyTest.java
index 15afbdd..8522e62 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/WrappedApplicationKeyTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/WrappedApplicationKeyTest.java
@@ -20,8 +20,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java b/core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java
index 7f0eb43..17486d5 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java
@@ -21,8 +21,8 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
index e69d1e7..d00d052 100644
--- a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
+++ b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.service.euicc;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -23,10 +24,11 @@
 
 import android.os.Parcel;
 import android.service.carrier.CarrierIdentifier;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.telephony.UiccAccessRule;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
index 8a3ba8c..4aa1000 100644
--- a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
+++ b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.service.notification;
 
 import static junit.framework.Assert.assertEquals;
@@ -28,9 +29,10 @@
 import android.content.pm.PackageManager;
 import android.metrics.LogMaker;
 import android.os.UserHandle;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
diff --git a/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java b/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java
index ab541a1..9c8e868 100644
--- a/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java
+++ b/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java
@@ -16,16 +16,12 @@
 
 package android.service.settings.suggestions;
 
-import android.support.annotation.VisibleForTesting;
-
 import java.util.ArrayList;
 import java.util.List;
 
 public class MockSuggestionService extends SuggestionService {
 
-    @VisibleForTesting
     static boolean sOnSuggestionLaunchedCalled;
-    @VisibleForTesting
     static boolean sOnSuggestionDismissedCalled;
 
     public static void reset() {
diff --git a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java
index dca8c09..64edda5 100644
--- a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java
+++ b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java
@@ -21,10 +21,11 @@
 import android.content.Intent;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.rule.ServiceTestRule;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ServiceTestRule;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java
index b0ec55d..8c47fcb 100644
--- a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java
+++ b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java
@@ -24,9 +24,10 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.Icon;
 import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/text/AndroidCharacterTest.java b/core/tests/coretests/src/android/text/AndroidCharacterTest.java
index 0c7e730..1c5986a 100644
--- a/core/tests/coretests/src/android/text/AndroidCharacterTest.java
+++ b/core/tests/coretests/src/android/text/AndroidCharacterTest.java
@@ -19,7 +19,8 @@
 import static org.junit.Assert.assertArrayEquals;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 
diff --git a/core/tests/coretests/src/android/text/BidiFormatterTest.java b/core/tests/coretests/src/android/text/BidiFormatterTest.java
index 1b936c7..312fb68 100644
--- a/core/tests/coretests/src/android/text/BidiFormatterTest.java
+++ b/core/tests/coretests/src/android/text/BidiFormatterTest.java
@@ -19,8 +19,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java b/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
index c69f4f5..cca1ad3 100644
--- a/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
+++ b/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
@@ -22,8 +22,9 @@
 import static org.junit.Assert.assertTrue;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/DynamicLayoutTest.java b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
index ea954f6..699243b 100644
--- a/core/tests/coretests/src/android/text/DynamicLayoutTest.java
+++ b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
@@ -27,11 +27,12 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.style.ReplacementSpan;
 import android.util.ArraySet;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/EmojiTest.java b/core/tests/coretests/src/android/text/EmojiTest.java
index 313f1b6..1948994 100644
--- a/core/tests/coretests/src/android/text/EmojiTest.java
+++ b/core/tests/coretests/src/android/text/EmojiTest.java
@@ -21,8 +21,9 @@
 
 import android.icu.lang.UCharacterDirection;
 import android.icu.text.Bidi;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/FontFallbackSetup.java b/core/tests/coretests/src/android/text/FontFallbackSetup.java
index 5592aac..cc51ec3 100644
--- a/core/tests/coretests/src/android/text/FontFallbackSetup.java
+++ b/core/tests/coretests/src/android/text/FontFallbackSetup.java
@@ -24,9 +24,10 @@
 import android.graphics.fonts.FontCustomizationParser;
 import android.graphics.fonts.FontFamily;
 import android.graphics.fonts.SystemFonts;
-import android.support.test.InstrumentationRegistry;
 import android.util.ArrayMap;
 
+import androidx.test.InstrumentationRegistry;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
diff --git a/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java b/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java
index 1208d7c..96e7fb9 100644
--- a/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java
+++ b/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java
@@ -22,12 +22,13 @@
 import android.graphics.Path;
 import android.graphics.Typeface;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.method.MetaKeyKeyListener;
 import android.view.KeyEvent;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/LayoutTest.java b/core/tests/coretests/src/android/text/LayoutTest.java
index 97937a4..990161a 100644
--- a/core/tests/coretests/src/android/text/LayoutTest.java
+++ b/core/tests/coretests/src/android/text/LayoutTest.java
@@ -31,11 +31,12 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout.Alignment;
 import android.text.style.StrikethroughSpan;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
index a0dca2c..57bb434 100644
--- a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
+++ b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
@@ -23,9 +23,10 @@
 
 import android.content.Context;
 import android.graphics.Typeface;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/PackedIntVectorTest.java b/core/tests/coretests/src/android/text/PackedIntVectorTest.java
index d9dc6fc..ba15b92 100644
--- a/core/tests/coretests/src/android/text/PackedIntVectorTest.java
+++ b/core/tests/coretests/src/android/text/PackedIntVectorTest.java
@@ -19,8 +19,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java b/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java
index d0f2d46..91b8c6a 100644
--- a/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java
+++ b/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java
@@ -16,18 +16,18 @@
 
 package android.text;
 
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.style.BulletSpan;
 import android.text.style.QuoteSpan;
 import android.text.style.SubscriptSpan;
 import android.text.style.UnderlineSpan;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java b/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java
index 6c05601..9149f7b 100644
--- a/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java
+++ b/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java
@@ -21,11 +21,12 @@
 import static org.junit.Assert.assertNotNull;
 
 import android.annotation.NonNull;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.style.QuoteSpan;
 import android.text.style.UnderlineSpan;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/SpannableTest.java b/core/tests/coretests/src/android/text/SpannableTest.java
index f368428..d248a1f 100644
--- a/core/tests/coretests/src/android/text/SpannableTest.java
+++ b/core/tests/coretests/src/android/text/SpannableTest.java
@@ -19,10 +19,11 @@
 import static org.junit.Assert.assertEquals;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.MoreAsserts;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java b/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java
index 380e315..ca43733 100644
--- a/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java
+++ b/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java
@@ -21,11 +21,12 @@
 import static org.junit.Assert.assertNotNull;
 
 import android.annotation.NonNull;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.style.QuoteSpan;
 import android.text.style.UnderlineSpan;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/SpannedTest.java b/core/tests/coretests/src/android/text/SpannedTest.java
index 5737571..3ab0755 100644
--- a/core/tests/coretests/src/android/text/SpannedTest.java
+++ b/core/tests/coretests/src/android/text/SpannedTest.java
@@ -21,13 +21,14 @@
 import android.graphics.Typeface;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.style.CharacterStyle;
 import android.text.style.StyleSpan;
 import android.text.style.TextAppearanceSpan;
 import android.text.style.TypefaceSpan;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
index bf0d427..32370b3e 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
@@ -19,10 +19,11 @@
 import static org.junit.Assert.assertEquals;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java b/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
index 5cf5426..4221ac2 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
@@ -19,11 +19,12 @@
 import static org.junit.Assert.fail;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout.Directions;
 import android.text.StaticLayoutTest.LayoutBuilder;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
index 2521712..b1c896e 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -25,13 +25,14 @@
 import android.graphics.Paint.FontMetricsInt;
 import android.os.LocaleList;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout.Alignment;
 import android.text.method.EditorState;
 import android.text.style.LocaleSpan;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java b/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
index f6888e3..0d42326 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
@@ -19,10 +19,11 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout.Alignment;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/TextLayoutTest.java b/core/tests/coretests/src/android/text/TextLayoutTest.java
index 24020ce..15fbc9e 100644
--- a/core/tests/coretests/src/android/text/TextLayoutTest.java
+++ b/core/tests/coretests/src/android/text/TextLayoutTest.java
@@ -17,8 +17,9 @@
 package android.text;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/text/TextLineTest.java b/core/tests/coretests/src/android/text/TextLineTest.java
index 2fe882c..90ce305 100644
--- a/core/tests/coretests/src/android/text/TextLineTest.java
+++ b/core/tests/coretests/src/android/text/TextLineTest.java
@@ -25,14 +25,15 @@
 import android.graphics.Paint;
 import android.graphics.Typeface;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.filters.Suppress;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout.TabStops;
 import android.text.style.ReplacementSpan;
 import android.text.style.TabStopSpan;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index 72290bf..be6ef19 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -26,15 +26,16 @@
 
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.MoreAsserts;
 import android.text.style.StyleSpan;
 import android.text.util.Rfc822Token;
 import android.text.util.Rfc822Tokenizer;
 import android.view.View;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.google.android.collect.Lists;
 
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/text/VariationParserTest.java b/core/tests/coretests/src/android/text/VariationParserTest.java
index fbd2412..0afe811 100644
--- a/core/tests/coretests/src/android/text/VariationParserTest.java
+++ b/core/tests/coretests/src/android/text/VariationParserTest.java
@@ -21,8 +21,9 @@
 
 import android.graphics.fonts.FontVariationAxis;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/format/DateFormatTest.java b/core/tests/coretests/src/android/text/format/DateFormatTest.java
index 9000ed0..5a0a84d 100644
--- a/core/tests/coretests/src/android/text/format/DateFormatTest.java
+++ b/core/tests/coretests/src/android/text/format/DateFormatTest.java
@@ -20,8 +20,9 @@
 import static org.junit.Assert.assertTrue;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
index 872b71a..381c051 100644
--- a/core/tests/coretests/src/android/text/format/DateUtilsTest.java
+++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
@@ -22,8 +22,9 @@
 import android.content.res.Resources;
 import android.os.LocaleList;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index 82e4bff..068d047 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -25,11 +25,12 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.format.Formatter.BytesResult;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/text/format/TimeTest.java b/core/tests/coretests/src/android/text/format/TimeTest.java
index d563f2e..ac00411 100644
--- a/core/tests/coretests/src/android/text/format/TimeTest.java
+++ b/core/tests/coretests/src/android/text/format/TimeTest.java
@@ -21,12 +21,13 @@
 import static org.junit.Assert.fail;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.filters.Suppress;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 import android.util.TimeFormatException;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/method/BackspaceTest.java b/core/tests/coretests/src/android/text/method/BackspaceTest.java
index df4609f..ddae652 100644
--- a/core/tests/coretests/src/android/text/method/BackspaceTest.java
+++ b/core/tests/coretests/src/android/text/method/BackspaceTest.java
@@ -17,15 +17,16 @@
 package android.text.method;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 import android.util.KeyUtils;
 import android.view.KeyEvent;
 import android.widget.EditText;
 import android.widget.TextView.BufferType;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/method/EditorState.java b/core/tests/coretests/src/android/text/method/EditorState.java
index 12bb8c8..4eff7a4 100644
--- a/core/tests/coretests/src/android/text/method/EditorState.java
+++ b/core/tests/coretests/src/android/text/method/EditorState.java
@@ -21,8 +21,6 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import android.graphics.Canvas;
-import android.graphics.Paint;
 import android.text.Editable;
 import android.text.Spannable;
 import android.text.SpannableString;
diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
index 45a5010..45b63e0 100644
--- a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
+++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
@@ -17,15 +17,16 @@
 package android.text.method;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 import android.util.KeyUtils;
 import android.view.KeyEvent;
 import android.widget.EditText;
 import android.widget.TextView.BufferType;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/method/WordIteratorTest.java b/core/tests/coretests/src/android/text/method/WordIteratorTest.java
index 6845863..cc345f5 100644
--- a/core/tests/coretests/src/android/text/method/WordIteratorTest.java
+++ b/core/tests/coretests/src/android/text/method/WordIteratorTest.java
@@ -22,8 +22,9 @@
 import static org.junit.Assert.fail;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java b/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java
index 3d7e5ba..a0d2f85 100644
--- a/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java
+++ b/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java
@@ -16,17 +16,17 @@
 
 package android.text.style;
 
-
 import static org.junit.Assert.assertEquals;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.StaticLayout;
 import android.text.TextPaint;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/util/LinkifyTest.java b/core/tests/coretests/src/android/text/util/LinkifyTest.java
index be3a0be..107ecd7 100644
--- a/core/tests/coretests/src/android/text/util/LinkifyTest.java
+++ b/core/tests/coretests/src/android/text/util/LinkifyTest.java
@@ -23,9 +23,6 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.os.LocaleList;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.method.LinkMovementMethod;
@@ -33,6 +30,10 @@
 import android.util.Patterns;
 import android.widget.TextView;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/transition/AutoTransitionTest.java b/core/tests/coretests/src/android/transition/AutoTransitionTest.java
index 834fb7a..deae967 100644
--- a/core/tests/coretests/src/android/transition/AutoTransitionTest.java
+++ b/core/tests/coretests/src/android/transition/AutoTransitionTest.java
@@ -16,16 +16,16 @@
 
 package android.transition;
 
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(AndroidJUnit4.class)
 public class AutoTransitionTest {
     @Test
diff --git a/core/tests/coretests/src/android/transition/FadeTransitionTest.java b/core/tests/coretests/src/android/transition/FadeTransitionTest.java
index 22365ba..2077d94 100644
--- a/core/tests/coretests/src/android/transition/FadeTransitionTest.java
+++ b/core/tests/coretests/src/android/transition/FadeTransitionTest.java
@@ -22,13 +22,14 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.transition.Transition.TransitionListener;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.util.concurrent.CountDownLatch;
diff --git a/core/tests/coretests/src/android/transition/SlideTransitionTest.java b/core/tests/coretests/src/android/transition/SlideTransitionTest.java
index 8b9ec74..046e49d 100644
--- a/core/tests/coretests/src/android/transition/SlideTransitionTest.java
+++ b/core/tests/coretests/src/android/transition/SlideTransitionTest.java
@@ -19,18 +19,18 @@
 import android.animation.AnimatorSetActivity;
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-
 public class SlideTransitionTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> {
 
     Activity mActivity;
diff --git a/core/tests/coretests/src/android/transition/TransitionTest.java b/core/tests/coretests/src/android/transition/TransitionTest.java
index 7e629f9..f59c406 100644
--- a/core/tests/coretests/src/android/transition/TransitionTest.java
+++ b/core/tests/coretests/src/android/transition/TransitionTest.java
@@ -19,7 +19,6 @@
 import android.animation.AnimatorSetActivity;
 import android.app.Activity;
 import android.graphics.Rect;
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase2;
 import android.transition.Transition.EpicenterCallback;
 import android.util.ArrayMap;
@@ -27,6 +26,8 @@
 import android.view.animation.AccelerateInterpolator;
 import android.widget.TextView;
 
+import androidx.test.filters.LargeTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.lang.reflect.Field;
diff --git a/core/tests/coretests/src/android/util/ArrayMapTest.java b/core/tests/coretests/src/android/util/ArrayMapTest.java
index f0cc7f7..b212cf6 100644
--- a/core/tests/coretests/src/android/util/ArrayMapTest.java
+++ b/core/tests/coretests/src/android/util/ArrayMapTest.java
@@ -14,10 +14,10 @@
 
 package android.util;
 
-import android.support.test.filters.LargeTest;
-import android.util.ArrayMap;
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
+
 import org.junit.Test;
 
 import java.util.ConcurrentModificationException;
diff --git a/core/tests/coretests/src/android/util/Base64Test.java b/core/tests/coretests/src/android/util/Base64Test.java
index af608c3..15c51af 100644
--- a/core/tests/coretests/src/android/util/Base64Test.java
+++ b/core/tests/coretests/src/android/util/Base64Test.java
@@ -16,7 +16,7 @@
 
 package android.util;
 
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/util/DataUnitTest.java b/core/tests/coretests/src/android/util/DataUnitTest.java
index 4eae8b4..ec296b7 100644
--- a/core/tests/coretests/src/android/util/DataUnitTest.java
+++ b/core/tests/coretests/src/android/util/DataUnitTest.java
@@ -16,7 +16,7 @@
 
 package android.util;
 
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java b/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java
index 4c5ad76..572e9b0 100644
--- a/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java
+++ b/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java
@@ -16,10 +16,11 @@
 
 package android.util;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 import java.util.Calendar;
-import android.test.suitebuilder.annotation.SmallTest;
 
 /**
  * Unit tests for {@link DayOfMonthCursor}.
diff --git a/core/tests/coretests/src/android/util/InternalSelectionView.java b/core/tests/coretests/src/android/util/InternalSelectionView.java
index a0fb0f1..4a1baef 100644
--- a/core/tests/coretests/src/android/util/InternalSelectionView.java
+++ b/core/tests/coretests/src/android/util/InternalSelectionView.java
@@ -16,19 +16,16 @@
 
 package android.util;
 
-import com.android.frameworks.coretests.R;
-
-import android.view.View;
-import android.view.KeyEvent;
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.graphics.Paint;
 import android.graphics.Canvas;
-import android.graphics.Rect;
 import android.graphics.Color;
-import android.util.AttributeSet;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.view.KeyEvent;
+import android.view.View;
 
-
+import com.android.frameworks.coretests.R;
 
 /**
  * A view that has a known number of selectable rows, and maintains a notion of which
diff --git a/core/tests/coretests/src/android/util/KeyUtils.java b/core/tests/coretests/src/android/util/KeyUtils.java
index 593f727..612643e 100644
--- a/core/tests/coretests/src/android/util/KeyUtils.java
+++ b/core/tests/coretests/src/android/util/KeyUtils.java
@@ -17,16 +17,10 @@
 package android.util;
 
 import android.app.Instrumentation;
-import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.InstrumentationTestCase;
-import android.view.Gravity;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
 import android.view.ViewConfiguration;
-import android.view.ViewGroup;
 
 /**
  * Reusable methods for generating key events.
diff --git a/core/tests/coretests/src/android/util/KeyValueListParserTest.java b/core/tests/coretests/src/android/util/KeyValueListParserTest.java
index 038f0b7..f65c4c7 100644
--- a/core/tests/coretests/src/android/util/KeyValueListParserTest.java
+++ b/core/tests/coretests/src/android/util/KeyValueListParserTest.java
@@ -19,8 +19,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/util/ListUtil.java b/core/tests/coretests/src/android/util/ListUtil.java
index 2a7cb96..3748cf8 100644
--- a/core/tests/coretests/src/android/util/ListUtil.java
+++ b/core/tests/coretests/src/android/util/ListUtil.java
@@ -20,13 +20,11 @@
 import android.view.KeyEvent;
 import android.widget.ListView;
 
-
 /**
  * Various useful stuff for instrumentation testing listview.
  */
 public class ListUtil {
 
-
     private final ListView mListView;
     private final Instrumentation mInstrumentation;
 
diff --git a/core/tests/coretests/src/android/util/LocalLogTest.java b/core/tests/coretests/src/android/util/LocalLogTest.java
index 5144c85..6cdcb5e 100644
--- a/core/tests/coretests/src/android/util/LocalLogTest.java
+++ b/core/tests/coretests/src/android/util/LocalLogTest.java
@@ -16,7 +16,7 @@
 
 package android.util;
 
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/util/LogNullabilityTest.java b/core/tests/coretests/src/android/util/LogNullabilityTest.java
index 3f4776d..370885d 100644
--- a/core/tests/coretests/src/android/util/LogNullabilityTest.java
+++ b/core/tests/coretests/src/android/util/LogNullabilityTest.java
@@ -19,8 +19,8 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/util/LogTest.java b/core/tests/coretests/src/android/util/LogTest.java
index 30c81b0..d783c12 100644
--- a/core/tests/coretests/src/android/util/LogTest.java
+++ b/core/tests/coretests/src/android/util/LogTest.java
@@ -16,13 +16,12 @@
 
 package android.util;
 
-import junit.framework.Assert;
-import junit.framework.TestCase;
-
 import android.os.SystemProperties;
 import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.Suppress;
-import android.util.Log;
+
+import androidx.test.filters.Suppress;
+
+import junit.framework.TestCase;
 
 //This is an empty TestCase.
 @Suppress
diff --git a/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java b/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java
index 3f03db9..a1d48e6 100644
--- a/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java
+++ b/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java
@@ -16,7 +16,7 @@
 
 package android.util;
 
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/util/LruCacheTest.java b/core/tests/coretests/src/android/util/LruCacheTest.java
index 5a97158..1928bfd 100644
--- a/core/tests/coretests/src/android/util/LruCacheTest.java
+++ b/core/tests/coretests/src/android/util/LruCacheTest.java
@@ -16,12 +16,13 @@
 
 package android.util;
 
+import junit.framework.TestCase;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import junit.framework.TestCase;
 
 public final class LruCacheTest extends TestCase {
     private int expectedCreateCount;
diff --git a/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java b/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java
index 55da665..30d5f77 100644
--- a/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java
+++ b/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java
@@ -16,12 +16,12 @@
 
 package android.util;
 
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.util.Calendar;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
+import java.util.Calendar;
+
 /**
  * Unit tests for {@link MonthDisplayHelper}.
  */
diff --git a/core/tests/coretests/src/android/util/OrientationUtil.java b/core/tests/coretests/src/android/util/OrientationUtil.java
index ecdca5d..0361194 100644
--- a/core/tests/coretests/src/android/util/OrientationUtil.java
+++ b/core/tests/coretests/src/android/util/OrientationUtil.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.pm.ActivityInfo;
-
 import android.test.ActivityInstrumentationTestCase2;
 
 import com.android.internal.util.Preconditions;
diff --git a/core/tests/coretests/src/android/util/PatternsTest.java b/core/tests/coretests/src/android/util/PatternsTest.java
index 360b875..6cea2f3 100644
--- a/core/tests/coretests/src/android/util/PatternsTest.java
+++ b/core/tests/coretests/src/android/util/PatternsTest.java
@@ -13,15 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.util;
 
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
+
+import junit.framework.TestCase;
 
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import junit.framework.TestCase;
-
 public class PatternsTest extends TestCase {
 
     // Tests for Patterns.TOP_LEVEL_DOMAIN
diff --git a/core/tests/coretests/src/android/util/RecurrenceRuleTest.java b/core/tests/coretests/src/android/util/RecurrenceRuleTest.java
index 39d492d..caa1208 100644
--- a/core/tests/coretests/src/android/util/RecurrenceRuleTest.java
+++ b/core/tests/coretests/src/android/util/RecurrenceRuleTest.java
@@ -16,7 +16,7 @@
 
 package android.util;
 
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/util/SparseLongArrayTest.java b/core/tests/coretests/src/android/util/SparseLongArrayTest.java
index 5a5e893..df2d752 100644
--- a/core/tests/coretests/src/android/util/SparseLongArrayTest.java
+++ b/core/tests/coretests/src/android/util/SparseLongArrayTest.java
@@ -19,9 +19,10 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import android.support.annotation.NonNull;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import android.annotation.NonNull;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/util/StateSetTest.java b/core/tests/coretests/src/android/util/StateSetTest.java
index e481ce0..b5d6270 100644
--- a/core/tests/coretests/src/android/util/StateSetTest.java
+++ b/core/tests/coretests/src/android/util/StateSetTest.java
@@ -16,8 +16,9 @@
 
 package android.util;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 
 /**
  * Tests for {@link StateSet}
diff --git a/core/tests/coretests/src/android/util/TimestampedValueTest.java b/core/tests/coretests/src/android/util/TimestampedValueTest.java
index 03b4abd..6e3ab79 100644
--- a/core/tests/coretests/src/android/util/TimestampedValueTest.java
+++ b/core/tests/coretests/src/android/util/TimestampedValueTest.java
@@ -21,7 +21,8 @@
 import static org.junit.Assert.fail;
 
 import android.os.Parcel;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/util/TimingsTraceLogTest.java b/core/tests/coretests/src/android/util/TimingsTraceLogTest.java
index 7bb4ab8..77d0552 100644
--- a/core/tests/coretests/src/android/util/TimingsTraceLogTest.java
+++ b/core/tests/coretests/src/android/util/TimingsTraceLogTest.java
@@ -19,8 +19,9 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Trace;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -28,7 +29,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-
 /**
  * Tests for {@link TimingsTraceLog}.
  * <p>Usage: bit FrameworksCoreTests:android.util.TimingsTraceLogTest
diff --git a/core/tests/coretests/src/android/util/TouchModeFlexibleAsserts.java b/core/tests/coretests/src/android/util/TouchModeFlexibleAsserts.java
index ca12a15..fc08235 100644
--- a/core/tests/coretests/src/android/util/TouchModeFlexibleAsserts.java
+++ b/core/tests/coretests/src/android/util/TouchModeFlexibleAsserts.java
@@ -16,12 +16,12 @@
 
 package android.util;
 
-import junit.framework.Assert;
-
 import android.test.InstrumentationTestCase;
 import android.test.TouchUtils;
 import android.view.View;
 
+import junit.framework.Assert;
+
 /**
  * When entering touch mode via touch, the tests can be flaky.  These asserts
  * are more flexible (allowing up to MAX_ATTEMPTS touches to enter touch mode via touch or
diff --git a/core/tests/coretests/src/android/view/BigCache.java b/core/tests/coretests/src/android/view/BigCache.java
index 2182176..6a1bcaa 100644
--- a/core/tests/coretests/src/android/view/BigCache.java
+++ b/core/tests/coretests/src/android/view/BigCache.java
@@ -16,16 +16,12 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
 import android.app.Activity;
+import android.os.Bundle;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
-import android.view.ViewGroup;
-import android.view.View;
-import android.view.Display;
-import android.view.ViewConfiguration;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * This activity contains two Views, one as big as the screen, one much larger. The large one
diff --git a/core/tests/coretests/src/android/view/BigCacheTest.java b/core/tests/coretests/src/android/view/BigCacheTest.java
index 8c2c865..ed4b996 100644
--- a/core/tests/coretests/src/android/view/BigCacheTest.java
+++ b/core/tests/coretests/src/android/view/BigCacheTest.java
@@ -16,14 +16,12 @@
 
 package android.view;
 
-import android.view.BigCache;
-import com.android.frameworks.coretests.R;
-
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
-import android.view.ViewConfiguration;
 import android.graphics.Bitmap;
+import android.test.ActivityInstrumentationTestCase;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Builds the drawing cache of two Views, one smaller than the maximum cache size,
diff --git a/core/tests/coretests/src/android/view/BitmapDrawable.java b/core/tests/coretests/src/android/view/BitmapDrawable.java
index f7bad84..42c176f 100644
--- a/core/tests/coretests/src/android/view/BitmapDrawable.java
+++ b/core/tests/coretests/src/android/view/BitmapDrawable.java
@@ -16,19 +16,10 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AbsoluteLayout;
-import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
 
 public class BitmapDrawable extends Activity {
     @Override
diff --git a/core/tests/coretests/src/android/view/CreateViewTest.java b/core/tests/coretests/src/android/view/CreateViewTest.java
index 16656f6..520f83f 100644
--- a/core/tests/coretests/src/android/view/CreateViewTest.java
+++ b/core/tests/coretests/src/android/view/CreateViewTest.java
@@ -16,16 +16,17 @@
 
 package android.view;
 
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
 import android.content.Context;
 import android.test.AndroidTestCase;
 import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.View;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.test.filters.SmallTest;
+
 public class CreateViewTest extends AndroidTestCase implements PerformanceTestCase {
 
     public boolean isPerformanceOnly() {
diff --git a/core/tests/coretests/src/android/view/Disabled.java b/core/tests/coretests/src/android/view/Disabled.java
index d3c7470..ce90039 100644
--- a/core/tests/coretests/src/android/view/Disabled.java
+++ b/core/tests/coretests/src/android/view/Disabled.java
@@ -16,13 +16,12 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
-import android.widget.Button;
-import android.view.View;
-import android.view.View.OnClickListener;
 import android.app.Activity;
+import android.os.Bundle;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercise View's disabled state.
diff --git a/core/tests/coretests/src/android/view/DisabledLongpressTest.java b/core/tests/coretests/src/android/view/DisabledLongpressTest.java
index faa0865..a9fec01 100644
--- a/core/tests/coretests/src/android/view/DisabledLongpressTest.java
+++ b/core/tests/coretests/src/android/view/DisabledLongpressTest.java
@@ -18,11 +18,12 @@
 
 import android.test.ActivityInstrumentationTestCase;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.KeyUtils;
 import android.view.View.OnLongClickListener;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/view/DisabledTest.java b/core/tests/coretests/src/android/view/DisabledTest.java
index 291a11c..8922e5f 100644
--- a/core/tests/coretests/src/android/view/DisabledTest.java
+++ b/core/tests/coretests/src/android/view/DisabledTest.java
@@ -18,12 +18,11 @@
 
 import android.test.ActivityInstrumentationTestCase;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.KeyEvent;
-import android.view.View;
 import android.widget.Button;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
index 8e4f2cd..dd50af877 100644
--- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -33,17 +33,17 @@
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.DisplayCutout.ParcelableWrapper;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.util.Arrays;
 import java.util.Collections;
 
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 @Presubmit
diff --git a/core/tests/coretests/src/android/view/DrawableBgMinSize.java b/core/tests/coretests/src/android/view/DrawableBgMinSize.java
index 58bfb8a..ba9ba00 100644
--- a/core/tests/coretests/src/android/view/DrawableBgMinSize.java
+++ b/core/tests/coretests/src/android/view/DrawableBgMinSize.java
@@ -16,12 +16,9 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.AbsoluteLayout;
 import android.widget.Button;
@@ -30,6 +27,8 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Views should obey their background {@link Drawable}'s minimum size
  * requirements ({@link Drawable#getMinimumHeight()} and
diff --git a/core/tests/coretests/src/android/view/DrawableBgMinSizeTest.java b/core/tests/coretests/src/android/view/DrawableBgMinSizeTest.java
index e705c87..1735e8c 100644
--- a/core/tests/coretests/src/android/view/DrawableBgMinSizeTest.java
+++ b/core/tests/coretests/src/android/view/DrawableBgMinSizeTest.java
@@ -16,14 +16,9 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-import android.view.DrawableBgMinSize;
-import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.MediumTest;
-
 import android.graphics.drawable.Drawable;
 import android.test.ActivityInstrumentationTestCase;
-import android.view.View;
+import android.test.TouchUtils;
 import android.widget.AbsoluteLayout;
 import android.widget.Button;
 import android.widget.FrameLayout;
@@ -31,6 +26,10 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * {@link DrawableBgMinSize} exercises Views to obey their background drawable's
  * minimum sizes.
diff --git a/core/tests/coretests/src/android/view/FocusFinderTest.java b/core/tests/coretests/src/android/view/FocusFinderTest.java
index 2732a04..b35c64a 100644
--- a/core/tests/coretests/src/android/view/FocusFinderTest.java
+++ b/core/tests/coretests/src/android/view/FocusFinderTest.java
@@ -18,7 +18,8 @@
 
 import android.graphics.Rect;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 public class FocusFinderTest extends AndroidTestCase {
 
diff --git a/core/tests/coretests/src/android/view/GlobalFocusChange.java b/core/tests/coretests/src/android/view/GlobalFocusChange.java
index 041c0de..ee92b64 100644
--- a/core/tests/coretests/src/android/view/GlobalFocusChange.java
+++ b/core/tests/coretests/src/android/view/GlobalFocusChange.java
@@ -16,12 +16,10 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.ViewTreeObserver;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
 
 public class GlobalFocusChange extends Activity implements ViewTreeObserver.OnGlobalFocusChangeListener {
     public View mOldFocus;
diff --git a/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java b/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java
index dab7b90..960654a 100644
--- a/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java
+++ b/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java
@@ -17,13 +17,13 @@
 package android.view;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.FlakyTest;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.Suppress;
-import android.view.View;
-import android.view.KeyEvent;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 import com.android.frameworks.coretests.R;
 
 @Suppress // Flaky
@@ -50,7 +50,7 @@
         super.tearDown();
     }
 
-    @FlakyTest(tolerance = 4)
+    @FlakyTest
     @LargeTest
     public void testFocusChange() throws Exception {
         sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
@@ -62,7 +62,7 @@
         assertSame(mRight, mActivity.mNewFocus);        
     }
 
-    @FlakyTest(tolerance = 4)
+    @FlakyTest
     @MediumTest
     public void testEnterTouchMode() throws Exception {
         assertTrue(mLeft.isFocused());
@@ -73,7 +73,7 @@
         assertSame(null, mActivity.mNewFocus);        
     }
 
-    @FlakyTest(tolerance = 4)
+    @FlakyTest
     @MediumTest
     public void testLeaveTouchMode() throws Exception {
         assertTrue(mLeft.isFocused());
diff --git a/core/tests/coretests/src/android/view/HandlerActionQueueTest.java b/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
index fd8f23a..bedb75b 100644
--- a/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
+++ b/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
@@ -17,7 +17,8 @@
 package android.view;
 
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 public class HandlerActionQueueTest extends AndroidTestCase {
 
diff --git a/core/tests/coretests/src/android/view/Include.java b/core/tests/coretests/src/android/view/Include.java
index e90c484..4b6aefb 100644
--- a/core/tests/coretests/src/android/view/Include.java
+++ b/core/tests/coretests/src/android/view/Include.java
@@ -16,10 +16,10 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
 import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercise <include /> tag in XML files.
diff --git a/core/tests/coretests/src/android/view/IncludeTest.java b/core/tests/coretests/src/android/view/IncludeTest.java
index cdcfa3c..e490559 100644
--- a/core/tests/coretests/src/android/view/IncludeTest.java
+++ b/core/tests/coretests/src/android/view/IncludeTest.java
@@ -16,13 +16,11 @@
 
 package android.view;
 
-import android.view.Include;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
-import android.view.ViewGroup;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
 
 public class IncludeTest extends ActivityInstrumentationTestCase<Include> {
     public IncludeTest() {
diff --git a/core/tests/coretests/src/android/view/InflateTest.java b/core/tests/coretests/src/android/view/InflateTest.java
index cb4f8e2..939d6ea 100644
--- a/core/tests/coretests/src/android/view/InflateTest.java
+++ b/core/tests/coretests/src/android/view/InflateTest.java
@@ -20,13 +20,11 @@
 import android.content.res.Resources;
 import android.test.AndroidTestCase;
 import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import com.android.frameworks.coretests.R;
 
-import java.util.Map;
+import androidx.test.filters.SmallTest;
+
+import com.android.frameworks.coretests.R;
 
 public class InflateTest extends AndroidTestCase implements PerformanceTestCase {
     private LayoutInflater mInflater;
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 81ca910..7f00ad9 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -18,7 +18,9 @@
 
 import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.TYPE_TOP_BAR;
+
 import static junit.framework.Assert.assertEquals;
+
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
@@ -27,12 +29,13 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 import android.view.SurfaceControl.Transaction;
 import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
 
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index d3d274a..d447451 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -17,18 +17,20 @@
 package android.view;
 
 import static android.view.InsetsState.TYPE_TOP_BAR;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNull;
+
 import static org.mockito.Mockito.mock;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mockito;
 
 @Presubmit
 @FlakyTest(detail = "Promote once confirmed non-flaky")
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 6d0f984..82cd213 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import static android.view.InsetsState.TYPE_TOP_BAR;
+
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.reset;
@@ -24,10 +25,11 @@
 import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.SurfaceControl.Transaction;
 
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/InsetsSourceTest.java b/core/tests/coretests/src/android/view/InsetsSourceTest.java
index ed472d2..98ab3e7 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceTest.java
@@ -17,13 +17,15 @@
 package android.view;
 
 import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
+
 import static junit.framework.Assert.assertEquals;
 
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 95af525..9857b7a 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -24,20 +24,23 @@
 import static android.view.InsetsState.TYPE_SIDE_BAR_2;
 import static android.view.InsetsState.TYPE_SIDE_BAR_3;
 import static android.view.InsetsState.TYPE_TOP_BAR;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
+
 import static org.junit.Assert.assertNotEquals;
 
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseIntArray;
 import android.view.WindowInsets.Type;
 
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/KeyEventTest.java b/core/tests/coretests/src/android/view/KeyEventTest.java
index b9d95e5..88d3bdb 100644
--- a/core/tests/coretests/src/android/view/KeyEventTest.java
+++ b/core/tests/coretests/src/android/view/KeyEventTest.java
@@ -20,8 +20,8 @@
 
 import static org.junit.Assert.assertEquals;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/ListContextMenu.java b/core/tests/coretests/src/android/view/ListContextMenu.java
index 1b4ece6..e333b96 100644
--- a/core/tests/coretests/src/android/view/ListContextMenu.java
+++ b/core/tests/coretests/src/android/view/ListContextMenu.java
@@ -16,24 +16,17 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.ListActivity;
 import android.content.Context;
 import android.os.Bundle;
 import android.util.Log;
-import android.view.ContextMenu;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.SubMenu;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercises context menus in lists
  */
diff --git a/core/tests/coretests/src/android/view/Longpress.java b/core/tests/coretests/src/android/view/Longpress.java
index e8e6f13..86fa9e5 100644
--- a/core/tests/coretests/src/android/view/Longpress.java
+++ b/core/tests/coretests/src/android/view/Longpress.java
@@ -16,11 +16,11 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 public class Longpress extends Activity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/core/tests/coretests/src/android/view/LongpressTest.java b/core/tests/coretests/src/android/view/LongpressTest.java
index d3d7589..4dfecd0 100644
--- a/core/tests/coretests/src/android/view/LongpressTest.java
+++ b/core/tests/coretests/src/android/view/LongpressTest.java
@@ -18,11 +18,12 @@
 
 import android.test.ActivityInstrumentationTestCase;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.KeyUtils;
 import android.view.View.OnLongClickListener;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/view/MenuTest.java b/core/tests/coretests/src/android/view/MenuTest.java
index 116b38a..794769cc 100644
--- a/core/tests/coretests/src/android/view/MenuTest.java
+++ b/core/tests/coretests/src/android/view/MenuTest.java
@@ -17,7 +17,8 @@
 package android.view;
 
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.frameworks.coretests.R;
 import com.android.internal.view.menu.MenuBuilder;
diff --git a/core/tests/coretests/src/android/view/Merge.java b/core/tests/coretests/src/android/view/Merge.java
index bdacd81..8020e4b 100644
--- a/core/tests/coretests/src/android/view/Merge.java
+++ b/core/tests/coretests/src/android/view/Merge.java
@@ -16,13 +16,11 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
 import android.app.Activity;
+import android.os.Bundle;
 import android.widget.LinearLayout;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercise <merge /> tag in XML files.
diff --git a/core/tests/coretests/src/android/view/MergeTest.java b/core/tests/coretests/src/android/view/MergeTest.java
index acfee7e..eccc9cb 100644
--- a/core/tests/coretests/src/android/view/MergeTest.java
+++ b/core/tests/coretests/src/android/view/MergeTest.java
@@ -16,11 +16,9 @@
 
 package android.view;
 
-import android.view.Merge;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.ViewGroup;
+
+import androidx.test.filters.MediumTest;
 
 public class MergeTest extends ActivityInstrumentationTestCase<Merge> {
     public MergeTest() {
diff --git a/core/tests/coretests/src/android/view/MotionEventTest.java b/core/tests/coretests/src/android/view/MotionEventTest.java
index 023526f..cadf37e 100644
--- a/core/tests/coretests/src/android/view/MotionEventTest.java
+++ b/core/tests/coretests/src/android/view/MotionEventTest.java
@@ -22,11 +22,12 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/MutateDrawable.java b/core/tests/coretests/src/android/view/MutateDrawable.java
index 39b5789..1ec525d 100644
--- a/core/tests/coretests/src/android/view/MutateDrawable.java
+++ b/core/tests/coretests/src/android/view/MutateDrawable.java
@@ -18,8 +18,9 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.widget.LinearLayout;
 import android.widget.Button;
+import android.widget.LinearLayout;
+
 import com.android.frameworks.coretests.R;
 
 public class MutateDrawable extends Activity {
diff --git a/core/tests/coretests/src/android/view/MutateDrawableTest.java b/core/tests/coretests/src/android/view/MutateDrawableTest.java
index 74e011d..d63ffb1 100644
--- a/core/tests/coretests/src/android/view/MutateDrawableTest.java
+++ b/core/tests/coretests/src/android/view/MutateDrawableTest.java
@@ -17,9 +17,8 @@
 package android.view;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
-import android.view.MutateDrawable;
+
+import androidx.test.filters.MediumTest;
 
 public class MutateDrawableTest extends ActivityInstrumentationTestCase2<MutateDrawable> {
     private View mFirstButton;
diff --git a/core/tests/coretests/src/android/view/PinchZoomAction.java b/core/tests/coretests/src/android/view/PinchZoomAction.java
index 97fe980..bec9b55 100644
--- a/core/tests/coretests/src/android/view/PinchZoomAction.java
+++ b/core/tests/coretests/src/android/view/PinchZoomAction.java
@@ -30,8 +30,6 @@
 import android.support.test.espresso.ViewAction;
 import android.support.test.espresso.action.Swiper;
 import android.support.test.espresso.util.HumanReadables;
-import android.view.MotionEvent;
-import android.view.View;
 
 import org.hamcrest.Matcher;
 
diff --git a/core/tests/coretests/src/android/view/PopupWindowVisibility.java b/core/tests/coretests/src/android/view/PopupWindowVisibility.java
index 85ce04f..e6430d3 100644
--- a/core/tests/coretests/src/android/view/PopupWindowVisibility.java
+++ b/core/tests/coretests/src/android/view/PopupWindowVisibility.java
@@ -18,7 +18,6 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.ArrayAdapter;
 import android.widget.AutoCompleteTextView;
diff --git a/core/tests/coretests/src/android/view/PreDrawListener.java b/core/tests/coretests/src/android/view/PreDrawListener.java
index 60bbee4..77bd36c 100644
--- a/core/tests/coretests/src/android/view/PreDrawListener.java
+++ b/core/tests/coretests/src/android/view/PreDrawListener.java
@@ -20,15 +20,12 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewTreeObserver;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.LinearLayout;
 
 import com.android.frameworks.coretests.R;
 
-
 /**
  * Tests views with popupWindows becoming invisible
  */
diff --git a/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java b/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
index b52d98c..786c22b 100644
--- a/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
+++ b/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
@@ -21,10 +21,11 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/RunQueue.java b/core/tests/coretests/src/android/view/RunQueue.java
index 85dd32e..7544433 100644
--- a/core/tests/coretests/src/android/view/RunQueue.java
+++ b/core/tests/coretests/src/android/view/RunQueue.java
@@ -19,8 +19,7 @@
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.TextView;
-import android.view.View;
-import android.view.ViewTreeObserver;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/view/RunQueueTest.java b/core/tests/coretests/src/android/view/RunQueueTest.java
index d69860b..f42f590 100644
--- a/core/tests/coretests/src/android/view/RunQueueTest.java
+++ b/core/tests/coretests/src/android/view/RunQueueTest.java
@@ -17,7 +17,8 @@
 package android.view;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
 
 public class RunQueueTest extends ActivityInstrumentationTestCase<RunQueue> {
     public RunQueueTest() {
diff --git a/core/tests/coretests/src/android/view/ScaleGesture.java b/core/tests/coretests/src/android/view/ScaleGesture.java
index a954a4a..235b224 100644
--- a/core/tests/coretests/src/android/view/ScaleGesture.java
+++ b/core/tests/coretests/src/android/view/ScaleGesture.java
@@ -16,16 +16,11 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
 import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
-import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
 
 public class ScaleGesture extends Activity {
     private ScaleGestureDetector mScaleGestureDetector;
diff --git a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
index fba8eae..1990135 100644
--- a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
+++ b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
@@ -16,26 +16,22 @@
 
 package android.view;
 
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
 import android.content.Context;
-import android.support.test.filters.LargeTest;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.DisplayMetrics;
-import android.view.PinchZoomAction;
-import android.view.ScaleGesture;
-import android.view.WindowManager;
 import android.widget.TextView;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
 import com.android.frameworks.coretests.R;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.Espresso.onView;
 
 @LargeTest
 public class ScaleGestureDetectorTest extends ActivityInstrumentationTestCase2<ScaleGesture> {
diff --git a/core/tests/coretests/src/android/view/SetTagsTest.java b/core/tests/coretests/src/android/view/SetTagsTest.java
index 373dce6..1699713 100644
--- a/core/tests/coretests/src/android/view/SetTagsTest.java
+++ b/core/tests/coretests/src/android/view/SetTagsTest.java
@@ -16,12 +16,13 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-import android.test.suitebuilder.annotation.MediumTest;
-
 import android.test.ActivityInstrumentationTestCase2;
 import android.widget.Button;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercises {@link android.view.View}'s tags property.
  */
diff --git a/core/tests/coretests/src/android/view/StubbedView.java b/core/tests/coretests/src/android/view/StubbedView.java
index 612095c..c96b9b7 100644
--- a/core/tests/coretests/src/android/view/StubbedView.java
+++ b/core/tests/coretests/src/android/view/StubbedView.java
@@ -16,11 +16,10 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
 import android.app.Activity;
-import android.view.View;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercise <ViewStub /> tag in XML files.
diff --git a/core/tests/coretests/src/android/view/VelocityTest.java b/core/tests/coretests/src/android/view/VelocityTest.java
index 7f32208..c116f4d 100644
--- a/core/tests/coretests/src/android/view/VelocityTest.java
+++ b/core/tests/coretests/src/android/view/VelocityTest.java
@@ -16,16 +16,17 @@
 
 package android.view;
 
-import android.test.suitebuilder.annotation.Suppress;
-import junit.framework.Assert;
-
 import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import junit.framework.Assert;
+
 /**
  * Exercises {@link android.view.VelocityTracker} to compute correct velocity.<br>
  * To launch this test, use :<br>
diff --git a/core/tests/coretests/src/android/view/ViewAttachTest.java b/core/tests/coretests/src/android/view/ViewAttachTest.java
index aa8f8d8..1a8dd99 100644
--- a/core/tests/coretests/src/android/view/ViewAttachTest.java
+++ b/core/tests/coretests/src/android/view/ViewAttachTest.java
@@ -16,16 +16,13 @@
 
 package android.view;
 
-import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.graphics.PixelFormat;
 import android.os.SystemClock;
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/view/ViewAttachTestActivity.java b/core/tests/coretests/src/android/view/ViewAttachTestActivity.java
index 59e25ae..bcbc813 100644
--- a/core/tests/coretests/src/android/view/ViewAttachTestActivity.java
+++ b/core/tests/coretests/src/android/view/ViewAttachTestActivity.java
@@ -16,11 +16,11 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 public class ViewAttachTestActivity extends Activity {
     public static final String TAG = "OnAttachedTest";
     @Override
diff --git a/core/tests/coretests/src/android/view/ViewAttachView.java b/core/tests/coretests/src/android/view/ViewAttachView.java
index 5af2d8f..2f3ff8f 100644
--- a/core/tests/coretests/src/android/view/ViewAttachView.java
+++ b/core/tests/coretests/src/android/view/ViewAttachView.java
@@ -22,7 +22,6 @@
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.View;
 
 /**
  * A View that will throw a RuntimeException if onAttachedToWindow and
diff --git a/core/tests/coretests/src/android/view/ViewCaptureTest.java b/core/tests/coretests/src/android/view/ViewCaptureTest.java
index 4405934..218047c 100644
--- a/core/tests/coretests/src/android/view/ViewCaptureTest.java
+++ b/core/tests/coretests/src/android/view/ViewCaptureTest.java
@@ -21,14 +21,15 @@
 import android.app.Activity;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.support.test.filters.SmallTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseIntArray;
 import android.view.ViewDebug.CanvasProvider;
 import android.view.ViewDebug.HardwareCanvasProvider;
 import android.view.ViewDebug.SoftwareCanvasProvider;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.frameworks.coretests.R;
 
 import org.junit.Assert;
diff --git a/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java b/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
index 20e3eb5..2f51c24 100644
--- a/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
+++ b/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.os.Bundle;
+
 import com.android.frameworks.coretests.R;
 
 public class ViewCaptureTestActivity extends Activity {
diff --git a/core/tests/coretests/src/android/view/ViewGroupAttributesTest.java b/core/tests/coretests/src/android/view/ViewGroupAttributesTest.java
index b4ef0e7..c24cd35 100644
--- a/core/tests/coretests/src/android/view/ViewGroupAttributesTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupAttributesTest.java
@@ -18,7 +18,8 @@
 
 import android.content.Context;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 public class ViewGroupAttributesTest extends AndroidTestCase {
 
diff --git a/core/tests/coretests/src/android/view/ViewGroupChildren.java b/core/tests/coretests/src/android/view/ViewGroupChildren.java
index f39720b..d5d9879 100644
--- a/core/tests/coretests/src/android/view/ViewGroupChildren.java
+++ b/core/tests/coretests/src/android/view/ViewGroupChildren.java
@@ -16,12 +16,10 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
-import android.widget.Button;
-import android.view.View;
 import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercise ViewGroup's ability to add and remove children.
diff --git a/core/tests/coretests/src/android/view/ViewGroupChildrenTest.java b/core/tests/coretests/src/android/view/ViewGroupChildrenTest.java
index d1665ef..07cb2a1 100644
--- a/core/tests/coretests/src/android/view/ViewGroupChildrenTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupChildrenTest.java
@@ -16,18 +16,16 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-import android.view.ViewGroupChildren;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.ViewAsserts;
-import android.test.UiThreadTest;
-import android.view.View;
-import android.view.ViewGroup;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercises {@link android.view.ViewGroup}'s ability to add/remove children.
  */
diff --git a/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java b/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java
index 93ad41f0..54524b2 100644
--- a/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java
@@ -22,12 +22,13 @@
 import android.app.Activity;
 import android.content.Context;
 import android.graphics.Canvas;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.widget.FrameLayout;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/ViewInvalidateTest.java b/core/tests/coretests/src/android/view/ViewInvalidateTest.java
index 115504b..c25a2deb 100644
--- a/core/tests/coretests/src/android/view/ViewInvalidateTest.java
+++ b/core/tests/coretests/src/android/view/ViewInvalidateTest.java
@@ -21,24 +21,30 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.content.Context;
 import android.graphics.Rect;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
+import android.view.ViewTreeObserver.OnDrawListener;
 import android.widget.FrameLayout;
 
-import com.android.compatibility.common.util.WidgetTestUtils;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Test of invalidates, drawing, and the flags that support them
  */
@@ -281,4 +287,42 @@
                 View.PFLAG_DRAWN);
         assertTrue(getViewRoot(mParent).mIsAnimating);
     }
+
+    /** Copied from cts/common/device-side/util. */
+    static class WidgetTestUtils {
+        public static void runOnMainAndDrawSync(@NonNull final ActivityTestRule activityTestRule,
+                @NonNull final View view, @Nullable final Runnable runner) throws Throwable {
+            final CountDownLatch latch = new CountDownLatch(1);
+
+            activityTestRule.runOnUiThread(() -> {
+                final OnDrawListener listener = new OnDrawListener() {
+                    @Override
+                    public void onDraw() {
+                        // posting so that the sync happens after the draw that's about to happen
+                        view.post(() -> {
+                            activityTestRule.getActivity().getWindow().getDecorView()
+                                    .getViewTreeObserver().removeOnDrawListener(this);
+                            latch.countDown();
+                        });
+                    }
+                };
+
+                activityTestRule.getActivity().getWindow().getDecorView()
+                        .getViewTreeObserver().addOnDrawListener(listener);
+
+                if (runner != null) {
+                    runner.run();
+                }
+                view.invalidate();
+            });
+
+            try {
+                Assert.assertTrue("Expected draw pass occurred within 5 seconds",
+                        latch.await(5, TimeUnit.SECONDS));
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+    }
 }
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index ca6d6cf..9a57847 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -23,9 +23,10 @@
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/ViewStubTest.java b/core/tests/coretests/src/android/view/ViewStubTest.java
index ebd52a6..504a4ec 100644
--- a/core/tests/coretests/src/android/view/ViewStubTest.java
+++ b/core/tests/coretests/src/android/view/ViewStubTest.java
@@ -16,14 +16,12 @@
 
 package android.view;
 
-import android.view.StubbedView;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.UiThreadTest;
-import android.view.View;
-import android.view.ViewStub;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
 
 public class ViewStubTest extends ActivityInstrumentationTestCase<StubbedView> {
     public ViewStubTest() {
diff --git a/core/tests/coretests/src/android/view/ViewTransientStateTest.java b/core/tests/coretests/src/android/view/ViewTransientStateTest.java
index 36ea01d..3f73b07 100644
--- a/core/tests/coretests/src/android/view/ViewTransientStateTest.java
+++ b/core/tests/coretests/src/android/view/ViewTransientStateTest.java
@@ -18,13 +18,12 @@
 
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
 
 import com.android.frameworks.coretests.R;
 
-import static org.junit.Assert.assertFalse;
-
 /**
  * Exercise set View's transient state
  */
diff --git a/core/tests/coretests/src/android/view/Visibility.java b/core/tests/coretests/src/android/view/Visibility.java
index 031568c..8e3de4e 100644
--- a/core/tests/coretests/src/android/view/Visibility.java
+++ b/core/tests/coretests/src/android/view/Visibility.java
@@ -16,12 +16,11 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
+import android.app.Activity;
 import android.os.Bundle;
 import android.widget.Button;
-import android.view.View;
-import android.app.Activity;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercise View's ability to change their visibility: GONE, INVISIBLE and
diff --git a/core/tests/coretests/src/android/view/VisibilityCallback.java b/core/tests/coretests/src/android/view/VisibilityCallback.java
index f98a0a8..c965973 100644
--- a/core/tests/coretests/src/android/view/VisibilityCallback.java
+++ b/core/tests/coretests/src/android/view/VisibilityCallback.java
@@ -16,16 +16,15 @@
 
 package android.view;
 
+import android.app.Activity;
 import android.content.Context;
+import android.os.Bundle;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.widget.TextView;
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
 import android.widget.Button;
-import android.view.View;
-import android.app.Activity;
+import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercise View's ability to change their visibility: GONE, INVISIBLE and
diff --git a/core/tests/coretests/src/android/view/VisibilityCallbackTest.java b/core/tests/coretests/src/android/view/VisibilityCallbackTest.java
index ec956d2..d7c7b4c 100644
--- a/core/tests/coretests/src/android/view/VisibilityCallbackTest.java
+++ b/core/tests/coretests/src/android/view/VisibilityCallbackTest.java
@@ -17,12 +17,12 @@
 package android.view;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
-import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.TextView;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/view/VisibilityTest.java b/core/tests/coretests/src/android/view/VisibilityTest.java
index 29c1c8a..83a7702 100644
--- a/core/tests/coretests/src/android/view/VisibilityTest.java
+++ b/core/tests/coretests/src/android/view/VisibilityTest.java
@@ -20,11 +20,12 @@
 import static android.view.KeyEvent.KEYCODE_DPAD_LEFT;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.Button;
 import android.widget.TextView;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java
index 1513a1a..15a96a1 100644
--- a/core/tests/coretests/src/android/view/WindowInsetsTest.java
+++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java
@@ -17,18 +17,18 @@
 package android.view;
 
 import static android.view.WindowInsets.Type.ime;
-import static android.view.WindowInsets.Type.indexOf;
 import static android.view.WindowInsets.Type.sideBars;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.WindowInsets.Builder;
-import android.view.WindowInsets.Type;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/ZeroSized.java b/core/tests/coretests/src/android/view/ZeroSized.java
index f2a6b3e..9e2dfcb 100644
--- a/core/tests/coretests/src/android/view/ZeroSized.java
+++ b/core/tests/coretests/src/android/view/ZeroSized.java
@@ -16,10 +16,10 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
 import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * This activity contains Views with various widths and heights. The goal is to exercise the
diff --git a/core/tests/coretests/src/android/view/ZeroSizedTest.java b/core/tests/coretests/src/android/view/ZeroSizedTest.java
index 193fc98..946bf68 100644
--- a/core/tests/coretests/src/android/view/ZeroSizedTest.java
+++ b/core/tests/coretests/src/android/view/ZeroSizedTest.java
@@ -16,13 +16,12 @@
 
 package android.view;
 
-import android.view.ZeroSized;
-import com.android.frameworks.coretests.R;
-
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
 import android.graphics.Bitmap;
+import android.test.ActivityInstrumentationTestCase;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Builds the drawing cache of Views of various dimension. The assumption is that
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
index 7f675ff..a88968b 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
@@ -28,10 +28,11 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
index 3e03414..46c96c9 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
@@ -21,7 +21,8 @@
 import static junit.framework.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
index 318d122..ab24f89 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
@@ -22,10 +22,12 @@
 
 import android.os.Bundle;
 import android.os.RemoteException;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import libcore.util.EmptyArray;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 506e544..0ed690c 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -25,11 +25,12 @@
 import static org.junit.Assert.fail;
 
 import android.os.Parcel;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArraySet;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.util.CollectionUtils;
 
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
index 4814c61..11f4e3c 100644
--- a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
@@ -14,7 +14,7 @@
 
 package android.view.accessibility;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java b/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
index 7619af2..33bc593 100644
--- a/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
+++ b/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.view.autofill;
 
 import static com.google.common.truth.Truth.assertThat;
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index 73cceae..05c0df7 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.view.contentcapture;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -96,6 +97,22 @@
         assertThat(structure.getAutofillId()).isEqualTo(childId);
     }
 
+    @Test
+    public void testNotifyViewsDisappeared_invalid() {
+        // Null parent
+        assertThrows(NullPointerException.class,
+                () -> mSession1.notifyViewsDisappeared(null, new int[] {42}));
+        // Null child
+        assertThrows(IllegalArgumentException.class,
+                () -> mSession1.notifyViewsDisappeared(new AutofillId(42), null));
+        // Empty child
+        assertThrows(IllegalArgumentException.class,
+                () -> mSession1.notifyViewsDisappeared(new AutofillId(42), new int[] {}));
+        // Virtual parent
+        assertThrows(IllegalArgumentException.class,
+                () -> mSession1.notifyViewsDisappeared(new AutofillId(42, 108), new int[] {666}));
+    }
+
     // Cannot use @Spy because we need to pass the session id on constructor
     private class MyContentCaptureSession extends ContentCaptureSession {
 
@@ -114,7 +131,7 @@
         }
 
         @Override
-        void flush() {
+        void flush(int reason) {
             throw new UnsupportedOperationException("should not have been called");
         }
 
diff --git a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
index bbfe01c..099f41d 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.view.contentcapture;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -24,7 +25,6 @@
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
 import android.view.View;
 import android.view.ViewStructure.HtmlInfo;
 import android.view.autofill.AutofillId;
@@ -32,6 +32,8 @@
 import android.view.contentcapture.ViewNode.ViewStructureImpl;
 import android.widget.FrameLayout;
 
+import androidx.test.InstrumentationRegistry;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
diff --git a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
index 0fd0136..ace6611 100644
--- a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
@@ -28,11 +28,12 @@
 import android.graphics.Matrix;
 import android.graphics.RectF;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
 import android.view.inputmethod.CursorAnchorInfo.Builder;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
index 1b00e09..f24e232 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
@@ -26,9 +26,10 @@
 import android.content.pm.ServiceInfo;
 import android.os.Bundle;
 import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
index 55e5e36..9f259a8 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
@@ -20,11 +20,12 @@
 import static org.junit.Assert.assertNotNull;
 
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.WindowManager;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
index 8df1848..e2fb46a 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
@@ -19,10 +19,11 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
index c76359e..1e0e1235 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
@@ -23,10 +23,11 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
index 8c96b58..453ad72 100644
--- a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
@@ -23,10 +23,11 @@
 
 import android.graphics.RectF;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
index 657a7fc..ba85d76 100644
--- a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
+++ b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.graphics.Point;
-import android.support.test.filters.MediumTest;
 import android.test.ActivityInstrumentationTestCase;
 import android.util.PollingCheck;
 import android.view.Display;
@@ -26,6 +25,8 @@
 import android.view.WindowManager;
 import android.widget.espresso.ContextMenuUtils;
 
+import androidx.test.filters.MediumTest;
+
 @MediumTest
 public class ContextMenuTest extends ActivityInstrumentationTestCase<ContextMenuActivity> {
 
diff --git a/core/tests/coretests/src/android/view/menu/MenuLayout.java b/core/tests/coretests/src/android/view/menu/MenuLayout.java
index 356c948..33ee515 100644
--- a/core/tests/coretests/src/android/view/menu/MenuLayout.java
+++ b/core/tests/coretests/src/android/view/menu/MenuLayout.java
@@ -16,8 +16,6 @@
 
 package android.view.menu;
 
-import android.view.menu.MenuScenario.Params;
-
 import android.os.Bundle;
 import android.view.Menu;
 import android.widget.Button;
diff --git a/core/tests/coretests/src/android/view/menu/MenuLayoutLandscapeTest.java b/core/tests/coretests/src/android/view/menu/MenuLayoutLandscapeTest.java
index 8ed0d86..ff9f166 100644
--- a/core/tests/coretests/src/android/view/menu/MenuLayoutLandscapeTest.java
+++ b/core/tests/coretests/src/android/view/menu/MenuLayoutLandscapeTest.java
@@ -16,13 +16,10 @@
 
 package android.view.menu;
 
-import android.util.KeyUtils;
-import com.android.internal.view.menu.IconMenuView;
-import com.android.internal.view.menu.MenuBuilder;
-
-import android.content.pm.ActivityInfo;
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase;
+import android.util.KeyUtils;
+
+import androidx.test.filters.LargeTest;
 
 @LargeTest
 public class MenuLayoutLandscapeTest extends ActivityInstrumentationTestCase<MenuLayoutLandscape> {
diff --git a/core/tests/coretests/src/android/view/menu/MenuLayoutPortraitTest.java b/core/tests/coretests/src/android/view/menu/MenuLayoutPortraitTest.java
index ccf1264..360be53 100644
--- a/core/tests/coretests/src/android/view/menu/MenuLayoutPortraitTest.java
+++ b/core/tests/coretests/src/android/view/menu/MenuLayoutPortraitTest.java
@@ -16,11 +16,11 @@
 
 package android.view.menu;
 
-import android.content.pm.ActivityInfo;
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase;
 import android.util.KeyUtils;
 
+import androidx.test.filters.LargeTest;
+
 @LargeTest
 public class MenuLayoutPortraitTest extends ActivityInstrumentationTestCase<MenuLayoutPortrait> {
     private static final String LONG_TITLE = "Really really really really really really really really really really long title";
diff --git a/core/tests/coretests/src/android/view/menu/MenuWith1ItemTest.java b/core/tests/coretests/src/android/view/menu/MenuWith1ItemTest.java
index 82ad858..c18e361 100644
--- a/core/tests/coretests/src/android/view/menu/MenuWith1ItemTest.java
+++ b/core/tests/coretests/src/android/view/menu/MenuWith1ItemTest.java
@@ -16,17 +16,12 @@
 
 package android.view.menu;
 
-import android.view.menu.MenuWith1Item;
-import android.util.KeyUtils;
-import com.android.internal.view.menu.MenuBuilder;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.TouchUtils;
-
 import android.test.ActivityInstrumentationTestCase;
+import android.util.KeyUtils;
 import android.view.KeyEvent;
-import android.view.View;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 public class MenuWith1ItemTest extends ActivityInstrumentationTestCase<MenuWith1Item> {
     private MenuWith1Item mActivity;
diff --git a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
index 4a6c093..780e15a 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
@@ -22,8 +22,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.app.Person;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.google.android.textclassifier.ActionsSuggestionsModel;
 
diff --git a/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java b/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
index 0180856..fef6583 100644
--- a/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
+++ b/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
@@ -21,6 +21,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -29,9 +30,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.support.test.InstrumentationRegistry;
 
-import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
 
 import com.google.common.base.Preconditions;
 
diff --git a/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java
index aaadefb..3fc8e4c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java
@@ -13,14 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.view.textclassifier;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Intent;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.google.android.textclassifier.AnnotatorModel;
 
diff --git a/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java
index 88d162b..74b8e3b 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.view.textclassifier;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -20,9 +21,10 @@
 import static org.mockito.Mockito.when;
 
 import android.os.LocaleList;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java b/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
index a3c6179..46e3a4c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
@@ -19,8 +19,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
index 54007fb..9662182 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
@@ -20,8 +20,8 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index a3f69d9..4fcd51c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -26,9 +26,10 @@
 import android.content.Intent;
 import android.os.LocaleList;
 import android.service.textclassifier.TextClassifierService;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index aaf7312..99c959e 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -32,11 +32,12 @@
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index 82eaf88..7009fb2 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -24,11 +24,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.LocaleList;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
 import android.text.Spannable;
 import android.text.SpannableString;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
@@ -377,10 +378,10 @@
                         ConversationActions.Message.PERSON_USER_REMOTE)
                         .setText("Where are you?")
                         .build();
-        ConversationActions.TypeConfig typeConfig =
-                new ConversationActions.TypeConfig.Builder().includeTypesFromTextClassifier(false)
+        TextClassifier.EntityConfig typeConfig =
+                new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
                         .setIncludedTypes(
-                                Collections.singletonList(ConversationActions.TYPE_TEXT_REPLY))
+                                Collections.singletonList(ConversationAction.TYPE_TEXT_REPLY))
                         .build();
         ConversationActions.Request request =
                 new ConversationActions.Request.Builder(Collections.singletonList(message))
@@ -391,10 +392,10 @@
         ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
         assertTrue(conversationActions.getConversationActions().size() > 0);
         assertTrue(conversationActions.getConversationActions().size() == 1);
-        for (ConversationActions.ConversationAction conversationAction :
+        for (ConversationAction conversationAction :
                 conversationActions.getConversationActions()) {
             assertThat(conversationAction,
-                    isConversationAction(ConversationActions.TYPE_TEXT_REPLY));
+                    isConversationAction(ConversationAction.TYPE_TEXT_REPLY));
         }
     }*/
 
@@ -406,10 +407,10 @@
                         ConversationActions.Message.PERSON_USER_REMOTE)
                         .setText("Where are you?")
                         .build();
-        ConversationActions.TypeConfig typeConfig =
-                new ConversationActions.TypeConfig.Builder().includeTypesFromTextClassifier(false)
+        TextClassifier.EntityConfig typeConfig =
+                new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
                         .setIncludedTypes(
-                                Collections.singletonList(ConversationActions.TYPE_TEXT_REPLY))
+                                Collections.singletonList(ConversationAction.TYPE_TEXT_REPLY))
                         .build();
         ConversationActions.Request request =
                 new ConversationActions.Request.Builder(Collections.singletonList(message))
@@ -418,10 +419,10 @@
 
         ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
         assertTrue(conversationActions.getConversationActions().size() > 1);
-        for (ConversationActions.ConversationAction conversationAction :
+        for (ConversationAction conversationAction :
                 conversationActions.getConversationActions()) {
             assertThat(conversationAction,
-                    isConversationAction(ConversationActions.TYPE_TEXT_REPLY));
+                    isConversationAction(ConversationAction.TYPE_TEXT_REPLY));
         }
     }
 
@@ -524,20 +525,19 @@
         };
     }
 
-    private static Matcher<ConversationActions.ConversationAction> isConversationAction(
-            String actionType) {
-        return new BaseMatcher<ConversationActions.ConversationAction>() {
+    private static Matcher<ConversationAction> isConversationAction(String actionType) {
+        return new BaseMatcher<ConversationAction>() {
             @Override
             public boolean matches(Object o) {
-                if (!(o instanceof ConversationActions.ConversationAction)) {
+                if (!(o instanceof ConversationAction)) {
                     return false;
                 }
-                ConversationActions.ConversationAction conversationAction =
-                        (ConversationActions.ConversationAction) o;
+                ConversationAction conversationAction =
+                        (ConversationAction) o;
                 if (!actionType.equals(conversationAction.getType())) {
                     return false;
                 }
-                if (ConversationActions.TYPE_TEXT_REPLY.equals(actionType)) {
+                if (ConversationAction.TYPE_TEXT_REPLY.equals(actionType)) {
                     if (conversationAction.getTextReply() == null) {
                         return false;
                     }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
index 1dcaed6..d0d32e3 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
@@ -21,8 +21,9 @@
 import android.icu.util.ULocale;
 import android.os.Bundle;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
index f022d04..b9cc8f4 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
@@ -21,10 +21,11 @@
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
index 2ea49f7..30cc4e8 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
@@ -21,8 +21,9 @@
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
index 8e4f02c..5e8e582 100644
--- a/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
@@ -23,13 +23,14 @@
 import static org.mockito.Mockito.mock;
 
 import android.metrics.LogMaker;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
 import android.view.textclassifier.GenerateLinksLogger;
 import android.view.textclassifier.TextClassifier;
 import android.view.textclassifier.TextLinks;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
index 344f79d..b1b7416 100644
--- a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.view.textclassifier.logging;
 
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE;
@@ -24,13 +25,14 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.metrics.LogMaker;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.view.textclassifier.ConversationActions;
+import android.view.textclassifier.ConversationAction;
 import android.view.textclassifier.TextClassificationContext;
 import android.view.textclassifier.TextClassifierEvent;
 import android.view.textclassifier.TextClassifierEventTronLogger;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.logging.MetricsLogger;
 
 import org.junit.Before;
@@ -69,7 +71,7 @@
                 new TextClassifierEvent.Builder(
                         TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS,
                         TextClassifierEvent.TYPE_SMART_ACTION)
-                        .setEntityType(ConversationActions.TYPE_CALL_PHONE)
+                        .setEntityType(ConversationAction.TYPE_CALL_PHONE)
                         .setEventTime(EVENT_TIME)
                         .setEventContext(textClassificationContext)
                         .build();
@@ -84,7 +86,7 @@
         assertThat(logMaker.getType()).isEqualTo(
                 ACTION_TEXT_SELECTION_SMART_SHARE);
         assertThat(logMaker.getTaggedData(FIELD_SELECTION_ENTITY_TYPE))
-                .isEqualTo(ConversationActions.TYPE_CALL_PHONE);
+                .isEqualTo(ConversationAction.TYPE_CALL_PHONE);
         assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME))
                 .isEqualTo(EVENT_TIME);
         assertThat(logMaker.getPackageName()).isEqualTo(PACKAGE_NAME);
diff --git a/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java b/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java
index 4a1c414..638d894 100644
--- a/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java
+++ b/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java
@@ -16,15 +16,16 @@
 
 package android.view.textservice;
 
+import static android.test.MoreAsserts.assertNotEqual;
+
 import android.os.Parcel;
 import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import java.util.Arrays;
 import java.util.Locale;
 
-import static android.test.MoreAsserts.assertNotEqual;
-
 /**
  * TODO: Most of part can be, and probably should be, moved to CTS.
  */
diff --git a/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java b/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java
index 4f31c4e..6edc162 100644
--- a/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java
+++ b/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java
@@ -24,18 +24,14 @@
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.view.ViewGroup.OnHierarchyChangeListener;
 
-import com.android.frameworks.coretests.R;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
-import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Future;
+import com.android.frameworks.coretests.R;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -43,6 +39,11 @@
 import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+
 /**
  * Tests for AppWidgetHostView
  */
diff --git a/core/tests/coretests/src/android/widget/AutoCompleteTextViewCallbacks.java b/core/tests/coretests/src/android/widget/AutoCompleteTextViewCallbacks.java
index 8e73b52..01e82a5 100644
--- a/core/tests/coretests/src/android/widget/AutoCompleteTextViewCallbacks.java
+++ b/core/tests/coretests/src/android/widget/AutoCompleteTextViewCallbacks.java
@@ -18,7 +18,8 @@
 
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.FlakyTest;
+
+import androidx.test.filters.FlakyTest;
 
 // TODO: tests fail intermittently. Add back MediumTest annotation when fixed
 public class AutoCompleteTextViewCallbacks
@@ -32,7 +33,7 @@
 
     /** Test that the initial popup of the suggestions does not select anything.
      */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupNoSelection() throws Exception {
         AutoCompleteTextViewSimple theActivity = getActivity();
         AutoCompleteTextView textView = theActivity.getTextView();
@@ -57,7 +58,7 @@
     }
 
     /** Test that arrow-down into the popup calls the onSelected callback. */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupEnterSelection() throws Exception {
         final AutoCompleteTextViewSimple theActivity = getActivity();
         AutoCompleteTextView textView = theActivity.getTextView();
@@ -106,7 +107,7 @@
     }
 
     /** Test that arrow-up out of the popup calls the onNothingSelected callback */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupLeaveSelection() {
         final AutoCompleteTextViewSimple theActivity = getActivity();
         AutoCompleteTextView textView = theActivity.getTextView();
diff --git a/core/tests/coretests/src/android/widget/AutoCompleteTextViewPopup.java b/core/tests/coretests/src/android/widget/AutoCompleteTextViewPopup.java
index ee0abae..21e4184 100644
--- a/core/tests/coretests/src/android/widget/AutoCompleteTextViewPopup.java
+++ b/core/tests/coretests/src/android/widget/AutoCompleteTextViewPopup.java
@@ -18,8 +18,8 @@
 
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.FlakyTest;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.FlakyTest;
 
 /**
  * A collection of tests on aspects of the AutoCompleteTextView's popup
@@ -41,7 +41,7 @@
     }
 
     /** Test that we can move the selection and it responds as expected */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupSetListSelection() throws Throwable {
         AutoCompleteTextViewSimple theActivity = getActivity();
         final AutoCompleteTextView textView = theActivity.getTextView();
@@ -73,7 +73,7 @@
     }
 
     /** Test that we can look at the selection as we move around */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupGetListSelection() throws Throwable {
         AutoCompleteTextViewSimple theActivity = getActivity();
         final AutoCompleteTextView textView = theActivity.getTextView();
@@ -100,7 +100,7 @@
     }
 
     /** Test that we can clear the selection */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupClearListSelection() throws Throwable {
         AutoCompleteTextViewSimple theActivity = getActivity();
         final AutoCompleteTextView textView = theActivity.getTextView();
@@ -133,7 +133,7 @@
     }
 
     /** Make sure we handle an empty adapter properly */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupNavigateNoAdapter() throws Throwable {
         AutoCompleteTextViewSimple theActivity = getActivity();
         final AutoCompleteTextView textView = theActivity.getTextView();
@@ -167,7 +167,7 @@
     }
 
     /** Test the show/hide behavior of the drop-down. */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupShow() throws Throwable {
         AutoCompleteTextViewSimple theActivity = getActivity();
         final AutoCompleteTextView textView = theActivity.getTextView();
diff --git a/core/tests/coretests/src/android/widget/AutoCompleteTextViewSimple.java b/core/tests/coretests/src/android/widget/AutoCompleteTextViewSimple.java
index b4e05aa..063bec5 100644
--- a/core/tests/coretests/src/android/widget/AutoCompleteTextViewSimple.java
+++ b/core/tests/coretests/src/android/widget/AutoCompleteTextViewSimple.java
@@ -16,8 +16,6 @@
 
 package android.widget;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.util.Log;
@@ -25,6 +23,8 @@
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemSelectedListener;
 
+import com.android.frameworks.coretests.R;
+
 public class AutoCompleteTextViewSimple extends Activity 
         implements OnItemClickListener, OnItemSelectedListener {
 
diff --git a/core/tests/coretests/src/android/widget/DatePickerActivity.java b/core/tests/coretests/src/android/widget/DatePickerActivity.java
index c3b25a1..9e455b2 100644
--- a/core/tests/coretests/src/android/widget/DatePickerActivity.java
+++ b/core/tests/coretests/src/android/widget/DatePickerActivity.java
@@ -18,6 +18,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/DatePickerFocusTest.java b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
index be85450..f067230 100644
--- a/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
+++ b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
@@ -19,11 +19,12 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.os.SystemClock;
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.KeyEvent;
 import android.view.View;
 
+import androidx.test.filters.LargeTest;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/DateTimeViewTest.java b/core/tests/coretests/src/android/widget/DateTimeViewTest.java
index 40a6b7a..d0bd4b8 100644
--- a/core/tests/coretests/src/android/widget/DateTimeViewTest.java
+++ b/core/tests/coretests/src/android/widget/DateTimeViewTest.java
@@ -16,10 +16,10 @@
 
 package android.widget;
 
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/widget/EditorCursorTest.java b/core/tests/coretests/src/android/widget/EditorCursorTest.java
index 9186827b..e4f55df 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorTest.java
@@ -31,10 +31,11 @@
 
 import android.app.Activity;
 import android.app.Instrumentation;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/widget/ListViewTest.java b/core/tests/coretests/src/android/widget/ListViewTest.java
index 449b696..254af2a 100644
--- a/core/tests/coretests/src/android/widget/ListViewTest.java
+++ b/core/tests/coretests/src/android/widget/ListViewTest.java
@@ -16,20 +16,19 @@
 
 package android.widget;
 
-import android.test.suitebuilder.annotation.Suppress;
-import com.google.android.collect.Lists;
-
-import junit.framework.Assert;
-
 import android.content.Context;
 import android.content.res.Resources;
 import android.test.InstrumentationTestCase;
 import android.test.mock.MockContext;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import com.google.android.collect.Lists;
+
+import junit.framework.Assert;
 
 import java.util.List;
 
diff --git a/core/tests/coretests/src/android/widget/RadioGroupActivity.java b/core/tests/coretests/src/android/widget/RadioGroupActivity.java
index c87aa3a..dd3b30a 100644
--- a/core/tests/coretests/src/android/widget/RadioGroupActivity.java
+++ b/core/tests/coretests/src/android/widget/RadioGroupActivity.java
@@ -17,11 +17,11 @@
 
 package android.widget;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 public class RadioGroupActivity extends Activity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/core/tests/coretests/src/android/widget/RadioGroupPreCheckedTest.java b/core/tests/coretests/src/android/widget/RadioGroupPreCheckedTest.java
index 1ab3628..18c1ea1 100644
--- a/core/tests/coretests/src/android/widget/RadioGroupPreCheckedTest.java
+++ b/core/tests/coretests/src/android/widget/RadioGroupPreCheckedTest.java
@@ -16,12 +16,13 @@
 
 package android.widget;
 
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercises {@link android.widget.RadioGroup}'s check feature.
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java b/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
index 06b860a..da53f6d 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
@@ -38,11 +38,12 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.frameworks.coretests.R;
 import com.android.internal.widget.IRemoteViewsFactory;
 
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
index 36792bb..8cb7e1b 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
@@ -32,12 +32,13 @@
 import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.frameworks.coretests.R;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java b/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java
index 2add221..74aad9a 100644
--- a/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java
+++ b/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java
@@ -22,7 +22,8 @@
 
 import android.graphics.PointF;
 import android.graphics.RectF;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java b/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
index 1731c08..a79b30d 100644
--- a/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
+++ b/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
@@ -16,14 +16,15 @@
 
 package android.widget;
 
-import android.test.suitebuilder.annotation.Suppress;
-import com.google.android.collect.Lists;
-
 import android.content.Context;
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+
+import com.google.android.collect.Lists;
 
 import java.util.ArrayList;
 import java.util.Random;
diff --git a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
index eafe427..483270e 100644
--- a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
+++ b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
@@ -36,13 +36,13 @@
 import static android.widget.espresso.SuggestionsPopupwindowUtils.onSuggestionsPopup;
 import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
 import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
+
 import static org.hamcrest.Matchers.is;
+
 import android.content.res.TypedArray;
 import android.support.test.espresso.NoMatchingViewException;
 import android.support.test.espresso.ViewAssertion;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.Spanned;
@@ -51,6 +51,8 @@
 import android.text.style.TextAppearanceSpan;
 import android.view.View;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
index ff4a7da..41fa08b 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
@@ -43,14 +43,15 @@
 import static android.widget.espresso.TextViewAssertions.hasSelection;
 
 import android.app.Activity;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.Suppress;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.MotionEvent;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textclassifier.TextClassifier;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.frameworks.coretests.R;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 90758ba..9d93421 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -27,10 +27,8 @@
 import static android.support.test.espresso.matcher.ViewMatchers.withText;
 import static android.widget.espresso.CustomViewActions.longPressAtRelativeCoordinates;
 import static android.widget.espresso.DragHandleUtils.onHandleView;
-import static android.widget.espresso.FloatingToolbarEspressoUtils
-        .assertFloatingToolbarContainsItem;
-import static android.widget.espresso.FloatingToolbarEspressoUtils
-        .assertFloatingToolbarDoesNotContainItem;
+import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem;
+import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarDoesNotContainItem;
 import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed;
 import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarItemIndex;
 import static android.widget.espresso.FloatingToolbarEspressoUtils.clickFloatingToolbarItem;
@@ -62,13 +60,8 @@
 import android.app.Instrumentation;
 import android.content.ClipData;
 import android.content.ClipboardManager;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.espresso.action.EspressoKey;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.support.test.uiautomator.UiDevice;
-import android.test.suitebuilder.annotation.Suppress;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.Spannable;
@@ -85,6 +78,12 @@
 import android.view.textclassifier.TextLinksParams;
 import android.widget.espresso.CustomViewActions.RelativeCoordinatesProvider;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.frameworks.coretests.R;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/widget/TextViewFallbackLineSpacingTest.java b/core/tests/coretests/src/android/widget/TextViewFallbackLineSpacingTest.java
index e9d1d3e..113db9d 100644
--- a/core/tests/coretests/src/android/widget/TextViewFallbackLineSpacingTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewFallbackLineSpacingTest.java
@@ -21,8 +21,6 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
 import android.text.DynamicLayout;
 import android.text.FontFallbackSetup;
 import android.text.Layout;
@@ -31,6 +29,9 @@
 import android.view.View;
 import android.widget.TextView.BufferType;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/widget/TextViewPerformanceTest.java b/core/tests/coretests/src/android/widget/TextViewPerformanceTest.java
index cf173fb..a769ea4 100644
--- a/core/tests/coretests/src/android/widget/TextViewPerformanceTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewPerformanceTest.java
@@ -20,14 +20,15 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Paint;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.SpannedString;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index 1c5610b..585360f 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -27,11 +27,6 @@
 import android.content.Intent;
 import android.graphics.Paint;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.GetChars;
 import android.text.Layout;
 import android.text.PrecomputedText;
@@ -40,6 +35,12 @@
 import android.view.View;
 import android.widget.TextView.BufferType;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java b/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java
index 75da6fe..85a4509 100644
--- a/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java
+++ b/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java
@@ -16,12 +16,11 @@
 
 package android.widget.focus;
 
-import android.util.InternalSelectionView;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.widget.LinearLayout;
+import android.util.InternalSelectionView;
 import android.view.ViewGroup;
+import android.widget.LinearLayout;
 
 /**
  * {@link android.view.FocusFinder#findNextFocus(android.view.ViewGroup, android.view.View, int)}
diff --git a/core/tests/coretests/src/android/widget/focus/DescendantFocusability.java b/core/tests/coretests/src/android/widget/focus/DescendantFocusability.java
index f6b0520..fe6d3c8 100644
--- a/core/tests/coretests/src/android/widget/focus/DescendantFocusability.java
+++ b/core/tests/coretests/src/android/widget/focus/DescendantFocusability.java
@@ -16,13 +16,13 @@
 
 package android.widget.focus;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.ViewGroup;
 import android.widget.Button;
 
+import com.android.frameworks.coretests.R;
+
 public class DescendantFocusability extends Activity {
 
     public ViewGroup beforeDescendants;
diff --git a/core/tests/coretests/src/android/widget/focus/DescendantFocusabilityTest.java b/core/tests/coretests/src/android/widget/focus/DescendantFocusabilityTest.java
index 2af42ac..1c570df 100644
--- a/core/tests/coretests/src/android/widget/focus/DescendantFocusabilityTest.java
+++ b/core/tests/coretests/src/android/widget/focus/DescendantFocusabilityTest.java
@@ -16,15 +16,14 @@
 
 package android.widget.focus;
 
-import android.widget.focus.DescendantFocusability;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.UiThreadTest;
 import android.test.TouchUtils;
 import android.view.ViewGroup;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 public class DescendantFocusabilityTest extends ActivityInstrumentationTestCase<DescendantFocusability> {
 
     private DescendantFocusability a;
diff --git a/core/tests/coretests/src/android/widget/focus/FocusAfterRemoval.java b/core/tests/coretests/src/android/widget/focus/FocusAfterRemoval.java
index b3d5ec5..0cb80ce 100644
--- a/core/tests/coretests/src/android/widget/focus/FocusAfterRemoval.java
+++ b/core/tests/coretests/src/android/widget/focus/FocusAfterRemoval.java
@@ -16,13 +16,13 @@
 
 package android.widget.focus;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.widget.LinearLayout;
-import android.widget.Button;
 import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercises cases where elements of the UI are removed (and
diff --git a/core/tests/coretests/src/android/widget/focus/FocusAfterRemovalTest.java b/core/tests/coretests/src/android/widget/focus/FocusAfterRemovalTest.java
index a1b7bcb..6c46d08 100644
--- a/core/tests/coretests/src/android/widget/focus/FocusAfterRemovalTest.java
+++ b/core/tests/coretests/src/android/widget/focus/FocusAfterRemovalTest.java
@@ -16,15 +16,15 @@
 
 package android.widget.focus;
 
-import android.widget.focus.FocusAfterRemoval;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.Button;
-import android.widget.LinearLayout;
 import android.view.KeyEvent;
 import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * {@link FocusAfterRemoval} is set up to exercise cases where the views that
diff --git a/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java b/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java
index 8f8f184..26dc233 100644
--- a/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java
+++ b/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java
@@ -16,14 +16,13 @@
 
 package android.widget.focus;
 
-import android.widget.focus.AdjacentVerticalRectLists;
-import android.util.InternalSelectionView;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.util.InternalSelectionView;
 import android.view.KeyEvent;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 /**
  * {@link android.view.FocusFinder#findNextFocus(android.view.ViewGroup, android.view.View, int)}
  * and
diff --git a/core/tests/coretests/src/android/widget/focus/GoneParentFocusedChildTest.java b/core/tests/coretests/src/android/widget/focus/GoneParentFocusedChildTest.java
index dcbddef..b7974e3 100644
--- a/core/tests/coretests/src/android/widget/focus/GoneParentFocusedChildTest.java
+++ b/core/tests/coretests/src/android/widget/focus/GoneParentFocusedChildTest.java
@@ -17,10 +17,10 @@
 package android.widget.focus;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.view.View;
-import android.widget.focus.GoneParentFocusedChild;
+
+import androidx.test.filters.MediumTest;
 
 /**
  * When a parent is GONE, key events shouldn't go to its children, even if they
diff --git a/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearch.java b/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearch.java
index 11cac1e..aab9119 100644
--- a/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearch.java
+++ b/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearch.java
@@ -17,12 +17,12 @@
 package android.widget.focus;
 
 import android.app.Activity;
-import android.widget.LinearLayout;
-import android.widget.Button;
-import android.widget.TextView;
+import android.content.Context;
 import android.os.Bundle;
 import android.view.ViewGroup;
-import android.content.Context;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
 
 public class HorizontalFocusSearch extends Activity {
 
diff --git a/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearchTest.java b/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearchTest.java
index 43986ee..855a3219 100644
--- a/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearchTest.java
+++ b/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearchTest.java
@@ -16,18 +16,17 @@
 
 package android.widget.focus;
 
-import android.widget.focus.HorizontalFocusSearch;
-
-import android.support.test.filters.LargeTest;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.LinearLayout;
-import android.widget.Button;
-import android.view.View;
-
 import static android.widget.focus.VerticalFocusSearchTest.FocusSearchAlg;
 import static android.widget.focus.VerticalFocusSearchTest.NewFocusSearchAlg;
 
+import android.test.ActivityInstrumentationTestCase;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
+
 /**
  * Tests that focus searching works on a horizontal linear layout of buttons of
  * various widths and vertical placements.
diff --git a/core/tests/coretests/src/android/widget/focus/LinearLayoutGrid.java b/core/tests/coretests/src/android/widget/focus/LinearLayoutGrid.java
index acd632f..ec234bc 100644
--- a/core/tests/coretests/src/android/widget/focus/LinearLayoutGrid.java
+++ b/core/tests/coretests/src/android/widget/focus/LinearLayoutGrid.java
@@ -21,6 +21,7 @@
 import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.LinearLayout;
+
 import com.android.frameworks.coretests.R;
 
 public class LinearLayoutGrid extends Activity {
diff --git a/core/tests/coretests/src/android/widget/focus/LinearLayoutGridTest.java b/core/tests/coretests/src/android/widget/focus/LinearLayoutGridTest.java
index 89cb8bb..c81317c 100644
--- a/core/tests/coretests/src/android/widget/focus/LinearLayoutGridTest.java
+++ b/core/tests/coretests/src/android/widget/focus/LinearLayoutGridTest.java
@@ -17,11 +17,11 @@
 package android.widget.focus;
 
 import android.test.SingleLaunchActivityTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.FocusFinder;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.focus.LinearLayoutGrid;
+
+import androidx.test.filters.MediumTest;
 
 /**
  * Tests focus searching between buttons within a grid that are touching, for example,
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfButtons.java b/core/tests/coretests/src/android/widget/focus/ListOfButtons.java
index 308861d..5663ed2 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfButtons.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfButtons.java
@@ -16,8 +16,6 @@
 
 package android.widget.focus;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.ListActivity;
 import android.content.Context;
 import android.os.Bundle;
@@ -26,6 +24,8 @@
 import android.widget.ArrayAdapter;
 import android.widget.Button;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * A layout with a ListView containing buttons.
  */
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java b/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
index bec6f80..4cf4a3a 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
@@ -16,17 +16,17 @@
 
 package android.widget.focus;
 
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.focus.ListOfButtons;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListAdapter;
-import android.widget.Button;
-import android.widget.ListView;
 import android.view.KeyEvent;
 import android.view.View;
+import android.widget.Button;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Tests that focus works as expected when navigating into and out of
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java b/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java
index c2e7a26..936c999 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java
@@ -21,7 +21,12 @@
 import android.os.Bundle;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.*;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+
 import com.google.android.collect.Lists;
 
 import java.util.List;
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
index 53b866c..73e4ea8 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
@@ -19,11 +19,11 @@
 import android.app.Activity;
 import android.graphics.Point;
 import android.os.Bundle;
+import android.util.InternalSelectionView;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
 import android.widget.ListView;
-import android.util.InternalSelectionView;
 
 /**
  * A list of {@link InternalSelectionView}s paramatarized by the number of items,
diff --git a/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabels.java b/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabels.java
index b908201..8accf21 100644
--- a/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabels.java
+++ b/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabels.java
@@ -27,9 +27,10 @@
 import android.widget.Button;
 import android.widget.TextView;
 
-import com.google.android.collect.Lists;
 import com.android.frameworks.coretests.R;
 
+import com.google.android.collect.Lists;
+
 import java.util.List;
 
 public class ListWithFooterViewAndNewLabels extends ListActivity {
diff --git a/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabelsTest.java b/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabelsTest.java
index 57dbb78..d0fcde5 100644
--- a/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabelsTest.java
+++ b/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabelsTest.java
@@ -16,14 +16,13 @@
 
 package android.widget.focus;
 
-import android.widget.focus.ListWithFooterViewAndNewLabels;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
 import android.widget.Button;
 import android.widget.ListAdapter;
 import android.widget.ListView;
 
+import com.android.frameworks.coretests.R;
+
 public class ListWithFooterViewAndNewLabelsTest
         extends ActivityInstrumentationTestCase<ListWithFooterViewAndNewLabels> {
 
diff --git a/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java b/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
index 5c891f9..50a8614 100644
--- a/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
+++ b/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
@@ -16,19 +16,20 @@
 
 package android.widget.focus;
 
-import com.android.frameworks.coretests.R;
-import com.google.android.collect.Lists;
-
 import android.app.ListActivity;
+import android.content.Context;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebView;
 import android.widget.ArrayAdapter;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
-import android.webkit.WebView;
+
+import com.android.frameworks.coretests.R;
+
+import com.google.android.collect.Lists;
 
 import java.util.List;
 
diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocus.java b/core/tests/coretests/src/android/widget/focus/RequestFocus.java
index 4daf0b4..5042efd 100644
--- a/core/tests/coretests/src/android/widget/focus/RequestFocus.java
+++ b/core/tests/coretests/src/android/widget/focus/RequestFocus.java
@@ -16,13 +16,13 @@
 
 package android.widget.focus;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.os.Handler;
 import android.widget.Button;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercises cases where elements of the UI are requestFocus()ed.
  */
diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
index cdfa217..bc770c5 100644
--- a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
+++ b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
@@ -21,16 +21,18 @@
 
 import android.os.Handler;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.AndroidRuntimeException;
 import android.view.View;
 import android.view.View.OnFocusChangeListener;
 import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
 import android.widget.Button;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
+
 import org.mockito.InOrder;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java b/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
index 06cb75d..e6e76cc 100644
--- a/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
+++ b/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
@@ -18,12 +18,12 @@
 
 import android.graphics.Rect;
 import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.InternalSelectionView;
 import android.view.KeyEvent;
 import android.widget.ListView;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 /**
  * TODO: extract base test case that launches {@link ListOfInternalSelectionViews} with
diff --git a/core/tests/coretests/src/android/widget/focus/VerticalFocusSearch.java b/core/tests/coretests/src/android/widget/focus/VerticalFocusSearch.java
index 4a809e0..2ca9f6d 100644
--- a/core/tests/coretests/src/android/widget/focus/VerticalFocusSearch.java
+++ b/core/tests/coretests/src/android/widget/focus/VerticalFocusSearch.java
@@ -17,13 +17,13 @@
 package android.widget.focus;
 
 import android.app.Activity;
+import android.content.Context;
 import android.os.Bundle;
-import android.widget.LinearLayout;
-import android.widget.Button;
-import android.widget.TextView;
 import android.view.Gravity;
 import android.view.ViewGroup;
-import android.content.Context;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
 
 /**
  * Holds a few buttons of various sizes and horizontal placements in a
diff --git a/core/tests/coretests/src/android/widget/focus/VerticalFocusSearchTest.java b/core/tests/coretests/src/android/widget/focus/VerticalFocusSearchTest.java
index f01422e..319756c 100644
--- a/core/tests/coretests/src/android/widget/focus/VerticalFocusSearchTest.java
+++ b/core/tests/coretests/src/android/widget/focus/VerticalFocusSearchTest.java
@@ -16,17 +16,16 @@
 
 package android.widget.focus;
 
-import android.widget.focus.VerticalFocusSearch;
-
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.FocusFinder;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.LinearLayout;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
+
 /**
  * Tests that focus searching works on a vertical linear layout of buttons of
  * various widths and horizontal placements.
diff --git a/core/tests/coretests/src/android/widget/gridview/GridDelete.java b/core/tests/coretests/src/android/widget/gridview/GridDelete.java
index 57ae8f39..b040f69 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridDelete.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridDelete.java
@@ -16,6 +16,7 @@
 
 package android.widget.gridview;
 
+import android.util.GridScenario;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -23,8 +24,6 @@
 import android.widget.GridView;
 import android.widget.ListAdapter;
 
-import android.util.GridScenario;
-
 import java.util.ArrayList;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/gridview/GridInHorizontalTest.java b/core/tests/coretests/src/android/widget/gridview/GridInHorizontalTest.java
index 21ca655..5247009 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridInHorizontalTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridInHorizontalTest.java
@@ -17,10 +17,9 @@
 package android.widget.gridview;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.GridView;
 
-import android.widget.gridview.GridInHorizontal;
+import androidx.test.filters.MediumTest;
 
 public class GridInHorizontalTest extends ActivityInstrumentationTestCase<GridInHorizontal> {
 
diff --git a/core/tests/coretests/src/android/widget/gridview/GridInVerticalTest.java b/core/tests/coretests/src/android/widget/gridview/GridInVerticalTest.java
index a674db2..290f70e 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridInVerticalTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridInVerticalTest.java
@@ -17,10 +17,9 @@
 package android.widget.gridview;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.GridView;
 
-import android.widget.gridview.GridInVertical;
+import androidx.test.filters.MediumTest;
 
 public class GridInVerticalTest extends ActivityInstrumentationTestCase<GridInVertical> {
 
diff --git a/core/tests/coretests/src/android/widget/gridview/GridPaddingTest.java b/core/tests/coretests/src/android/widget/gridview/GridPaddingTest.java
index ecd4b1c..d2ae7cf 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridPaddingTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridPaddingTest.java
@@ -17,9 +17,10 @@
 package android.widget.gridview;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.GridView;
 
+import androidx.test.filters.MediumTest;
+
 public class GridPaddingTest extends ActivityInstrumentationTestCase2<GridPadding> {
     private GridView mGridView;
 
diff --git a/core/tests/coretests/src/android/widget/gridview/GridScrollListenerTest.java b/core/tests/coretests/src/android/widget/gridview/GridScrollListenerTest.java
index 53eeb48..466c55f 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridScrollListenerTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridScrollListenerTest.java
@@ -19,12 +19,13 @@
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.AbsListView;
 import android.widget.GridView;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 public class GridScrollListenerTest extends ActivityInstrumentationTestCase<GridScrollListener> implements
         AbsListView.OnScrollListener {
     private GridScrollListener mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java
index 0e362b6..db4f2dc 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java
@@ -16,13 +16,13 @@
 
 package android.widget.gridview;
 
-import android.util.GridScenario;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.ViewAsserts;
+import android.util.GridScenario;
 import android.widget.GridView;
 
+import androidx.test.filters.MediumTest;
+
 public class GridSetSelectionBaseTest<T extends GridScenario> extends ActivityInstrumentationTestCase<T> {
     private T mActivity;
     private GridView mGridView;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionManyTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionManyTest.java
index 6739645..17a6044 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionManyTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionManyTest.java
@@ -16,8 +16,6 @@
 
 package android.widget.gridview;
 
-import android.widget.gridview.GridSetSelectionMany;
-
 public class GridSetSelectionManyTest extends GridSetSelectionBaseTest<GridSetSelectionMany> {
     public GridSetSelectionManyTest() {
         super(GridSetSelectionMany.class);
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomManyTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomManyTest.java
index 46922b9..a71f732 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomManyTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomManyTest.java
@@ -16,8 +16,6 @@
 
 package android.widget.gridview;
 
-import android.widget.gridview.GridSetSelectionStackFromBottomMany;
-
 public class GridSetSelectionStackFromBottomManyTest extends GridSetSelectionBaseTest<GridSetSelectionStackFromBottomMany> {
     public GridSetSelectionStackFromBottomManyTest() {
         super(GridSetSelectionStackFromBottomMany.class);
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomTest.java
index 67dd6f1..4e6e8aa 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomTest.java
@@ -16,8 +16,6 @@
 
 package android.widget.gridview;
 
-import android.widget.gridview.GridSetSelectionStackFromBottom;
-
 public class GridSetSelectionStackFromBottomTest extends GridSetSelectionBaseTest<GridSetSelectionStackFromBottom> {
     public GridSetSelectionStackFromBottomTest() {
         super(GridSetSelectionStackFromBottom.class);
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionTest.java
index 2127b3c..68802fe 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionTest.java
@@ -16,8 +16,6 @@
 
 package android.widget.gridview;
 
-import android.widget.gridview.GridSetSelection;
-
 public class GridSetSelectionTest extends GridSetSelectionBaseTest<GridSetSelection> {
     public GridSetSelectionTest() {
         super(GridSetSelection.class);
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSimple.java b/core/tests/coretests/src/android/widget/gridview/GridSimple.java
index 7c2c696..67bb751 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSimple.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSimple.java
@@ -18,12 +18,11 @@
 
 import android.graphics.drawable.PaintDrawable;
 import android.os.Bundle;
+import android.util.GridScenario;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
-import android.util.GridScenario;
-
 public class GridSimple extends GridScenario {
     @Override
     protected void init(Params params) {
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSingleColumnTest.java b/core/tests/coretests/src/android/widget/gridview/GridSingleColumnTest.java
index 3b2504e..0f67522 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSingleColumnTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSingleColumnTest.java
@@ -17,10 +17,9 @@
 package android.widget.gridview;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.GridView;
 
-import android.widget.gridview.GridSingleColumn;
+import androidx.test.filters.MediumTest;
 
 public class GridSingleColumnTest extends ActivityInstrumentationTestCase<GridSingleColumn> {
     private GridSingleColumn mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomManyTest.java b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomManyTest.java
index 640737e..a369616 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomManyTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomManyTest.java
@@ -16,11 +16,10 @@
 
 package android.widget.gridview;
 
-import android.widget.gridview.GridStackFromBottomMany;
-
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.GridView;
 import android.test.ActivityInstrumentationTestCase;
+import android.widget.GridView;
+
+import androidx.test.filters.MediumTest;
 
 public class GridStackFromBottomManyTest extends ActivityInstrumentationTestCase<GridStackFromBottomMany> {
     private GridStackFromBottomMany mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomTest.java
index 8fec241..da1b638 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomTest.java
@@ -16,12 +16,11 @@
 
 package android.widget.gridview;
 
-import android.widget.gridview.GridStackFromBottom;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.GridView;
 
+import androidx.test.filters.MediumTest;
+
 public class GridStackFromBottomTest extends ActivityInstrumentationTestCase<GridStackFromBottom> {
     private GridStackFromBottom mActivity;
     private GridView mGridView;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridThrasher.java b/core/tests/coretests/src/android/widget/gridview/GridThrasher.java
index ad89bb6..34c19c3 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridThrasher.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridThrasher.java
@@ -16,20 +16,20 @@
 
 package android.widget.gridview;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.Handler;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.LayoutInflater;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.GridView;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 import java.util.Random;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchSetSelectionTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchSetSelectionTest.java
index ca789af..ab5fcfa 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchSetSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchSetSelectionTest.java
@@ -17,14 +17,14 @@
 package android.widget.gridview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
 import android.view.View;
 import android.widget.GridView;
-
 import android.widget.gridview.GridSimple;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 /**
  * Tests setting the selection in touch mode
  */
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomManyTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomManyTest.java
index 9a8d307..e312873 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomManyTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomManyTest.java
@@ -16,14 +16,14 @@
 
 package android.widget.gridview.touch;
 
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ActivityInstrumentationTestCase;
 import android.test.TouchUtils;
+import android.view.View;
+import android.widget.GridView;
 import android.widget.gridview.GridStackFromBottomMany;
 
-import android.widget.GridView;
-import android.view.View;
-import android.test.ActivityInstrumentationTestCase;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 public class GridTouchStackFromBottomManyTest extends ActivityInstrumentationTestCase<GridStackFromBottomMany> {
     private GridStackFromBottomMany mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomTest.java
index d8d4e43..c98c10a 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomTest.java
@@ -16,13 +16,13 @@
 
 package android.widget.gridview.touch;
 
-import android.widget.gridview.GridStackFromBottom;
-import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.MediumTest;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.widget.GridView;
+import android.test.TouchUtils;
 import android.view.View;
+import android.widget.GridView;
+import android.widget.gridview.GridStackFromBottom;
+
+import androidx.test.filters.MediumTest;
 
 public class GridTouchStackFromBottomTest extends ActivityInstrumentationTestCase<GridStackFromBottom> {
     private GridStackFromBottom mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
index 55a66d9..0d3092c 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
@@ -18,16 +18,16 @@
 
 import android.content.Context;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.widget.GridView;
-
 import android.widget.gridview.GridVerticalSpacingStackFromBottom;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 public class GridTouchVerticalSpacingStackFromBottomTest extends ActivityInstrumentationTestCase<GridVerticalSpacingStackFromBottom> {
     private GridVerticalSpacingStackFromBottom mActivity;
     private GridView mGridView;
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingTest.java
index bae4ee7..e831e62 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingTest.java
@@ -17,16 +17,16 @@
 package android.widget.gridview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.widget.GridView;
-
 import android.widget.gridview.GridVerticalSpacing;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 public class GridTouchVerticalSpacingTest extends ActivityInstrumentationTestCase<GridVerticalSpacing> {
     private GridVerticalSpacing mActivity;
     private GridView mGridView;
diff --git a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravity.java b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravity.java
index 9791e36..d159be8 100644
--- a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravity.java
+++ b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravity.java
@@ -16,11 +16,10 @@
 
 package android.widget.layout.frame;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
 
 public class FrameLayoutGravity extends Activity {
     @Override
diff --git a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravityTest.java b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravityTest.java
index fe4e932..0cab660 100644
--- a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravityTest.java
+++ b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravityTest.java
@@ -16,12 +16,13 @@
 
 package android.widget.layout.frame;
 
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.ViewAsserts;
 import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.ViewAsserts;
 import android.view.View;
-import android.widget.layout.frame.FrameLayoutGravity;
+
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 public class FrameLayoutGravityTest extends ActivityInstrumentationTestCase<FrameLayoutGravity> {
diff --git a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMargin.java b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMargin.java
index 81b3ea1..8c54557 100644
--- a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMargin.java
+++ b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMargin.java
@@ -16,11 +16,10 @@
 
 package android.widget.layout.frame;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
 
 public class FrameLayoutMargin extends Activity {
     @Override
diff --git a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMarginTest.java b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMarginTest.java
index c052d65..4973078 100644
--- a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMarginTest.java
+++ b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMarginTest.java
@@ -16,13 +16,14 @@
 
 package android.widget.layout.frame;
 
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.ViewAsserts;
 import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.ViewAsserts;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.layout.frame.FrameLayoutMargin;
+
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 public class FrameLayoutMarginTest extends ActivityInstrumentationTestCase<FrameLayoutMargin> {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravity.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravity.java
index 766dd0a..79a34e5 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravity.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravity.java
@@ -16,11 +16,10 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
 
 public class BaselineAlignmentCenterGravity extends Activity {
     @Override
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravityTest.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravityTest.java
index 079e9d0..60b7c2f 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravityTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravityTest.java
@@ -18,13 +18,13 @@
 
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.ViewAsserts;
 import android.view.View;
 import android.widget.Button;
 
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.BaselineAlignmentCenterGravity;
 
 public class BaselineAlignmentCenterGravityTest extends ActivityInstrumentationTestCase<BaselineAlignmentCenterGravity> {
     private Button mButton1;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentSpinnerButton.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentSpinnerButton.java
index c3bfe3a..a429b75 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentSpinnerButton.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentSpinnerButton.java
@@ -18,12 +18,12 @@
 
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.ViewAsserts;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.HorizontalOrientationVerticalAlignment;
 
 public class BaselineAlignmentSpinnerButton extends ActivityInstrumentationTestCase<HorizontalOrientationVerticalAlignment> {
     private View mSpinner;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeight.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeight.java
index 5ed5e71..f33feb0 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeight.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeight.java
@@ -16,12 +16,12 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.View;
 
+import com.android.frameworks.coretests.R;
+
 public class BaselineAlignmentZeroWidthAndWeight extends Activity {
     @Override
     protected void onCreate(Bundle icicle) {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java
index 2dd2bb8..443b0f7 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java
@@ -16,16 +16,15 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.BaselineAlignmentZeroWidthAndWeight;
-import android.widget.layout.linear.ExceptionTextView;
-
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.Button;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 public class BaselineAlignmentZeroWidthAndWeightTest extends ActivityInstrumentationTestCase<BaselineAlignmentZeroWidthAndWeight> {
     private Button mShowButton;
 
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineButtons.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineButtons.java
index c9ad831..9d91316 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineButtons.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineButtons.java
@@ -16,11 +16,10 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
 
 public class BaselineButtons extends Activity {
     @Override
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineButtonsTest.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineButtonsTest.java
index 6f1fc90..ac3c5d8 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineButtonsTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineButtonsTest.java
@@ -18,12 +18,12 @@
 
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 import android.widget.ImageButton;
 
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.BaselineButtons;
 
 public class BaselineButtonsTest extends ActivityInstrumentationTestCase<BaselineButtons> {
     private View mCurrentTime;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java b/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java
index 6129b5b..c684501 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java
@@ -21,7 +21,6 @@
 import android.util.AttributeSet;
 import android.widget.EditText;
 
-
 /**
  * A special EditText that sets {@link #isFailed()} to true as its internal makeNewLayout() method is called
  * with a width lower than 0. This is used to fail the unit test in
diff --git a/core/tests/coretests/src/android/widget/layout/linear/FillInWrap.java b/core/tests/coretests/src/android/widget/layout/linear/FillInWrap.java
index 50aa5b7..c8a5f34 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/FillInWrap.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/FillInWrap.java
@@ -16,12 +16,12 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 public class FillInWrap extends Activity {
     @Override
     protected void onCreate(Bundle icicle) {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/FillInWrapTest.java b/core/tests/coretests/src/android/widget/layout/linear/FillInWrapTest.java
index f161802..0e69efc 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/FillInWrapTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/FillInWrapTest.java
@@ -18,9 +18,10 @@
 
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 public class FillInWrapTest extends ActivityInstrumentationTestCase<FillInWrap> {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/HorizontalOrientationVerticalAlignment.java b/core/tests/coretests/src/android/widget/layout/linear/HorizontalOrientationVerticalAlignment.java
index 9f937a9..255f7b3 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/HorizontalOrientationVerticalAlignment.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/HorizontalOrientationVerticalAlignment.java
@@ -16,11 +16,10 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
 
 public class HorizontalOrientationVerticalAlignment extends Activity {
     @Override
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LLEditTextThenButton.java b/core/tests/coretests/src/android/widget/layout/linear/LLEditTextThenButton.java
index 83331ca..a0745dd 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LLEditTextThenButton.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LLEditTextThenButton.java
@@ -16,14 +16,14 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.LinearLayout;
 
+import com.android.frameworks.coretests.R;
+
 public class LLEditTextThenButton extends Activity {
     private EditText mEditText;
     private Button mButton;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons1.java b/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons1.java
index ab2f060..1153062 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons1.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons1.java
@@ -18,10 +18,10 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.view.View;
 import android.widget.Button;
 import android.widget.LinearLayout;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons2.java b/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons2.java
index 77f564d..0aca699 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons2.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons2.java
@@ -22,5 +22,4 @@
  */
 public class LLOfButtons2  extends LLOfButtons1 {
 
-
 }
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTexts.java b/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTexts.java
index 90db788..5d37245 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTexts.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTexts.java
@@ -16,11 +16,11 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 public class LinearLayoutEditTexts extends Activity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTextsTest.java b/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTextsTest.java
index d5998b7..966ed6d 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTextsTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTextsTest.java
@@ -16,13 +16,13 @@
 
 package android.widget.layout.linear;
 
-import android.widget.layout.linear.LinearLayoutEditTexts;
-import com.android.frameworks.coretests.R;
-
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
 import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.view.View;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
 
 public class LinearLayoutEditTextsTest extends ActivityInstrumentationTestCase<LinearLayoutEditTexts> {
     private View mChild;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/Weight.java b/core/tests/coretests/src/android/widget/layout/linear/Weight.java
index 20edd7c..3722a14f 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/Weight.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/Weight.java
@@ -16,11 +16,11 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 public class Weight extends Activity {
     @Override
     protected void onCreate(Bundle icicle) {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/WeightSum.java b/core/tests/coretests/src/android/widget/layout/linear/WeightSum.java
index 2e421da..144600b 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/WeightSum.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/WeightSum.java
@@ -16,11 +16,10 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
 
 public class WeightSum extends Activity {
     @Override
diff --git a/core/tests/coretests/src/android/widget/layout/linear/WeightSumTest.java b/core/tests/coretests/src/android/widget/layout/linear/WeightSumTest.java
index f9a94ce..1d07db2 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/WeightSumTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/WeightSumTest.java
@@ -18,11 +18,11 @@
 
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.WeightSum;
 
 public class WeightSumTest extends ActivityInstrumentationTestCase<WeightSum> {
     private View mChild;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/WeightTest.java b/core/tests/coretests/src/android/widget/layout/linear/WeightTest.java
index 1c42e7c..db52495 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/WeightTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/WeightTest.java
@@ -18,13 +18,13 @@
 
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.ViewAsserts;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.Weight;
 
 @Suppress // Failing.
 public class WeightTest extends ActivityInstrumentationTestCase<Weight> {
diff --git a/core/tests/coretests/src/android/widget/layout/table/AddColumn.java b/core/tests/coretests/src/android/widget/layout/table/AddColumn.java
index 400c32c..b407941 100644
--- a/core/tests/coretests/src/android/widget/layout/table/AddColumn.java
+++ b/core/tests/coretests/src/android/widget/layout/table/AddColumn.java
@@ -16,8 +16,6 @@
 
 package android.widget.layout.table;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.View;
@@ -26,6 +24,8 @@
 import android.widget.TableRow;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * This test adds an extra row with an extra column in the table.
  */
diff --git a/core/tests/coretests/src/android/widget/layout/table/AddColumnTest.java b/core/tests/coretests/src/android/widget/layout/table/AddColumnTest.java
index bfb4d17..08ae030 100644
--- a/core/tests/coretests/src/android/widget/layout/table/AddColumnTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/AddColumnTest.java
@@ -16,16 +16,16 @@
 
 package android.widget.layout.table;
 
-import android.widget.layout.table.AddColumn;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.Button;
 import android.widget.TableLayout;
 import android.widget.TableRow;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * {@link android.widget.layout.table.AddColumn} is
  * setup to exercise the case of adding row programmatically in a table.
diff --git a/core/tests/coretests/src/android/widget/layout/table/CellSpan.java b/core/tests/coretests/src/android/widget/layout/table/CellSpan.java
index d91cf56..3102ac1 100644
--- a/core/tests/coretests/src/android/widget/layout/table/CellSpan.java
+++ b/core/tests/coretests/src/android/widget/layout/table/CellSpan.java
@@ -16,11 +16,11 @@
 
 package android.widget.layout.table;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercise table layout with cells spanning.
  */
diff --git a/core/tests/coretests/src/android/widget/layout/table/CellSpanTest.java b/core/tests/coretests/src/android/widget/layout/table/CellSpanTest.java
index 331ec45..aa8e66c 100644
--- a/core/tests/coretests/src/android/widget/layout/table/CellSpanTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/CellSpanTest.java
@@ -16,13 +16,13 @@
 
 package android.widget.layout.table;
 
-import android.widget.layout.table.CellSpan;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * {@link android.widget.layout.table.CellSpan} is
  * setup to exercise tables in which cells use spanning.
diff --git a/core/tests/coretests/src/android/widget/layout/table/FixedWidth.java b/core/tests/coretests/src/android/widget/layout/table/FixedWidth.java
index 435815a..c587f74 100644
--- a/core/tests/coretests/src/android/widget/layout/table/FixedWidth.java
+++ b/core/tests/coretests/src/android/widget/layout/table/FixedWidth.java
@@ -16,11 +16,11 @@
 
 package android.widget.layout.table;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercise table layout with cells having a fixed width and height.
  */
diff --git a/core/tests/coretests/src/android/widget/layout/table/FixedWidthTest.java b/core/tests/coretests/src/android/widget/layout/table/FixedWidthTest.java
index b20ec84..7d02453 100644
--- a/core/tests/coretests/src/android/widget/layout/table/FixedWidthTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/FixedWidthTest.java
@@ -16,13 +16,13 @@
 
 package android.widget.layout.table;
 
-import android.widget.layout.table.FixedWidth;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * {@link android.widget.layout.table.FixedWidth} is
  * setup to exercise tables in which cells use fixed width and height.
diff --git a/core/tests/coretests/src/android/widget/layout/table/HorizontalGravity.java b/core/tests/coretests/src/android/widget/layout/table/HorizontalGravity.java
index 1444f60..6f5148b 100644
--- a/core/tests/coretests/src/android/widget/layout/table/HorizontalGravity.java
+++ b/core/tests/coretests/src/android/widget/layout/table/HorizontalGravity.java
@@ -16,11 +16,11 @@
 
 package android.widget.layout.table;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercise table layout with cells using a horizontal gravity.
  */
diff --git a/core/tests/coretests/src/android/widget/layout/table/HorizontalGravityTest.java b/core/tests/coretests/src/android/widget/layout/table/HorizontalGravityTest.java
index 964df82..73e8334 100644
--- a/core/tests/coretests/src/android/widget/layout/table/HorizontalGravityTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/HorizontalGravityTest.java
@@ -16,14 +16,14 @@
 
 package android.widget.layout.table;
 
-import android.widget.layout.table.HorizontalGravity;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.ViewAsserts;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * {@link android.widget.layout.table.HorizontalGravity} is
  * setup to exercise tables in which cells use horizontal gravity.
diff --git a/core/tests/coretests/src/android/widget/layout/table/VerticalGravity.java b/core/tests/coretests/src/android/widget/layout/table/VerticalGravity.java
index 4fdb378..9055b32 100644
--- a/core/tests/coretests/src/android/widget/layout/table/VerticalGravity.java
+++ b/core/tests/coretests/src/android/widget/layout/table/VerticalGravity.java
@@ -16,11 +16,11 @@
 
 package android.widget.layout.table;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercise table layout with cells using a vertical gravity.
  */
diff --git a/core/tests/coretests/src/android/widget/layout/table/VerticalGravityTest.java b/core/tests/coretests/src/android/widget/layout/table/VerticalGravityTest.java
index 1d6be3f..f14fa1c 100644
--- a/core/tests/coretests/src/android/widget/layout/table/VerticalGravityTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/VerticalGravityTest.java
@@ -16,15 +16,15 @@
 
 package android.widget.layout.table;
 
-import android.widget.layout.table.VerticalGravity;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.test.ViewAsserts;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * {@link android.widget.layout.table.VerticalGravity} is
  * setup to exercise tables in which cells use vertical gravity.
diff --git a/core/tests/coretests/src/android/widget/layout/table/Weight.java b/core/tests/coretests/src/android/widget/layout/table/Weight.java
index 6d4d51d..5c08247 100644
--- a/core/tests/coretests/src/android/widget/layout/table/Weight.java
+++ b/core/tests/coretests/src/android/widget/layout/table/Weight.java
@@ -16,11 +16,11 @@
 
 package android.widget.layout.table;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercise table layout with cells having a weight.
  */
diff --git a/core/tests/coretests/src/android/widget/layout/table/WeightTest.java b/core/tests/coretests/src/android/widget/layout/table/WeightTest.java
index b665573..fcf3de2 100644
--- a/core/tests/coretests/src/android/widget/layout/table/WeightTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/WeightTest.java
@@ -16,13 +16,13 @@
 
 package android.widget.layout.table;
 
-import android.widget.layout.table.Weight;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * {@link android.widget.layout.table.Weight} is
  * setup to exercise tables in which cells use a weight.
diff --git a/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java b/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java
index a386ebd..cd76d70 100644
--- a/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java
+++ b/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java
@@ -16,8 +16,6 @@
 
 package android.widget.listview;
 
-import android.view.Gravity;
-
 import android.util.ListScenario;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java b/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java
index 519816c..e048e3e 100644
--- a/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java
+++ b/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java
@@ -16,8 +16,6 @@
 
 package android.widget.listview;
 
-import android.view.Gravity;
-
 import android.util.ListScenario;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/listview/ListBottomGravityManyTest.java b/core/tests/coretests/src/android/widget/listview/ListBottomGravityManyTest.java
index e1171eb..bd8dbe4 100644
--- a/core/tests/coretests/src/android/widget/listview/ListBottomGravityManyTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListBottomGravityManyTest.java
@@ -17,10 +17,9 @@
 package android.widget.listview;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.ListView;
 
-import android.widget.listview.ListBottomGravityMany;
+import androidx.test.filters.MediumTest;
 
 public class ListBottomGravityManyTest extends ActivityInstrumentationTestCase<ListBottomGravityMany> {
     private ListBottomGravityMany mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListBottomGravityTest.java b/core/tests/coretests/src/android/widget/listview/ListBottomGravityTest.java
index c595f62..8da7358 100644
--- a/core/tests/coretests/src/android/widget/listview/ListBottomGravityTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListBottomGravityTest.java
@@ -17,10 +17,9 @@
 package android.widget.listview;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.ListView;
 
-import android.widget.listview.ListBottomGravity;
+import androidx.test.filters.MediumTest;
 
 public class ListBottomGravityTest extends ActivityInstrumentationTestCase<ListBottomGravity> {
     private ListBottomGravity mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java b/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java
index bbed73c..8640741 100644
--- a/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java
+++ b/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java
@@ -16,10 +16,10 @@
 
 package android.widget.listview;
 
-import android.util.ListItemFactory;
 import static android.util.ListItemFactory.Slot;
-import android.util.ListScenario;
 
+import android.util.ListItemFactory;
+import android.util.ListScenario;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
diff --git a/core/tests/coretests/src/android/widget/listview/ListEmptyViewTest.java b/core/tests/coretests/src/android/widget/listview/ListEmptyViewTest.java
index 258d3ef..81d71a9 100644
--- a/core/tests/coretests/src/android/widget/listview/ListEmptyViewTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListEmptyViewTest.java
@@ -19,12 +19,13 @@
 import android.app.Instrumentation;
 import android.content.Intent;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 public class ListEmptyViewTest extends ActivityInstrumentationTestCase<ListWithEmptyView> {
     private ListWithEmptyView mActivity;
     private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/ListFilter.java b/core/tests/coretests/src/android/widget/listview/ListFilter.java
index c2ac90e..1cda717 100644
--- a/core/tests/coretests/src/android/widget/listview/ListFilter.java
+++ b/core/tests/coretests/src/android/widget/listview/ListFilter.java
@@ -25,7 +25,6 @@
 
 import com.android.frameworks.coretests.R;
 
-
 /**
  * Tests hiding and showing the list filter by hiding and showing an ancestor of the 
  * ListView
diff --git a/core/tests/coretests/src/android/widget/listview/ListFocusableTest.java b/core/tests/coretests/src/android/widget/listview/ListFocusableTest.java
index bf18a13..10b4a79 100644
--- a/core/tests/coretests/src/android/widget/listview/ListFocusableTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListFocusableTest.java
@@ -17,10 +17,11 @@
 package android.widget.listview;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
-import android.widget.ListAdapter;
 import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import androidx.test.filters.MediumTest;
 
 public class ListFocusableTest extends ActivityInstrumentationTestCase<ListTopGravity> {
     private ListTopGravity mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java b/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java
index 33d61a0..c691ed7 100644
--- a/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java
@@ -17,10 +17,11 @@
 package android.widget.listview;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.ListView;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
 import java.util.Arrays;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java b/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java
index 1f59c30..74eda3b 100644
--- a/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java
+++ b/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java
@@ -16,11 +16,10 @@
 
 package android.widget.listview;
 
-import android.view.View;
-import android.view.ViewGroup;
-
 import android.util.ListItemFactory;
 import android.util.ListScenario;
+import android.view.View;
+import android.view.ViewGroup;
 
 /**
  * List that has different view types
diff --git a/core/tests/coretests/src/android/widget/listview/ListHeterogeneousTest.java b/core/tests/coretests/src/android/widget/listview/ListHeterogeneousTest.java
index 01b39db..dbd58d7 100644
--- a/core/tests/coretests/src/android/widget/listview/ListHeterogeneousTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListHeterogeneousTest.java
@@ -18,12 +18,11 @@
 
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.ListView;
 
-import android.widget.listview.ListHeterogeneous;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 public class ListHeterogeneousTest extends ActivityInstrumentationTestCase<ListHeterogeneous> {
     private ListHeterogeneous mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java b/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java
index 2ff65de..e98de9c 100644
--- a/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java
+++ b/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java
@@ -16,11 +16,11 @@
 
 package android.widget.listview;
 
-import android.util.ListItemFactory;
 import static android.util.ListItemFactory.Slot;
-import android.util.ListScenario;
 
 import android.content.Context;
+import android.util.ListItemFactory;
+import android.util.ListScenario;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
diff --git a/core/tests/coretests/src/android/widget/listview/ListInHorizontal.java b/core/tests/coretests/src/android/widget/listview/ListInHorizontal.java
index a373a5b..6622c0d 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInHorizontal.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInHorizontal.java
@@ -18,10 +18,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.os.Handler;
 import android.widget.ArrayAdapter;
-import android.widget.GridView;
-import android.widget.TextView;
 import android.widget.ListView;
 
 import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/widget/listview/ListInHorizontalTest.java b/core/tests/coretests/src/android/widget/listview/ListInHorizontalTest.java
index 3643f79..d8508ec 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInHorizontalTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInHorizontalTest.java
@@ -16,8 +16,6 @@
 
 package android.widget.listview;
 
-import android.widget.listview.ListInHorizontal;
-
 public class ListInHorizontalTest extends ListUnspecifiedMeasure<ListInHorizontal> {
     public ListInHorizontalTest() {
         super(ListInHorizontal.class);
diff --git a/core/tests/coretests/src/android/widget/listview/ListInVertical.java b/core/tests/coretests/src/android/widget/listview/ListInVertical.java
index 3b4885a..4ecf25d 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInVertical.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInVertical.java
@@ -18,10 +18,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.os.Handler;
 import android.widget.ArrayAdapter;
-import android.widget.GridView;
-import android.widget.TextView;
 import android.widget.ListView;
 
 import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/widget/listview/ListInVerticalTest.java b/core/tests/coretests/src/android/widget/listview/ListInVerticalTest.java
index 8586429..5e385a3 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInVerticalTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInVerticalTest.java
@@ -16,8 +16,6 @@
 
 package android.widget.listview;
 
-import android.widget.listview.ListInVertical;
-
 public class ListInVerticalTest extends ListUnspecifiedMeasure<ListInVertical> {
     public ListInVerticalTest() {
         super(ListInVertical.class);
diff --git a/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java b/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java
index d5da28e..0ec7a24 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java
@@ -16,13 +16,14 @@
 
 package android.widget.listview;
 
+import android.util.ListItemFactory;
+import android.util.ListScenario;
 import android.view.View;
- import android.view.ViewGroup;
- import com.google.android.collect.Sets;
- import android.util.ListScenario;
- import android.util.ListItemFactory;
+import android.view.ViewGroup;
 
- import java.util.Set;
+import com.google.android.collect.Sets;
+
+import java.util.Set;
 
 /**
  * List that interleaves focusable items.
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java b/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java
index f7c01b1..3159e53 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java
@@ -16,12 +16,10 @@
 
 package android.widget.listview;
 
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
 import android.util.ListItemFactory;
 import android.util.ListScenario;
+import android.view.View;
+import android.view.ViewGroup;
 
 /**
  * A list where the items may befocusable, but the second item isn't actually focusabe.
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java
index b529b2e..861e2a91 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java
@@ -16,8 +16,8 @@
 
 package android.widget.listview;
 
-import android.util.ListScenario;
 import android.util.ListItemFactory;
+import android.util.ListScenario;
 import android.view.View;
 import android.view.ViewGroup;
 
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java
index 59987ec..e9c9c1d 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java
@@ -16,10 +16,10 @@
 
 package android.widget.listview;
 
-import android.view.View;
-import android.view.ViewGroup;
 import android.util.ListItemFactory;
 import android.util.ListScenario;
+import android.view.View;
+import android.view.ViewGroup;
 
 /**
  * A list where each item is tall with buttons that are farther apart than the screen
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java b/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java
index ea2c5f2..2a0e013 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java
@@ -17,13 +17,13 @@
 package android.widget.listview;
 
 import android.content.Context;
+import android.util.InternalSelectionView;
+import android.util.ListScenario;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-import android.util.InternalSelectionView;
-import android.util.ListScenario;
 
 /**
  * Each item is an internal selection view, a button, and some filler
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemRequestRectAboveThinFirstItemTest.java b/core/tests/coretests/src/android/widget/listview/ListItemRequestRectAboveThinFirstItemTest.java
index 73eb0a8..91ff06b 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemRequestRectAboveThinFirstItemTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemRequestRectAboveThinFirstItemTest.java
@@ -18,13 +18,13 @@
 
 import android.graphics.Rect;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.view.View;
 import android.view.KeyEvent;
+import android.view.View;
 import android.widget.ListView;
-import android.widget.listview.ListOfThinItems;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 public class ListItemRequestRectAboveThinFirstItemTest
         extends ActivityInstrumentationTestCase<ListOfThinItems> {
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java b/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java
index a5fe17a..d80fd90 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java
@@ -17,13 +17,12 @@
 package android.widget.listview;
 
 import android.content.Context;
+import android.util.ListScenario;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AbsListView;
 import android.widget.TextView;
 
-import android.util.ListScenario;
-
 /**
  * A list where each item expands by 1.5 when selected.
  */
diff --git a/core/tests/coretests/src/android/widget/listview/ListManagedCursor.java b/core/tests/coretests/src/android/widget/listview/ListManagedCursor.java
index 12b5ef4..54f302c 100644
--- a/core/tests/coretests/src/android/widget/listview/ListManagedCursor.java
+++ b/core/tests/coretests/src/android/widget/listview/ListManagedCursor.java
@@ -20,14 +20,13 @@
 import android.content.Intent;
 import android.database.Cursor;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.provider.Contacts.People;
+import android.provider.Settings;
 import android.view.View;
 import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ListAdapter;
 import android.widget.SimpleCursorAdapter;
-import android.widget.AdapterView.OnItemClickListener;
-
 
 public class ListManagedCursor extends ListActivity implements OnItemClickListener {
     
diff --git a/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java b/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java
index bc3776c..8e0b6fe 100644
--- a/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java
@@ -18,11 +18,12 @@
 
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
 import android.view.KeyEvent;
 import android.widget.ListView;
-import android.test.TouchUtils;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 /**
  * Tests restoring the scroll position in a list with a managed cursor.
diff --git a/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java b/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java
index 919ef69..70b9081 100644
--- a/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java
+++ b/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java
@@ -16,12 +16,11 @@
 
 package android.widget.listview;
 
+import android.util.ListScenario;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
 
-import android.util.ListScenario;
-
 /**
  * Each list item has two focusables that are close enough together that
  * it shouldn't require panning to move focus.
diff --git a/core/tests/coretests/src/android/widget/listview/ListRecyclerProfiling.java b/core/tests/coretests/src/android/widget/listview/ListRecyclerProfiling.java
index 76814fb..075712e 100644
--- a/core/tests/coretests/src/android/widget/listview/ListRecyclerProfiling.java
+++ b/core/tests/coretests/src/android/widget/listview/ListRecyclerProfiling.java
@@ -18,11 +18,11 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.ImageButton;
-import android.view.ViewDebug;
 import android.view.View;
+import android.view.ViewDebug;
+import android.widget.ArrayAdapter;
+import android.widget.ImageButton;
+import android.widget.ListView;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/widget/listview/ListRetainsFocusAcrossLayoutsTest.java b/core/tests/coretests/src/android/widget/listview/ListRetainsFocusAcrossLayoutsTest.java
index 896bd19..be14de8 100644
--- a/core/tests/coretests/src/android/widget/listview/ListRetainsFocusAcrossLayoutsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListRetainsFocusAcrossLayoutsTest.java
@@ -16,12 +16,11 @@
 
 package android.widget.listview;
 
-import android.widget.listview.ListItemFocusablesClose;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 
+import androidx.test.filters.MediumTest;
+
 public class ListRetainsFocusAcrossLayoutsTest extends ActivityInstrumentationTestCase<ListItemFocusablesClose> {
 
     public ListRetainsFocusAcrossLayoutsTest() {
diff --git a/core/tests/coretests/src/android/widget/listview/ListScrollListenerTest.java b/core/tests/coretests/src/android/widget/listview/ListScrollListenerTest.java
index 7b29a66..28addd6 100644
--- a/core/tests/coretests/src/android/widget/listview/ListScrollListenerTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListScrollListenerTest.java
@@ -19,12 +19,13 @@
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.AbsListView;
 import android.widget.ListView;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 public class ListScrollListenerTest extends ActivityInstrumentationTestCase<ListScrollListener> implements
         AbsListView.OnScrollListener {
     private ListScrollListener mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListSetSelection.java b/core/tests/coretests/src/android/widget/listview/ListSetSelection.java
index 6c2e264..af8e899 100644
--- a/core/tests/coretests/src/android/widget/listview/ListSetSelection.java
+++ b/core/tests/coretests/src/android/widget/listview/ListSetSelection.java
@@ -16,12 +16,12 @@
 
 package android.widget.listview;
 
+import android.os.Bundle;
 import android.util.ListScenario;
 import android.view.KeyEvent;
 import android.view.View;
-import android.os.Bundle;
-import android.widget.LinearLayout;
 import android.widget.Button;
+import android.widget.LinearLayout;
 
 /**
  * List of 1,000 items used to test calls to setSelection() in touch mode.
diff --git a/core/tests/coretests/src/android/widget/listview/ListSetSelectionTest.java b/core/tests/coretests/src/android/widget/listview/ListSetSelectionTest.java
index 4cef164..2caca13 100644
--- a/core/tests/coretests/src/android/widget/listview/ListSetSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListSetSelectionTest.java
@@ -17,10 +17,11 @@
 package android.widget.listview;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.ListView;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
 /**
  * Basic tests of setting & clearing the selection
  */
diff --git a/core/tests/coretests/src/android/widget/listview/ListSimple.java b/core/tests/coretests/src/android/widget/listview/ListSimple.java
index 6accae1..f53638e 100644
--- a/core/tests/coretests/src/android/widget/listview/ListSimple.java
+++ b/core/tests/coretests/src/android/widget/listview/ListSimple.java
@@ -16,11 +16,10 @@
 
 package android.widget.listview;
 
+import android.os.Bundle;
 import android.util.ListScenario;
-
 import android.view.View;
 import android.view.ViewGroup;
-import android.os.Bundle;
 import android.widget.TextView;
 
 public class ListSimple extends ListScenario {
diff --git a/core/tests/coretests/src/android/widget/listview/ListTakeFocusFromSide.java b/core/tests/coretests/src/android/widget/listview/ListTakeFocusFromSide.java
index 95f09f6..c4e9fe9 100644
--- a/core/tests/coretests/src/android/widget/listview/ListTakeFocusFromSide.java
+++ b/core/tests/coretests/src/android/widget/listview/ListTakeFocusFromSide.java
@@ -16,17 +16,17 @@
 
 package android.widget.listview;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.ListActivity;
 import android.content.Context;
 import android.os.Bundle;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.LayoutInflater;
 import android.widget.BaseAdapter;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercises moving focus into the list from the side
  */
diff --git a/core/tests/coretests/src/android/widget/listview/ListThrasher.java b/core/tests/coretests/src/android/widget/listview/ListThrasher.java
index 0237a95..d82f68d 100644
--- a/core/tests/coretests/src/android/widget/listview/ListThrasher.java
+++ b/core/tests/coretests/src/android/widget/listview/ListThrasher.java
@@ -16,19 +16,19 @@
 
 package android.widget.listview;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.ListActivity;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.Handler;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.LayoutInflater;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 import java.util.Random;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/listview/ListTopGravity.java b/core/tests/coretests/src/android/widget/listview/ListTopGravity.java
index 986cc57..31339e9 100644
--- a/core/tests/coretests/src/android/widget/listview/ListTopGravity.java
+++ b/core/tests/coretests/src/android/widget/listview/ListTopGravity.java
@@ -16,8 +16,6 @@
 
 package android.widget.listview;
 
-import android.view.Gravity;
-
 import android.util.ListScenario;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/listview/ListUnspecifiedMeasure.java b/core/tests/coretests/src/android/widget/listview/ListUnspecifiedMeasure.java
index 199d069..0fc87ea 100644
--- a/core/tests/coretests/src/android/widget/listview/ListUnspecifiedMeasure.java
+++ b/core/tests/coretests/src/android/widget/listview/ListUnspecifiedMeasure.java
@@ -16,13 +16,14 @@
 
 package android.widget.listview;
 
-import com.android.frameworks.coretests.R;
-
-import android.test.ActivityInstrumentationTestCase;
 import android.app.Activity;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ActivityInstrumentationTestCase;
 import android.widget.ListView;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 public class ListUnspecifiedMeasure<T extends Activity> extends ActivityInstrumentationTestCase<T> {
     private T mActivity;
     private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/ListViewHeightTest.java b/core/tests/coretests/src/android/widget/listview/ListViewHeightTest.java
index 5ab2757..63941f1 100644
--- a/core/tests/coretests/src/android/widget/listview/ListViewHeightTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListViewHeightTest.java
@@ -18,12 +18,12 @@
 
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.Button;
 import android.widget.ListView;
 
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
-import android.widget.listview.ListViewHeight;
 
 public class ListViewHeightTest extends ActivityInstrumentationTestCase<ListViewHeight> {
     private ListViewHeight mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithDisappearingItemBug.java b/core/tests/coretests/src/android/widget/listview/ListWithDisappearingItemBug.java
index 348ea1b..10ba8b7 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithDisappearingItemBug.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithDisappearingItemBug.java
@@ -16,8 +16,6 @@
 
 package android.widget.listview;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.ListActivity;
 import android.database.Cursor;
 import android.os.Bundle;
@@ -32,6 +30,8 @@
 import android.widget.SimpleCursorAdapter;
 import android.widget.Toast;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * See 1080989. You need some contacts for this adapter.
  */
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithEmptyView.java b/core/tests/coretests/src/android/widget/listview/ListWithEmptyView.java
index 74dd06c..52273fd 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithEmptyView.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithEmptyView.java
@@ -16,8 +16,6 @@
 
 package android.widget.listview;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.ListActivity;
 import android.content.Context;
 import android.os.Bundle;
@@ -26,6 +24,8 @@
 import android.view.View;
 import android.widget.ArrayAdapter;
 
+import com.android.frameworks.coretests.R;
+
 
 /**
  * Tests using an empty view with a list */
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java b/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java
index aea091a..6030582 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java
@@ -16,9 +16,8 @@
 
 package android.widget.listview;
 
-import android.util.ListScenario;
-
 import android.os.Bundle;
+import android.util.ListScenario;
 import android.widget.Button;
 import android.widget.ListAdapter;
 import android.widget.ListView;
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java b/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java
index 26e1d5d..13e770c 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java
@@ -16,8 +16,8 @@
 
 package android.widget.listview;
 
-import android.widget.TextView;
 import android.util.ListScenario;
+import android.widget.TextView;
 
 /**
  * The header text view echos the value of the selected item by using (indirectly)
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListInterleaveFocusablesTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListInterleaveFocusablesTest.java
index ec8ab7e..22c28c2 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListInterleaveFocusablesTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListInterleaveFocusablesTest.java
@@ -17,13 +17,14 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.ListUtil;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.listview.ListInterleaveFocusables;
 
+import androidx.test.filters.MediumTest;
+
 public class ListInterleaveFocusablesTest extends ActivityInstrumentationTestCase2<ListInterleaveFocusables> {
     private ListView mListView;
     private ListUtil mListUtil;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java
index 82f48801..c645b7c 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java
@@ -17,11 +17,12 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
 import android.view.KeyEvent;
+import android.widget.ListView;
 import android.widget.listview.ListItemFocusableAboveUnfocusable;
 
+import androidx.test.filters.MediumTest;
+
 public class ListItemFocusableAboveUnfocusableTest extends ActivityInstrumentationTestCase<ListItemFocusableAboveUnfocusable> {
     private ListView mListView;
 
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesCloseTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesCloseTest.java
index 3b30ebe..c7525b3 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesCloseTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesCloseTest.java
@@ -17,12 +17,13 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.listview.ListItemFocusablesClose;
 
+import androidx.test.filters.MediumTest;
+
 public class ListItemFocusablesCloseTest extends ActivityInstrumentationTestCase<ListItemFocusablesClose> {
     private ListView mListView;
     private int mListTop;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesFarApartTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesFarApartTest.java
index 475930d..4bb2206 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesFarApartTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesFarApartTest.java
@@ -17,7 +17,6 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -25,6 +24,8 @@
 import android.widget.ListView;
 import android.widget.listview.ListItemFocusablesFarApart;
 
+import androidx.test.filters.MediumTest;
+
 public class ListItemFocusablesFarApartTest extends ActivityInstrumentationTestCase<ListItemFocusablesFarApart> {
     private ListView mListView;
     private int mListTop;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemsExpandOnSelectionTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemsExpandOnSelectionTest.java
index 91a1eba..7605291 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemsExpandOnSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemsExpandOnSelectionTest.java
@@ -17,13 +17,14 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.ListView;
 import android.view.KeyEvent;
+import android.widget.ListView;
 import android.widget.listview.ListItemsExpandOnSelection;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 public class ListItemsExpandOnSelectionTest extends ActivityInstrumentationTestCase<ListItemsExpandOnSelection> {
     private ListView mListView;
     private int mListTop;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java
index 5bc121a..fdae483 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java
@@ -17,12 +17,13 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
-import android.view.View;
 import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
 import android.widget.listview.ListLastItemPartiallyVisible;
 
+import androidx.test.filters.MediumTest;
+
 public class ListLastItemPartiallyVisibleTest extends ActivityInstrumentationTestCase<ListLastItemPartiallyVisible> {
     private ListView mListView;
     private int mListBottom;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java
index bda71d0..d44b130 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java
@@ -17,14 +17,15 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.listview.ListOfItemsShorterThanScreen;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 public class ListOfItemsShorterThanScreenTest
         extends ActivityInstrumentationTestCase<ListOfItemsShorterThanScreen> {
     private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java
index 2135445..1decdad 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java
@@ -17,13 +17,14 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.listview.ListOfItemsTallerThanScreen;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 public class ListOfItemsTallerThanScreenTest
         extends ActivityInstrumentationTestCase2<ListOfItemsTallerThanScreen> {
 
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortShortTallShortShortTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortShortTallShortShortTest.java
index ef70b5a..67808f1 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortShortTallShortShortTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortShortTallShortShortTest.java
@@ -17,13 +17,14 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.ListUtil;
 import android.view.KeyEvent;
 import android.widget.ListView;
 import android.widget.listview.ListOfShortShortTallShortShort;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 public class ListOfShortShortTallShortShortTest extends ActivityInstrumentationTestCase2<ListOfShortShortTallShortShort> {
     private ListView mListView;
     private ListUtil mListUtil;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortTallShortTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortTallShortTest.java
index c958591..f9aa6dc 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortTallShortTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortTallShortTest.java
@@ -17,11 +17,12 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
 import android.view.KeyEvent;
+import android.widget.ListView;
 import android.widget.listview.ListOfShortTallShort;
 
+import androidx.test.filters.MediumTest;
+
 public class ListOfShortTallShortTest extends ActivityInstrumentationTestCase<ListOfShortTallShort> {
     private ListView mListView;
 
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfThinItemsTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfThinItemsTest.java
index c191d71..6bd1cb5 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfThinItemsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfThinItemsTest.java
@@ -17,14 +17,15 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.listview.ListOfThinItems;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 public class ListOfThinItemsTest extends ActivityInstrumentationTestCase<ListOfThinItems> {
     private ListView mListView;
 
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
index 9a8e634..60bc115 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
@@ -16,12 +16,13 @@
 
 package android.widget.listview.arrowscroll;
 
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.KeyEvent;
+import android.widget.AdapterView;
 import android.widget.ListView;
 import android.widget.listview.ListWithFirstScreenUnSelectable;
-import android.widget.AdapterView;
+
+import androidx.test.filters.LargeTest;
 
 @LargeTest
 public class ListWithFirstScreenUnSelectableTest
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithNoFadingEdgeTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithNoFadingEdgeTest.java
index 56ca009..a60054e 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithNoFadingEdgeTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithNoFadingEdgeTest.java
@@ -17,12 +17,13 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.ListView;
 import android.widget.listview.ListWithNoFadingEdge;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 public class ListWithNoFadingEdgeTest extends ActivityInstrumentationTestCase<ListWithNoFadingEdge> {
 
     private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java
index cf319d1..80e70c6 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java
@@ -17,14 +17,15 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.listview.ListWithOffScreenNextSelectable;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 @Suppress // Failing.
 public class ListWithOffScreenNextSelectableTest
         extends ActivityInstrumentationTestCase<ListWithOffScreenNextSelectable> {
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOnItemSelectedActionTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOnItemSelectedActionTest.java
index feea9b2..819b739 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOnItemSelectedActionTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOnItemSelectedActionTest.java
@@ -17,12 +17,13 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
 import android.widget.ListView;
 import android.widget.TextView;
-import android.view.KeyEvent;
 import android.widget.listview.ListWithOnItemSelectedAction;
 
+import androidx.test.filters.MediumTest;
+
 public class ListWithOnItemSelectedActionTest extends ActivityInstrumentationTestCase<ListWithOnItemSelectedAction> {
     private ListView mListView;
 
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java
index 211c8c8..9bbdc2a 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java
@@ -17,13 +17,14 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.listview.ListWithScreenOfNoSelectables;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 public class ListWithScreenOfNoSelectablesTest extends ActivityInstrumentationTestCase2<ListWithScreenOfNoSelectables> {
 
     private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithSeparatorsTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithSeparatorsTest.java
index 42058f0..21fa51d 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithSeparatorsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithSeparatorsTest.java
@@ -17,11 +17,12 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
 import android.view.KeyEvent;
+import android.widget.ListView;
 import android.widget.listview.ListWithSeparators;
 
+import androidx.test.filters.MediumTest;
+
 public class ListWithSeparatorsTest extends ActivityInstrumentationTestCase<ListWithSeparators> {
     private ListWithSeparators mActivity;
     private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java b/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
index 6a7466b..e9baabf 100644
--- a/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
+++ b/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
@@ -16,14 +16,14 @@
 
 package android.widget.listview.focus;
 
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.listview.AdjacentListsWithAdjacentISVsInside;
-import android.util.InternalSelectionView;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.util.InternalSelectionView;
 import android.view.KeyEvent;
 import android.widget.ListView;
+import android.widget.listview.AdjacentListsWithAdjacentISVsInside;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 public class AdjacentListsWithAdjacentISVsInsideTest extends ActivityInstrumentationTestCase<AdjacentListsWithAdjacentISVsInside> {
 
diff --git a/core/tests/coretests/src/android/widget/listview/focus/ListButtonsDiagonalAcrossItemsTest.java b/core/tests/coretests/src/android/widget/listview/focus/ListButtonsDiagonalAcrossItemsTest.java
index 5540d65..3fbdacc 100644
--- a/core/tests/coretests/src/android/widget/listview/focus/ListButtonsDiagonalAcrossItemsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/focus/ListButtonsDiagonalAcrossItemsTest.java
@@ -16,15 +16,15 @@
 
 package android.widget.listview.focus;
 
-import android.widget.listview.ListButtonsDiagonalAcrossItems;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.FocusFinder;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.Button;
 import android.widget.ListView;
+import android.widget.listview.ListButtonsDiagonalAcrossItems;
+
+import androidx.test.filters.MediumTest;
 
 /**
  * Test that ListView will override default behavior of focus searching to
diff --git a/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java b/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
index edc60b5..5448952 100644
--- a/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
@@ -17,12 +17,13 @@
 package android.widget.listview.focus;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.Button;
 import android.widget.ListView;
 import android.widget.listview.ListHorizontalFocusWithinItemWins;
 
+import androidx.test.filters.MediumTest;
+
 public class ListHorizontalFocusWithinItemWinsTest extends ActivityInstrumentationTestCase<ListHorizontalFocusWithinItemWins> {
 
     private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/focus/ListWithEditTextHeaderTest.java b/core/tests/coretests/src/android/widget/listview/focus/ListWithEditTextHeaderTest.java
index b449b61..0b17aaf 100644
--- a/core/tests/coretests/src/android/widget/listview/focus/ListWithEditTextHeaderTest.java
+++ b/core/tests/coretests/src/android/widget/listview/focus/ListWithEditTextHeaderTest.java
@@ -17,17 +17,18 @@
 package android.widget.listview.focus;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.FlakyTest;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.AbsListView;
 import android.widget.ListView;
 import android.widget.listview.ListWithEditTextHeader;
 
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 public class ListWithEditTextHeaderTest extends ActivityInstrumentationTestCase2<ListWithEditTextHeader> {
     private ListView mListView;
 
@@ -49,7 +50,7 @@
         assertTrue("header does not have focus", mListView.getChildAt(0).isFocused());
     }
 
-    @FlakyTest(tolerance=2)
+    @FlakyTest
     @LargeTest
     public void testClickingHeaderKeepsFocus() {
         TouchUtils.clickView(this, mListView.getChildAt(0));
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListGetSelectedViewTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListGetSelectedViewTest.java
index 28f899e..262d0f4 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListGetSelectedViewTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListGetSelectedViewTest.java
@@ -17,14 +17,14 @@
 package android.widget.listview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
-import android.widget.ListView;
 import android.view.View;
-
+import android.widget.ListView;
 import android.widget.listview.ListGetSelectedView;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 /**
  * This test is made to check that getSelectedView() will return
  * null in touch mode.
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListOfTouchablesTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListOfTouchablesTest.java
index ffa9a5e..48e8c5e 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListOfTouchablesTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListOfTouchablesTest.java
@@ -17,15 +17,14 @@
 package android.widget.listview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.widget.ListView;
-
 import android.widget.listview.ListOfTouchables;
-import android.test.TouchUtils;
+
+import androidx.test.filters.MediumTest;
 
 /**
  * Touch tests for a list where all of the items fit on the screen.
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListSetSelectionTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListSetSelectionTest.java
index aed513a..716683a 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListSetSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListSetSelectionTest.java
@@ -17,15 +17,15 @@
 package android.widget.listview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.View;
 import android.widget.ListView;
-
 import android.widget.listview.ListSimple;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 /**
  * Tests setting the selection in touch mode
  */
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityManyTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityManyTest.java
index 7daf64e..6a1f076 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityManyTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityManyTest.java
@@ -17,16 +17,16 @@
 package android.widget.listview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.widget.ListView;
-
 import android.widget.listview.ListBottomGravityMany;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 /**
  * Touch tests for a list where all of the items do not fit on the screen, and the list 
  * stacks from the bottom.
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityTest.java
index 4086cf0..89498d66 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityTest.java
@@ -17,13 +17,13 @@
 package android.widget.listview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
 import android.view.View;
 import android.widget.ListView;
-
 import android.widget.listview.ListBottomGravity;
 
+import androidx.test.filters.MediumTest;
+
 /**
  * Touch tests for a list where all of the items fit on the screen, and the list 
  * stacks from the bottom.
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListTouchManyTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListTouchManyTest.java
index 30d56ca..c7f2371 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListTouchManyTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListTouchManyTest.java
@@ -17,16 +17,16 @@
 package android.widget.listview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.widget.ListView;
-
 import android.widget.listview.ListTopGravityMany;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 /**
  * Touch tests for a list where all of the items do not fit on the screen.
  */
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListTouchTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListTouchTest.java
index 5b064b3..8a557ab 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListTouchTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListTouchTest.java
@@ -17,13 +17,13 @@
 package android.widget.listview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
 import android.view.View;
 import android.widget.ListView;
-
 import android.widget.listview.ListTopGravity;
 
+import androidx.test.filters.MediumTest;
+
 /**
  * Touch tests for a list where all of the items fit on the screen.
  */
diff --git a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java
index a7f5c05..a30985b 100644
--- a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java
+++ b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java
@@ -18,7 +18,6 @@
 
 import android.util.InternalSelectionView;
 import android.util.ScrollViewScenario;
-
 import android.widget.Button;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java
index 8123228..825aa1a 100644
--- a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java
@@ -16,14 +16,13 @@
 
 package android.widget.scroll;
 
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.scroll.ButtonAboveTallInternalSelectionView;
-import android.util.InternalSelectionView;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.util.InternalSelectionView;
 import android.view.KeyEvent;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 @Suppress // Failing.
 public class ButtonAboveTallInternalSelectionViewTest extends
         ActivityInstrumentationTestCase<ButtonAboveTallInternalSelectionView> {
diff --git a/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java b/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java
index 3d5f86d..47d36dd 100644
--- a/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java
+++ b/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java
@@ -17,7 +17,6 @@
 package android.widget.scroll;
 
 import android.util.ScrollViewScenario;
-
 import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.TextView;
diff --git a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisible.java b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisible.java
index afc275f..dba07a0 100644
--- a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisible.java
+++ b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisible.java
@@ -16,15 +16,15 @@
 
 package android.widget.scroll;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
-import android.os.Bundle;
 import android.graphics.Rect;
+import android.os.Bundle;
 import android.view.View;
 import android.widget.ScrollView;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * A screen with some scenarios that exercise {@link ScrollView}'s implementation
  * of {@link android.view.ViewGroup#requestChildRectangleOnScreen}:
diff --git a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleTest.java b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleTest.java
index f8abdb2..7c3df91 100644
--- a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleTest.java
@@ -16,19 +16,19 @@
 
 package android.widget.scroll;
 
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.scroll.RequestRectangleVisible;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.ViewAsserts;
+import android.view.KeyEvent;
+import android.view.View;
 import android.widget.Button;
 import android.widget.ScrollView;
 import android.widget.TextView;
-import android.view.View;
-import android.view.KeyEvent;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * {@link RequestRectangleVisible} is set up to exercise the cases of moving a
diff --git a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScroll.java b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScroll.java
index 731b25a..105686a 100644
--- a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScroll.java
+++ b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScroll.java
@@ -16,15 +16,14 @@
 
 package android.widget.scroll;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
-import android.os.Bundle;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.Button;
-import android.view.View;
 import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
 
 public class RequestRectangleVisibleWithInternalScroll extends Activity {
 
diff --git a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScrollTest.java b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScrollTest.java
index 5e9b520..1a221ff 100644
--- a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScrollTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScrollTest.java
@@ -16,16 +16,17 @@
 
 package android.widget.scroll;
 
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
 import android.test.ViewAsserts;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.widget.Button;
 import android.widget.ScrollView;
 import android.widget.TextView;
 
+import androidx.test.filters.Suppress;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * This is suppressed because {@link TextView#scrollBy} isn't working.
  */
diff --git a/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabels.java b/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabels.java
index 027ea0f..92a3152 100644
--- a/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabels.java
+++ b/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabels.java
@@ -16,15 +16,14 @@
 
 package android.widget.scroll;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
 import android.widget.TextView;
-import android.widget.Button;
 
+import com.android.frameworks.coretests.R;
 
 /**
  * Basic scroll view example
diff --git a/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabelsTest.java b/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabelsTest.java
index 3fd17ee..8d71f84 100644
--- a/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabelsTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabelsTest.java
@@ -17,14 +17,14 @@
 package android.widget.scroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 public class ScrollViewButtonsAndLabelsTest
         extends ActivityInstrumentationTestCase<ScrollViewButtonsAndLabels> {
diff --git a/core/tests/coretests/src/android/widget/scroll/ShortButtons.java b/core/tests/coretests/src/android/widget/scroll/ShortButtons.java
index 3a0f29a..90ede7d 100644
--- a/core/tests/coretests/src/android/widget/scroll/ShortButtons.java
+++ b/core/tests/coretests/src/android/widget/scroll/ShortButtons.java
@@ -17,7 +17,6 @@
 package android.widget.scroll;
 
 import android.util.ScrollViewScenario;
-
 import android.widget.Button;
 import android.widget.LinearLayout;
 
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java
index 56d7ed2..04f5ac8 100644
--- a/core/tests/coretests/src/android/widget/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java
@@ -16,16 +16,16 @@
 
 package android.widget.scroll.arrowscroll;
 
-import android.widget.scroll.ButtonsWithTallTextViewInBetween;
-
 import android.graphics.Rect;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.Button;
 import android.widget.ScrollView;
 import android.widget.TextView;
+import android.widget.scroll.ButtonsWithTallTextViewInBetween;
+
+import androidx.test.filters.MediumTest;
 
 public class ButtonsWithTallTextViewInBetweenTest
         extends ActivityInstrumentationTestCase<ButtonsWithTallTextViewInBetween> {
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
index 6ce4c15..2f45098 100644
--- a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
@@ -16,14 +16,14 @@
 
 package android.widget.scroll.arrowscroll;
 
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.scroll.arrowscroll.MultiPageTextWithPadding;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
-import android.widget.TextView;
 import android.widget.ScrollView;
+import android.widget.TextView;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 @Suppress // Flaky
 public class MultiPageTextWithPaddingTest extends
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/ShortButtonsTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/ShortButtonsTest.java
index 267d8ee..a2928cb 100644
--- a/core/tests/coretests/src/android/widget/scroll/arrowscroll/ShortButtonsTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/ShortButtonsTest.java
@@ -16,15 +16,15 @@
 
 package android.widget.scroll.arrowscroll;
 
-import android.widget.scroll.ShortButtons;
-
 import android.graphics.Rect;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.Button;
 import android.widget.ScrollView;
+import android.widget.scroll.ShortButtons;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 public class ShortButtonsTest extends ActivityInstrumentationTestCase<ShortButtons> {
 
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/TallTextAboveButtonTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/TallTextAboveButtonTest.java
index 5351839..0681081 100644
--- a/core/tests/coretests/src/android/widget/scroll/arrowscroll/TallTextAboveButtonTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/TallTextAboveButtonTest.java
@@ -16,13 +16,13 @@
 
 package android.widget.scroll.arrowscroll;
 
-import android.widget.scroll.TallTextAboveButton;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.ScrollView;
 import android.widget.TextView;
+import android.widget.scroll.TallTextAboveButton;
+
+import androidx.test.filters.MediumTest;
 
 public class TallTextAboveButtonTest extends ActivityInstrumentationTestCase<TallTextAboveButton> {
     private ScrollView mScrollView;
diff --git a/core/tests/coretests/src/android/widget/touchmode/ChangeTouchModeTest.java b/core/tests/coretests/src/android/widget/touchmode/ChangeTouchModeTest.java
index 449c95c..aa20c9b 100644
--- a/core/tests/coretests/src/android/widget/touchmode/ChangeTouchModeTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/ChangeTouchModeTest.java
@@ -16,16 +16,17 @@
 
 package android.widget.touchmode;
 
-import android.widget.layout.linear.LLOfButtons1;
-import android.widget.layout.linear.LLOfButtons2;
 import static android.util.TouchModeFlexibleAsserts.assertInTouchModeAfterClick;
-import static android.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
 import static android.util.TouchModeFlexibleAsserts.assertInTouchModeAfterTap;
+import static android.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
+import android.widget.layout.linear.LLOfButtons1;
+import android.widget.layout.linear.LLOfButtons2;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 /**
  * Tests that the touch mode changes from various events, and that the state
diff --git a/core/tests/coretests/src/android/widget/touchmode/FocusableInTouchModeClickTest.java b/core/tests/coretests/src/android/widget/touchmode/FocusableInTouchModeClickTest.java
index 691b25a..97c982f 100644
--- a/core/tests/coretests/src/android/widget/touchmode/FocusableInTouchModeClickTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/FocusableInTouchModeClickTest.java
@@ -16,12 +16,12 @@
 
 package android.widget.touchmode;
 
-import android.widget.layout.linear.LLOfTwoFocusableInTouchMode;
-
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.layout.linear.LLOfTwoFocusableInTouchMode;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 public class FocusableInTouchModeClickTest extends ActivityInstrumentationTestCase2<LLOfTwoFocusableInTouchMode> {
 
diff --git a/core/tests/coretests/src/android/widget/touchmode/StartInTouchWithViewInFocusTest.java b/core/tests/coretests/src/android/widget/touchmode/StartInTouchWithViewInFocusTest.java
index 5339188..88aa9ca 100644
--- a/core/tests/coretests/src/android/widget/touchmode/StartInTouchWithViewInFocusTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/StartInTouchWithViewInFocusTest.java
@@ -16,14 +16,15 @@
 
 package android.widget.touchmode;
 
-import android.widget.layout.linear.LLEditTextThenButton;
 import static android.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.Button;
 import android.widget.EditText;
+import android.widget.layout.linear.LLEditTextThenButton;
+
+import androidx.test.filters.MediumTest;
 
 public class StartInTouchWithViewInFocusTest extends 
         ActivityInstrumentationTestCase2<LLEditTextThenButton> {
diff --git a/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java b/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java
index 5a6110c..f192f68 100644
--- a/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java
@@ -21,11 +21,11 @@
 import static android.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.Button;
 import android.widget.layout.linear.LLOfButtons1;
 
+import androidx.test.filters.MediumTest;
 
 /**
  * Make sure focus isn't kept by buttons when entering touch mode.
diff --git a/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusableTest.java b/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusableTest.java
index 3ddeef0..87f33a4 100644
--- a/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusableTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusableTest.java
@@ -20,12 +20,13 @@
 import static android.util.TouchModeFlexibleAsserts.assertInTouchModeAfterTap;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.layout.linear.LLEditTextThenButton;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 /**
  * Some views, like edit texts, can keep and gain focus even when in touch mode.
  */
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index a302657..aadfcbc 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -57,7 +57,6 @@
 import android.provider.Settings;
 import android.speech.tts.TextToSpeech;
 import android.speech.tts.Voice;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.mock.MockContentResolver;
 import android.text.TextUtils;
 import android.view.Window;
@@ -66,6 +65,8 @@
 import android.view.accessibility.IAccessibilityManager;
 import android.widget.Toast;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.R;
 import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkObjectProvider;
 import com.android.internal.util.test.FakeSettingsProvider;
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 1859378..aaa624e 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -16,6 +16,30 @@
 
 package com.android.internal.app;
 
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.usage.UsageStatsManager;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.R;
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
 
@@ -25,32 +49,8 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 
-import android.app.usage.UsageStats;
-import android.app.usage.UsageStatsManager;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.os.UserHandle;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.times;
 
 /**
  * Chooser activity instrumentation tests
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index c446f3c..60529f6 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -16,14 +16,14 @@
 
 package com.android.internal.app;
 
+import static org.mockito.Mockito.mock;
+
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 
 import java.util.function.Function;
 
-import static org.mockito.Mockito.mock;
-
 public class ChooserWrapperActivity extends ChooserActivity {
     /*
      * Simple wrapper around chooser activity to be able to initiate it under test
diff --git a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
index cfb6bdd..9b13af2 100644
--- a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
@@ -46,9 +46,10 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 404c99c..fe2fb85 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -16,6 +16,29 @@
 
 package com.android.internal.app;
 
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import static com.android.internal.app.ResolverWrapperActivity.sOverrides;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.R;
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
 import com.android.internal.widget.ResolverDrawerLayout;
@@ -26,37 +49,8 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 
-import android.app.usage.UsageStats;
-import android.app.usage.UsageStatsManager;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.os.UserHandle;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.view.View;
-import android.widget.RelativeLayout;
-
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
-
-import static android.os.SystemClock.sleep;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static com.android.internal.app.ResolverWrapperActivity.sOverrides;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 /**
  * Resolver activity instrumentation tests
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java b/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
index c710b9a..850b466 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
@@ -23,10 +23,6 @@
 import android.content.pm.ResolveInfo;
 import android.os.UserHandle;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
 /**
  * Utility class used by resolver tests to create mock data
  */
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
index 284ab60..fcec00e 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
@@ -25,34 +25,31 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.when;
 
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.mockito.stubbing.Answer;
-
 import android.app.usage.IUsageStatsManager;
 import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.content.Intent;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
 
-import java.io.File;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
index 163211e..83f6bc2 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
@@ -16,17 +16,12 @@
 
 package com.android.internal.app;
 
-import android.app.usage.UsageStatsManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.os.RemoteException;
-
-import java.util.function.Function;
-
 import static org.mockito.Mockito.mock;
 
+import android.app.usage.UsageStatsManager;
+import android.content.pm.PackageManager;
+
+import java.util.function.Function;
 
 /*
  * Simple wrapper around chooser activity to be able to initiate it under test
diff --git a/core/tests/coretests/src/com/android/internal/app/WindowDecorActionBarTest.java b/core/tests/coretests/src/com/android/internal/app/WindowDecorActionBarTest.java
index 472958a..87ad124 100644
--- a/core/tests/coretests/src/com/android/internal/app/WindowDecorActionBarTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/WindowDecorActionBarTest.java
@@ -17,12 +17,13 @@
 package com.android.internal.app;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.ActionMode;
 import android.view.Menu;
 import android.view.MenuItem;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.SmallTest;
+
 /**
  * Tests for {@link WindowDecorActionBar}.
  */
diff --git a/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java b/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java
index 115af5e..f7fea3b 100644
--- a/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java
@@ -16,20 +16,14 @@
 
 package com.android.internal.app.procstats;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-
-import android.os.BatteryStats;
 import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
-import org.mockito.Mockito;
-
 /**
  * Provides test cases for SparseMappingTable.
  */
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
index 629f7b6..222e494 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
@@ -18,10 +18,11 @@
 
 import static org.junit.Assert.assertEquals;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.WindowManager.LayoutParams;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
index 8179328..ba63908 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
@@ -18,8 +18,8 @@
 
 import static org.junit.Assert.assertEquals;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
index 992b46f..b687801 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
@@ -13,6 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import static android.os.BatteryStats.STATS_SINCE_CHARGED;
@@ -20,10 +21,11 @@
 import android.app.ActivityManager;
 import android.os.BatteryStats;
 import android.os.WorkSource;
-import android.support.test.filters.SmallTest;
 import android.util.ArrayMap;
 import android.view.Display;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 /**
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
index 08f8dd1..37f818a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
@@ -13,11 +13,13 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import android.os.BatteryStats;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
index ee8d508..0179ead 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import static android.os.BatteryStats.STATS_SINCE_CHARGED;
@@ -36,11 +37,12 @@
 
 import android.os.BatteryStats;
 import android.os.UserHandle;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseLongArray;
 import android.view.Display;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.util.ArrayUtils;
 
 import org.junit.Before;
@@ -64,7 +66,7 @@
  * Install: adb install -r \
  * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
  * Run: adb shell am instrument -e class com.android.internal.os.BatteryStatsCpuTimesTest -w \
- * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ * com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  *
  * or
  *
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java
index 3a5a9f5..efb8710 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java
@@ -13,10 +13,12 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import android.os.BatteryStats;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
index 19dab79..a42286f 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
@@ -13,11 +13,13 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import android.os.BatteryStats;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
index 7467114..355601c 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
@@ -17,7 +17,6 @@
 
 package com.android.internal.os;
 
-
 import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -37,12 +36,13 @@
 import android.content.pm.PackageManager;
 import android.os.BatteryStats;
 import android.os.Process;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.format.DateUtils;
 import android.util.StatsLog;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import junit.framework.TestCase;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java
index 10a3189..cc0ddb7 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java
@@ -13,18 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import static org.junit.Assert.assertEquals;
-
 import android.content.Context;
 import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
index 613de45..dc93675 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import static android.os.BatteryStats.STATS_SINCE_CHARGED;
@@ -31,12 +32,13 @@
 import static org.mockito.Mockito.when;
 
 import android.os.BatteryStats;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.Display;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.util.ArrayUtils;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 8cbe5d6..3e33273 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -13,6 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import static android.os.BatteryStats.STATS_CURRENT;
@@ -20,21 +21,20 @@
 import static android.os.BatteryStats.WAKE_TYPE_PARTIAL;
 
 import android.app.ActivityManager;
-import android.os.BatteryManager;
 import android.os.BatteryStats;
 import android.os.BatteryStats.HistoryItem;
 import android.os.BatteryStats.Uid.Sensor;
 import android.os.WorkSource;
-import android.support.test.filters.SmallTest;
 import android.view.Display;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.internal.os.BatteryStatsImpl.DualTimer;
 import com.android.internal.os.BatteryStatsImpl.Uid;
+
 import junit.framework.TestCase;
 
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -47,7 +47,7 @@
  * Install: adb install -r \
  *      ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
  * Run: adb shell am instrument -e class com.android.internal.os.BatteryStatsNoteTest -w \
- *      com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ *      com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  */
 public class BatteryStatsNoteTest extends TestCase {
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
index 251ceb0..61d20df 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
@@ -13,11 +13,13 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import android.os.BatteryStats;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
index a751f90..b851f0a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
@@ -13,13 +13,15 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import android.app.ActivityManager;
 import android.os.BatteryStats;
-import android.support.test.filters.SmallTest;
 import android.view.Display;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 /**
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
index 5fd8225..b9995c4 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
@@ -18,7 +18,8 @@
 
 import android.os.BatteryStats;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.Assert;
 import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java
index 015314e..f76f316 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java
@@ -13,10 +13,12 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import android.os.BatteryStats;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 225515e..d69e1d1 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
index 3190d9e..bce8b40 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
@@ -16,19 +16,20 @@
 
 package com.android.internal.os;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
 import android.os.BatteryStats;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
 import org.mockito.Mockito;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
 /**
  * Provides test cases for android.os.BatteryStats.
  */
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
index 98d0f7f..87dc2f3 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
@@ -18,16 +18,17 @@
 
 import android.os.BatteryStats;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
 import android.util.StringBuilderPrinter;
 
-import junit.framework.Assert;
-import junit.framework.TestCase;
+import androidx.test.filters.SmallTest;
 
 import com.android.internal.os.BatteryStatsImpl.Clocks;
 import com.android.internal.os.BatteryStatsImpl.TimeBase;
 import com.android.internal.os.BatteryStatsImpl.Timer;
 
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
 /**
  * Provides test cases for android.os.BatteryStats.
  */
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
index a7e75a2..4df3190 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
@@ -16,22 +16,10 @@
 
 package com.android.internal.os;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
+import androidx.test.filters.SmallTest;
 
-import android.os.BatteryStats;
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import junit.framework.Assert;
 import junit.framework.TestCase;
 
-import com.android.internal.os.BatteryStatsImpl;
-
-import org.mockito.Mockito;
-
 /**
  * Provides test cases for android.os.BatteryStats.
  */
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
index 450473d..e7a1bca 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
@@ -28,12 +28,13 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.support.test.uiautomator.UiDevice;
 import android.util.ArraySet;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.BeforeClass;
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index dc3a12f..1d35143 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -22,11 +22,12 @@
 import android.os.Binder;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
 import android.util.SparseArray;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.os.BinderInternal.CallSession;
 
 import org.junit.Assert;
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index 42c9139..01515bd 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import static android.os.BatteryStats.UID_TIMES_TYPE_ALL;
@@ -33,9 +34,6 @@
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
 
-import com.android.frameworks.coretests.aidl.ICmdCallback;
-import com.android.frameworks.coretests.aidl.ICmdReceiver;
-
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
 import android.content.ComponentName;
@@ -52,14 +50,18 @@
 import android.os.Process;
 import android.os.SystemClock;
 import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.support.test.uiautomator.UiDevice;
 import android.text.TextUtils;
 import android.util.DebugUtils;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.coretests.aidl.ICmdCallback;
+import com.android.frameworks.coretests.aidl.ICmdReceiver;
+
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Rule;
diff --git a/core/tests/coretests/src/com/android/internal/os/DebugTest.java b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
index efb78d7..2a8a857 100644
--- a/core/tests/coretests/src/com/android/internal/os/DebugTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
@@ -18,7 +18,8 @@
 
 import android.os.Debug;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 @SmallTest
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java
index 8360126..a25a7489 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java
@@ -24,9 +24,10 @@
 import android.content.Context;
 import android.os.FileUtils;
 import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java
index 2663f2b..7a31605 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java
@@ -24,9 +24,10 @@
 import android.content.Context;
 import android.os.FileUtils;
 import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
new file mode 100644
index 0000000..c03d1f3
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
@@ -0,0 +1,214 @@
+/*
+ * 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.internal.os;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.os.SystemClock;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.KernelCpuThreadReader.ProcessCpuUsage;
+import com.android.internal.os.KernelCpuThreadReader.ThreadCpuUsage;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.List;
+import java.util.OptionalDouble;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+/**
+ * End to end test for {@link KernelCpuThreadReader} that checks the accuracy of the reported times
+ * by spawning threads that do a predictable amount of work
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class KernelCpuThreadReaderEndToEndTest {
+
+    private static final int TIMED_NUM_SAMPLES = 5;
+    private static final int TIMED_START_MILLIS = 500;
+    private static final int TIMED_END_MILLIS = 2000;
+    private static final int TIMED_INCREMENT_MILLIS = 500;
+    private static final int TIMED_COMPARISON_DELTA_MILLIS = 200;
+
+    private static final int ITERATIVE_NUM_SAMPLES = 100;
+    private static final long ITERATIVE_LOW_ITERATIONS = (long) 1e8;
+    private static final long ITERATIVE_HIGH_ITERATIONS = (long) 2e8;
+    private static final double ITERATIONS_COMPARISONS_DELTA = 0.25;
+
+    /**
+     * Test that when we busy-wait for the thread-local time to reach N seconds, the time reported
+     * is also N seconds. Takes ~10s.
+     */
+    @Test
+    public void testTimedWork() throws InterruptedException {
+        for (int millis = TIMED_START_MILLIS;
+                millis <= TIMED_END_MILLIS;
+                millis += TIMED_INCREMENT_MILLIS) {
+            final Duration targetDuration = Duration.ofMillis(millis);
+            final Runnable work = timedWork(targetDuration);
+            Duration resultDuration = getAverageWorkTime(
+                    work, String.format("timed%dms", millis), TIMED_NUM_SAMPLES);
+            assertEquals(
+                    "Time worked according to currentThreadTimeMillis doesn't match "
+                            + "KernelCpuThreadReader",
+                    targetDuration.toMillis(), resultDuration.toMillis(),
+                    TIMED_COMPARISON_DELTA_MILLIS);
+        }
+    }
+
+    /**
+     * Test that when we scale up the amount of work by N, the time reported also scales by N. Takes
+     * ~15s.
+     */
+    @Test
+    public void testIterativeWork() throws InterruptedException {
+        final Runnable lowAmountWork = iterativeWork(ITERATIVE_LOW_ITERATIONS);
+        final Runnable highAmountWork = iterativeWork(ITERATIVE_HIGH_ITERATIONS);
+        final Duration lowResultDuration =
+                getAverageWorkTime(lowAmountWork, "iterlow", ITERATIVE_NUM_SAMPLES);
+        final Duration highResultDuration =
+                getAverageWorkTime(highAmountWork, "iterhigh", ITERATIVE_NUM_SAMPLES);
+        assertEquals(
+                "Work scale and CPU time scale do not match",
+                ((double) ITERATIVE_HIGH_ITERATIONS) / ((double) ITERATIVE_LOW_ITERATIONS),
+                ((double) highResultDuration.toMillis()) / ((double) lowResultDuration.toMillis()),
+                ITERATIONS_COMPARISONS_DELTA);
+    }
+
+    /**
+     * Run some work {@code numSamples} times, and take the average CPU duration used for that work
+     * according to {@link KernelCpuThreadReader}
+     */
+    private Duration getAverageWorkTime(
+            Runnable work, String tag, int numSamples) throws InterruptedException {
+        // Count down every time a thread finishes work, so that we can wait for work to complete
+        final CountDownLatch workFinishedLatch = new CountDownLatch(numSamples);
+        // Count down once when threads can terminate (after we get them from
+        // `KernelCpuThreadReader`)
+        final CountDownLatch threadFinishedLatch = new CountDownLatch(1);
+
+        // Start `NUM_SAMPLE` threads to do the work
+        for (int i = 0; i < numSamples; i++) {
+            final String threadName = String.format("%s%d", tag, i);
+            // Check the thread name, as we rely on it later to identify threads
+            assertTrue("Max name length for linux threads is 15", threadName.length() <= 15);
+            doWork(work, threadName, workFinishedLatch, threadFinishedLatch);
+        }
+
+        // Wait for threads to finish
+        workFinishedLatch.await();
+
+        // Get thread data from KernelCpuThreadReader
+        final KernelCpuThreadReader kernelCpuThreadReader = KernelCpuThreadReader.create();
+        assertNotNull(kernelCpuThreadReader);
+        final ProcessCpuUsage currentProcessCpuUsage =
+                kernelCpuThreadReader.getCurrentProcessCpuUsage();
+
+        // Threads can terminate, as we've finished crawling them from /proc
+        threadFinishedLatch.countDown();
+
+        // Check that we've got times for every thread we spawned
+        final List<ThreadCpuUsage> threadCpuUsages = currentProcessCpuUsage.threadCpuUsages
+                .stream()
+                .filter((thread) -> thread.threadName.startsWith(tag))
+                .collect(Collectors.toList());
+        assertEquals(
+                "Incorrect number of threads returned by KernelCpuThreadReader",
+                numSamples, threadCpuUsages.size());
+
+        // Calculate the average time spent working
+        final OptionalDouble averageWorkTimeMillis = threadCpuUsages.stream()
+                .mapToDouble((t) -> Arrays.stream(t.usageTimesMillis).sum())
+                .average();
+        assertTrue(averageWorkTimeMillis.isPresent());
+        return Duration.ofMillis((long) averageWorkTimeMillis.getAsDouble());
+    }
+
+    /**
+     * Work that lasts {@code duration} according to {@link SystemClock#currentThreadTimeMillis()}
+     */
+    private Runnable timedWork(Duration duration) {
+        return () -> {
+            // Busy loop until `duration` has elapsed for the thread timer
+            final long startTimeMillis = SystemClock.currentThreadTimeMillis();
+            final long durationMillis = duration.toMillis();
+            while (true) {
+                final long elapsedMillis = SystemClock.currentThreadTimeMillis() - startTimeMillis;
+                if (elapsedMillis >= durationMillis) {
+                    break;
+                }
+            }
+        };
+    }
+
+    /**
+     * Work that iterates {@code iterations} times
+     */
+    private Runnable iterativeWork(long iterations) {
+        Consumer<Long> empty = (i) -> {
+        };
+        return () -> {
+            long count = 0;
+            for (long i = 0; i < iterations; i++) {
+                // Alternate branching to reduce effect of branch prediction
+                if (i % 2 == 0) {
+                    count++;
+                }
+            }
+            // Call empty function with value to avoid loop getting optimized away
+            empty.accept(count);
+        };
+    }
+
+    /**
+     * Perform some work in another thread
+     *
+     * @param work                the work to perform
+     * @param threadName          the name of the spawned thread
+     * @param workFinishedLatch   latch to register that the work has been completed
+     * @param threadFinishedLatch latch to pause termination of the thread until the latch is
+     *                            decremented
+     */
+    private void doWork(
+            Runnable work,
+            String threadName,
+            CountDownLatch workFinishedLatch,
+            CountDownLatch threadFinishedLatch) {
+        Runnable workWrapped = () -> {
+            // Do the work
+            work.run();
+            // Notify that the work is finished
+            workFinishedLatch.countDown();
+            // Wait until `threadFinishLatch` has been released in order to keep the thread alive so
+            // we can see it in `proc` filesystem
+            try {
+                threadFinishedLatch.await();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        };
+        new Thread(workWrapped, threadName).start();
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
index b242a34..0c56b8a 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
@@ -23,9 +23,10 @@
 
 import android.content.Context;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
index adafda0..1b13a99 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import static org.junit.Assert.assertEquals;
@@ -20,11 +21,12 @@
 
 import android.content.Context;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseLongArray;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader;
 
 import org.junit.After;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
index ad20d84..2ea80da 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -22,11 +23,12 @@
 
 import android.content.Context;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
 
 import org.junit.After;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
index 1d3a98a..0b6fed3 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -24,11 +25,12 @@
 
 import android.content.Context;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
 
 import org.junit.After;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
index 9b4512b..8f81ea2 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -23,11 +24,12 @@
 import android.content.Context;
 import android.os.FileUtils;
 import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
 
 import org.junit.After;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java b/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java
index 32317ee..60dac85 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java
@@ -1,11 +1,27 @@
+/*
+ * 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.
+ */
+
 package com.android.internal.os;
 
-import android.support.test.filters.SmallTest;
 import android.util.LongSparseLongArray;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
-import org.junit.Assert;
 import org.mockito.Mockito;
 
 import java.io.BufferedReader;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
index 29227f9..479e19e 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
@@ -21,10 +21,11 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.os.KernelSingleUidTimeReader.Injector;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java
index 28570e8..12f6c18 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java
@@ -20,8 +20,8 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java
index 85dce02..532f337 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java
@@ -21,10 +21,11 @@
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.when;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
index 67c4e61..6d2980b 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
@@ -24,10 +24,11 @@
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -53,7 +54,7 @@
  * Install: adb install -r \
  * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
  * Run: adb shell am instrument -e class com.android.internal.os.KernelUidCpuFreqTimeReaderTest -w \
- * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ * com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  *
  * or
  *
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
index 4e4bb3507..78b6843 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
@@ -13,9 +13,10 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java b/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java
index fe62764..cb8a62c 100644
--- a/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java
@@ -16,7 +16,9 @@
 
 package com.android.internal.os;
 
-import android.test.suitebuilder.annotation.Suppress;
+import androidx.test.filters.Suppress;
+
+import junit.framework.TestCase;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -25,8 +27,6 @@
 import java.util.Collections;
 import java.util.List;
 
-import junit.framework.TestCase;
-
 // this test causes a IllegalAccessError: superclass not accessible
 @Suppress
 public class LoggingPrintStreamTest extends TestCase {
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
index 37b4e41a..0516bb7 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
@@ -30,8 +30,9 @@
 import static org.mockito.Mockito.when;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -55,7 +56,7 @@
  * Install: adb install -r \
  *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
  * Run: adb shell am instrument -e class com.android.internal.os.LongSamplingCounterArrayTest -w \
- *     com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ *     com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
index 853bf8a..d2f5735 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
@@ -28,8 +28,9 @@
 import static org.mockito.Mockito.when;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index b65c1e6..2c597b1 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -23,8 +23,9 @@
 import android.os.Looper;
 import android.os.Message;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Assert;
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index b68f6b1..c18445e 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -21,6 +21,7 @@
 import android.util.SparseIntArray;
 
 import com.android.internal.location.gnssmetrics.GnssMetrics;
+
 import java.util.ArrayList;
 import java.util.Queue;
 import java.util.concurrent.Future;
diff --git a/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java
index 14d62e0..c592ab6 100644
--- a/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java
@@ -17,13 +17,13 @@
 
 package com.android.internal.os;
 
-
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.os.BatteryStats;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
index 2853c96..5862368 100644
--- a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
@@ -17,8 +17,8 @@
 
 package com.android.internal.os;
 
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java b/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java
index 489e164..e97caf8 100644
--- a/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java
@@ -20,9 +20,10 @@
 
 import android.content.Context;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java b/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
index 2893066..9db3f8a 100644
--- a/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
@@ -22,9 +22,10 @@
 
 import android.content.Context;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java b/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
index c051a1c..85eafc5 100644
--- a/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
@@ -15,15 +15,17 @@
  */
 
 package com.android.internal.os;
+
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.content.Context;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
@@ -36,7 +38,6 @@
 import java.io.File;
 import java.nio.file.Files;
 
-
 /**
  * Test class for {@link StoragedUidIoStatsReader}.
  *
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
index 2a24881..8e0c1fe 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
@@ -17,8 +17,6 @@
 package com.android.internal.policy;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.ActionMode;
 import android.view.ActionMode.Callback;
 import android.view.KeyEvent;
@@ -32,7 +30,8 @@
 import android.view.WindowManager.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
 
-import java.util.List;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.SmallTest;
 
 /**
  * Tests {@link PhoneWindow}'s {@link ActionMode} related methods.
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
index d4b8566..6c2d630 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
@@ -28,12 +28,13 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.ActionMode;
 import android.view.ContextThemeWrapper;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.frameworks.coretests.R;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java
index b3897ce..d026735 100644
--- a/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java
@@ -13,9 +13,11 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.util;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 import java.util.ArrayList;
diff --git a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
index a44b860..4716312 100644
--- a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.util;
 
 import static com.android.internal.util.DumpUtils.CRITICAL_SECTION_COMPONENTS;
diff --git a/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
index 4845c4e..b2a2265 100644
--- a/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
@@ -19,11 +19,8 @@
 import junit.framework.TestCase;
 
 import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
 import java.io.Writer;
 import java.util.ArrayList;
-import java.util.LinkedList;
 import java.util.List;
 
 /**
diff --git a/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java
index f00c48c..867152e 100644
--- a/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.util;
 
 import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/util/TokenBucketTest.java b/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java
similarity index 90%
rename from core/tests/coretests/src/android/util/TokenBucketTest.java
rename to core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java
index f7ac20c..6c50bce 100644
--- a/core/tests/coretests/src/android/util/TokenBucketTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java
@@ -18,6 +18,7 @@
 
 import android.os.SystemClock;
 import android.text.format.DateUtils;
+
 import junit.framework.TestCase;
 
 public class TokenBucketTest extends TestCase {
@@ -54,9 +55,9 @@
 
         drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 100), 10);
 
-        drain(new TokenBucket((int)DateUtils.MINUTE_IN_MILLIS, 50), 50);
-        drain(new TokenBucket((int)DateUtils.HOUR_IN_MILLIS, 10), 10);
-        drain(new TokenBucket((int)DateUtils.DAY_IN_MILLIS, 200), 200);
+        drain(new TokenBucket((int) DateUtils.MINUTE_IN_MILLIS, 50), 50);
+        drain(new TokenBucket((int) DateUtils.HOUR_IN_MILLIS, 10), 10);
+        drain(new TokenBucket((int) DateUtils.DAY_IN_MILLIS, 200), 200);
     }
 
     public void testReset() {
@@ -163,16 +164,16 @@
 
     void assertDuration(long expected, long elapsed) {
         String msg = String.format(
-            "expected elapsed time at least %d ms, but was %d ms", expected, elapsed);
+                "expected elapsed time at least %d ms, but was %d ms", expected, elapsed);
         elapsed += 1; // one millisecond extra guard
         assertTrue(msg, elapsed >= expected);
     }
 
-    void assertThrow(Fn fn)     {
-      try {
-          fn.call();
-          fail("expected n exception to be thrown.");
-      } catch (Throwable t) {}
+    void assertThrow(Fn fn) {
+        try {
+            fn.call();
+            fail("expected n exception to be thrown.");
+        } catch (Throwable t) { }
     }
 
     interface Fn { void call(); }
diff --git a/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java b/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java
index 912b7ec..b372366 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java
@@ -18,11 +18,12 @@
 
 import android.content.Context;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.ActionMode;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.test.filters.SmallTest;
+
 /**
  * Tests for {@link ActionBarContainer}.
  */
diff --git a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
index d782c0c..d10f173 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
@@ -29,9 +29,6 @@
 import android.content.Context;
 import android.graphics.Insets;
 import android.graphics.Rect;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.DisplayCutout;
 import android.view.View;
 import android.view.View.OnApplyWindowInsetsListener;
@@ -40,6 +37,10 @@
 import android.widget.FrameLayout;
 import android.widget.Toolbar;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/widget/BackgroundFallbackTest.java b/core/tests/coretests/src/com/android/internal/widget/BackgroundFallbackTest.java
index e21143d..0fada06 100644
--- a/core/tests/coretests/src/com/android/internal/widget/BackgroundFallbackTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/BackgroundFallbackTest.java
@@ -32,10 +32,11 @@
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.support.test.InstrumentationRegistry;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import androidx.test.InstrumentationRegistry;
+
 import org.junit.Before;
 import org.junit.Test;
 
diff --git a/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java b/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java
index 1806b22..2e0dbb4 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java
@@ -19,12 +19,13 @@
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
 import android.text.Layout;
 import android.view.View.MeasureSpec;
 import android.widget.TextView;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
index f73950a..6167c4b 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
@@ -20,8 +20,9 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.UserHandle;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
index 41082b7..6af7c88 100644
--- a/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
@@ -21,12 +21,12 @@
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.text.Layout;
 import android.view.LayoutInflater;
 import android.view.View.MeasureSpec;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
 
 import org.junit.Before;
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index 0dd9d09..28a8afe 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -318,6 +318,27 @@
             mMaxVolume = maxVolume;
             mIsMute = isMute;
         }
+
+        @Override
+        public void setSystemAudioModeOnForAudioOnlySource() {
+        }
+
+        @Override
+        public int getPhysicalAddress() {
+            return 0x0000;
+        }
+
+        @Override
+        public void powerOffRemoteDevice(int logicalAddress, int powerStatus) {
+        }
+
+        @Override
+        public void powerOnRemoteDevice(int logicalAddress, int powerStatus) {
+        }
+
+        @Override
+        public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) {
+        }
     }
 
 }
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk
index f3d98a8..afbcd46 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_PACKAGE_NAME := MultiDexLegacyTestServicesTests2
 
 LOCAL_JAVA_LIBRARIES := android-support-multidex
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
 
 LOCAL_SDK_VERSION := 9
 
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml
index 0ab2959..01285e7 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml
@@ -7,7 +7,7 @@
     <uses-sdk android:minSdkVersion="9" />
     <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
     <instrumentation
-        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.framework.multidexlegacytestservices" />
 
     <application
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java
index 900f203..f2c72f0 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java
@@ -19,22 +19,26 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.File;
 import java.io.FileFilter;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.util.concurrent.TimeoutException;
-import junit.framework.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Run the tests with: <code>adb shell am instrument -w
- * com.android.framework.multidexlegacytestservices.test2/android.support.test.runner.AndroidJUnitRunner
+ * com.android.framework.multidexlegacytestservices.test2/androidx.test.runner.AndroidJUnitRunner
  * </code>
  */
 @RunWith(AndroidJUnit4.class)
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 0bffa38..035ee10 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -39,9 +39,38 @@
     name: "privapp-permissions-platform.xml",
     sub_dir: "permissions",
     src: "privapp-permissions-platform.xml",
-    required: [
-        "privapp_whitelist_com.android.settings.intelligence",
-    ]
+}
+
+prebuilt_etc {
+    name: "privapp_whitelist_com.android.carrierconfig",
+    product_specific: true,
+    sub_dir: "permissions",
+    src: "com.android.carrierconfig.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
+    name: "privapp_whitelist_com.android.contacts",
+    product_specific: true,
+    sub_dir: "permissions",
+    src: "com.android.contacts.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
+    name: "privapp_whitelist_com.android.launcher3",
+    product_specific: true,
+    sub_dir: "permissions",
+    src: "com.android.launcher3.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
+    name: "privapp_whitelist_com.android.provision",
+    product_specific: true,
+    sub_dir: "permissions",
+    src: "com.android.provision.xml",
+    filename_from_src: true,
 }
 
 prebuilt_etc {
@@ -54,12 +83,21 @@
 
 prebuilt_etc {
     name: "privapp_whitelist_com.android.settings.intelligence",
+    product_specific: true,
     sub_dir: "permissions",
     src: "com.android.settings.intelligence.xml",
     filename_from_src: true,
 }
 
 prebuilt_etc {
+    name: "privapp_whitelist_com.android.storagemanager",
+    product_specific: true,
+    sub_dir: "permissions",
+    src: "com.android.storagemanager.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
     name: "privapp_whitelist_com.android.systemui",
     product_specific: true,
     sub_dir: "permissions",
diff --git a/data/etc/com.android.carrierconfig.xml b/data/etc/com.android.carrierconfig.xml
new file mode 100644
index 0000000..17efb03
--- /dev/null
+++ b/data/etc/com.android.carrierconfig.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<permissions>
+    <privapp-permissions package="com.android.carrierconfig">
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.contacts.xml b/data/etc/com.android.contacts.xml
new file mode 100644
index 0000000..78eae40
--- /dev/null
+++ b/data/etc/com.android.contacts.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<permissions>
+    <privapp-permissions package="com.android.contacts">
+        <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
+        <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.launcher3.xml b/data/etc/com.android.launcher3.xml
new file mode 100644
index 0000000..337e153
--- /dev/null
+++ b/data/etc/com.android.launcher3.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<permissions>
+    <privapp-permissions package="com.android.launcher3">
+        <permission name="android.permission.BIND_APPWIDGET"/>
+        <permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
+        <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.provision.xml b/data/etc/com.android.provision.xml
new file mode 100644
index 0000000..05404ef
--- /dev/null
+++ b/data/etc/com.android.provision.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<permissions>
+    <privapp-permissions package="com.android.provision">
+        <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.storagemanager.xml b/data/etc/com.android.storagemanager.xml
new file mode 100644
index 0000000..e85a82c
--- /dev/null
+++ b/data/etc/com.android.storagemanager.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<permissions>
+    <privapp-permissions package="com.android.storagemanager">
+        <permission name="android.permission.DELETE_PACKAGES"/>
+        <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+        <permission name="android.permission.MANAGE_USERS"/>
+        <permission name="android.permission.PACKAGE_USAGE_STATS"/>
+        <permission name="android.permission.USE_RESERVED_DISK"/>
+        <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 221708b..3562a8f 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -44,6 +44,7 @@
         <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.permission.REAL_GET_TASKS"/>
         <permission name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE"/>
+        <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
         <permission name="android.permission.START_ACTIVITY_AS_CALLER"/>
         <permission name="android.permission.START_TASKS_FROM_RECENTS"/>
         <permission name="android.permission.STATUS_BAR"/>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 4a2db0a..fb43e41 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -223,12 +223,12 @@
          code to link against. -->
 
     <library name="android.test.base"
-            file="/system/framework/android.test.base.impl.jar" />
+            file="/system/framework/android.test.base.jar" />
     <library name="android.test.mock"
-            file="/system/framework/android.test.mock.impl.jar"
+            file="/system/framework/android.test.mock.jar"
             dependency="android.test.base" />
     <library name="android.test.runner"
-            file="/system/framework/android.test.runner.impl.jar"
+            file="/system/framework/android.test.runner.jar"
             dependency="android.test.base:android.test.mock" />
 
     <!-- In BOOT_JARS historically, and now added to legacy applications. -->
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 393a2a6..597d14a 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -33,10 +33,6 @@
         <permission name="android.permission.CRYPT_KEEPER"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.carrierconfig">
-        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
-    </privapp-permissions>
-
     <privapp-permissions package="com.android.cellbroadcastreceiver">
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MANAGE_USERS"/>
@@ -45,11 +41,6 @@
         <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.contacts">
-        <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
-        <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
-    </privapp-permissions>
-
     <privapp-permissions package="com.android.defcontainer">
         <permission name="android.permission.ACCESS_CACHE_FILESYSTEM"/>
         <permission name="android.permission.ALLOCATE_AGGRESSIVE"/>
@@ -79,12 +70,6 @@
         <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.launcher3">
-        <permission name="android.permission.BIND_APPWIDGET"/>
-        <permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
-        <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
-    </privapp-permissions>
-
     <privapp-permissions package="com.android.location.fused">
         <permission name="android.permission.INSTALL_LOCATION_PROVIDER"/>
     </privapp-permissions>
@@ -238,10 +223,6 @@
         <permission name="android.permission.USE_RESERVED_DISK"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.provision">
-        <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
-    </privapp-permissions>
-
     <privapp-permissions package="com.android.mainline.networkstack">
         <permission name="android.permission.ACCESS_NETWORK_CONDITIONS"/>
         <permission name="android.permission.CHANGE_BACKGROUND_DATA_SETTING"/>
@@ -335,6 +316,7 @@
         <permission name="android.permission.SET_TIME"/>
         <permission name="android.permission.SET_TIME_ZONE"/>
         <permission name="android.permission.SIGNAL_PERSISTENT_PROCESSES"/>
+        <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
         <permission name="android.permission.START_TASKS_FROM_RECENTS" />
         <permission name="android.permission.STOP_APP_SWITCHES"/>
         <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
@@ -349,15 +331,6 @@
         <permission name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.storagemanager">
-        <permission name="android.permission.DELETE_PACKAGES"/>
-        <permission name="android.permission.INTERACT_ACROSS_USERS"/>
-        <permission name="android.permission.MANAGE_USERS"/>
-        <permission name="android.permission.PACKAGE_USAGE_STATS"/>
-        <permission name="android.permission.USE_RESERVED_DISK"/>
-        <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
-    </privapp-permissions>
-
     <privapp-permissions package="com.android.tv">
         <permission name="android.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE"/>
         <permission name="android.permission.DVB_DEVICE"/>
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index ca9dc47..65aaba1 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -22,6 +22,7 @@
 import android.annotation.Size;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Canvas.VertexMode;
+import android.graphics.text.MeasuredText;
 import android.text.GraphicsOperations;
 import android.text.MeasuredParagraph;
 import android.text.PrecomputedText;
@@ -554,14 +555,12 @@
                     final int paraStart = pt.getParagraphStart(paraIndex);
                     final MeasuredParagraph mp = pt.getMeasuredParagraph(paraIndex);
                     // Only support the text in the same paragraph.
-                    nDrawTextRun(mNativeCanvasWrapper,
-                            mp.getChars(),
-                            start - paraStart,
-                            end - start,
-                            contextStart - paraStart,
-                            contextEnd - contextStart,
-                            x, y, isRtl, paint.getNativeInstance(),
-                            mp.getMeasuredText().getNativePtr());
+                    drawTextRun(mp.getMeasuredText(),
+                                start - paraStart,
+                                end - paraStart,
+                                contextStart - paraStart,
+                                contextEnd - paraStart,
+                                x, y, isRtl, paint);
                     return;
                 }
             }
@@ -576,6 +575,14 @@
         }
     }
 
+    public void drawTextRun(@NonNull MeasuredText measuredText, int start, int end,
+            int contextStart, int contextEnd, float x, float y, boolean isRtl,
+            @NonNull Paint paint) {
+        nDrawTextRun(mNativeCanvasWrapper, measuredText.getChars(), start, end - start,
+                contextStart, contextEnd - contextStart, x, y, isRtl, paint.getNativeInstance(),
+                measuredText.getNativePtr());
+    }
+
     public void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts,
             int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors,
             int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount,
diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java
index 901c211..4f60935 100644
--- a/graphics/java/android/graphics/BaseRecordingCanvas.java
+++ b/graphics/java/android/graphics/BaseRecordingCanvas.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Size;
+import android.graphics.text.MeasuredText;
 import android.text.GraphicsOperations;
 import android.text.MeasuredParagraph;
 import android.text.PrecomputedText;
@@ -522,14 +523,12 @@
                     final int paraStart = pt.getParagraphStart(paraIndex);
                     final MeasuredParagraph mp = pt.getMeasuredParagraph(paraIndex);
                     // Only support if the target is in the same paragraph.
-                    nDrawTextRun(mNativeCanvasWrapper,
-                            mp.getChars(),
+                    drawTextRun(mp.getMeasuredText(),
                             start - paraStart,
-                            end - start,
+                            end - paraStart,
                             contextStart - paraStart,
-                            contextEnd - contextStart,
-                            x, y, isRtl, paint.getNativeInstance(),
-                            mp.getMeasuredText().getNativePtr());
+                            contextEnd - paraStart,
+                            x, y, isRtl, paint);
                     return;
                 }
             }
@@ -545,6 +544,15 @@
     }
 
     @Override
+    public void drawTextRun(@NonNull MeasuredText measuredText, int start, int end,
+            int contextStart, int contextEnd, float x, float y, boolean isRtl,
+            @NonNull Paint paint) {
+        nDrawTextRun(mNativeCanvasWrapper, measuredText.getChars(), start, end - start,
+                contextStart, contextEnd - contextStart, x, y, isRtl, paint.getNativeInstance(),
+                measuredText.getNativePtr());
+    }
+
+    @Override
     public final void drawVertices(@NonNull VertexMode mode, int vertexCount,
             @NonNull float[] verts, int vertOffset, @Nullable float[] texs, int texOffset,
             @Nullable int[] colors, int colorOffset, @Nullable short[] indices, int indexOffset,
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 790b37e..30f0bfa 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -18,9 +18,11 @@
 
 import android.annotation.CheckResult;
 import android.annotation.ColorInt;
+import android.annotation.ColorLong;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Size;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.annotation.WorkerThread;
 import android.content.res.ResourcesImpl;
@@ -1780,6 +1782,30 @@
     }
 
     /**
+     * Fills the bitmap's pixels with the specified {@link Color}.
+     *
+     * @throws IllegalStateException if the bitmap is not mutable.
+     * @throws IllegalArgumentException if the color space encoded in the long
+     *                                  is invalid or unknown.
+     *
+     * @hide pending API approval
+     */
+    @TestApi
+    public void eraseColor(@ColorLong long c) {
+        checkRecycled("Can't erase a recycled bitmap");
+        if (!isMutable()) {
+            throw new IllegalStateException("cannot erase immutable bitmaps");
+        }
+
+        ColorSpace cs = Color.colorSpace(c);
+        float r = Color.red(c);
+        float g = Color.green(c);
+        float b = Color.blue(c);
+        float a = Color.alpha(c);
+        nativeErase(mNativePtr, cs, r, g, b, a);
+    }
+
+    /**
      * Returns the {@link Color} at the specified location. Throws an exception
      * if x or y are out of bounds (negative or >= to the width or height
      * respectively). The returned color is a non-premultiplied ARGB value in
@@ -2123,6 +2149,8 @@
                                             int quality, OutputStream stream,
                                             byte[] tempStorage);
     private static native void nativeErase(long nativeBitmap, int color);
+    private static native void nativeErase(long nativeBitmap, ColorSpace cs,
+                                           float r, float g, float b, float a);
     private static native int nativeRowBytes(long nativeBitmap);
     private static native int nativeConfig(long nativeBitmap);
 
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 63a806e..8c1bae2 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.Size;
 import android.annotation.UnsupportedAppUsage;
+import android.graphics.text.MeasuredText;
 import android.os.Build;
 
 import dalvik.annotation.optimization.CriticalNative;
@@ -2122,7 +2123,8 @@
      * the text next to it.
      * <p>
      * All text outside the range {@code contextStart..contextEnd} is ignored. The text between
-     * {@code start} and {@code end} will be laid out and drawn.
+     * {@code start} and {@code end} will be laid out and drawn. The context range is useful for
+     * contextual shaping, e.g. Kerning, Arabic contextural form.
      * <p>
      * The direction of the run is explicitly specified by {@code isRtl}. Thus, this method is
      * suitable only for runs of a single direction. Alignment of the text is as determined by the
@@ -2151,6 +2153,31 @@
     }
 
     /**
+     * Draw a run of text, all in a single direction, with optional context for complex text
+     * shaping.
+     * <p>
+     * See {@link #drawTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)} for
+     * more details. This method uses a {@link MeasuredText} rather than CharSequence to represent
+     * the string.
+     *
+     * @param text the text to render
+     * @param start the start of the text to render. Data before this position can be used for
+     *            shaping context.
+     * @param end the end of the text to render. Data at or after this position can be used for
+     *            shaping context.
+     * @param contextStart the index of the start of the shaping context
+     * @param contextEnd the index of the end of the shaping context
+     * @param x the x position at which to draw the text
+     * @param y the y position at which to draw the text
+     * @param isRtl whether the run is in RTL direction
+     * @param paint the paint
+     */
+    public void drawTextRun(@NonNull MeasuredText text, int start, int end, int contextStart,
+            int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) {
+        super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, isRtl, paint);
+    }
+
+    /**
      * Draw the array of vertices, interpreted as triangles (based on mode). The verts array is
      * required, and specifies the x,y pairs for each vertex. If texs is non-null, then it is used
      * to specify the coordinate in shader coordinates to use at each vertex (the paint must have a
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 95317a4..9fa70a5 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -1661,10 +1661,12 @@
      * @param rhs 3x3 matrix, as a non-null array of 9 floats
      * @return A new array of 9 floats containing the result of the multiplication
      *         of rhs by lhs
+     *
+     * @hide
      */
     @NonNull
     @Size(9)
-    private static float[] mul3x3(@NonNull @Size(9) float[] lhs, @NonNull @Size(9) float[] rhs) {
+    public static float[] mul3x3(@NonNull @Size(9) float[] lhs, @NonNull @Size(9) float[] rhs) {
         float[] r = new float[9];
         r[0] = lhs[0] * rhs[0] + lhs[3] * rhs[1] + lhs[6] * rhs[2];
         r[1] = lhs[1] * rhs[0] + lhs[4] * rhs[1] + lhs[7] * rhs[2];
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 3342fd2..cbb780d 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -17,12 +17,14 @@
 package android.graphics;
 
 import android.annotation.ColorInt;
+import android.annotation.ColorLong;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Px;
 import android.annotation.Size;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.fonts.FontVariationAxis;
 import android.os.Build;
@@ -972,6 +974,31 @@
     }
 
     /**
+     * Set the paint's color with a {@link ColorLong}. Note that the color is
+     * a long with an encoded {@link ColorSpace} as well as alpha and r,g,b.
+     * These values are not premultiplied, meaning that alpha can be any value,
+     * regardless of the values of r,g,b. See the {@link Color} class for more
+     * details.
+     *
+     * @param color The new color (including alpha and {@link ColorSpace})
+     *      to set in the paint.
+     * @throws IllegalArgumentException if the color space encoded in the long
+     *      is invalid or unknown.
+     *
+     * @hide pending API approval
+     */
+    @TestApi
+    public void setColor(@ColorLong long color) {
+        ColorSpace cs = Color.colorSpace(color);
+        float r = Color.red(color);
+        float g = Color.green(color);
+        float b = Color.blue(color);
+        float a = Color.alpha(color);
+
+        nSetColor(mNativePaint, cs, r, g, b, a);
+    }
+
+    /**
      * Helper to getColor() that just returns the color's alpha value. This is
      * the same as calling getColor() >>> 24. It always returns a value between
      * 0 (completely transparent) and 255 (completely opaque).
@@ -1370,12 +1397,45 @@
      * The alpha of the shadow will be the paint's alpha if the shadow color is
      * opaque, or the alpha from the shadow color if not.
      */
-    public void setShadowLayer(float radius, float dx, float dy, int shadowColor) {
-      mShadowLayerRadius = radius;
-      mShadowLayerDx = dx;
-      mShadowLayerDy = dy;
-      mShadowLayerColor = shadowColor;
-      nSetShadowLayer(mNativePaint, radius, dx, dy, shadowColor);
+    public void setShadowLayer(float radius, float dx, float dy, @ColorInt int shadowColor) {
+        mShadowLayerRadius = radius;
+        mShadowLayerDx = dx;
+        mShadowLayerDy = dy;
+        mShadowLayerColor = shadowColor;
+        // FIXME: Share a single native method with the ColorLong version.
+        nSetShadowLayer(mNativePaint, radius, dx, dy, shadowColor);
+    }
+
+    /**
+     * This draws a shadow layer below the main layer, with the specified
+     * offset and color, and blur radius. If radius is 0, then the shadow
+     * layer is removed.
+     * <p>
+     * Can be used to create a blurred shadow underneath text. Support for use
+     * with other drawing operations is constrained to the software rendering
+     * pipeline.
+     * <p>
+     * The alpha of the shadow will be the paint's alpha if the shadow color is
+     * opaque, or the alpha from the shadow color if not.
+     *
+     * @throws IllegalArgumentException if the color space encoded in the long
+     *      is invalid or unknown.
+     *
+     * @hide pending API approval
+     */
+    @TestApi
+    public void setShadowLayer(float radius, float dx, float dy, @ColorLong long shadowColor) {
+        ColorSpace cs = Color.colorSpace(shadowColor);
+        float r = Color.red(shadowColor);
+        float g = Color.green(shadowColor);
+        float b = Color.blue(shadowColor);
+        float a = Color.alpha(shadowColor);
+        nSetShadowLayer(mNativePaint, radius, dx, dy, cs, r, g, b, a);
+
+        mShadowLayerRadius = radius;
+        mShadowLayerDx = dx;
+        mShadowLayerDy = dy;
+        mShadowLayerColor = Color.toArgb(shadowColor);
     }
 
     /**
@@ -2906,6 +2966,11 @@
             int contextStart, int contextEnd, boolean isRtl, int offset);
     private static native int nGetOffsetForAdvance(long paintPtr, char[] text, int start, int end,
             int contextStart, int contextEnd, boolean isRtl, float advance);
+    private static native void nSetColor(long paintPtr, ColorSpace cs,
+            float r, float g, float b, float a);
+    private static native void nSetShadowLayer(long paintPtr,
+            float radius, float dx, float dy, ColorSpace cs,
+            float r, float g, float b, float a);
 
 
     // ---------------- @FastNative ------------------------
@@ -2961,7 +3026,7 @@
             int mMinikinLocaleListId);
     @CriticalNative
     private static native void nSetShadowLayer(long paintPtr,
-            float radius, float dx, float dy, int color);
+            float radius, float dx, float dy, @ColorInt int color);
     @CriticalNative
     private static native boolean nHasShadowLayer(long paintPtr);
     @CriticalNative
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index ad9ec02..3c35d9b 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -20,8 +20,9 @@
 
 #include <algorithm>
 #include <iterator>
-#include <set>
 #include <map>
+#include <set>
+#include <sstream>
 
 #include "android-base/logging.h"
 #include "android-base/stringprintf.h"
@@ -372,6 +373,9 @@
   uint32_t best_offset = 0u;
   uint32_t type_flags = 0u;
 
+  Resolution::Step::Type resolution_type;
+  std::vector<Resolution::Step> resolution_steps;
+
   // If desired_config is the same as the set configuration, then we can use our filtered list
   // and we don't need to match the configurations, since they already matched.
   const bool use_fast_path = desired_config == &configuration_;
@@ -403,8 +407,8 @@
     // If the package is an overlay, then even configurations that are the same MUST be chosen.
     const bool package_is_overlay = loaded_package->IsOverlay();
 
-    const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
     if (use_fast_path) {
+      const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
       const std::vector<ResTable_config>& candidate_configs = filtered_group.configurations;
       const size_t type_count = candidate_configs.size();
       for (uint32_t i = 0; i < type_count; i++) {
@@ -412,21 +416,34 @@
 
         // We can skip calling ResTable_config::match() because we know that all candidate
         // configurations that do NOT match have been filtered-out.
-        if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
-            (package_is_overlay && this_config.compare(*best_config) == 0)) {
-          // The configuration matches and is better than the previous selection.
-          // Find the entry value if it exists for this configuration.
-          const ResTable_type* type_chunk = filtered_group.types[i];
-          const uint32_t offset = LoadedPackage::GetEntryOffset(type_chunk, local_entry_idx);
-          if (offset == ResTable_type::NO_ENTRY) {
-            continue;
-          }
+        if (best_config == nullptr) {
+          resolution_type = Resolution::Step::Type::INITIAL;
+        } else if (this_config.isBetterThan(*best_config, desired_config)) {
+          resolution_type = Resolution::Step::Type::BETTER_MATCH;
+        } else if (package_is_overlay && this_config.compare(*best_config) == 0) {
+          resolution_type = Resolution::Step::Type::OVERLAID;
+        } else {
+          continue;
+        }
 
-          best_cookie = cookie;
-          best_package = loaded_package;
-          best_type = type_chunk;
-          best_config = &this_config;
-          best_offset = offset;
+        // The configuration matches and is better than the previous selection.
+        // Find the entry value if it exists for this configuration.
+        const ResTable_type* type = filtered_group.types[i];
+        const uint32_t offset = LoadedPackage::GetEntryOffset(type, local_entry_idx);
+        if (offset == ResTable_type::NO_ENTRY) {
+          continue;
+        }
+
+        best_cookie = cookie;
+        best_package = loaded_package;
+        best_type = type;
+        best_config = &this_config;
+        best_offset = offset;
+
+        if (resource_resolution_logging_enabled_) {
+          resolution_steps.push_back(Resolution::Step{resolution_type,
+                                                      this_config.toString(),
+                                                      &loaded_package->GetPackageName()});
         }
       }
     } else {
@@ -440,23 +457,38 @@
         ResTable_config this_config;
         this_config.copyFromDtoH((*iter)->config);
 
-        if (this_config.match(*desired_config)) {
-          if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
-              (package_is_overlay && this_config.compare(*best_config) == 0)) {
-            // The configuration matches and is better than the previous selection.
-            // Find the entry value if it exists for this configuration.
-            const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx);
-            if (offset == ResTable_type::NO_ENTRY) {
-              continue;
-            }
+        if (!this_config.match(*desired_config)) {
+          continue;
+        }
 
-            best_cookie = cookie;
-            best_package = loaded_package;
-            best_type = *iter;
-            best_config_copy = this_config;
-            best_config = &best_config_copy;
-            best_offset = offset;
-          }
+        if (best_config == nullptr) {
+          resolution_type = Resolution::Step::Type::INITIAL;
+        } else if (this_config.isBetterThan(*best_config, desired_config)) {
+          resolution_type = Resolution::Step::Type::BETTER_MATCH;
+        } else if (package_is_overlay && this_config.compare(*best_config) == 0) {
+          resolution_type = Resolution::Step::Type::OVERLAID;
+        } else {
+          continue;
+        }
+
+        // The configuration matches and is better than the previous selection.
+        // Find the entry value if it exists for this configuration.
+        const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx);
+        if (offset == ResTable_type::NO_ENTRY) {
+          continue;
+        }
+
+        best_cookie = cookie;
+        best_package = loaded_package;
+        best_type = *iter;
+        best_config_copy = this_config;
+        best_config = &best_config_copy;
+        best_offset = offset;
+
+        if (resource_resolution_logging_enabled_) {
+          resolution_steps.push_back(Resolution::Step{resolution_type,
+                                                      this_config.toString(),
+                                                      &loaded_package->GetPackageName()});
         }
       }
     }
@@ -478,9 +510,95 @@
   out_entry->entry_string_ref =
       StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
   out_entry->dynamic_ref_table = &package_group.dynamic_ref_table;
+
+  if (resource_resolution_logging_enabled_) {
+    last_resolution.resid = resid;
+    last_resolution.cookie = best_cookie;
+    last_resolution.steps = resolution_steps;
+
+    // Cache only the type/entry refs since that's all that's needed to build name
+    last_resolution.type_string_ref =
+        StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1);
+    last_resolution.entry_string_ref =
+        StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
+  }
+
   return best_cookie;
 }
 
+void AssetManager2::SetResourceResolutionLoggingEnabled(bool enabled) {
+  resource_resolution_logging_enabled_ = enabled;
+
+  if (!enabled) {
+    last_resolution.cookie = kInvalidCookie;
+    last_resolution.resid = 0;
+    last_resolution.steps.clear();
+    last_resolution.type_string_ref = StringPoolRef();
+    last_resolution.entry_string_ref = StringPoolRef();
+  }
+}
+
+std::string AssetManager2::GetLastResourceResolution() const {
+  if (!resource_resolution_logging_enabled_) {
+    LOG(ERROR) << "Must enable resource resolution logging before getting path.";
+    return std::string();
+  }
+
+  auto cookie = last_resolution.cookie;
+  if (cookie == kInvalidCookie) {
+    LOG(ERROR) << "AssetManager hasn't resolved a resource to read resolution path.";
+    return std::string();
+  }
+
+  uint32_t resid = last_resolution.resid;
+  std::vector<Resolution::Step>& steps = last_resolution.steps;
+
+  ResourceName resource_name;
+  std::string resource_name_string;
+
+  const LoadedPackage* package =
+      apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
+
+  if (package != nullptr) {
+    ToResourceName(last_resolution.type_string_ref,
+                   last_resolution.entry_string_ref,
+                   package,
+                   &resource_name);
+    resource_name_string = ToFormattedResourceString(&resource_name);
+  }
+
+  std::stringstream log_stream;
+  log_stream << base::StringPrintf("Resolution for 0x%08x ", resid)
+            << resource_name_string
+            << "\n\tFor config -"
+            << configuration_.toString();
+
+  std::string prefix;
+  for (Resolution::Step step : steps) {
+    switch (step.type) {
+      case Resolution::Step::Type::INITIAL:
+        prefix = "Found initial";
+        break;
+      case Resolution::Step::Type::BETTER_MATCH:
+        prefix = "Found better";
+        break;
+      case Resolution::Step::Type::OVERLAID:
+        prefix = "Overlaid";
+        break;
+    }
+
+    if (!prefix.empty()) {
+      log_stream << "\n\t" << prefix << ": " << *step.package_name;
+
+      if (!step.config_name.isEmpty()) {
+        log_stream << " -" << step.config_name;
+      }
+    }
+  }
+
+  return log_stream.str();
+}
+
 bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const {
   FindEntryResult entry;
   ApkAssetsCookie cookie =
@@ -495,27 +613,10 @@
     return false;
   }
 
-  out_name->package = package->GetPackageName().data();
-  out_name->package_len = package->GetPackageName().size();
-
-  out_name->type = entry.type_string_ref.string8(&out_name->type_len);
-  out_name->type16 = nullptr;
-  if (out_name->type == nullptr) {
-    out_name->type16 = entry.type_string_ref.string16(&out_name->type_len);
-    if (out_name->type16 == nullptr) {
-      return false;
-    }
-  }
-
-  out_name->entry = entry.entry_string_ref.string8(&out_name->entry_len);
-  out_name->entry16 = nullptr;
-  if (out_name->entry == nullptr) {
-    out_name->entry16 = entry.entry_string_ref.string16(&out_name->entry_len);
-    if (out_name->entry16 == nullptr) {
-      return false;
-    }
-  }
-  return true;
+  return ToResourceName(entry.type_string_ref,
+                        entry.entry_string_ref,
+                        package,
+                        out_name);
 }
 
 bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const {
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index 3dc1f2c..18d74ef 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -286,6 +286,7 @@
     value.dataType = Res_value::TYPE_NULL;
     value.data = Res_value::DATA_NULL_UNDEFINED;
     config.density = 0;
+    uint32_t source_style_resid = 0;
 
     // Try to find a value for this attribute...  we prioritize values
     // coming from, first XML attributes, then XML style, then default
@@ -309,6 +310,7 @@
         cookie = entry->cookie;
         type_set_flags = style_flags;
         value = entry->value;
+        source_style_resid = entry->style;
         if (kDebugStyles) {
           ALOGI("-> From style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data,
               entry->style);
@@ -325,8 +327,10 @@
         type_set_flags = def_style_flags;
         value = entry->value;
         if (kDebugStyles) {
-          ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
+          ALOGI("-> From def style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data,
+              entry->style);
         }
+        source_style_resid = entry->style;
       }
     }
 
@@ -382,6 +386,7 @@
     out_values[STYLE_RESOURCE_ID] = resid;
     out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
     out_values[STYLE_DENSITY] = config.density;
+    out_values[SYTLE_SOURCE_STYLE] = source_style_resid;
 
     if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
       indices_idx++;
diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp
index 5694115..a99e77f 100644
--- a/libs/androidfw/CursorWindow.cpp
+++ b/libs/androidfw/CursorWindow.cpp
@@ -94,7 +94,7 @@
         if (size < 0) {
             result = UNKNOWN_ERROR;
         } else {
-            int dupAshmemFd = ::dup(ashmemFd);
+            int dupAshmemFd = ::fcntl(ashmemFd, F_DUPFD_CLOEXEC, 0);
             if (dupAshmemFd < 0) {
                 result = -errno;
             } else {
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 5a26780..70ce9bc 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -593,7 +593,12 @@
           return {};
         }
 
-        // Iterate over the overlayable policy chunks
+        std::string name;
+        util::ReadUtf16StringFromDevice(header->name, arraysize(header->name), &name);
+        std::string actor;
+        util::ReadUtf16StringFromDevice(header->actor, arraysize(header->actor), &actor);
+
+        // Iterate over the overlayable policy chunks contained within the overlayable chunk data
         ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
         while (overlayable_iter.HasNext()) {
           const Chunk overlayable_child_chunk = overlayable_iter.Next();
@@ -613,7 +618,7 @@
                 return {};
               }
 
-              // Retrieve all the ids belonging to this policy
+              // Retrieve all the resource ids belonging to this policy chunk
               std::unordered_set<uint32_t> ids;
               const auto ids_begin =
                   reinterpret_cast<const ResTable_ref*>(overlayable_child_chunk.data_ptr());
@@ -622,8 +627,10 @@
                 ids.insert(dtohl(id_iter->ident));
               }
 
-              // Add the pairing of overlayable properties to resource ids to the package
+              // Add the pairing of overlayable properties and resource ids to the package
               OverlayableInfo overlayable_info{};
+              overlayable_info.name = name;
+              overlayable_info.actor = actor;
               overlayable_info.policy_flags = policy_header->policy_flags;
               loaded_package->overlayable_infos_.push_back(std::make_pair(overlayable_info, ids));
               break;
@@ -636,7 +643,7 @@
         }
 
         if (overlayable_iter.HadError()) {
-          LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_POLICY_TYPE: %s",
+          LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_TYPE: %s",
                                      overlayable_iter.GetLastError().c_str());
           if (overlayable_iter.HadFatalError()) {
             return {};
diff --git a/libs/androidfw/ResourceUtils.cpp b/libs/androidfw/ResourceUtils.cpp
index d63feb01..645984d 100644
--- a/libs/androidfw/ResourceUtils.cpp
+++ b/libs/androidfw/ResourceUtils.cpp
@@ -48,4 +48,65 @@
          !(has_type_separator && out_type->empty());
 }
 
+bool ToResourceName(StringPoolRef& type_string_ref,
+                    StringPoolRef& entry_string_ref,
+                    const LoadedPackage* package,
+                    AssetManager2::ResourceName* out_name) {
+  out_name->package = package->GetPackageName().data();
+  out_name->package_len = package->GetPackageName().size();
+
+  out_name->type = type_string_ref.string8(&out_name->type_len);
+  out_name->type16 = nullptr;
+  if (out_name->type == nullptr) {
+    out_name->type16 = type_string_ref.string16(&out_name->type_len);
+    if (out_name->type16 == nullptr) {
+      return false;
+    }
+  }
+
+  out_name->entry = entry_string_ref.string8(&out_name->entry_len);
+  out_name->entry16 = nullptr;
+  if (out_name->entry == nullptr) {
+    out_name->entry16 = entry_string_ref.string16(&out_name->entry_len);
+    if (out_name->entry16 == nullptr) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name) {
+  std::string result;
+  if (resource_name->package != nullptr) {
+    result.append(resource_name->package, resource_name->package_len);
+  }
+
+  if (resource_name->type != nullptr || resource_name->type16 != nullptr) {
+    if (!result.empty()) {
+      result += ":";
+    }
+
+    if (resource_name->type != nullptr) {
+      result.append(resource_name->type, resource_name->type_len);
+    } else {
+      result += util::Utf16ToUtf8(StringPiece16(resource_name->type16, resource_name->type_len));
+    }
+  }
+
+  if (resource_name->entry != nullptr || resource_name->entry16 != nullptr) {
+    if (!result.empty()) {
+      result += "/";
+    }
+
+    if (resource_name->entry != nullptr) {
+      result.append(resource_name->entry, resource_name->entry_len);
+    } else {
+      result += util::Utf16ToUtf8(StringPiece16(resource_name->entry16, resource_name->entry_len));
+    }
+  }
+
+  return result;
+}
+
 }  // namespace android
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 0d49298..f29769b 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -229,6 +229,14 @@
                                    ResTable_config* in_out_selected_config, uint32_t* in_out_flags,
                                    uint32_t* out_last_reference) const;
 
+  // Enables or disables resource resolution logging. Clears stored steps when
+  // disabled.
+  void SetResourceResolutionLoggingEnabled(bool enabled);
+
+  // Returns formatted log of last resource resolution path, or empty if no
+  // resource has been resolved yet.
+  std::string GetLastResourceResolution() const;
+
   // Retrieves the best matching bag/map resource with ID `resid`.
   // This method will resolve all parent references for this bag and merge keys with the child.
   // To iterate over the keys, use the following idiom:
@@ -346,6 +354,48 @@
   // Cached set of bags. These are cached because they can inherit keys from parent bags,
   // which involves some calculation.
   std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_;
+
+  // Whether or not to save resource resolution steps
+  bool resource_resolution_logging_enabled_ = false;
+
+  struct Resolution {
+
+    struct Step {
+
+      enum class Type {
+        INITIAL,
+        BETTER_MATCH,
+        OVERLAID
+      };
+
+      // Marks what kind of override this step was.
+      Type type;
+
+      // Built name of configuration for this step.
+      String8 config_name;
+
+      // Marks the package name of the better resource found in this step.
+      const std::string* package_name;
+    };
+
+    // Last resolved resource ID.
+    uint32_t resid;
+
+    // Last resolved resource result cookie.
+    ApkAssetsCookie cookie = kInvalidCookie;
+
+    // Last resolved resource type.
+    StringPoolRef type_string_ref;
+
+    // Last resolved resource entry.
+    StringPoolRef entry_string_ref;
+
+    // Steps taken to resolve last resource.
+    std::vector<Step> steps;
+  };
+
+  // Record of the last resolved resource's resolution path.
+  mutable Resolution last_resolution;
 };
 
 class Theme {
diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h
index 35ef98d..c88004c 100644
--- a/libs/androidfw/include/androidfw/AttributeResolution.h
+++ b/libs/androidfw/include/androidfw/AttributeResolution.h
@@ -23,15 +23,17 @@
 namespace android {
 
 // Offsets into the outValues array populated by the methods below. outValues is a uint32_t
-// array, but each logical element takes up 6 uint32_t-sized physical elements.
+// array, but each logical element takes up 7 uint32_t-sized physical elements.
+// Keep these in sync with android.content.res.TypedArray java class
 enum {
-  STYLE_NUM_ENTRIES = 6,
+  STYLE_NUM_ENTRIES = 7,
   STYLE_TYPE = 0,
   STYLE_DATA = 1,
   STYLE_ASSET_COOKIE = 2,
   STYLE_RESOURCE_ID = 3,
   STYLE_CHANGING_CONFIGURATIONS = 4,
-  STYLE_DENSITY = 5
+  STYLE_DENSITY = 5,
+  SYTLE_SOURCE_STYLE = 6
 };
 
 // These are all variations of the same method. They each perform the exact same operation,
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 8c5c3b7..be62f30 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -78,6 +78,8 @@
 using TypeSpecPtr = util::unique_cptr<TypeSpec>;
 
 struct OverlayableInfo {
+  std::string name;
+  std::string actor;
   uint32_t policy_flags;
 };
 
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 9b05d1f..1655e89 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1611,6 +1611,12 @@
 struct ResTable_overlayable_header
 {
   struct ResChunk_header header;
+
+  // The name of the overlayable set of resources that overlays target.
+  uint16_t name[256];
+
+ // The component responsible for enabling and disabling overlays targeting this chunk.
+  uint16_t actor[256];
 };
 
 /**
@@ -1637,10 +1643,6 @@
     // The overlay must reside of the product partition or must have existed on the product
     // partition before an upgrade to overlay these resources.
     POLICY_PRODUCT_PARTITION = 0x00000008,
-
-    // The overlay must reside of the product services partition or must have existed on the product
-    // services partition before an upgrade to overlay these resources.
-    POLICY_PRODUCT_SERVICES_PARTITION = 0x00000010,
   };
   uint32_t policy_flags;
 
diff --git a/libs/androidfw/include/androidfw/ResourceUtils.h b/libs/androidfw/include/androidfw/ResourceUtils.h
index d94779b..eb6eb8e 100644
--- a/libs/androidfw/include/androidfw/ResourceUtils.h
+++ b/libs/androidfw/include/androidfw/ResourceUtils.h
@@ -17,6 +17,7 @@
 #ifndef ANDROIDFW_RESOURCEUTILS_H
 #define ANDROIDFW_RESOURCEUTILS_H
 
+#include "androidfw/AssetManager2.h"
 #include "androidfw/StringPiece.h"
 
 namespace android {
@@ -27,6 +28,17 @@
 bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, StringPiece* out_type,
                          StringPiece* out_entry);
 
+// Convert a type_string_ref, entry_string_ref, and package
+// to AssetManager2::ResourceName. Useful for getting
+// resource name without re-running AssetManager2::FindEntry searches.
+bool ToResourceName(StringPoolRef& type_string_ref,
+                    StringPoolRef& entry_string_ref,
+                    const LoadedPackage* package,
+                    AssetManager2::ResourceName* out_name);
+
+// Formats a ResourceName to "package:type/entry_name".
+std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name);
+
 inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) {
   return (resid & 0x00ffffffu) | (static_cast<uint32_t>(package_id) << 24);
 }
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 5449a54..105dcd2 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -586,4 +586,111 @@
   EXPECT_THAT(asset_dir->getFileType(2), Eq(FileType::kFileTypeDirectory));
 }
 
+TEST_F(AssetManager2Test, GetLastPathWithoutEnablingReturnsEmpty) {
+  ResTable_config desired_config;
+
+  AssetManager2 assetmanager;
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({basic_assets_.get()});
+  assetmanager.SetResourceResolutionLoggingEnabled(false);
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ApkAssetsCookie cookie =
+      assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+                               0 /*density_override*/, &value, &selected_config, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+
+  auto result = assetmanager.GetLastResourceResolution();
+  EXPECT_EQ("", result);
+}
+
+TEST_F(AssetManager2Test, GetLastPathWithoutResolutionReturnsEmpty) {
+  ResTable_config desired_config;
+
+  AssetManager2 assetmanager;
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({basic_assets_.get()});
+
+  auto result = assetmanager.GetLastResourceResolution();
+  EXPECT_EQ("", result);
+}
+
+TEST_F(AssetManager2Test, GetLastPathWithSingleApkAssets) {
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+  desired_config.language[0] = 'd';
+  desired_config.language[1] = 'e';
+
+  AssetManager2 assetmanager;
+  assetmanager.SetResourceResolutionLoggingEnabled(true);
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({basic_assets_.get()});
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ApkAssetsCookie cookie =
+      assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+                               0 /*density_override*/, &value, &selected_config, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+
+  auto result = assetmanager.GetLastResourceResolution();
+  EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n\tFor config -de\n\tFound initial: com.android.basic", result);
+}
+
+TEST_F(AssetManager2Test, GetLastPathWithMultipleApkAssets) {
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+  desired_config.language[0] = 'd';
+  desired_config.language[1] = 'e';
+
+  AssetManager2 assetmanager;
+  assetmanager.SetResourceResolutionLoggingEnabled(true);
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({basic_assets_.get(), basic_de_fr_assets_.get()});
+
+  Res_value value = Res_value();
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ApkAssetsCookie cookie =
+      assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+                               0 /*density_override*/, &value, &selected_config, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+
+  auto result = assetmanager.GetLastResourceResolution();
+  EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n\tFor config -de\n\tFound initial: com.android.basic\n\tFound better: com.android.basic -de", result);
+}
+
+TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) {
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+
+  AssetManager2 assetmanager;
+  assetmanager.SetResourceResolutionLoggingEnabled(true);
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({basic_assets_.get()});
+
+  Res_value value = Res_value();
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ApkAssetsCookie cookie =
+      assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+                               0 /*density_override*/, &value, &selected_config, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+
+  auto resultEnabled = assetmanager.GetLastResourceResolution();
+  ASSERT_NE("", resultEnabled);
+
+  assetmanager.SetResourceResolutionLoggingEnabled(false);
+
+  auto resultDisabled = assetmanager.GetLastResourceResolution();
+  EXPECT_EQ("", resultDisabled);
+}
+
 }  // namespace android
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 22d587a..b8d3c6b 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -294,22 +294,29 @@
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable1);
   ASSERT_THAT(info, NotNull());
+  EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+  EXPECT_THAT(info->actor, Eq("overlay://theme"));
   EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable2);
   ASSERT_THAT(info, NotNull());
+  EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+  EXPECT_THAT(info->actor, Eq("overlay://theme"));
   EXPECT_THAT(info->policy_flags,
               Eq(ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION
                  | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable3);
   ASSERT_THAT(info, NotNull());
+  EXPECT_THAT(info->name, Eq("OverlayableResources2"));
+  EXPECT_THAT(info->actor, Eq("overlay://com.android.overlayable"));
   EXPECT_THAT(info->policy_flags,
               Eq(ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION
-                 | ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION
                  | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable4);
+  EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+  EXPECT_THAT(info->actor, Eq("overlay://theme"));
   ASSERT_THAT(info, NotNull());
   EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
 }
diff --git a/libs/androidfw/tests/data/overlayable/overlayable.apk b/libs/androidfw/tests/data/overlayable/overlayable.apk
index 85ab4be..047e6af 100644
--- a/libs/androidfw/tests/data/overlayable/overlayable.apk
+++ b/libs/androidfw/tests/data/overlayable/overlayable.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
index 11aa735..fcdbe94 100644
--- a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
+++ b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
@@ -15,7 +15,7 @@
 -->
 
 <resources>
-<overlayable>
+<overlayable name="OverlayableResources1" actor="overlay://theme">
     <!-- Any overlay can overlay the value of @string/overlayable1 -->
     <item type="string" name="overlayable1" />
 
@@ -31,10 +31,10 @@
     </policy>
 </overlayable>
 
-<overlayable>
-    <!-- Any overlay on the product_services, vendor, or product partition can overlay the value of
-   @string/overlayable3 -->
-    <policy type="product_services|vendor|product">
+<overlayable name="OverlayableResources2" actor="overlay://com.android.overlayable">
+    <!-- Any overlay on the vendor or product partition can overlay the value of
+        @string/overlayable3 -->
+    <policy type="vendor|product">
         <item type="string" name="overlayable3" />
     </policy>
 </overlayable>
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index ed167e5..56b1885 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -79,8 +79,7 @@
     switch (wcgDataspace) {
         case ui::Dataspace::DISPLAY_P3:
             *colorGamut = SkColorSpace::Gamut::kDCIP3_D65_Gamut;
-            *colorSpace = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
-                                                SkColorSpace::Gamut::kDCIP3_D65_Gamut);
+            *colorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
             break;
         case ui::Dataspace::V0_SCRGB:
             *colorGamut = SkColorSpace::Gamut::kSRGB_Gamut;
diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp
index 9170d6d..68541b4 100644
--- a/libs/hwui/WebViewFunctorManager.cpp
+++ b/libs/hwui/WebViewFunctorManager.cpp
@@ -86,6 +86,26 @@
     mCallbacks.gles.draw(mFunctor, mData, drawInfo);
 }
 
+void WebViewFunctor::initVk(const VkFunctorInitParams& params) {
+    ATRACE_NAME("WebViewFunctor::initVk");
+    if (!mHasContext) {
+        mHasContext = true;
+    } else {
+        return;
+    }
+    mCallbacks.vk.initialize(mFunctor, mData, params);
+}
+
+void WebViewFunctor::drawVk(const VkFunctorDrawParams& params) {
+    ATRACE_NAME("WebViewFunctor::drawVk");
+    mCallbacks.vk.draw(mFunctor, mData, params);
+}
+
+void WebViewFunctor::postDrawVk() {
+    ATRACE_NAME("WebViewFunctor::postDrawVk");
+    mCallbacks.vk.postDraw(mFunctor, mData);
+}
+
 void WebViewFunctor::destroyContext() {
     if (mHasContext) {
         mHasContext = false;
diff --git a/libs/hwui/WebViewFunctorManager.h b/libs/hwui/WebViewFunctorManager.h
index 1719ce7..2846cb1 100644
--- a/libs/hwui/WebViewFunctorManager.h
+++ b/libs/hwui/WebViewFunctorManager.h
@@ -42,6 +42,12 @@
 
         void drawGl(const DrawGlInfo& drawInfo) const { mReference.drawGl(drawInfo); }
 
+        void initVk(const VkFunctorInitParams& params) { mReference.initVk(params); }
+
+        void drawVk(const VkFunctorDrawParams& params) { mReference.drawVk(params); }
+
+        void postDrawVk() { mReference.postDrawVk(); }
+
     private:
         friend class WebViewFunctor;
 
@@ -53,6 +59,9 @@
     int id() const { return mFunctor; }
     void sync(const WebViewSyncData& syncData) const;
     void drawGl(const DrawGlInfo& drawInfo);
+    void initVk(const VkFunctorInitParams& params);
+    void drawVk(const VkFunctorDrawParams& params);
+    void postDrawVk();
     void destroyContext();
 
     sp<Handle> createHandle() {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 4338b1c..e6e6b0e 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -96,7 +96,7 @@
 
     SkASSERT(mRenderThread.getGrContext() != nullptr);
     sk_sp<SkSurface> surface(SkSurface::MakeFromBackendRenderTarget(
-            mRenderThread.getGrContext(), backendRT, kBottomLeft_GrSurfaceOrigin, colorType,
+            mRenderThread.getGrContext(), backendRT, this->getSurfaceOrigin(), colorType,
             mSurfaceColorSpace, &props));
 
     SkiaPipeline::updateLighting(lightGeometry, lightInfo);
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 47991069..6692922 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -39,6 +39,7 @@
               const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
               const std::vector<sp<RenderNode> >& renderNodes,
               FrameInfoVisualizer* profiler) override;
+    GrSurfaceOrigin getSurfaceOrigin() override { return kBottomLeft_GrSurfaceOrigin; }
     bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
                      FrameInfo* currentFrameInfo, bool* requireSwap) override;
     DeferredLayerUpdater* createTextureLayer() override;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 2e7850d..d7faaf7 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -174,7 +174,8 @@
         SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
         SkASSERT(mRenderThread.getGrContext() != nullptr);
         node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
-                                                          SkBudgeted::kYes, info, 0, &props));
+                                                          SkBudgeted::kYes, info, 0,
+                                                          this->getSurfaceOrigin(), &props));
         if (node->getLayerSurface()) {
             // update the transform in window of the layer to reset its origin wrt light source
             // position
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index ff87313..94a699b 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -48,7 +48,7 @@
     bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
                              ErrorHandler* errorHandler) override;
 
-    SkColorType getSurfaceColorType() const { return mSurfaceColorType; }
+    SkColorType getSurfaceColorType() const override { return mSurfaceColorType; }
     sk_sp<SkColorSpace> getSurfaceColorSpace() override { return mSurfaceColorSpace; }
 
     void renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 6eefed9..d54275f 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -125,8 +125,6 @@
                                              uirenderer::GlFunctorLifecycleListener* listener) {
     FunctorDrawable* functorDrawable;
     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
-        // TODO(cblume) use VkFunctorDrawable instead of VkInteropFunctorDrawable here when the
-        // interop is disabled/moved.
         functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(
                 functor, listener, asSkCanvas());
     } else {
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 53ffc44..9343076 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -35,6 +35,7 @@
               const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
               const std::vector<sp<RenderNode> >& renderNodes,
               FrameInfoVisualizer* profiler) override;
+    GrSurfaceOrigin getSurfaceOrigin() override { return kTopLeft_GrSurfaceOrigin; }
     bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
                      FrameInfo* currentFrameInfo, bool* requireSwap) override;
     DeferredLayerUpdater* createTextureLayer() override;
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index 156f74a..2f8d381 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -17,6 +17,8 @@
 #include "VkFunctorDrawable.h"
 #include <private/hwui/DrawVkInfo.h>
 
+#include "renderthread/VulkanManager.h"
+#include "renderthread/RenderThread.h"
 #include <GrBackendDrawableInfo.h>
 #include <SkImage.h>
 #include <utils/Color.h>
@@ -31,34 +33,58 @@
 namespace uirenderer {
 namespace skiapipeline {
 
-VkFunctorDrawHandler::VkFunctorDrawHandler(Functor* functor) : INHERITED(), mFunctor(functor) {}
+VkFunctorDrawHandler::VkFunctorDrawHandler(sp<WebViewFunctor::Handle> functor_handle,
+                                           const SkMatrix& matrix, const SkIRect& clip,
+                                           const SkImageInfo& image_info)
+        : INHERITED()
+        , mFunctorHandle(functor_handle)
+        , mMatrix(matrix)
+        , mClip(clip)
+        , mImageInfo(image_info) {}
 
 VkFunctorDrawHandler::~VkFunctorDrawHandler() {
-    // TODO(cblume) Fill in the DrawVkInfo parameters.
-    (*mFunctor)(DrawVkInfo::kModePostComposite, nullptr);
+    mFunctorHandle->postDrawVk();
 }
 
 void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) {
     ATRACE_CALL();
+    if (!renderthread::RenderThread::isCurrent())
+        LOG_ALWAYS_FATAL("VkFunctorDrawHandler::draw not called on render thread");
 
     GrVkDrawableInfo vulkan_info;
     if (!info.getVkDrawableInfo(&vulkan_info)) {
         return;
     }
+    renderthread::VulkanManager& vk_manager =
+            renderthread::RenderThread::getInstance().vulkanManager();
+    mFunctorHandle->initVk(vk_manager.getVkFunctorInitParams());
 
-    DrawVkInfo draw_vk_info;
-    // TODO(cblume) Fill in the rest of the parameters and test the actual call.
-    draw_vk_info.isLayer = true;
+    SkMatrix44 mat4(mMatrix);
+    VkFunctorDrawParams params{
+      .width = mImageInfo.width(),
+      .height = mImageInfo.height(),
+      .is_layer = false,  // TODO(boliu): Populate is_layer.
+      .color_space_ptr = mImageInfo.colorSpace(),
+      .clip_left = mClip.fLeft,
+      .clip_top = mClip.fTop,
+      .clip_right = mClip.fRight,
+      .clip_bottom = mClip.fBottom,
+    };
+    mat4.asColMajorf(&params.transform[0]);
+    params.secondary_command_buffer = vulkan_info.fSecondaryCommandBuffer;
+    params.color_attachment_index = vulkan_info.fColorAttachmentIndex;
+    params.compatible_render_pass = vulkan_info.fCompatibleRenderPass;
+    params.format = vulkan_info.fFormat;
 
-    (*mFunctor)(DrawVkInfo::kModeComposite, &draw_vk_info);
+    mFunctorHandle->drawVk(params);
+
+    vulkan_info.fDrawBounds->offset.x = mClip.fLeft;
+    vulkan_info.fDrawBounds->offset.y = mClip.fTop;
+    vulkan_info.fDrawBounds->extent.width = mClip.fRight - mClip.fLeft;
+    vulkan_info.fDrawBounds->extent.height = mClip.fBottom - mClip.fTop;
 }
 
 VkFunctorDrawable::~VkFunctorDrawable() {
-    if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) {
-        if (lp->listener) {
-            lp->listener->onGlFunctorReleased(lp->functor);
-        }
-    }
 }
 
 void VkFunctorDrawable::onDraw(SkCanvas* /*canvas*/) {
@@ -67,16 +93,17 @@
 }
 
 std::unique_ptr<FunctorDrawable::GpuDrawHandler> VkFunctorDrawable::onSnapGpuDrawHandler(
-        GrBackendApi backendApi, const SkMatrix& matrix) {
+        GrBackendApi backendApi, const SkMatrix& matrix, const SkIRect& clip,
+        const SkImageInfo& image_info) {
     if (backendApi != GrBackendApi::kVulkan) {
         return nullptr;
     }
     std::unique_ptr<VkFunctorDrawHandler> draw;
     if (mAnyFunctor.index() == 0) {
-        LOG_ALWAYS_FATAL("Not implemented");
-        return nullptr;
+        return std::make_unique<VkFunctorDrawHandler>(std::get<0>(mAnyFunctor).handle, matrix, clip,
+                                                      image_info);
     } else {
-        return std::make_unique<VkFunctorDrawHandler>(std::get<1>(mAnyFunctor).functor);
+        LOG_ALWAYS_FATAL("Not implemented");
     }
 }
 
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
index d6fefc1..1a53c8f 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
@@ -32,15 +32,18 @@
  */
 class VkFunctorDrawHandler : public FunctorDrawable::GpuDrawHandler {
 public:
-    explicit VkFunctorDrawHandler(Functor* functor);
+    VkFunctorDrawHandler(sp<WebViewFunctor::Handle> functor_handle, const SkMatrix& matrix,
+                         const SkIRect& clip, const SkImageInfo& image_info);
     ~VkFunctorDrawHandler() override;
 
     void draw(const GrBackendDrawableInfo& info) override;
 
 private:
     typedef GpuDrawHandler INHERITED;
-
-    Functor* mFunctor;
+    sp<WebViewFunctor::Handle> mFunctorHandle;
+    const SkMatrix mMatrix;
+    const SkIRect mClip;
+    const SkImageInfo mImageInfo;
 };
 
 /**
@@ -57,7 +60,8 @@
     // SkDrawable functions:
     void onDraw(SkCanvas* canvas) override;
     std::unique_ptr<FunctorDrawable::GpuDrawHandler> onSnapGpuDrawHandler(
-            GrBackendApi backendApi, const SkMatrix& matrix) override;
+            GrBackendApi backendApi, const SkMatrix& matrix, const SkIRect& clip,
+            const SkImageInfo& image_info) override;
 };
 
 }  // namespace skiapipeline
diff --git a/libs/hwui/private/hwui/DrawVkInfo.h b/libs/hwui/private/hwui/DrawVkInfo.h
index b2351fc..abc4dbf 100644
--- a/libs/hwui/private/hwui/DrawVkInfo.h
+++ b/libs/hwui/private/hwui/DrawVkInfo.h
@@ -17,89 +17,61 @@
 #ifndef ANDROID_HWUI_DRAW_VK_INFO_H
 #define ANDROID_HWUI_DRAW_VK_INFO_H
 
+#include <SkColorSpace.h>
 #include <vulkan/vulkan.h>
 
 namespace android {
 namespace uirenderer {
 
-/**
- * Structure used by VulkanRenderer::callDrawVKFunction() to pass and receive data from Vulkan
- * functors.
- */
-struct DrawVkInfo {
-    // Input: current width/height of destination surface
-    int width;
-    int height;
+struct VkFunctorInitParams {
+  VkInstance instance;
+  VkPhysicalDevice physical_device;
+  VkDevice device;
+  VkQueue queue;
+  uint32_t graphics_queue_index;
+  uint32_t instance_version;
+  const char* const* enabled_instance_extension_names;
+  uint32_t enabled_instance_extension_names_length;
+  const char* const* enabled_device_extension_names;
+  uint32_t enabled_device_extension_names_length;
+  const VkPhysicalDeviceFeatures2* device_features_2;
+};
 
-    // Input: is the render target an FBO
-    bool isLayer;
+struct VkFunctorDrawParams {
+  // Input: current width/height of destination surface.
+  int width;
+  int height;
 
-    // Input: current transform matrix, in OpenGL format
-    float transform[16];
+  // Input: is the render target a FBO
+  bool is_layer;
 
-    // Input: WebView should do its main compositing draws into this. It cannot do anything that
-    // would require stopping the render pass.
-    VkCommandBuffer secondaryCommandBuffer;
+  // Input: current transform matrix
+  float transform[16];
 
-    // Input: The main color attachment index where secondaryCommandBuffer will eventually be
-    // submitted.
-    uint32_t colorAttachmentIndex;
+  // Input WebView should do its main compositing draws into this. It cannot do
+  // anything that would require stopping the render pass.
+  VkCommandBuffer secondary_command_buffer;
 
-    // Input: A render pass which will be compatible to the one which the secondaryCommandBuffer
-    // will be submitted into.
-    VkRenderPass compatibleRenderPass;
+  // Input: The main color attachment index where secondary_command_buffer will
+  // eventually be submitted.
+  uint32_t color_attachment_index;
 
-    // Input: Format of the destination surface.
-    VkFormat format;
+  // Input: A render pass which will be compatible to the one which the
+  // secondary_command_buffer will be submitted into.
+  VkRenderPass compatible_render_pass;
 
-    // Input: Color space transfer params
-    float g;
-    float a;
-    float b;
-    float c;
-    float d;
-    float e;
-    float f;
+  // Input: Format of the destination surface.
+  VkFormat format;
 
-    // Input: Color space transformation from linear RGB to D50-adapted XYZ
-    float colorSpaceTransform[9];
+  // Input: Color space.
+  const SkColorSpace* color_space_ptr;
 
-    // Input: current clip rect
-    int clipLeft;
-    int clipTop;
-    int clipRight;
-    int clipBottom;
-
-    /**
-     * Values used as the "what" parameter of the functor.
-     */
-    enum Mode {
-        // Called once at WebView start
-        kModeInit,
-        // Called when things need to be re-created
-        kModeReInit,
-        // Notifies the app that the composite functor will be called soon. This allows WebView to
-        // begin work early.
-        kModePreComposite,
-        // Do the actual composite work
-        kModeComposite,
-        // This allows WebView to begin using the previously submitted objects in future work.
-        kModePostComposite,
-        // Invoked every time the UI thread pushes over a frame to the render thread and the owning
-        // view has a dirty display list*. This is a signal to sync any data that needs to be
-        // shared between the UI thread and the render thread. During this time the UI thread is
-        // blocked.
-        kModeSync
-    };
-
-    /**
-     * Values used by Vulkan functors to tell the framework what to do next.
-     */
-    enum Status {
-        // The functor is done
-        kStatusDone = 0x0,
-    };
-};  // struct DrawVkInfo
+  // Input: current clip rect
+  int clip_left;
+  int clip_top;
+  int clip_right;
+  int clip_bottom;
+};
 
 }  // namespace uirenderer
 }  // namespace android
diff --git a/libs/hwui/private/hwui/WebViewFunctor.h b/libs/hwui/private/hwui/WebViewFunctor.h
index da3d06a..96da947 100644
--- a/libs/hwui/private/hwui/WebViewFunctor.h
+++ b/libs/hwui/private/hwui/WebViewFunctor.h
@@ -19,6 +19,7 @@
 
 #include <cutils/compiler.h>
 #include <private/hwui/DrawGlInfo.h>
+#include <private/hwui/DrawVkInfo.h>
 
 namespace android::uirenderer {
 
@@ -52,18 +53,12 @@
             // Called on RenderThread. initialize is guaranteed to happen before this call
             void (*draw)(int functor, void* data, const DrawGlInfo& params);
         } gles;
-        // TODO: VK support. The current DrawVkInfo is monolithic and needs to be split up for
-        // what params are valid on what callbacks
         struct {
             // Called either the first time the functor is used or the first time it's used after
             // a call to onContextDestroyed.
-            // void (*initialize)(int functor, const InitParams& params);
-            // void (*frameStart)(int functor, /* todo: what params are actually needed for this to
-            // be useful? Is this useful? */)
-            // void (*draw)(int functor, const CompositeParams& params /* todo: rename - composite
-            // almost always means something else, and we aren't compositing */);
-            // void (*frameEnd)(int functor, const PostCompositeParams& params /* todo: same as
-            // CompositeParams - rename */);
+            void (*initialize)(int functor, void* data, const VkFunctorInitParams& params);
+            void (*draw)(int functor, void* data, const VkFunctorDrawParams& params);
+            void (*postDraw)(int functor, void*);
         } vk;
     };
 };
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 42e17b273..d4dd629 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -84,6 +84,7 @@
     virtual void onPrepareTree() = 0;
     virtual SkColorType getSurfaceColorType() const = 0;
     virtual sk_sp<SkColorSpace> getSurfaceColorSpace() = 0;
+    virtual GrSurfaceOrigin getSurfaceOrigin() = 0;
 
     virtual ~IRenderPipeline() {}
 };
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index c06fadd..8bef359 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -171,6 +171,9 @@
     mRenderState = new RenderState(*this);
     mVkManager = new VulkanManager(*this);
     mCacheManager = new CacheManager(mDisplayInfo);
+    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+        mVkManager->initialize();
+    }
 }
 
 void RenderThread::requireGlContext() {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 5272227..1ef83fb 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -47,6 +47,10 @@
 class RenderState;
 class TestUtils;
 
+namespace skiapipeline {
+class VkFunctorDrawHandler;
+}
+
 namespace renderthread {
 
 class CanvasContext;
@@ -124,6 +128,7 @@
     friend class DummyVsyncSource;
     friend class android::uirenderer::TestUtils;
     friend class android::uirenderer::WebViewFunctor;
+    friend class android::uirenderer::skiapipeline::VkFunctorDrawHandler;
 
     RenderThread();
     virtual ~RenderThread();
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index aa7a141..6c540f6 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -34,6 +34,23 @@
 namespace uirenderer {
 namespace renderthread {
 
+static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& features) {
+    // All Vulkan structs that could be part of the features chain will start with the
+    // structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
+    // so we can get access to the pNext for the next struct.
+    struct CommonVulkanHeader {
+        VkStructureType sType;
+        void*           pNext;
+    };
+
+    void* pNext = features.pNext;
+    while (pNext) {
+        void* current = pNext;
+        pNext = static_cast<CommonVulkanHeader*>(current)->pNext;
+        free(current);
+    }
+}
+
 #define GET_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vk" #F)
 #define GET_INST_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(mInstance, "vk" #F)
 #define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(mDevice, "vk" #F)
@@ -66,6 +83,11 @@
     mDevice = VK_NULL_HANDLE;
     mPhysicalDevice = VK_NULL_HANDLE;
     mInstance = VK_NULL_HANDLE;
+    mInstanceVersion = 0u;
+    mInstanceExtensions.clear();
+    mDeviceExtensions.clear();
+    free_features_extensions_structs(mPhysicalDeviceFeatures2);
+    mPhysicalDeviceFeatures2 = {};
 }
 
 bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFeatures2& features) {
@@ -81,7 +103,6 @@
         VK_MAKE_VERSION(1, 1, 0),           // apiVersion
     };
 
-    std::vector<const char*> instanceExtensions;
     {
         GET_PROC(EnumerateInstanceExtensionProperties);
 
@@ -99,7 +120,7 @@
         bool hasKHRSurfaceExtension = false;
         bool hasKHRAndroidSurfaceExtension = false;
         for (uint32_t i = 0; i < extensionCount; ++i) {
-            instanceExtensions.push_back(extensions[i].extensionName);
+            mInstanceExtensions.push_back(extensions[i].extensionName);
             if (!strcmp(extensions[i].extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) {
                 hasKHRSurfaceExtension = true;
             }
@@ -120,8 +141,8 @@
         &app_info,                                 // pApplicationInfo
         0,                                         // enabledLayerNameCount
         nullptr,                                   // ppEnabledLayerNames
-        (uint32_t) instanceExtensions.size(),      // enabledExtensionNameCount
-        instanceExtensions.data(),                 // ppEnabledExtensionNames
+        (uint32_t) mInstanceExtensions.size(),     // enabledExtensionNameCount
+        mInstanceExtensions.data(),                // ppEnabledExtensionNames
     };
 
     GET_PROC(CreateInstance);
@@ -201,7 +222,6 @@
     // presentation with any native window. So just use the first one.
     mPresentQueueIndex = 0;
 
-    std::vector<const char*> deviceExtensions;
     {
         uint32_t extensionCount = 0;
         err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount,
@@ -220,7 +240,7 @@
         }
         bool hasKHRSwapchainExtension = false;
         for (uint32_t i = 0; i < extensionCount; ++i) {
-            deviceExtensions.push_back(extensions[i].extensionName);
+            mDeviceExtensions.push_back(extensions[i].extensionName);
             if (!strcmp(extensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
                 hasKHRSwapchainExtension = true;
             }
@@ -237,8 +257,8 @@
         }
         return vkGetInstanceProcAddr(instance, proc_name);
     };
-    grExtensions.init(getProc, mInstance, mPhysicalDevice, instanceExtensions.size(),
-            instanceExtensions.data(), deviceExtensions.size(), deviceExtensions.data());
+    grExtensions.init(getProc, mInstance, mPhysicalDevice, mInstanceExtensions.size(),
+            mInstanceExtensions.data(), mDeviceExtensions.size(), mDeviceExtensions.data());
 
     if (!grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
         this->destroy();
@@ -308,8 +328,8 @@
         queueInfo,                               // pQueueCreateInfos
         0,                                       // layerCount
         nullptr,                                 // ppEnabledLayerNames
-        (uint32_t) deviceExtensions.size(),      // extensionCount
-        deviceExtensions.data(),                 // ppEnabledExtensionNames
+        (uint32_t) mDeviceExtensions.size(),     // extensionCount
+        mDeviceExtensions.data(),                // ppEnabledExtensionNames
         nullptr,                                 // ppEnabledFeatures
     };
 
@@ -351,36 +371,17 @@
     return true;
 }
 
-static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& features) {
-    // All Vulkan structs that could be part of the features chain will start with the
-    // structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
-    // so we can get access to the pNext for the next struct.
-    struct CommonVulkanHeader {
-        VkStructureType sType;
-        void*           pNext;
-    };
-
-    void* pNext = features.pNext;
-    while (pNext) {
-        void* current = pNext;
-        pNext = static_cast<CommonVulkanHeader*>(current)->pNext;
-        free(current);
-    }
-}
-
 void VulkanManager::initialize() {
     if (mDevice != VK_NULL_HANDLE) {
         return;
     }
 
     GET_PROC(EnumerateInstanceVersion);
-    uint32_t instanceVersion = 0;
-    LOG_ALWAYS_FATAL_IF(mEnumerateInstanceVersion(&instanceVersion));
-    LOG_ALWAYS_FATAL_IF(instanceVersion < VK_MAKE_VERSION(1, 1, 0));
+    LOG_ALWAYS_FATAL_IF(mEnumerateInstanceVersion(&mInstanceVersion));
+    LOG_ALWAYS_FATAL_IF(mInstanceVersion < VK_MAKE_VERSION(1, 1, 0));
 
     GrVkExtensions extensions;
-    VkPhysicalDeviceFeatures2 features;
-    LOG_ALWAYS_FATAL_IF(!this->setupDevice(extensions, features));
+    LOG_ALWAYS_FATAL_IF(!this->setupDevice(extensions, mPhysicalDeviceFeatures2));
 
     mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
 
@@ -397,9 +398,9 @@
     backendContext.fDevice = mDevice;
     backendContext.fQueue = mGraphicsQueue;
     backendContext.fGraphicsQueueIndex = mGraphicsQueueIndex;
-    backendContext.fInstanceVersion = instanceVersion;
+    backendContext.fInstanceVersion = mInstanceVersion;
     backendContext.fVkExtensions = &extensions;
-    backendContext.fDeviceFeatures2 = &features;
+    backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2;
     backendContext.fGetProc = std::move(getProc);
 
     // create the command pool for the command buffers
@@ -433,13 +434,29 @@
     LOG_ALWAYS_FATAL_IF(!grContext.get());
     mRenderThread.setGrContext(grContext);
 
-    free_features_extensions_structs(features);
-
     if (Properties::enablePartialUpdates && Properties::useBufferAge) {
         mSwapBehavior = SwapBehavior::BufferAge;
     }
 }
 
+VkFunctorInitParams VulkanManager::getVkFunctorInitParams() const {
+    return VkFunctorInitParams{
+            .instance = mInstance,
+            .physical_device = mPhysicalDevice,
+            .device = mDevice,
+            .queue = mGraphicsQueue,
+            .graphics_queue_index = mGraphicsQueueIndex,
+            .instance_version = mInstanceVersion,
+            .enabled_instance_extension_names = mInstanceExtensions.data(),
+            .enabled_instance_extension_names_length =
+                    static_cast<uint32_t>(mInstanceExtensions.size()),
+            .enabled_device_extension_names = mDeviceExtensions.data(),
+            .enabled_device_extension_names_length =
+                    static_cast<uint32_t>(mDeviceExtensions.size()),
+            .device_features_2 = &mPhysicalDeviceFeatures2,
+    };
+}
+
 // Returns the next BackbufferInfo to use for the next draw. The function will make sure all
 // previous uses have finished before returning.
 VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurface* surface) {
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 9eb942c..105ee09 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -132,6 +132,9 @@
     // Creates a fence that is signaled, when all the pending Vulkan commands are flushed.
     status_t createReleaseFence(sp<Fence>& nativeFence);
 
+    // Returned pointers are owned by VulkanManager.
+    VkFunctorInitParams getVkFunctorInitParams() const;
+
 private:
     friend class RenderThread;
 
@@ -234,6 +237,12 @@
 
     VkCommandBuffer mDummyCB = VK_NULL_HANDLE;
 
+    // Variables saved to populate VkFunctorInitParams.
+    uint32_t mInstanceVersion = 0u;
+    std::vector<const char*> mInstanceExtensions;
+    std::vector<const char*> mDeviceExtensions;
+    VkPhysicalDeviceFeatures2 mPhysicalDeviceFeatures2{};
+
     enum class SwapBehavior {
         Discard,
         BufferAge,
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index f3a7648..f6178af 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -44,8 +44,8 @@
 }
 
 TEST(SkiaCanvas, colorSpaceXform) {
-    sk_sp<SkColorSpace> adobe = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
-                                                      SkColorSpace::kAdobeRGB_Gamut);
+    sk_sp<SkColorSpace> adobe = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
+                                                      SkNamedGamut::kAdobeRGB);
 
     SkImageInfo adobeInfo = SkImageInfo::Make(1, 1, kN32_SkColorType, kOpaque_SkAlphaType, adobe);
     sk_sp<Bitmap> adobeBitmap = Bitmap::allocateHeapBitmap(adobeInfo);
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index dc347f6..4415a59 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -25,38 +25,6 @@
 namespace android {
 namespace uirenderer {
 
-static inline bool almostEqual(float a, float b) {
-    return std::abs(a - b) < 1e-2f;
-}
-
-bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace) {
-    if (colorSpace == nullptr) return true;
-    if (colorSpace->isSRGB()) return true;
-
-    SkColorSpaceTransferFn transferFunction;
-    if (colorSpace->isNumericalTransferFn(&transferFunction)) {
-        // sRGB transfer function params:
-        const float sRGBParamA = 1 / 1.055f;
-        const float sRGBParamB = 0.055f / 1.055f;
-        const float sRGBParamC = 1 / 12.92f;
-        const float sRGBParamD = 0.04045f;
-        const float sRGBParamE = 0.0f;
-        const float sRGBParamF = 0.0f;
-        const float sRGBParamG = 2.4f;
-
-        // This comparison will catch Display P3
-        return almostEqual(sRGBParamA, transferFunction.fA) &&
-               almostEqual(sRGBParamB, transferFunction.fB) &&
-               almostEqual(sRGBParamC, transferFunction.fC) &&
-               almostEqual(sRGBParamD, transferFunction.fD) &&
-               almostEqual(sRGBParamE, transferFunction.fE) &&
-               almostEqual(sRGBParamF, transferFunction.fF) &&
-               almostEqual(sRGBParamG, transferFunction.fG);
-    }
-
-    return false;
-}
-
 android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) {
     switch (colorType) {
         case kRGBA_8888_SkColorType:
@@ -79,19 +47,19 @@
 
 sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
 
-    SkColorSpace::Gamut gamut;
+    skcms_Matrix3x3 gamut;
     switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
         case HAL_DATASPACE_STANDARD_BT709:
-            gamut = SkColorSpace::kSRGB_Gamut;
+            gamut = SkNamedGamut::kSRGB;
             break;
         case HAL_DATASPACE_STANDARD_BT2020:
-            gamut = SkColorSpace::kRec2020_Gamut;
+            gamut = SkNamedGamut::kRec2020;
             break;
         case HAL_DATASPACE_STANDARD_DCI_P3:
-            gamut = SkColorSpace::kDCIP3_D65_Gamut;
+            gamut = SkNamedGamut::kDCIP3;
             break;
         case HAL_DATASPACE_STANDARD_ADOBE_RGB:
-            gamut = SkColorSpace::kAdobeRGB_Gamut;
+            gamut = SkNamedGamut::kAdobeRGB;
             break;
         case HAL_DATASPACE_STANDARD_UNSPECIFIED:
             return nullptr;
@@ -109,9 +77,9 @@
 
     switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
         case HAL_DATASPACE_TRANSFER_LINEAR:
-            return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, gamut);
+            return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut);
         case HAL_DATASPACE_TRANSFER_SRGB:
-            return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, gamut);
+            return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
         case HAL_DATASPACE_TRANSFER_GAMMA2_2:
             return SkColorSpace::MakeRGB({2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
         case HAL_DATASPACE_TRANSFER_GAMMA2_6:
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 4473ce6..3880252 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -111,11 +111,6 @@
 #endif
 }
 
-// Returns whether the specified color space's transfer function can be
-// approximated with the native sRGB transfer function. This method
-// returns true for sRGB, gamma 2.2 and Display P3 for instance
-bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
-
 android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType);
 
 ANDROID_API sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index b4f19c9..d742cc3 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -255,7 +255,7 @@
 
     if (presentation == PRESENTATION_POINTER && mLocked.additionalMouseResources.empty()) {
         mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
-                                              &mLocked.animationResources);
+                &mLocked.animationResources, mLocked.viewport.displayId);
     }
 
     if (mLocked.presentation != presentation) {
@@ -727,14 +727,14 @@
 }
 
 void PointerController::loadResourcesLocked() REQUIRES(mLock) {
-    mPolicy->loadPointerResources(&mResources);
+    mPolicy->loadPointerResources(&mResources, mLocked.viewport.displayId);
 
     if (mLocked.presentation == PRESENTATION_POINTER) {
         mLocked.additionalMouseResources.clear();
         mLocked.animationResources.clear();
-        mPolicy->loadPointerIcon(&mLocked.pointerIcon);
+        mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId);
         mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
-                                              &mLocked.animationResources);
+                &mLocked.animationResources, mLocked.viewport.displayId);
     }
 
     mLocked.pointerIconChanged = true;
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index a32cc42..be05786 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -62,10 +62,10 @@
     virtual ~PointerControllerPolicyInterface() { }
 
 public:
-    virtual void loadPointerIcon(SpriteIcon* icon) = 0;
-    virtual void loadPointerResources(PointerResources* outResources) = 0;
+    virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId) = 0;
+    virtual void loadPointerResources(PointerResources* outResources, int32_t displayId) = 0;
     virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
-            std::map<int32_t, PointerAnimation>* outAnimationResources) = 0;
+            std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) = 0;
     virtual int32_t getDefaultPointerIconId() = 0;
     virtual int32_t getCustomPointerIconId() = 0;
 };
diff --git a/libs/services/include/android/os/DropBoxManager.h b/libs/services/include/android/os/DropBoxManager.h
index 75b26c6..0747243 100644
--- a/libs/services/include/android/os/DropBoxManager.h
+++ b/libs/services/include/android/os/DropBoxManager.h
@@ -62,7 +62,7 @@
     // file descriptor.
     Status addFile(const String16& tag, int fd, int flags);
 
-    class Entry : public virtual RefBase, public Parcelable {
+    class Entry : public Parcelable {
     public:
         Entry();
         virtual ~Entry();
@@ -89,9 +89,6 @@
         friend class DropBoxManager;
     };
 
-    // Get the next entry from the drop box after the specified time.
-    Status getNextEntry(const String16& tag, long msec, Entry* entry);
-
 private:
     enum {
         HAS_BYTE_ARRAY = 8
diff --git a/libs/services/src/os/DropBoxManager.cpp b/libs/services/src/os/DropBoxManager.cpp
index 8282518..681d5f7 100644
--- a/libs/services/src/os/DropBoxManager.cpp
+++ b/libs/services/src/os/DropBoxManager.cpp
@@ -228,15 +228,4 @@
     return service->add(entry);
 }
 
-Status
-DropBoxManager::getNextEntry(const String16& tag, long msec, Entry* entry)
-{
-    sp<IDropBoxManagerService> service = interface_cast<IDropBoxManagerService>(
-        defaultServiceManager()->getService(android::String16("dropbox")));
-    if (service == NULL) {
-        return Status::fromExceptionCode(Status::EX_NULL_POINTER, "can't find dropbox service");
-    }
-    return service->getNextEntry(tag, msec, android::String16("android"), entry);
-}
-
 }} // namespace android::os
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index f179bc3..602cc3e 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -48,6 +48,7 @@
     private int mMultipathIndicator;
     private double mSnrInDb;
     private double mAutomaticGainControlLevelInDb;
+    private int mCodeType;
 
     // The following enumerations must be in sync with the values declared in gps.h
 
@@ -58,6 +59,7 @@
     private static final int HAS_CARRIER_PHASE = (1<<11);
     private static final int HAS_CARRIER_PHASE_UNCERTAINTY = (1<<12);
     private static final int HAS_AUTOMATIC_GAIN_CONTROL = (1<<13);
+    private static final int HAS_CODE_TYPE = (1 << 14);
 
     /**
      * The status of the multipath indicator.
@@ -202,6 +204,104 @@
     public static final int ADR_STATE_HALF_CYCLE_REPORTED = (1<<4);
 
     /**
+     * GNSS measurement code type.
+     * @hide
+     */
+    @IntDef(prefix = { "CODE_TYPE_" }, value = {
+            CODE_TYPE_UNKNOWN, CODE_TYPE_A, CODE_TYPE_B, CODE_TYPE_C, CODE_TYPE_I, CODE_TYPE_L,
+            CODE_TYPE_M, CODE_TYPE_P, CODE_TYPE_Q, CODE_TYPE_S, CODE_TYPE_W, CODE_TYPE_X,
+            CODE_TYPE_Y, CODE_TYPE_Z, CODE_TYPE_CODELESS
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CodeType {}
+
+    /** The GNSS Measurement's code type is unknown. */
+    public static final int CODE_TYPE_UNKNOWN = -1;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GALILEO E1A, GALILEO E6A, IRNSS
+     * L5A, IRNSS SA.
+     */
+    public static final int CODE_TYPE_A = 0;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GALILEO E1B, GALILEO E6B, IRNSS
+     * L5B, IRNSS SB.
+     */
+    public static final int CODE_TYPE_B = 1;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1 C/A,  GPS L2 C/A, GLONASS G1
+     * C/A, GLONASS G2 C/A, GALILEO E1C, GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C.
+     */
+    public static final int CODE_TYPE_C = 2;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L5 I, GLONASS G3 I, GALILEO E5a
+     * I, GALILEO E5b I, GALILEO E5a+b I, SBAS L5 I, QZSS L5 I, BDS B1 I, BDS B2 I, BDS B3 I.
+     */
+    public static final int CODE_TYPE_I = 3;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1C (P), GPS L2C (L), QZSS L1C
+     * (P), QZSS L2C (L), LEX(6) L.
+     */
+    public static final int CODE_TYPE_L = 4;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1M, GPS L2M.
+     */
+    public static final int CODE_TYPE_M = 5;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1P, GPS L2P, GLONASS G1P,
+     * GLONASS G2P.
+     */
+    public static final int CODE_TYPE_P = 6;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L5 Q, GLONASS G3 Q, GALILEO E5a
+     * Q, GALILEO E5b Q, GALILEO E5a+b Q, SBAS L5 Q, QZSS L5 Q, BDS B1 Q, BDS B2 Q, BDS B3 Q.
+     */
+    public static final int CODE_TYPE_Q = 7;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1C (D), GPS L2C (M), QZSS L1C
+     * (D), QZSS L2C (M), LEX(6) S.
+     */
+    public static final int CODE_TYPE_S = 8;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1 Z-tracking, GPS L2
+     * Z-tracking.
+     */
+    public static final int CODE_TYPE_W = 9;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1C (D+P), GPS L2C (M+L), GPS
+     * L5 (I+Q), GLONASS G3 (I+Q), GALILEO E1 (B+C), GALILEO E5a (I+Q), GALILEO E5b (I+Q), GALILEO
+     * E5a+b(I+Q), GALILEO E6 (B+C), SBAS L5 (I+Q), QZSS L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q),
+     * LEX(6) (S+L), BDS B1 (I+Q), BDS B2 (I+Q), BDS B3 (I+Q), IRNSS L5 (B+C).
+     */
+    public static final int CODE_TYPE_X = 10;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1Y, GPS L2Y.
+     */
+    public static final int CODE_TYPE_Y = 11;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GALILEO E1 (A+B+C), GALILEO E6
+     * (A+B+C), QZSS L1-SAIF.
+     */
+    public static final int CODE_TYPE_Z = 12;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1 codeless, GPS L2 codeless.
+     */
+    public static final int CODE_TYPE_CODELESS = 13;
+
+    /**
      * All the 'Accumulated Delta Range' flags.
      * @hide
      */
@@ -248,6 +348,7 @@
         mMultipathIndicator = measurement.mMultipathIndicator;
         mSnrInDb = measurement.mSnrInDb;
         mAutomaticGainControlLevelInDb = measurement.mAutomaticGainControlLevelInDb;
+        mCodeType = measurement.mCodeType;
     }
 
     /**
@@ -967,7 +1068,7 @@
      * <p>For internal and logging use only.
      */
     private String getMultipathIndicatorString() {
-        switch(mMultipathIndicator) {
+        switch (mMultipathIndicator) {
             case MULTIPATH_INDICATOR_UNKNOWN:
                 return "Unknown";
             case MULTIPATH_INDICATOR_DETECTED:
@@ -1063,6 +1164,89 @@
         mAutomaticGainControlLevelInDb = Double.NaN;
     }
 
+    /**
+     * Returns {@code true} if {@link #getCodeType()} is available,
+     * {@code false} otherwise.
+     */
+    public boolean hasCodeType() {
+        return isFlagSet(HAS_CODE_TYPE);
+    }
+
+    /**
+     * Gets the GNSS measurement's code type.
+     *
+     * <p>Similar to the Attribute field described in Rinex 3.03, e.g., in Tables 4-10, and Table
+     * A2 at the Rinex 3.03 Update 1 Document.
+     */
+    @CodeType
+    public int getCodeType() {
+        return mCodeType;
+    }
+
+    /**
+     * Sets the GNSS measurement's code type.
+     *
+     * @hide
+     */
+    @TestApi
+    public void setCodeType(@CodeType int codeType) {
+        setFlag(HAS_CODE_TYPE);
+        mCodeType = codeType;
+    }
+
+    /**
+     * Resets the GNSS measurement's code type.
+     *
+     * @hide
+     */
+    @TestApi
+    public void resetCodeType() {
+        resetFlag(HAS_CODE_TYPE);
+        mCodeType = CODE_TYPE_UNKNOWN;
+    }
+
+    /**
+     * Gets a string representation of the 'code type'.
+     *
+     * <p>For internal and logging use only.
+     */
+    private String getCodeTypeString() {
+        switch (mCodeType) {
+            case CODE_TYPE_UNKNOWN:
+                return "CODE_TYPE_UNKNOWN";
+            case CODE_TYPE_A:
+                return "CODE_TYPE_A";
+            case CODE_TYPE_B:
+                return "CODE_TYPE_B";
+            case CODE_TYPE_C:
+                return "CODE_TYPE_C";
+            case CODE_TYPE_I:
+                return "CODE_TYPE_I";
+            case CODE_TYPE_L:
+                return "CODE_TYPE_L";
+            case CODE_TYPE_M:
+                return "CODE_TYPE_M";
+            case CODE_TYPE_P:
+                return "CODE_TYPE_P";
+            case CODE_TYPE_Q:
+                return "CODE_TYPE_Q";
+            case CODE_TYPE_S:
+                return "CODE_TYPE_S";
+            case CODE_TYPE_W:
+                return "CODE_TYPE_W";
+            case CODE_TYPE_X:
+                return "CODE_TYPE_X";
+            case CODE_TYPE_Y:
+                return "CODE_TYPE_Y";
+            case CODE_TYPE_Z:
+                return "CODE_TYPE_Z";
+            case CODE_TYPE_CODELESS:
+                return "CODE_TYPE_CODELESS";
+            default:
+                return "<Invalid: " + mCodeType + ">";
+        }
+    }
+
     public static final Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() {
         @Override
         public GnssMeasurement createFromParcel(Parcel parcel) {
@@ -1088,6 +1272,7 @@
             gnssMeasurement.mMultipathIndicator = parcel.readInt();
             gnssMeasurement.mSnrInDb = parcel.readDouble();
             gnssMeasurement.mAutomaticGainControlLevelInDb = parcel.readDouble();
+            gnssMeasurement.mCodeType = parcel.readInt();
 
             return gnssMeasurement;
         }
@@ -1120,6 +1305,7 @@
         parcel.writeInt(mMultipathIndicator);
         parcel.writeDouble(mSnrInDb);
         parcel.writeDouble(mAutomaticGainControlLevelInDb);
+        parcel.writeInt(mCodeType);
     }
 
     @Override
@@ -1191,9 +1377,13 @@
                 "SnrInDb",
                 hasSnrInDb() ? mSnrInDb : null));
         builder.append(String.format(
-            format,
-            "AgcLevelDb",
-            hasAutomaticGainControlLevelDb() ? mAutomaticGainControlLevelInDb : null));
+                format,
+                "AgcLevelDb",
+                hasAutomaticGainControlLevelDb() ? mAutomaticGainControlLevelInDb : null));
+        builder.append(String.format(
+                format,
+                "CodeType",
+                hasCodeType() ? getCodeTypeString() : null));
 
         return builder.toString();
     }
@@ -1218,6 +1408,7 @@
         setMultipathIndicator(MULTIPATH_INDICATOR_UNKNOWN);
         resetSnrInDb();
         resetAutomaticGainControlLevel();
+        resetCodeType();
     }
 
     private void setFlag(int flag) {
diff --git a/media/Android.bp b/media/Android.bp
index d5da6f2..8ebc91a 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -1,4 +1,21 @@
 java_library {
+    name: "media1",
+
+    srcs: [
+        ":media1-srcs",
+    ],
+
+    sdk_version: "system_current",
+}
+
+filegroup {
+    name: "media1-srcs",
+    srcs: [
+        "java/android/media/session/MediaSessionProviderService.java",
+    ],
+}
+
+java_library {
     // TODO: include media2.jar in the media apex and add it to the bootclasspath.
     name: "media2",
 
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 4f23cca..f5a6f86 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -736,8 +736,9 @@
          * @param preset one of {@link MediaRecorder.AudioSource#DEFAULT},
          *     {@link MediaRecorder.AudioSource#MIC}, {@link MediaRecorder.AudioSource#CAMCORDER},
          *     {@link MediaRecorder.AudioSource#VOICE_RECOGNITION},
-         *     {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION} or
-         *     {@link MediaRecorder.AudioSource#UNPROCESSED}
+         *     {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION},
+         *     {@link MediaRecorder.AudioSource#UNPROCESSED} or
+         *     {@link MediaRecorder.AudioSource#VOICE_PERFORMANCE}
          * @return the same Builder instance.
          */
         @SystemApi
@@ -749,6 +750,7 @@
                 case MediaRecorder.AudioSource.VOICE_RECOGNITION:
                 case MediaRecorder.AudioSource.VOICE_COMMUNICATION:
                 case MediaRecorder.AudioSource.UNPROCESSED:
+                case MediaRecorder.AudioSource.VOICE_PERFORMANCE:
                     mSource = preset;
                     break;
                 default:
@@ -760,7 +762,7 @@
         /**
          * @hide
          * Same as {@link #setCapturePreset(int)} but authorizes the use of HOTWORD,
-         * REMOTE_SUBMIX, RADIO_TUNER, VOICE_DOWNLINK, VOICE_UPLINK and VOICE_CALL.
+         * REMOTE_SUBMIX, RADIO_TUNER, VOICE_DOWNLINK, VOICE_UPLINK, VOICE_CALL and ECHO_REFERENCE.
          * @param preset
          * @return the same Builder instance.
          */
@@ -771,7 +773,8 @@
                     || (preset == MediaRecorder.AudioSource.RADIO_TUNER)
                     || (preset == MediaRecorder.AudioSource.VOICE_DOWNLINK)
                     || (preset == MediaRecorder.AudioSource.VOICE_UPLINK)
-                    || (preset == MediaRecorder.AudioSource.VOICE_CALL)) {
+                    || (preset == MediaRecorder.AudioSource.VOICE_CALL)
+                    || (preset == MediaRecorder.AudioSource.ECHO_REFERENCE)) {
                 mSource = preset;
             } else {
                 setCapturePreset(preset);
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 793aa27..5516086 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -816,7 +817,7 @@
      *
      * @return The audio frame size in bytes corresponding to the encoding and the channel mask.
      */
-    public int getFrameSizeInBytes() {
+    public @IntRange(from = 1) int getFrameSizeInBytes() {
         return mFrameSizeInBytes;
     }
 
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 33f81f1..92afe7e 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -61,7 +61,8 @@
  * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to
  * the total recording buffer size.
  */
-public class AudioRecord implements AudioRouting, AudioRecordingMonitor, AudioRecordingMonitorClient
+public class AudioRecord implements AudioRouting, MicrophoneDirection,
+        AudioRecordingMonitor, AudioRecordingMonitorClient
 {
     //---------------------------------------------------------
     // Constants
@@ -1657,7 +1658,6 @@
         return activeMicrophones;
     }
 
-
     //--------------------------------------------------------------------------
     // Implementation of AudioRecordingMonitor interface
     //--------------------
@@ -1707,6 +1707,33 @@
         return native_getPortId();
     }
 
+    //--------------------------------------------------------------------------
+    // MicrophoneDirection
+    //--------------------
+    /**
+     * Specifies the logical microphone (for processing).
+     *
+     * @param direction Direction constant (MicrophoneDirection.MIC_DIRECTION_*)
+     * @return retval OK if the call is successful, an error code otherwise.
+     * @hide
+     */
+    public int setMicrophoneDirection(int direction) {
+        return native_set_microphone_direction(direction);
+    }
+
+    /**
+     * Specifies the zoom factor (i.e. the field dimension) for the selected microphone
+     * (for processing). The selected microphone is determined by the use-case for the stream.
+     *
+     * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle),
+     * though 0 (no zoom) to 1 (maximum zoom).
+     * @return retval OK if the call is successful, an error code otherwise.
+     * @hide
+     */
+    public int setMicrophoneFieldDimension(float zoom) {
+        return native_set_microphone_field_dimension(zoom);
+    }
+
     //---------------------------------------------------------
     // Interface definitions
     //--------------------
@@ -1860,6 +1887,9 @@
 
     private native int native_getPortId();
 
+    private native int native_set_microphone_direction(int direction);
+    private native int native_set_microphone_field_dimension(float zoom);
+
     //---------------------------------------------------------
     // Utility methods
     //------------------
diff --git a/media/java/android/media/AudioRecordingConfiguration.java b/media/java/android/media/AudioRecordingConfiguration.java
index de76aef..52771e4 100644
--- a/media/java/android/media/AudioRecordingConfiguration.java
+++ b/media/java/android/media/AudioRecordingConfiguration.java
@@ -172,7 +172,8 @@
         MediaRecorder.AudioSource.CAMCORDER,
         MediaRecorder.AudioSource.VOICE_RECOGNITION,
         MediaRecorder.AudioSource.VOICE_COMMUNICATION,
-        MediaRecorder.AudioSource.UNPROCESSED
+        MediaRecorder.AudioSource.UNPROCESSED,
+        MediaRecorder.AudioSource.VOICE_PERFORMANCE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface AudioSource {}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 45cde0f..de73649 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -541,6 +541,8 @@
     public static final int DEVICE_IN_BUS = DEVICE_BIT_IN | 0x100000;
     public static final int DEVICE_IN_PROXY = DEVICE_BIT_IN | 0x1000000;
     public static final int DEVICE_IN_USB_HEADSET = DEVICE_BIT_IN | 0x2000000;
+    public static final int DEVICE_IN_BLUETOOTH_BLE = DEVICE_BIT_IN | 0x4000000;
+    public static final int DEVICE_IN_ECHO_REFERENCE = DEVICE_BIT_IN | 0x10000000;
     @UnsupportedAppUsage
     public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;
 
@@ -567,6 +569,8 @@
                                              DEVICE_IN_BUS |
                                              DEVICE_IN_PROXY |
                                              DEVICE_IN_USB_HEADSET |
+                                             DEVICE_IN_BLUETOOTH_BLE |
+                                             DEVICE_IN_ECHO_REFERENCE |
                                              DEVICE_IN_DEFAULT);
     public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
     public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
@@ -641,6 +645,8 @@
     public static final String DEVICE_IN_BUS_NAME = "bus";
     public static final String DEVICE_IN_PROXY_NAME = "proxy";
     public static final String DEVICE_IN_USB_HEADSET_NAME = "usb_headset";
+    public static final String DEVICE_IN_BLUETOOTH_BLE_NAME = "bt_ble";
+    public static final String DEVICE_IN_ECHO_REFERENCE_NAME = "echo_reference";
 
     @UnsupportedAppUsage
     public static String getOutputDeviceName(int device)
@@ -757,6 +763,10 @@
             return DEVICE_IN_PROXY_NAME;
         case DEVICE_IN_USB_HEADSET:
             return DEVICE_IN_USB_HEADSET_NAME;
+        case DEVICE_IN_BLUETOOTH_BLE:
+            return DEVICE_IN_BLUETOOTH_BLE_NAME;
+        case DEVICE_IN_ECHO_REFERENCE:
+            return DEVICE_IN_ECHO_REFERENCE_NAME;
         case DEVICE_IN_DEFAULT:
         default:
             return Integer.toString(device);
diff --git a/media/java/android/media/IMediaSession2Service.aidl b/media/java/android/media/IMediaSession2Service.aidl
new file mode 100644
index 0000000..10ac1be
--- /dev/null
+++ b/media/java/android/media/IMediaSession2Service.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.os.Bundle;
+import android.media.Controller2Link;
+
+/**
+ * Interface from MediaController2 to MediaSession2Service.
+ * <p>
+ * Keep this interface oneway. Otherwise a malicious app may implement fake version of this,
+ * and holds calls from controller to make controller owner(s) frozen.
+ * @hide
+ */
+oneway interface IMediaSession2Service {
+    void connect(in Controller2Link caller, int seq, in Bundle connectionRequest) = 0;
+    // Next Id : 1
+}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index bc9500d..f756658 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1829,9 +1829,14 @@
 
         mBufferLock = new Object();
 
+        // save name used at creation
+        mNameAtCreation = nameIsType ? null : name;
+
         native_setup(name, nameIsType, encoder);
     }
 
+    private String mNameAtCreation;
+
     @Override
     protected void finalize() {
         native_finalize();
@@ -3317,12 +3322,36 @@
     private native void native_setAudioPresentation(int presentationId, int programId);
 
     /**
-     * Get the component name. If the codec was created by createDecoderByType
-     * or createEncoderByType, what component is chosen is not known beforehand.
+     * Retrieve the codec name.
+     *
+     * If the codec was created by createDecoderByType or createEncoderByType, what component is
+     * chosen is not known beforehand. This method returns the name of the codec that was
+     * selected by the platform.
+     *
+     * <strong>Note:</strong> Implementations may provide multiple aliases (codec
+     * names) for the same underlying codec, any of which can be used to instantiate the same
+     * underlying codec in {@link MediaCodec#createByCodecName}. This method returns the
+     * name used to create the codec in this case.
+     *
      * @throws IllegalStateException if in the Released state.
      */
     @NonNull
-    public native final String getName();
+    public final String getName() {
+        // get canonical name to handle exception
+        String canonicalName = getCanonicalName();
+        return mNameAtCreation != null ? mNameAtCreation : canonicalName;
+    }
+
+    /**
+     * Retrieve the underlying codec name.
+     *
+     * This method is similar to {@link #getName}, except that it returns the underlying component
+     * name even if an alias was used to create this MediaCodec object by name,
+     *
+     * @throws IllegalStateException if in the Released state.
+     */
+    @NonNull
+    public native final String getCanonicalName();
 
     /**
      *  Return Metrics data about the current codec instance.
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 10a1e3a..751d57b 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -32,8 +32,10 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.Vector;
 
 /**
  * Provides information about a given media codec available on the device. You can
@@ -61,15 +63,25 @@
  *
  */
 public final class MediaCodecInfo {
-    private boolean mIsEncoder;
+    private static final String TAG = "MediaCodecInfo";
+
+    private static final int FLAG_IS_ENCODER = (1 << 0);
+    private static final int FLAG_IS_VENDOR = (1 << 1);
+    private static final int FLAG_IS_SOFTWARE_ONLY = (1 << 2);
+    private static final int FLAG_IS_HARDWARE_ACCELERATED = (1 << 3);
+
+    private int mFlags;
     private String mName;
+    private String mCanonicalName;
     private Map<String, CodecCapabilities> mCaps;
 
     /* package private */ MediaCodecInfo(
-            String name, boolean isEncoder, CodecCapabilities[] caps) {
+            String name, String canonicalName, int flags, CodecCapabilities[] caps) {
         mName = name;
-        mIsEncoder = isEncoder;
+        mCanonicalName = canonicalName;
+        mFlags = flags;
         mCaps = new HashMap<String, CodecCapabilities>();
+
         for (CodecCapabilities c: caps) {
             mCaps.put(c.getMimeType(), c);
         }
@@ -77,16 +89,69 @@
 
     /**
      * Retrieve the codec name.
+     *
+     * <strong>Note:</strong> Implementations may provide multiple aliases (codec
+     * names) for the same underlying codec, any of which can be used to instantiate the same
+     * underlying codec in {@link MediaCodec#createByCodecName}.
+     *
+     * Applications targeting SDK < {@link android.os.Build.VERSION_CODES#Q}, cannot determine if
+     * the multiple codec names listed in MediaCodecList are in-fact for the same codec.
      */
+    @NonNull
     public final String getName() {
         return mName;
     }
 
     /**
+     * Retrieve the underlying codec name.
+     *
+     * Device implementations may provide multiple aliases (codec names) for the same underlying
+     * codec to maintain backward app compatibility. This method returns the name of the underlying
+     * codec name, which must not be another alias. For non-aliases this is always the name of the
+     * codec.
+     */
+    @NonNull
+    public final String getCanonicalName() {
+        return mCanonicalName;
+    }
+
+    /**
+     * Query if the codec is an alias for another underlying codec.
+     */
+    public final boolean isAlias() {
+        return !mName.equals(mCanonicalName);
+    }
+
+    /**
      * Query if the codec is an encoder.
      */
     public final boolean isEncoder() {
-        return mIsEncoder;
+        return (mFlags & FLAG_IS_ENCODER) != 0;
+    }
+
+    /**
+     * Query if the codec is provided by the Android platform (false) or the device manufacturer
+     * (true).
+     */
+    public final boolean isVendor() {
+        return (mFlags & FLAG_IS_VENDOR) != 0;
+    }
+
+    /**
+     * Query if the codec is software only. Software-only codecs are more secure as they run in
+     * a tighter security sandbox. On the other hand, software-only codecs do not provide any
+     * performance guarantees.
+     */
+    public final boolean isSoftwareOnly() {
+        return (mFlags & FLAG_IS_SOFTWARE_ONLY) != 0;
+    }
+
+    /**
+     * Query if the codec is hardware accelerated. This attribute is provided by the device
+     * manufacturer. Note that it cannot be tested for correctness.
+     */
+    public final boolean isHardwareAccelerated() {
+        return (mFlags & FLAG_IS_HARDWARE_ACCELERATED) != 0;
     }
 
     /**
@@ -163,7 +228,7 @@
         // such as B-frame support, arithmetic coding...
         public CodecProfileLevel[] profileLevels;  // NOTE this array is modifiable by user
 
-        // from OMX_COLOR_FORMATTYPE
+        // from MediaCodecConstants
         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
         public static final int COLOR_FormatMonochrome              = 1;
         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
@@ -344,7 +409,7 @@
         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
         public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
         // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference.
-        // In OMX this is called OMX_COLOR_FormatAndroidOpaque.
+        // Note: in OMX this is called OMX_COLOR_FormatAndroidOpaque.
         public static final int COLOR_FormatSurface                   = 0x7F000789;
 
         /**
@@ -435,8 +500,7 @@
         public static final int COLOR_QCOM_FormatYUV420SemiPlanar     = 0x7fa30c00;
 
         /**
-         * Defined in the OpenMAX IL specs, color format values are drawn from
-         * OMX_COLOR_FORMATTYPE.
+         * The color format for the media. This is one of the color constants defined in this class.
          */
         public int[] colorFormats; // NOTE this array is modifiable by user
 
@@ -462,6 +526,26 @@
         public static final String FEATURE_TunneledPlayback       = "tunneled-playback";
 
         /**
+         * If true, the timestamp of each output buffer is derived from the timestamp of the input
+         * buffer that produced the output. If false, the timestamp of each output buffer is
+         * derived from the timestamp of the first input buffer.
+         */
+        public static final String FEATURE_DynamicTimestamp = "dynamic-timestamp";
+
+        /**
+         * <b>decoder only</b>If true, the codec supports partial (including multiple) access units
+         * per input buffer.
+         */
+        public static final String FEATURE_FrameParsing = "frame-parsing";
+
+        /**
+         * If true, the codec supports multiple access units (for decoding, or to output for
+         * encoders). If false, the codec only supports single access units. Producing multiple
+         * access units for output is an optional feature.
+         */
+        public static final String FEATURE_MultipleFrames = "multiple-frames";
+
+        /**
          * <b>video decoder only</b>: codec supports queuing partial frames.
          */
         public static final String FEATURE_PartialFrame = "partial-frame";
@@ -497,10 +581,15 @@
             new Feature(FEATURE_SecurePlayback,   (1 << 1), false),
             new Feature(FEATURE_TunneledPlayback, (1 << 2), false),
             new Feature(FEATURE_PartialFrame,     (1 << 3), false),
+            new Feature(FEATURE_FrameParsing,     (1 << 4), false),
+            new Feature(FEATURE_MultipleFrames,   (1 << 5), false),
+            new Feature(FEATURE_DynamicTimestamp, (1 << 6), false),
         };
 
         private static final Feature[] encoderFeatures = {
             new Feature(FEATURE_IntraRefresh, (1 << 0), false),
+            new Feature(FEATURE_MultipleFrames, (1 << 1), false),
+            new Feature(FEATURE_DynamicTimestamp, (1 << 2), false),
         };
 
         /** @hide */
@@ -869,7 +958,7 @@
 
             CodecCapabilities ret = new CodecCapabilities(
                 new CodecProfileLevel[] { pl }, new int[0], true /* encoder */,
-                0 /* flags */, defaultFormat, new MediaFormat() /* info */);
+                defaultFormat, new MediaFormat() /* info */);
             if (ret.mError != 0) {
                 return null;
             }
@@ -878,10 +967,10 @@
 
         /* package private */ CodecCapabilities(
                 CodecProfileLevel[] profLevs, int[] colFmts,
-                boolean encoder, int flags,
+                boolean encoder,
                 Map<String, Object>defaultFormatMap,
                 Map<String, Object>capabilitiesMap) {
-            this(profLevs, colFmts, encoder, flags,
+            this(profLevs, colFmts, encoder,
                     new MediaFormat(defaultFormatMap),
                     new MediaFormat(capabilitiesMap));
         }
@@ -889,11 +978,11 @@
         private MediaFormat mCapabilitiesInfo;
 
         /* package private */ CodecCapabilities(
-                CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags,
+                CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder,
                 MediaFormat defaultFormat, MediaFormat info) {
             final Map<String, Object> map = info.getMap();
             colorFormats = colFmts;
-            mFlagsVerified = flags;
+            mFlagsVerified = 0; // TODO: remove as it is unused
             mDefaultFormat = defaultFormat;
             mCapabilitiesInfo = info;
             mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME);
@@ -1243,6 +1332,7 @@
         private Range<Rational> mBlockAspectRatioRange;
         private Range<Long> mBlocksPerSecondRange;
         private Map<Size, Range<Long>> mMeasuredFrameRates;
+        private Vector<PerformancePoint> mPerformancePoints;
         private Range<Integer> mFrameRateRange;
 
         private int mBlockWidth;
@@ -1524,6 +1614,158 @@
         }
 
         /**
+         * Video performance points are a set of standard performance points defined by pixel rate.
+         */
+        public static final class PerformancePoint {
+            /**
+             * Frame width in pixels.
+             */
+            public final int width;
+
+            /**
+             * Frame height in pixels.
+             */
+            public final int height;
+
+            /**
+             * Frame rate in frames per second.
+             */
+            public final int frameRate;
+
+            /* package private */
+            PerformancePoint(int width_, int height_, int frameRate_) {
+                width = width_;
+                height = height_;
+                frameRate = frameRate_;
+            }
+
+            /**
+             * Checks whether the performance point covers a media format.
+             *
+             * @param format Stream format considered
+             *
+             * @return {@code true} if the performance point covers the format.
+             */
+            public boolean covers(@NonNull MediaFormat format) {
+                // for simplicity, this code assumes a 16x16 block size.
+                long macroBlocks = ((width + 15) / 16) * (long)((height + 15) / 16);
+                long mbps = macroBlocks * frameRate;
+
+                long formatMacroBlocks =
+                    (long)((format.getInteger(MediaFormat.KEY_WIDTH, 0) + 15) / 16)
+                            * ((format.getInteger(MediaFormat.KEY_HEIGHT, 0) + 15) / 16);
+                double formatMbps =
+                    Math.ceil(formatMacroBlocks
+                              * format.getNumber(MediaFormat.KEY_FRAME_RATE, 0).doubleValue());
+                return formatMacroBlocks > 0 && formatMacroBlocks <= macroBlocks
+                        && formatMbps <= mbps;
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                if (o instanceof PerformancePoint) {
+                    PerformancePoint other = (PerformancePoint)o;
+                    return ((long)width * height) == ((long)other.width * other.height)
+                            && frameRate == other.frameRate;
+                }
+                return false;
+            }
+
+            /** 480p 24fps */
+            public static final PerformancePoint SD_24 = new PerformancePoint(720, 480, 24);
+            /** 576p 25fps */
+            public static final PerformancePoint SD_25 = new PerformancePoint(720, 576, 25);
+            /** 480p 30fps */
+            public static final PerformancePoint SD_30 = new PerformancePoint(720, 480, 30);
+            /** 480p 48fps */
+            public static final PerformancePoint SD_48 = new PerformancePoint(720, 480, 48);
+            /** 576p 50fps */
+            public static final PerformancePoint SD_50 = new PerformancePoint(720, 576, 50);
+            /** 480p 60fps */
+            public static final PerformancePoint SD_60 = new PerformancePoint(720, 480, 60);
+
+            /** 720p 24fps */
+            public static final PerformancePoint HD_24 = new PerformancePoint(1280, 720, 24);
+            /** 720p 25fps */
+            public static final PerformancePoint HD_25 = new PerformancePoint(1280, 720, 25);
+            /** 720p 30fps */
+            public static final PerformancePoint HD_30 = new PerformancePoint(1280, 720, 30);
+            /** 720p 50fps */
+            public static final PerformancePoint HD_50 = new PerformancePoint(1280, 720, 50);
+            /** 720p 60fps */
+            public static final PerformancePoint HD_60 = new PerformancePoint(1280, 720, 60);
+            /** 720p 100fps */
+            public static final PerformancePoint HD_100 = new PerformancePoint(1280, 720, 100);
+            /** 720p 120fps */
+            public static final PerformancePoint HD_120 = new PerformancePoint(1280, 720, 120);
+            /** 720p 200fps */
+            public static final PerformancePoint HD_200 = new PerformancePoint(1280, 720, 200);
+            /** 720p 240fps */
+            public static final PerformancePoint HD_240 = new PerformancePoint(1280, 720, 240);
+
+            /** 1080p 24fps */
+            public static final PerformancePoint FHD_24 = new PerformancePoint(1920, 1080, 24);
+            /** 1080p 25fps */
+            public static final PerformancePoint FHD_25 = new PerformancePoint(1920, 1080, 25);
+            /** 1080p 30fps */
+            public static final PerformancePoint FHD_30 = new PerformancePoint(1920, 1080, 30);
+            /** 1080p 50fps */
+            public static final PerformancePoint FHD_50 = new PerformancePoint(1920, 1080, 50);
+            /** 1080p 60fps */
+            public static final PerformancePoint FHD_60 = new PerformancePoint(1920, 1080, 60);
+            /** 1080p 100fps */
+            public static final PerformancePoint FHD_100 = new PerformancePoint(1920, 1080, 100);
+            /** 1080p 120fps */
+            public static final PerformancePoint FHD_120 = new PerformancePoint(1920, 1080, 120);
+            /** 1080p 200fps */
+            public static final PerformancePoint FHD_200 = new PerformancePoint(1920, 1080, 200);
+            /** 1080p 240fps */
+            public static final PerformancePoint FHD_240 = new PerformancePoint(1920, 1080, 240);
+
+            /** 2160p 24fps */
+            public static final PerformancePoint UHD_24 = new PerformancePoint(3840, 2160, 24);
+            /** 2160p 25fps */
+            public static final PerformancePoint UHD_25 = new PerformancePoint(3840, 2160, 25);
+            /** 2160p 30fps */
+            public static final PerformancePoint UHD_30 = new PerformancePoint(3840, 2160, 30);
+            /** 2160p 50fps */
+            public static final PerformancePoint UHD_50 = new PerformancePoint(3840, 2160, 50);
+            /** 2160p 60fps */
+            public static final PerformancePoint UHD_60 = new PerformancePoint(3840, 2160, 60);
+            /** 2160p 100fps */
+            public static final PerformancePoint UHD_100 = new PerformancePoint(3840, 2160, 100);
+            /** 2160p 120fps */
+            public static final PerformancePoint UHD_120 = new PerformancePoint(3840, 2160, 120);
+            /** 2160p 200fps */
+            public static final PerformancePoint UHD_200 = new PerformancePoint(3840, 2160, 200);
+            /** 2160p 240fps */
+            public static final PerformancePoint UHD_240 = new PerformancePoint(3840, 2160, 240);
+        }
+
+        /**
+         * Returns the supported performance points. May return {@code null} if the codec did not
+         * publish any performance point information (e.g. the vendor codecs have not been updated
+         * to the latest android release). May return an empty list if the codec published that
+         * if does not guarantee any performance points.
+         * <p>
+         * This is a performance guarantee provided by the device manufacturer for hardware codecs
+         * based on hardware capabilities of the device.
+         * <p>
+         * The returned list is sorted first by decreasing number of pixels, then by decreasing
+         * width, and finally by decreasing frame rate.
+         * Performance points assume a single active codec. For use cases where multiple
+         * codecs are active, should use that highest pixel count, and add the frame rates of
+         * each individual codec.
+         */
+        @Nullable
+        public List<PerformancePoint> getSupportedPerformancePoints() {
+            if (mPerformancePoints == null) {
+                return null;
+            }
+            return new ArrayList<PerformancePoint>(mPerformancePoints);
+        }
+
+        /**
          * Returns whether a given video size ({@code width} and
          * {@code height}) and {@code frameRate} combination is supported.
          */
@@ -1659,6 +1901,50 @@
             mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper();
         }
 
+        private @Nullable Vector<PerformancePoint> getPerformancePoints(Map<String, Object> map) {
+            Vector<PerformancePoint> ret = new Vector<>();
+            final String prefix = "performance-point-";
+            Set<String> keys = map.keySet();
+            for (String key : keys) {
+                // looking for: performance-point-WIDTHxHEIGHT-range
+                if (!key.startsWith(prefix)) {
+                    continue;
+                }
+                String subKey = key.substring(prefix.length());
+                if (subKey.equals("none") && ret.size() == 0) {
+                    // This means that component knowingly did not publish performance points.
+                    // This is different from when the component forgot to publish performance
+                    // points.
+                    return ret;
+                }
+                String[] temp = key.split("-");
+                if (temp.length != 4) {
+                    continue;
+                }
+                String sizeStr = temp[2];
+                Size size = Utils.parseSize(sizeStr, null);
+                if (size == null || size.getWidth() * size.getHeight() <= 0) {
+                    continue;
+                }
+                Range<Long> range = Utils.parseLongRange(map.get(key), null);
+                if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
+                    continue;
+                }
+                ret.add(new PerformancePoint(
+                        size.getWidth(), size.getHeight(), range.getLower().intValue()));
+            }
+            // check if the component specified no performance point indication
+            if (ret.size() == 0) {
+                return null;
+            }
+
+            // sort reversed by area first, then by frame rate
+            ret.sort((a, b) -> (a.width * a.height != b.width * b.height ?
+                                    (b.width * b.height - a.width * a.height) :
+                                    (b.frameRate - a.frameRate)));
+            return ret;
+        }
+
         private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) {
             Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>();
             final String prefix = "measured-frame-rate-";
@@ -1770,6 +2056,7 @@
             blockRates =
                 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
             mMeasuredFrameRates = getMeasuredFrameRates(map);
+            mPerformancePoints = getPerformancePoints(map);
             Pair<Range<Integer>, Range<Integer>> sizeRanges =
                 parseWidthHeightRanges(map.get("size-range"));
             if (sizeRanges != null) {
@@ -2879,7 +3166,9 @@
      * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field.
      */
     public static final class CodecProfileLevel {
-        // from OMX_VIDEO_AVCPROFILETYPE
+        // These constants were originally in-line with OMX values, but this
+        // correspondence is no longer maintained.
+
         public static final int AVCProfileBaseline = 0x01;
         public static final int AVCProfileMain     = 0x02;
         public static final int AVCProfileExtended = 0x04;
@@ -2890,7 +3179,6 @@
         public static final int AVCProfileConstrainedBaseline = 0x10000;
         public static final int AVCProfileConstrainedHigh     = 0x80000;
 
-        // from OMX_VIDEO_AVCLEVELTYPE
         public static final int AVCLevel1       = 0x01;
         public static final int AVCLevel1b      = 0x02;
         public static final int AVCLevel11      = 0x04;
@@ -2908,8 +3196,10 @@
         public static final int AVCLevel5       = 0x4000;
         public static final int AVCLevel51      = 0x8000;
         public static final int AVCLevel52      = 0x10000;
+        public static final int AVCLevel6       = 0x20000;
+        public static final int AVCLevel61      = 0x40000;
+        public static final int AVCLevel62      = 0x80000;
 
-        // from OMX_VIDEO_H263PROFILETYPE
         public static final int H263ProfileBaseline             = 0x01;
         public static final int H263ProfileH320Coding           = 0x02;
         public static final int H263ProfileBackwardCompatible   = 0x04;
@@ -2920,7 +3210,6 @@
         public static final int H263ProfileInterlace            = 0x80;
         public static final int H263ProfileHighLatency          = 0x100;
 
-        // from OMX_VIDEO_H263LEVELTYPE
         public static final int H263Level10      = 0x01;
         public static final int H263Level20      = 0x02;
         public static final int H263Level30      = 0x04;
@@ -2930,7 +3219,6 @@
         public static final int H263Level60      = 0x40;
         public static final int H263Level70      = 0x80;
 
-        // from OMX_VIDEO_MPEG4PROFILETYPE
         public static final int MPEG4ProfileSimple              = 0x01;
         public static final int MPEG4ProfileSimpleScalable      = 0x02;
         public static final int MPEG4ProfileCore                = 0x04;
@@ -2948,7 +3236,6 @@
         public static final int MPEG4ProfileAdvancedScalable    = 0x4000;
         public static final int MPEG4ProfileAdvancedSimple      = 0x8000;
 
-        // from OMX_VIDEO_MPEG4LEVELTYPE
         public static final int MPEG4Level0      = 0x01;
         public static final int MPEG4Level0b     = 0x02;
         public static final int MPEG4Level1      = 0x04;
@@ -2960,7 +3247,6 @@
         public static final int MPEG4Level5      = 0x80;
         public static final int MPEG4Level6      = 0x100;
 
-        // from OMX_VIDEO_MPEG2PROFILETYPE
         public static final int MPEG2ProfileSimple              = 0x00;
         public static final int MPEG2ProfileMain                = 0x01;
         public static final int MPEG2Profile422                 = 0x02;
@@ -2968,14 +3254,12 @@
         public static final int MPEG2ProfileSpatial             = 0x04;
         public static final int MPEG2ProfileHigh                = 0x05;
 
-        // from OMX_VIDEO_MPEG2LEVELTYPE
         public static final int MPEG2LevelLL     = 0x00;
         public static final int MPEG2LevelML     = 0x01;
         public static final int MPEG2LevelH14    = 0x02;
         public static final int MPEG2LevelHL     = 0x03;
         public static final int MPEG2LevelHP     = 0x04;
 
-        // from OMX_AUDIO_AACPROFILETYPE
         public static final int AACObjectMain       = 1;
         public static final int AACObjectLC         = 2;
         public static final int AACObjectSSR        = 3;
@@ -2990,16 +3274,13 @@
         /** xHE-AAC (includes USAC) */
         public static final int AACObjectXHE        = 42;
 
-        // from OMX_VIDEO_VP8LEVELTYPE
         public static final int VP8Level_Version0 = 0x01;
         public static final int VP8Level_Version1 = 0x02;
         public static final int VP8Level_Version2 = 0x04;
         public static final int VP8Level_Version3 = 0x08;
 
-        // from OMX_VIDEO_VP8PROFILETYPE
         public static final int VP8ProfileMain = 0x01;
 
-        // from OMX_VIDEO_VP9PROFILETYPE
         public static final int VP9Profile0 = 0x01;
         public static final int VP9Profile1 = 0x02;
         public static final int VP9Profile2 = 0x04;
@@ -3010,7 +3291,6 @@
         public static final int VP9Profile2HDR10Plus = 0x4000;
         public static final int VP9Profile3HDR10Plus = 0x8000;
 
-        // from OMX_VIDEO_VP9LEVELTYPE
         public static final int VP9Level1  = 0x1;
         public static final int VP9Level11 = 0x2;
         public static final int VP9Level2  = 0x4;
@@ -3026,14 +3306,12 @@
         public static final int VP9Level61 = 0x1000;
         public static final int VP9Level62 = 0x2000;
 
-        // from OMX_VIDEO_HEVCPROFILETYPE
         public static final int HEVCProfileMain        = 0x01;
         public static final int HEVCProfileMain10      = 0x02;
         public static final int HEVCProfileMainStill   = 0x04;
         public static final int HEVCProfileMain10HDR10 = 0x1000;
         public static final int HEVCProfileMain10HDR10Plus = 0x2000;
 
-        // from OMX_VIDEO_HEVCLEVELTYPE
         public static final int HEVCMainTierLevel1  = 0x1;
         public static final int HEVCHighTierLevel1  = 0x2;
         public static final int HEVCMainTierLevel2  = 0x4;
@@ -3067,7 +3345,6 @@
             HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 |
             HEVCHighTierLevel62;
 
-        // from OMX_VIDEO_DOLBYVISIONPROFILETYPE
         public static final int DolbyVisionProfileDvavPer = 0x1;
         public static final int DolbyVisionProfileDvavPen = 0x2;
         public static final int DolbyVisionProfileDvheDer = 0x4;
@@ -3079,7 +3356,6 @@
         public static final int DolbyVisionProfileDvheSt = 0x100;
         public static final int DolbyVisionProfileDvavSe = 0x200;
 
-        // from OMX_VIDEO_DOLBYVISIONLEVELTYPE
         public static final int DolbyVisionLevelHd24    = 0x1;
         public static final int DolbyVisionLevelHd30    = 0x2;
         public static final int DolbyVisionLevelFhd24   = 0x4;
@@ -3090,17 +3366,44 @@
         public static final int DolbyVisionLevelUhd48   = 0x80;
         public static final int DolbyVisionLevelUhd60   = 0x100;
 
+        public static final int AV1Profile0     = 0x1;
+        public static final int AV1Profile1     = 0x2;
+        public static final int AV1Profile2     = 0x4;
+
+        public static final int AV1Level2       = 0x1;
+        public static final int AV1Level21      = 0x2;
+        public static final int AV1Level22      = 0x4;
+        public static final int AV1Level23      = 0x8;
+        public static final int AV1Level3       = 0x10;
+        public static final int AV1Level31      = 0x20;
+        public static final int AV1Level32      = 0x40;
+        public static final int AV1Level33      = 0x80;
+        public static final int AV1Level4       = 0x100;
+        public static final int AV1Level41      = 0x200;
+        public static final int AV1Level42      = 0x400;
+        public static final int AV1Level43      = 0x800;
+        public static final int AV1Level5       = 0x1000;
+        public static final int AV1Level51      = 0x2000;
+        public static final int AV1Level52      = 0x4000;
+        public static final int AV1Level53      = 0x8000;
+        public static final int AV1Level6       = 0x10000;
+        public static final int AV1Level61      = 0x20000;
+        public static final int AV1Level62      = 0x40000;
+        public static final int AV1Level63      = 0x80000;
+        public static final int AV1Level7       = 0x100000;
+        public static final int AV1Level71      = 0x200000;
+        public static final int AV1Level72      = 0x400000;
+        public static final int AV1Level73      = 0x800000;
+
         /**
-         * Defined in the OpenMAX IL specs, depending on the type of media
-         * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE,
-         * OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_VP8PROFILETYPE or OMX_VIDEO_VP9PROFILETYPE.
+         * The profile of the media content. Depending on the type of media this can be
+         * one of the profile values defined in this class.
          */
         public int profile;
 
         /**
-         * Defined in the OpenMAX IL specs, depending on the type of media
-         * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
-         * OMX_VIDEO_MPEG4LEVELTYPE, OMX_VIDEO_VP8LEVELTYPE or OMX_VIDEO_VP9LEVELTYPE.
+         * The level of the media content. Depending on the type of media this can be
+         * one of the level values defined in this class.
          *
          * Note that VP9 decoder on platforms before {@link android.os.Build.VERSION_CODES#N} may
          * not advertise a profile level support. For those VP9 decoders, please use
@@ -3157,7 +3460,7 @@
         }
 
         return new MediaCodecInfo(
-                mName, mIsEncoder,
+                mName, mCanonicalName, mFlags,
                 caps.toArray(new CodecCapabilities[caps.size()]));
     }
 }
diff --git a/media/java/android/media/MediaCodecList.java b/media/java/android/media/MediaCodecList.java
index 2e47865..a460954 100644
--- a/media/java/android/media/MediaCodecList.java
+++ b/media/java/android/media/MediaCodecList.java
@@ -111,12 +111,14 @@
             caps[typeIx++] = getCodecCapabilities(index, type);
         }
         return new MediaCodecInfo(
-                getCodecName(index), isEncoder(index), caps);
+                getCodecName(index), getCanonicalName(index), getAttributes(index), caps);
     }
 
     /* package private */ static native final String getCodecName(int index);
 
-    /* package private */ static native final boolean isEncoder(int index);
+    /* package private */ static native final String getCanonicalName(int index);
+
+    /* package private */ static native final int getAttributes(int index);
 
     /* package private */ static native final String[] getSupportedTypes(int index);
 
diff --git a/media/java/android/media/MediaConstants.java b/media/java/android/media/MediaConstants.java
index 275b0ac..5a5747a 100644
--- a/media/java/android/media/MediaConstants.java
+++ b/media/java/android/media/MediaConstants.java
@@ -24,7 +24,7 @@
     static final String KEY_PACKAGE_NAME = "android.media.key.PACKAGE_NAME";
 
     // Bundle key for Parcelable
-    static final String KEY_SESSION2_STUB = "android.media.key.SESSION2_STUB";
+    static final String KEY_SESSION2LINK = "android.media.key.SESSION2LINK";
     static final String KEY_ALLOWED_COMMANDS = "android.media.key.ALLOWED_COMMANDS";
 
     private MediaConstants() {
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index b8381a7..165ea41 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -19,19 +19,23 @@
 import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS;
 import static android.media.MediaConstants.KEY_PACKAGE_NAME;
 import static android.media.MediaConstants.KEY_PID;
-import static android.media.MediaConstants.KEY_SESSION2_STUB;
+import static android.media.MediaConstants.KEY_SESSION2LINK;
 import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
 import static android.media.Session2Command.RESULT_INFO_SKIPPED;
 import static android.media.Session2Token.TYPE_SESSION;
 
 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.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -41,15 +45,15 @@
 
 /**
  * Allows an app to interact with an active {@link MediaSession2} or a
- * {@link MediaSession2Service} which would provide {@link MediaSession2}. Media buttons and other
+ * MediaSession2Service which would provide {@link MediaSession2}. Media buttons and other
  * commands can be sent to the session.
  * <p>
  * This API is not generally intended for third party application developers.
  * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
  * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
  * for consistent behavior across all devices.
- * @hide
  */
+// TODO: use @link for MediaSession2Service
 public class MediaController2 implements AutoCloseable {
     static final String TAG = "MediaController2";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -63,6 +67,7 @@
     private final Executor mCallbackExecutor;
     private final Controller2Link mControllerStub;
     private final Handler mResultHandler;
+    private final SessionServiceConnection mServiceConnection;
 
     private final Object mLock = new Object();
     //@GuardedBy("mLock")
@@ -118,20 +123,29 @@
         mPendingCommands = new ArrayMap<>();
         mRequestedCommandSeqNumbers = new ArraySet<>();
 
+        boolean connectRequested;
         if (token.getType() == TYPE_SESSION) {
-            connectToSession();
+            mServiceConnection = null;
+            connectRequested = requestConnectToSession();
         } else {
-            // TODO: Handle connect to session service.
+            mServiceConnection = new SessionServiceConnection();
+            connectRequested = requestConnectToService();
+        }
+        if (!connectRequested) {
+            close();
         }
     }
 
     @Override
     public void close() {
         synchronized (mLock) {
+            if (mServiceConnection != null) {
+                mContext.unbindService(mServiceConnection);
+            }
             if (mSessionBinder != null) {
                 try {
-                    mSessionBinder.unlinkToDeath(mDeathRecipient, 0);
                     mSessionBinder.disconnect(mControllerStub, getNextSeqNumber());
+                    mSessionBinder.unlinkToDeath(mDeathRecipient, 0);
                 } catch (RuntimeException e) {
                     // No-op
                 }
@@ -153,6 +167,7 @@
      * @return a token which will be sent together in {@link ControllerCallback#onCommandResult}
      *        when its result is received.
      */
+    @NonNull
     public Object sendSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) {
         if (command == null) {
             throw new IllegalArgumentException("command shouldn't be null");
@@ -208,7 +223,7 @@
     void onConnected(int seq, Bundle connectionResult) {
         final long token = Binder.clearCallingIdentity();
         try {
-            Session2Link sessionBinder = connectionResult.getParcelable(KEY_SESSION2_STUB);
+            Session2Link sessionBinder = connectionResult.getParcelable(KEY_SESSION2LINK);
             Session2CommandGroup allowedCommands =
                     connectionResult.getParcelable(KEY_ALLOWED_COMMANDS);
             if (DEBUG) {
@@ -298,18 +313,55 @@
         }
     }
 
-    private void connectToSession() {
-        Session2Link sessionBinder = mSessionToken.getSessionLink();
+    private Bundle createConnectionRequest() {
         Bundle connectionRequest = new Bundle();
         connectionRequest.putString(KEY_PACKAGE_NAME, mContext.getPackageName());
         connectionRequest.putInt(KEY_PID, Process.myPid());
+        return connectionRequest;
+    }
 
+    private boolean requestConnectToSession() {
+        Session2Link sessionBinder = mSessionToken.getSessionLink();
+        Bundle connectionRequest = createConnectionRequest();
         try {
             sessionBinder.connect(mControllerStub, getNextSeqNumber(), connectionRequest);
         } catch (RuntimeException e) {
-            Log.w(TAG, "Failed to call connection request. Framework will retry"
-                    + " automatically");
+            Log.w(TAG, "Failed to call connection request", e);
+            return false;
         }
+        return true;
+    }
+
+    private boolean requestConnectToService() {
+        // Service. Needs to get fresh binder whenever connection is needed.
+        final Intent intent = new Intent(MediaSession2Service.SERVICE_INTERFACE);
+        intent.setClassName(mSessionToken.getPackageName(), mSessionToken.getServiceName());
+
+        // Use bindService() instead of startForegroundService() to start session service for three
+        // reasons.
+        // 1. Prevent session service owner's stopSelf() from destroying service.
+        //    With the startForegroundService(), service's call of stopSelf() will trigger immediate
+        //    onDestroy() calls on the main thread even when onConnect() is running in another
+        //    thread.
+        // 2. Minimize APIs for developers to take care about.
+        //    With bindService(), developers only need to take care about Service.onBind()
+        //    but Service.onStartCommand() should be also taken care about with the
+        //    startForegroundService().
+        // 3. Future support for UI-less playback
+        //    If a service wants to keep running, it should be either foreground service or
+        //    bound service. But there had been request for the feature for system apps
+        //    and using bindService() will be better fit with it.
+        synchronized (mLock) {
+            boolean result = mContext.bindService(
+                    intent, mServiceConnection, Context.BIND_AUTO_CREATE);
+            if (!result) {
+                Log.w(TAG, "bind to " + mSessionToken + " failed");
+                return false;
+            } else if (DEBUG) {
+                Log.d(TAG, "bind to " + mSessionToken + " succeeded");
+            }
+        }
+        return true;
     }
 
     /**
@@ -349,7 +401,7 @@
          * @return the result for the session command. A runtime exception will be thrown if null
          *         is returned.
          */
-        @NonNull
+        @Nullable
         public Session2Command.Result onSessionCommand(@NonNull MediaController2 controller,
                 @NonNull Session2Command command, @Nullable Bundle args) {
             return null;
@@ -366,4 +418,59 @@
         public void onCommandResult(@NonNull MediaController2 controller, @NonNull Object token,
                 @NonNull Session2Command command, @NonNull Session2Command.Result result) {}
     }
+
+    // This will be called on the main thread.
+    private class SessionServiceConnection implements ServiceConnection {
+        SessionServiceConnection() {
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            // Note that it's always main-thread.
+            boolean connectRequested = false;
+            try {
+                if (DEBUG) {
+                    Log.d(TAG, "onServiceConnected " + name + " " + this);
+                }
+                // Sanity check
+                if (!mSessionToken.getPackageName().equals(name.getPackageName())) {
+                    Log.wtf(TAG, "Expected connection to " + mSessionToken.getPackageName()
+                            + " but is connected to " + name);
+                    return;
+                }
+                IMediaSession2Service iService = IMediaSession2Service.Stub.asInterface(service);
+                if (iService == null) {
+                    Log.wtf(TAG, "Service interface is missing.");
+                    return;
+                }
+                Bundle connectionRequest = createConnectionRequest();
+                iService.connect(mControllerStub, getNextSeqNumber(), connectionRequest);
+                connectRequested = true;
+            } catch (RemoteException e) {
+                Log.w(TAG, "Service " + name + " has died prematurely", e);
+            } finally {
+                if (!connectRequested) {
+                    close();
+                }
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            // Temporal lose of the binding because of the service crash. System will automatically
+            // rebind, so just no-op.
+            if (DEBUG) {
+                Log.w(TAG, "Session service " + name + " is disconnected.");
+            }
+            close();
+        }
+
+        @Override
+        public void onBindingDied(ComponentName name) {
+            // Permanent lose of the binding because of the service package update or removed.
+            // This SessionServiceRecord will be removed accordingly, but forget session binder here
+            // for sure.
+            close();
+        }
+    }
 }
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 594a224..c82b5f6 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -124,6 +124,7 @@
 public final class MediaFormat {
     public static final String MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
     public static final String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
+    public static final String MIMETYPE_VIDEO_AV1 = "video/av01";
     public static final String MIMETYPE_VIDEO_AVC = "video/avc";
     public static final String MIMETYPE_VIDEO_HEVC = "video/hevc";
     public static final String MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index df96994..aa79c41 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -60,6 +60,7 @@
 import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -67,6 +68,7 @@
 import java.util.Map;
 import java.util.Queue;
 import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
@@ -399,8 +401,7 @@
         clearSourceInfos();
 
         // Modular DRM clean up
-        mOnDrmConfigHelper = null;
-        synchronized (mDrmEventCbLock) {
+        synchronized (mDrmEventCallbackLock) {
             mDrmEventCallbackRecords.clear();
         }
 
@@ -775,7 +776,7 @@
                 }
                 boolean hasError = false;
                 for (DataSourceDesc dsd : dsds) {
-                    if (dsd != null) {
+                    if (dsd == null) {
                         hasError = true;
                         continue;
                     }
@@ -2889,7 +2890,7 @@
     }
 
     private void sendDrmEvent(final DrmEventNotifier notifier) {
-        synchronized (mDrmEventCbLock) {
+        synchronized (mDrmEventCallbackLock) {
             try {
                 for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
                     cb.first.execute(() -> notifier.notify(cb.second));
@@ -2901,12 +2902,28 @@
         }
     }
 
+    private <T> T sendDrmEventWait(final DrmEventNotifier<T> notifier)
+            throws InterruptedException, ExecutionException {
+        synchronized (mDrmEventCallbackLock) {
+            mDrmEventCallbackRecords.get(0);
+            for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
+                CompletableFuture<T> ret = new CompletableFuture<>();
+                cb.first.execute(() -> ret.complete(notifier.notifyWait(cb.second)));
+                return ret.get();
+            }
+        }
+        return null;
+    }
+
     private interface EventNotifier {
         void notify(EventCallback callback);
     }
 
-    private interface DrmEventNotifier {
-        void notify(DrmEventCallback callback);
+    private interface DrmEventNotifier<T> {
+        default void notify(DrmEventCallback callback) { }
+        default T notifyWait(DrmEventCallback callback) {
+            return null;
+        }
     }
 
     /* Do not change these values without updating their counterparts
@@ -3351,73 +3368,209 @@
     // Modular DRM begin
 
     /**
-     * Interface definition of a callback to be invoked when the app
-     * can do DRM configuration (get/set properties) before the session
-     * is opened. This facilitates configuration of the properties, like
-     * 'securityLevel', which has to be set after DRM scheme creation but
-     * before the DRM session is opened.
+     * An immutable structure per {@link DataSourceDesc} with settings required to initiate a DRM
+     * protected playback session.
      *
-     * The only allowed DRM calls in this listener are
-     * {@link MediaPlayer2#getDrmPropertyString(DataSourceDesc, String)}
-     * and {@link MediaPlayer2#setDrmPropertyString(DataSourceDesc, String, String)}.
-     * @hide
+     * @see DrmPreparationInfo.Builder
      */
-    public interface OnDrmConfigHelper {
+    public static final class DrmPreparationInfo {
+
         /**
-         * Called to give the app the opportunity to configure DRM before the session is created
-         *
-         * @param mp the {@code MediaPlayer2} associated with this callback
-         * @param dsd the DataSourceDesc of this data source
+         * Mutable builder to create a {@link MediaPlayer2.DrmPreparationInfo} object.
          */
-        public void onDrmConfig(MediaPlayer2 mp, DataSourceDesc dsd);
-    }
+        public static final class Builder {
 
-    /**
-     * Register a callback to be invoked for configuration of the DRM object before
-     * the session is created.
-     * The callback will be invoked synchronously during the execution
-     * of {@link #prepareDrm}.
-     *
-     * @param listener the callback that will be run
-     * @hide
-     */
-    // This is a synchronous call.
-    public void setOnDrmConfigHelper(OnDrmConfigHelper listener) {
-        mOnDrmConfigHelper = listener;
-    }
+            private UUID mUUID;
+            private byte[] mKeySetId;
+            private byte[] mInitData;
+            private String mMimeType;
+            private int mKeyType;
+            private Map<String, String> mOptionalParameters;
 
-    private OnDrmConfigHelper mOnDrmConfigHelper;
+            /**
+             * Set UUID of the crypto scheme selected to decrypt content. An UUID can be retrieved from
+             * the source listening to {@link MediaPlayer2.DrmEventCallback#onDrmInfo}.
+             *
+             * @param uuid of selected crypto scheme
+             * @return this
+             */
+            public Builder setUuid(@NonNull UUID uuid) {
+                this.mUUID = uuid;
+                return this;
+            }
+
+            /**
+             * Set identifier of a persisted offline key obtained from
+             * {@link MediaPlayer2.DrmEventCallback#onDrmPrepared(MediaPlayer2, DataSourceDesc, int, byte[])}.
+             *
+             * A {@code keySetId} can be used to restore persisted offline keys into a new playback
+             * session of a DRM protected data source. When {@code keySetId} is set, {@code initData},
+             * {@code mimeType}, {@code keyType}, {@code optionalParameters} are ignored.
+             *
+             * @param keySetId identifier of a persisted offline key
+             * @return this
+             */
+            public Builder setKeySetId(@Nullable byte[] keySetId) {
+                this.mKeySetId = keySetId;
+                return this;
+            }
+
+            /**
+             * Set container-specific DRM initialization data. Its meaning is interpreted based on
+             * {@code mimeType}. For example, it could contain the content ID, key ID or other data
+             * obtained from the content metadata that is required to generate a
+             * {@link MediaDrm.KeyRequest}.
+             *
+             * @param initData container-specific DRM initialization data
+             * @return this
+             */
+            public Builder setInitData(@Nullable byte[] initData) {
+                this.mInitData = initData;
+                return this;
+            }
+
+            /**
+             * Set mime type of the content
+             *
+             * @param mimeType mime type to the content
+             * @return this
+             */
+            public Builder setMimeType(@Nullable String mimeType) {
+                this.mMimeType = mimeType;
+                return this;
+            }
+
+            /**
+             * Set type of the key request. The request may be to acquire keys
+             * for streaming, {@link MediaDrm#KEY_TYPE_STREAMING}, or for offline content,
+             * {@link MediaDrm#KEY_TYPE_OFFLINE}. Releasing previously acquired keys
+             * ({@link MediaDrm#KEY_TYPE_RELEASE}) is not allowed.
+             *
+             * @param keyType type of the key request
+             * @return this
+             */
+            public Builder setKeyType(@MediaPlayer2.MediaDrmKeyType int keyType) {
+                this.mKeyType = keyType;
+                return this;
+            }
+
+            /**
+             * Set optional parameters to be included in a {@link MediaDrm.KeyRequest} message sent to
+             * the license server.
+             *
+             * @param optionalParameters optional parameters to be included in a key request
+             * @return this
+             */
+            public Builder setOptionalParameters(
+                    @Nullable Map<String, String> optionalParameters) {
+                this.mOptionalParameters = optionalParameters;
+                return this;
+            }
+
+            /**
+             * @return an immutable {@link MediaPlayer2.DrmPreparationInfo} representing the settings of this builder
+             */
+            public MediaPlayer2.DrmPreparationInfo build() {
+                return new MediaPlayer2.DrmPreparationInfo(mUUID, mKeySetId, mInitData, mMimeType, mKeyType,
+                        mOptionalParameters);
+            }
+
+        }
+
+        private final UUID mUUID;
+        private final byte[] mKeySetId;
+        private final byte[] mInitData;
+        private final String mMimeType;
+        private final int mKeyType;
+        private final Map<String, String> mOptionalParameters;
+
+        private DrmPreparationInfo(UUID mUUID, byte[] mKeySetId, byte[] mInitData, String mMimeType,
+                int mKeyType, Map<String, String> optionalParameters) {
+            this.mUUID = mUUID;
+            this.mKeySetId = mKeySetId;
+            this.mInitData = mInitData;
+            this.mMimeType = mMimeType;
+            this.mKeyType = mKeyType;
+            this.mOptionalParameters = optionalParameters;
+        }
+
+    }
 
     /**
      * Interface definition for callbacks to be invoked when the player has the corresponding
      * DRM events.
-     * @hide
      */
     public static class DrmEventCallback {
         /**
-         * Called to indicate DRM info is available
+         * Called to indicate DRM info is available. Return a {@link DrmPreparationInfo} object that
+         * bundles DRM initialization parameters.
          *
          * @param mp the {@code MediaPlayer2} associated with this callback
-         * @param dsd the DataSourceDesc of this data source
-         * @param drmInfo DRM info of the source including PSSH, and subset
-         *                of crypto schemes supported by this device
+         * @param dsd the {@link DataSourceDesc} of this data source
+         * @param drmInfo DRM info of the source including PSSH, and subset of crypto schemes
+         *        supported by this device
+         * @return a {@link DrmPreparationInfo} object to initialize DRM playback, or null to skip
+         *         DRM initialization
          */
-        public void onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) { }
+        public DrmPreparationInfo onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) {
+            return null;
+        }
 
         /**
-         * Called to notify the client that {@link MediaPlayer2#prepareDrm(DataSourceDesc, UUID)}
-         * is finished and ready for key request/response.
+         * Called to notify the client that {@code mp} is ready to decrypt DRM protected data source
+         * {@code dsd}
          *
          * @param mp the {@code MediaPlayer2} associated with this callback
-         * @param dsd the DataSourceDesc of this data source
+         * @param dsd the {@link DataSourceDesc} of this data source
          * @param status the result of DRM preparation.
+         * @param keySetId optional identifier that can be used to restore DRM playback initiated
+         *        with a {@link MediaDrm#KEY_TYPE_OFFLINE} key request.
+         *
+         * @see DrmPreparationInfo.Builder#setKeySetId(byte[])
          */
-        public void onDrmPrepared(
-                MediaPlayer2 mp, DataSourceDesc dsd, @PrepareDrmStatusCode int status) { }
+        public void onDrmPrepared(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+                @PrepareDrmStatusCode int status, @Nullable byte[] keySetId) { }
+
+        /**
+         * Called to give the app the opportunity to configure DRM before the session is created.
+         *
+         * This facilitates configuration of the properties, like 'securityLevel', which
+         * has to be set after DRM scheme creation but before the DRM session is opened.
+         *
+         * The only allowed DRM calls in this listener are
+         * {@link MediaDrm#getPropertyString(String)},
+         * {@link MediaDrm#getPropertyByteArray(String)},
+         * {@link MediaDrm#setPropertyString(String, String)},
+         * {@link MediaDrm#setPropertyByteArray(String, byte[])},
+         * {@link MediaDrm#setOnExpirationUpdateListener},
+         * and {@link MediaDrm#setOnKeyStatusChangeListener}.
+         *
+         * @param mp the {@code MediaPlayer2} associated with this callback
+         * @param dsd the {@link DataSourceDesc} of this data source
+         * @param drm handle to get/set DRM properties and listeners for this data source
+         */
+        public void onDrmConfig(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+                @NonNull MediaDrm drm) { }
+
+        /**
+         * Called to indicate the DRM session for {@code dsd} is ready for key request/response
+         *
+         * @param mp the {@code MediaPlayer2} associated with this callback
+         * @param dsd the {@link DataSourceDesc} of this data source
+         * @param request a {@link MediaDrm.KeyRequest} prepared using the
+         *        {@link DrmPreparationInfo} returned from
+         *        {@link #onDrmInfo(MediaPlayer2, DataSourceDesc, DrmInfo)}
+         * @return the response to {@code request} (from license server)
+         */
+        public byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+                @NonNull MediaDrm.KeyRequest request) {
+            return null;
+        }
+
     }
 
-    private final Object mDrmEventCbLock = new Object();
-    private ArrayList<Pair<Executor, DrmEventCallback>> mDrmEventCallbackRecords =
+    private final Object mDrmEventCallbackLock = new Object();
+    private List<Pair<Executor, DrmEventCallback>> mDrmEventCallbackRecords =
             new ArrayList<Pair<Executor, DrmEventCallback>>();
 
     /**
@@ -3425,10 +3578,9 @@
      *
      * @param eventCallback the callback that will be run
      * @param executor the executor through which the callback should be invoked
-     * @hide
      */
     // This is a synchronous call.
-    public void registerDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
+    public void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull DrmEventCallback eventCallback) {
         if (eventCallback == null) {
             throw new IllegalArgumentException("Illegal null EventCallback");
@@ -3437,8 +3589,9 @@
             throw new IllegalArgumentException(
                     "Illegal null Executor for the EventCallback");
         }
-        synchronized (mDrmEventCbLock) {
-            mDrmEventCallbackRecords.add(new Pair(executor, eventCallback));
+        synchronized (mDrmEventCallbackLock) {
+            mDrmEventCallbackRecords = Collections.singletonList(
+                    new Pair<Executor, DrmEventCallback>(executor, eventCallback));
         }
     }
 
@@ -3450,7 +3603,7 @@
      */
     // This is a synchronous call.
     public void unregisterDrmEventCallback(DrmEventCallback eventCallback) {
-        synchronized (mDrmEventCbLock) {
+        synchronized (mDrmEventCallbackLock) {
             for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
                 if (cb.second == eventCallback) {
                     mDrmEventCallbackRecords.remove(cb);
@@ -3564,7 +3717,7 @@
     /**
      * Prepares the DRM for the given data source
      * <p>
-     * If {@link OnDrmConfigHelper} is registered, it will be called during
+     * If {@link DrmEventCallback} is registered, it will be called during
      * preparation to allow configuration of the DRM properties before opening the
      * DRM session. It should be used only for a series of
      * {@link #getDrmPropertyString(DataSourceDesc, String)} and
@@ -3587,8 +3740,7 @@
      * @param dsd The DRM protected data source
      *
      * @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
-     * from the source through {@link #getDrmInfo(DataSourceDesc)} or registering a
-     * {@link DrmEventCallback#onDrmInfo}.
+     * from the source listening to {@link DrmEventCallback#onDrmInfo}.
      *
      * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
      * @hide
@@ -3661,8 +3813,8 @@
                     sendDrmEvent(new DrmEventNotifier() {
                         @Override
                         public void notify(DrmEventCallback callback) {
-                            callback.onDrmPrepared(
-                                    MediaPlayer2.this, dsd, prepareDrmStatus);
+                            callback.onDrmPrepared(MediaPlayer2.this, dsd, prepareDrmStatus,
+                                    /* TODO: keySetId */ null);
                         }
                     });
 
@@ -3876,7 +4028,6 @@
 
     /**
      * Encapsulates the DRM properties of the source.
-     * @hide
      */
     public static final class DrmInfo {
         private Map<UUID, byte[]> mMapPssh;
@@ -4013,10 +4164,8 @@
     };  // DrmInfo
 
     /**
-     * Thrown when a DRM method is called before preparing a DRM scheme through
-     * {@link MediaPlayer2#prepareDrm(DataSourceDesc, UUID)}.
+     * Thrown when a DRM method is called when there is no active DRM session.
      * Extends MediaDrm.MediaDrmException
-     * @hide
      */
     public static final class NoDrmSchemeException extends MediaDrmException {
         public NoDrmSchemeException(String detailMessage) {
@@ -4291,9 +4440,9 @@
         }
 
         void prepare(UUID uuid) throws UnsupportedSchemeException,
-                ResourceBusyException, NotProvisionedException {
-            final OnDrmConfigHelper onDrmConfigHelper = mOnDrmConfigHelper;
-            Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigHelper: " + onDrmConfigHelper);
+                ResourceBusyException, NotProvisionedException, InterruptedException,
+                ExecutionException {
+            Log.v(TAG, "prepareDrm: uuid: " + uuid);
 
             synchronized (this) {
                 if (mActiveDrmUUID != null) {
@@ -4334,9 +4483,13 @@
             }  // synchronized
 
             // call the callback outside the lock
-            if (onDrmConfigHelper != null)  {
-                onDrmConfigHelper.onDrmConfig(MediaPlayer2.this, mDSD);
-            }
+            sendDrmEventWait(new DrmEventNotifier<Void>() {
+                @Override
+                public Void notifyWait(DrmEventCallback callback) {
+                    callback.onDrmConfig(MediaPlayer2.this, mDSD, mDrmObj);
+                    return null;
+                }
+            });
 
             synchronized (this) {
                 mDrmConfigAllowed = false;
@@ -4506,7 +4659,7 @@
                 @Override
                 public void notify(DrmEventCallback callback) {
                     callback.onDrmPrepared(
-                            MediaPlayer2.this, mDSD, finalStatus);
+                            MediaPlayer2.this, mDSD, finalStatus, /* TODO: keySetId */ null);
                 }
             });
 
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 25b1df2..1304afe 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -302,6 +302,34 @@
          *  {@link #DEFAULT} otherwise. */
         public static final int UNPROCESSED = 9;
 
+
+        /**
+         * Source for capturing audio meant to be processed in real time and played back for live
+         * performance (e.g karaoke).
+         * <p>
+         * The capture path will minimize latency and coupling with
+         * playback path.
+         * </p>
+         */
+        public static final int VOICE_PERFORMANCE = 10;
+
+        /**
+         * Source for an echo canceller to capture the reference signal to be cancelled.
+         * <p>
+         * The echo reference signal will be captured as close as possible to the DAC in order
+         * to include all post processing applied to the playback path.
+         * </p><p>
+         * Capturing the echo reference requires the
+         * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT} permission.
+         * This permission is reserved for use by system components and is not available to
+         * third-party applications.
+         * </p>
+         * @hide
+         */
+        @SystemApi
+        @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)
+        public static final int ECHO_REFERENCE = 1997;
+
         /**
          * Audio source for capturing broadcast radio tuner output.
          * @hide
@@ -343,6 +371,7 @@
         case AudioSource.VOICE_COMMUNICATION:
         //case REMOTE_SUBMIX:  considered "system" as it requires system permissions
         case AudioSource.UNPROCESSED:
+        case AudioSource.VOICE_PERFORMANCE:
             return false;
         default:
             return true;
@@ -372,6 +401,10 @@
             return "REMOTE_SUBMIX";
         case AudioSource.UNPROCESSED:
             return "UNPROCESSED";
+        case AudioSource.ECHO_REFERENCE:
+            return "ECHO_REFERENCE";
+        case AudioSource.VOICE_PERFORMANCE:
+            return "VOICE_PERFORMANCE";
         case AudioSource.RADIO_TUNER:
             return "RADIO_TUNER";
         case AudioSource.HOTWORD:
@@ -524,7 +557,7 @@
      * @see android.media.MediaRecorder.AudioSource
      */
     public static final int getAudioSourceMax() {
-        return AudioSource.UNPROCESSED;
+        return AudioSource.VOICE_PERFORMANCE;
     }
 
     /**
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 7b20f7a..04999ca 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -19,7 +19,7 @@
 import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS;
 import static android.media.MediaConstants.KEY_PACKAGE_NAME;
 import static android.media.MediaConstants.KEY_PID;
-import static android.media.MediaConstants.KEY_SESSION2_STUB;
+import static android.media.MediaConstants.KEY_SESSION2LINK;
 import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
 import static android.media.Session2Command.RESULT_INFO_SKIPPED;
 import static android.media.Session2Token.TYPE_SESSION;
@@ -31,7 +31,6 @@
 import android.content.Intent;
 import android.media.session.MediaSessionManager;
 import android.media.session.MediaSessionManager.RemoteUserInfo;
-import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Process;
@@ -41,7 +40,6 @@
 import android.util.Log;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -56,10 +54,9 @@
  * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
  * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
  * for consistent behavior across all devices.
- * @hide
  */
 public class MediaSession2 implements AutoCloseable {
-    static final String TAG = "MediaSession";
+    static final String TAG = "MediaSession2";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     // Note: This checks the uniqueness of a session ID only in a single process.
@@ -89,7 +86,6 @@
     private final Handler mResultHandler;
 
     //@GuardedBy("mLock")
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
     private boolean mClosed;
 
     MediaSession2(@NonNull Context context, @NonNull String id, PendingIntent sessionActivity,
@@ -113,20 +109,25 @@
                 Context.MEDIA_SESSION_SERVICE);
         // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
         mResultHandler = new Handler(context.getMainLooper());
+        mClosed = false;
     }
 
     @Override
     public void close() {
         try {
+            List<ControllerInfo> controllerInfos;
+            synchronized (mLock) {
+                if (mClosed) {
+                    return;
+                }
+                mClosed = true;
+                controllerInfos = getConnectedControllers();
+                mConnectedControllers.clear();
+                mCallback.onSessionClosed(this);
+            }
             synchronized (MediaSession2.class) {
                 SESSION_ID_LIST.remove(mSessionId);
             }
-            Collection<ControllerInfo> controllerInfos;
-            synchronized (mLock) {
-                controllerInfos = mConnectedControllers.values();
-                mConnectedControllers.clear();
-                mClosed = true;
-            }
             for (ControllerInfo info : controllerInfos) {
                 info.notifyDisconnected();
             }
@@ -161,10 +162,7 @@
         if (command == null) {
             throw new IllegalArgumentException("command shouldn't be null");
         }
-        Collection<ControllerInfo> controllerInfos;
-        synchronized (mLock) {
-            controllerInfos = mConnectedControllers.values();
-        }
+        List<ControllerInfo> controllerInfos = getConnectedControllers();
         for (ControllerInfo controller : controllerInfos) {
             controller.sendSessionCommand(command, args, null);
         }
@@ -179,6 +177,7 @@
      * @return a token which will be sent together in {@link SessionCallback#onCommandResult}
      *     when its result is received.
      */
+    @NonNull
     public Object sendSessionCommand(@NonNull ControllerInfo controller,
             @NonNull Session2Command command, @Nullable Bundle args) {
         if (controller == null) {
@@ -206,7 +205,10 @@
      * @param controller the controller to get the session command
      * @param token the token which is returned from {@link #sendSessionCommand}.
      */
-    public void cancelSessionCommand(ControllerInfo controller, Object token) {
+    public void cancelSessionCommand(@NonNull ControllerInfo controller, @NonNull Object token) {
+        if (controller == null) {
+            throw new IllegalArgumentException("controller shouldn't be null");
+        }
         if (token == null) {
             throw new IllegalArgumentException("token shouldn't be null");
         }
@@ -219,23 +221,26 @@
         }
     }
 
-    // Called by Session2Link.onConnect
-    void onConnect(final Controller2Link controller, int seq, Bundle connectionRequest) {
-        if (controller == null || connectionRequest == null) {
-            return;
+    SessionCallback getCallback() {
+        return mCallback;
+    }
+
+    // Called by Session2Link.onConnect and MediaSession2Service.MediaSession2ServiceStub.connect
+    void onConnect(final Controller2Link controller, int callingPid, int callingUid, int seq,
+            Bundle connectionRequest) {
+        if (callingPid == 0) {
+            // The pid here is from Binder.getCallingPid(), which can be 0 for an oneway call from
+            // the remote process. If it's the case, use PID from the connectionRequest.
+            callingPid = connectionRequest.getInt(KEY_PID);
         }
-        final int uid = Binder.getCallingUid();
-        final int callingPid = Binder.getCallingPid();
-        final long token = Binder.clearCallingIdentity();
-        // Binder.getCallingPid() can be 0 for an oneway call from the remote process.
-        // If it's the case, use PID from the ConnectionRequest.
-        final int pid = (callingPid != 0) ? callingPid : connectionRequest.getInt(KEY_PID);
-        final String pkg = connectionRequest.getString(KEY_PACKAGE_NAME);
-        try {
-            RemoteUserInfo remoteUserInfo = new RemoteUserInfo(pkg, pid, uid);
-            final ControllerInfo controllerInfo = new ControllerInfo(remoteUserInfo,
-                    mSessionManager.isTrustedForMediaControl(remoteUserInfo), controller);
-            mCallbackExecutor.execute(() -> {
+        String callingPkg = connectionRequest.getString(KEY_PACKAGE_NAME);
+
+        RemoteUserInfo remoteUserInfo = new RemoteUserInfo(callingPkg, callingPid, callingUid);
+        final ControllerInfo controllerInfo = new ControllerInfo(remoteUserInfo,
+                mSessionManager.isTrustedForMediaControl(remoteUserInfo), controller);
+        mCallbackExecutor.execute(() -> {
+            boolean connected = false;
+            try {
                 if (isClosed()) {
                     return;
                 }
@@ -244,77 +249,71 @@
                 // Don't reject connection for the request from trusted app.
                 // Otherwise server will fail to retrieve session's information to dispatch
                 // media keys to.
-                boolean accept =
-                        controllerInfo.mAllowedCommands != null || controllerInfo.isTrusted();
-                if (accept) {
-                    if (controllerInfo.mAllowedCommands == null) {
-                        // For trusted apps, send non-null allowed commands to keep
-                        // connection.
-                        controllerInfo.mAllowedCommands =
-                                new Session2CommandGroup.Builder().build();
+                if (controllerInfo.mAllowedCommands == null && !controllerInfo.isTrusted()) {
+                    return;
+                }
+                if (controllerInfo.mAllowedCommands == null) {
+                    // For trusted apps, send non-null allowed commands to keep
+                    // connection.
+                    controllerInfo.mAllowedCommands =
+                            new Session2CommandGroup.Builder().build();
+                }
+                if (DEBUG) {
+                    Log.d(TAG, "Accepting connection: " + controllerInfo);
+                }
+                synchronized (mLock) {
+                    if (mConnectedControllers.containsKey(controller)) {
+                        Log.w(TAG, "Controller " + controllerInfo + " has sent connection"
+                                + " request multiple times");
                     }
+                    mConnectedControllers.put(controller, controllerInfo);
+                }
+                // If connection is accepted, notify the current state to the controller.
+                // It's needed because we cannot call synchronous calls between
+                // session/controller.
+                Bundle connectionResult = new Bundle();
+                connectionResult.putParcelable(KEY_SESSION2LINK, mSessionStub);
+                connectionResult.putParcelable(KEY_ALLOWED_COMMANDS,
+                        controllerInfo.mAllowedCommands);
+
+                // Double check if session is still there, because close() can be called in
+                // another thread.
+                if (isClosed()) {
+                    return;
+                }
+                controllerInfo.notifyConnected(connectionResult);
+                connected = true;
+            } finally {
+                if (!connected) {
                     if (DEBUG) {
-                        Log.d(TAG, "Accepting connection: " + controllerInfo);
+                        Log.d(TAG, "Rejecting connection or notifying that session is closed"
+                                + ", controllerInfo=" + controllerInfo);
                     }
                     synchronized (mLock) {
-                        if (mConnectedControllers.containsKey(controller)) {
-                            Log.w(TAG, "Controller " + controllerInfo + " has sent connection"
-                                    + " request multiple times");
-                        }
-                        mConnectedControllers.put(controller, controllerInfo);
-                    }
-                    // If connection is accepted, notify the current state to the controller.
-                    // It's needed because we cannot call synchronous calls between
-                    // session/controller.
-                    Bundle connectionResult = new Bundle();
-                    connectionResult.putParcelable(KEY_SESSION2_STUB, mSessionStub);
-                    connectionResult.putParcelable(KEY_ALLOWED_COMMANDS,
-                            controllerInfo.mAllowedCommands);
-
-                    // Double check if session is still there, because close() can be called in
-                    // another thread.
-                    if (isClosed()) {
-                        return;
-                    }
-                    controllerInfo.notifyConnected(connectionResult);
-                } else {
-                    if (DEBUG) {
-                        Log.d(TAG, "Rejecting connection, controllerInfo=" + controllerInfo);
+                        mConnectedControllers.remove(controller);
                     }
                     controllerInfo.notifyDisconnected();
                 }
-            });
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+            }
+        });
     }
 
     // Called by Session2Link.onDisconnect
-    void onDisconnect(final Controller2Link controller, int seq) {
-        if (controller == null) {
-            return;
-        }
+    void onDisconnect(@NonNull final Controller2Link controller, int seq) {
         final ControllerInfo controllerInfo;
         synchronized (mLock) {
-            controllerInfo = mConnectedControllers.get(controller);
+            controllerInfo = mConnectedControllers.remove(controller);
         }
         if (controllerInfo == null) {
             return;
         }
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            mCallbackExecutor.execute(() -> {
-                mCallback.onDisconnected(MediaSession2.this, controllerInfo);
-            });
-            mConnectedControllers.remove(controller);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+        mCallbackExecutor.execute(() -> {
+            mCallback.onDisconnected(MediaSession2.this, controllerInfo);
+        });
     }
 
     // Called by Session2Link.onSessionCommand
-    void onSessionCommand(final Controller2Link controller, final int seq,
+    void onSessionCommand(@NonNull final Controller2Link controller, final int seq,
             final Session2Command command, final Bundle args,
             @Nullable ResultReceiver resultReceiver) {
         if (controller == null) {
@@ -329,34 +328,28 @@
         }
 
         // TODO: check allowed commands.
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                controllerInfo.addRequestedCommandSeqNumber(seq);
-            }
-
-            mCallbackExecutor.execute(() -> {
-                if (!controllerInfo.removeRequestedCommandSeqNumber(seq)) {
-                    resultReceiver.send(RESULT_INFO_SKIPPED, null);
-                    return;
-                }
-                Session2Command.Result result = mCallback.onSessionCommand(
-                        MediaSession2.this, controllerInfo, command, args);
-                if (resultReceiver != null) {
-                    if (result == null) {
-                        throw new RuntimeException("onSessionCommand shouldn't return null");
-                    } else {
-                        resultReceiver.send(result.getResultCode(), result.getResultData());
-                    }
-                }
-            });
-        } finally {
-            Binder.restoreCallingIdentity(token);
+        synchronized (mLock) {
+            controllerInfo.addRequestedCommandSeqNumber(seq);
         }
+        mCallbackExecutor.execute(() -> {
+            if (!controllerInfo.removeRequestedCommandSeqNumber(seq)) {
+                resultReceiver.send(RESULT_INFO_SKIPPED, null);
+                return;
+            }
+            Session2Command.Result result = mCallback.onSessionCommand(
+                    MediaSession2.this, controllerInfo, command, args);
+            if (resultReceiver != null) {
+                if (result == null) {
+                    throw new RuntimeException("onSessionCommand shouldn't return null");
+                } else {
+                    resultReceiver.send(result.getResultCode(), result.getResultData());
+                }
+            }
+        });
     }
 
     // Called by Session2Link.onCancelCommand
-    void onCancelCommand(final Controller2Link controller, final int seq) {
+    void onCancelCommand(@NonNull final Controller2Link controller, final int seq) {
         final ControllerInfo controllerInfo;
         synchronized (mLock) {
             controllerInfo = mConnectedControllers.get(controller);
@@ -364,13 +357,15 @@
         if (controllerInfo == null) {
             return;
         }
+        controllerInfo.removeRequestedCommandSeqNumber(seq);
+    }
 
-        final long token = Binder.clearCallingIdentity();
-        try {
-            controllerInfo.removeRequestedCommandSeqNumber(seq);
-        } finally {
-            Binder.restoreCallingIdentity(token);
+    private List<ControllerInfo> getConnectedControllers() {
+        List<ControllerInfo> controllers = new ArrayList<>();
+        synchronized (mLock) {
+            controllers.addAll(mConnectedControllers.values());
         }
+        return controllers;
     }
 
     /**
@@ -558,7 +553,7 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (!(obj instanceof ControllerInfo)) return false;
             if (this == obj) return true;
 
@@ -570,6 +565,7 @@
         }
 
         @Override
+        @NonNull
         public String toString() {
             return "ControllerInfo {pkg=" + mRemoteUserInfo.getPackageName() + ", uid="
                     + mRemoteUserInfo.getUid() + ", allowedCommands=" + mAllowedCommands + "})";
@@ -656,6 +652,8 @@
      * This API is not generally intended for third party application developers.
      */
     public abstract static class SessionCallback {
+        ForegroundServiceEventCallback mForegroundServiceEventCallback;
+
         /**
          * Called when a controller is created for this session. Return allowed commands for
          * controller. By default it returns {@code null}.
@@ -693,7 +691,7 @@
          * @return the result for the session command. A runtime exception will be thrown if null
          *         is returned.
          */
-        @NonNull
+        @Nullable
         public Session2Command.Result onSessionCommand(@NonNull MediaSession2 session,
                 @NonNull ControllerInfo controller, @NonNull Session2Command command,
                 @Nullable Bundle args) {
@@ -712,5 +710,19 @@
         public void onCommandResult(@NonNull MediaSession2 session,
                 @NonNull ControllerInfo controller, @NonNull Object token,
                 @NonNull Session2Command command, @NonNull Session2Command.Result result) {}
+
+        final void onSessionClosed(MediaSession2 session) {
+            if (mForegroundServiceEventCallback != null) {
+                mForegroundServiceEventCallback.onSessionClosed(session);
+            }
+        }
+
+        void setForegroundServiceEventCallback(ForegroundServiceEventCallback callback) {
+            mForegroundServiceEventCallback = callback;
+        }
+
+        abstract static class ForegroundServiceEventCallback {
+            public void onSessionClosed(MediaSession2 session) {}
+        }
     }
 }
diff --git a/media/java/android/media/MediaSession2Service.java b/media/java/android/media/MediaSession2Service.java
new file mode 100644
index 0000000..8fb00fe
--- /dev/null
+++ b/media/java/android/media/MediaSession2Service.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Service containing {@link MediaSession2}.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
+ * @hide
+ */
+// TODO: Unhide
+// TODO: Add onUpdateNotification(), and calls it to get Notification for startForegroundService()
+//       when a session's player state becomes playing.
+public abstract class MediaSession2Service extends Service {
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    public static final String SERVICE_INTERFACE = "android.media.MediaSession2Service";
+
+    private static final String TAG = "MediaSession2Service";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private Map<String, MediaSession2> mSessions = new ArrayMap<>();
+
+    private MediaSession2ServiceStub mStub;
+
+    /**
+     * Called by the system when the service is first created. Do not call this method directly.
+     * <p>
+     * Override this method if you need your own initialization. Derived classes MUST call through
+     * to the super class's implementation of this method.
+     */
+    @CallSuper
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mStub = new MediaSession2ServiceStub(this);
+    }
+
+    @CallSuper
+    @Override
+    @Nullable
+    public IBinder onBind(@NonNull Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            return mStub;
+        }
+        return null;
+    }
+
+    @CallSuper
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        // TODO: Dispatch media key events to the primary session.
+        return START_STICKY;
+    }
+
+    /**
+     * Called by the system to notify that it is no longer used and is being removed. Do not call
+     * this method directly.
+     * <p>
+     * Override this method if you need your own clean up. Derived classes MUST call through
+     * to the super class's implementation of this method.
+     */
+    @CallSuper
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        synchronized (mLock) {
+            for (MediaSession2 session : mSessions.values()) {
+                session.getCallback().setForegroundServiceEventCallback(null);
+            }
+            mSessions.clear();
+        }
+        mStub.close();
+    }
+
+    /**
+     * Called when a {@link MediaController2} is created with the this service's
+     * {@link Session2Token}. Return the primary session for telling the controller which session to
+     * connect.
+     * <p>
+     * Primary session is the highest priority session that this service manages. Here are some
+     * recommendations of the primary session.
+     * <ol>
+     * <li>When there's no {@link MediaSession2}, create and return a new session. Resume the
+     * playback that the app has the lastly played with the new session. The behavior is what
+     * framework expects when the framework sends key events to the service.</li>
+     * <li>When there's multiple {@link MediaSession2}s, pick the session that has the lastly
+     * started the playback. This is the same way as the framework prioritize sessions to receive
+     * media key events.</li>
+     * </ol>
+     * <p>
+     * Session returned here will be added to this service automatically. You don't need to call
+     * {@link #addSession(MediaSession2)} for that.
+     * <p>
+     * Session service will accept or reject the connection with the
+     * {@link MediaSession2.SessionCallback} in the session returned here.
+     * <p>
+     * This method is always called on the main thread.
+     *
+     * @return a new session
+     * @see MediaSession2.Builder
+     * @see #getSessions()
+     */
+    @NonNull
+    public abstract MediaSession2 onGetPrimarySession();
+
+    /**
+     * Adds a session to this service.
+     * <p>
+     * Added session will be removed automatically when it's closed, or removed when
+     * {@link #removeSession} is called.
+     *
+     * @param session a session to be added.
+     * @see #removeSession(MediaSession2)
+     */
+    public final void addSession(@NonNull MediaSession2 session) {
+        if (session == null) {
+            throw new IllegalArgumentException("session shouldn't be null");
+        }
+        if (session.isClosed()) {
+            throw new IllegalArgumentException("session is already closed");
+        }
+        synchronized (mLock) {
+            MediaSession2 previousSession = mSessions.get(session.getSessionId());
+            if (previousSession != session) {
+                if (previousSession != null) {
+                    Log.w(TAG, "Session ID should be unique, ID=" + session.getSessionId()
+                            + ", previous=" + previousSession + ", session=" + session);
+                }
+                return;
+            }
+            mSessions.put(session.getSessionId(), session);
+            session.getCallback().setForegroundServiceEventCallback(
+                    new MediaSession2.SessionCallback.ForegroundServiceEventCallback() {
+                        @Override
+                        public void onSessionClosed(MediaSession2 session) {
+                            removeSession(session);
+                        }
+                    });
+        }
+    }
+
+    /**
+     * Removes a session from this service.
+     *
+     * @param session a session to be removed.
+     * @see #addSession(MediaSession2)
+     */
+    public final void removeSession(@NonNull MediaSession2 session) {
+        if (session == null) {
+            throw new IllegalArgumentException("session shouldn't be null");
+        }
+        synchronized (mLock) {
+            mSessions.remove(session.getSessionId());
+        }
+    }
+
+    /**
+     * Gets the list of {@link MediaSession2}s that you've added to this service.
+     *
+     * @return sessions
+     */
+    public final @NonNull List<MediaSession2> getSessions() {
+        List<MediaSession2> list = new ArrayList<>();
+        synchronized (mLock) {
+            list.addAll(mSessions.values());
+        }
+        return list;
+    }
+
+    private static final class MediaSession2ServiceStub extends IMediaSession2Service.Stub
+            implements AutoCloseable {
+        final WeakReference<MediaSession2Service> mService;
+        final Handler mHandler;
+
+        MediaSession2ServiceStub(MediaSession2Service service) {
+            mService = new WeakReference<>(service);
+            mHandler = new Handler(service.getMainLooper());
+        }
+
+        @Override
+        public void connect(Controller2Link caller, int seq, Bundle connectionRequest) {
+            if (mService.get() == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "Service is already destroyed");
+                }
+                return;
+            }
+            if (caller == null || connectionRequest == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "Ignoring calls with illegal arguments, caller=" + caller
+                            + ", connectionRequest=" + connectionRequest);
+                }
+                return;
+            }
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mHandler.post(() -> {
+                    boolean shouldNotifyDisconnected = true;
+                    try {
+                        final MediaSession2Service service = mService.get();
+                        if (service == null) {
+                            if (DEBUG) {
+                                Log.d(TAG, "Service isn't available");
+                            }
+                            return;
+                        }
+                        if (DEBUG) {
+                            Log.d(TAG, "Handling incoming connection request from the"
+                                    + " controller, controller=" + caller + ", uid=" + uid);
+                        }
+                        final MediaSession2 session;
+                        session = service.onGetPrimarySession();
+                        service.addSession(session);
+                        shouldNotifyDisconnected = false;
+                        session.onConnect(caller, pid, uid, seq, connectionRequest);
+                    } catch (Exception e) {
+                        // Don't propagate exception in service to the controller.
+                        Log.w(TAG, "Failed to add a session to session service", e);
+                    } finally {
+                        // Trick to call onDisconnected() in one place.
+                        if (shouldNotifyDisconnected) {
+                            if (DEBUG) {
+                                Log.d(TAG, "Service has destroyed prematurely."
+                                        + " Rejecting connection");
+                            }
+                            try {
+                                caller.notifyDisconnected(0);
+                            } catch (RuntimeException e) {
+                                // Controller may be died prematurely.
+                                // Not an issue because we'll ignore it anyway.
+                            }
+                        }
+                    }
+                });
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void close() {
+            mHandler.removeCallbacksAndMessages(null);
+            mService.clear();
+        }
+    }
+}
diff --git a/media/java/android/media/MicrophoneDirection.java b/media/java/android/media/MicrophoneDirection.java
new file mode 100644
index 0000000..99201c0
--- /dev/null
+++ b/media/java/android/media/MicrophoneDirection.java
@@ -0,0 +1,62 @@
+/*
+ * 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.media;
+
+/**
+ * @hide
+ */
+public interface MicrophoneDirection {
+    /**
+     * @hide
+     */
+    int MIC_DIRECTION_UNSPECIFIED = 0;
+
+    /**
+     * @hide
+     */
+    int MIC_DIRECTION_FRONT = 1;
+
+    /**
+     * @hide
+     */
+    int MIC_DIRECTION_BACK = 2;
+
+    /**
+     * @hide
+     */
+    int MIC_DIRECTION_EXTERNAL = 3;
+
+    /**
+     * Specifies the logical microphone (for processing).
+     *
+     * @param direction Direction constant (MicrophoneDirection.MIC_DIRECTION_*)
+     * @return retval OK if the call is successful, an error code otherwise.
+     * @hide
+     */
+    int setMicrophoneDirection(int direction);
+
+    /**
+     * Specifies the zoom factor (i.e. the field dimension) for the selected microphone
+     * (for processing). The selected microphone is determined by the use-case for the stream.
+     *
+     * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle),
+     * though 0 (no zoom) to 1 (maximum zoom).
+     * @return retval OK if the call is successful, an error code otherwise.
+     * @hide
+     */
+    int setMicrophoneFieldDimension(float zoom);
+}
diff --git a/media/java/android/media/Session2CommandGroup.java b/media/java/android/media/Session2CommandGroup.java
index 519888e..a189c26 100644
--- a/media/java/android/media/Session2CommandGroup.java
+++ b/media/java/android/media/Session2CommandGroup.java
@@ -59,6 +59,7 @@
      *
      * @param commands The collection of commands to copy.
      */
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
     Session2CommandGroup(@Nullable Collection<Session2Command> commands) {
         if (commands != null) {
             mCommands.addAll(commands);
diff --git a/media/java/android/media/Session2Link.java b/media/java/android/media/Session2Link.java
index 5fe558d..08664aa 100644
--- a/media/java/android/media/Session2Link.java
+++ b/media/java/android/media/Session2Link.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.annotation.NonNull;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -145,8 +146,9 @@
     }
 
     /** Stub implementation for IMediaSession2.connect */
-    public void onConnect(final Controller2Link caller, int seq, Bundle connectionRequest) {
-        mSession.onConnect(caller, seq, connectionRequest);
+    public void onConnect(final Controller2Link caller, int pid, int uid, int seq,
+            Bundle connectionRequest) {
+        mSession.onConnect(caller, pid, uid, seq, connectionRequest);
     }
 
     /** Stub implementation for IMediaSession2.disconnect */
@@ -168,23 +170,57 @@
     private class Session2Stub extends IMediaSession2.Stub {
         @Override
         public void connect(final Controller2Link caller, int seq, Bundle connectionRequest) {
-            Session2Link.this.onConnect(caller, seq, connectionRequest);
+            if (caller == null || connectionRequest == null) {
+                return;
+            }
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Session2Link.this.onConnect(caller, pid, uid, seq, connectionRequest);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
 
         @Override
         public void disconnect(final Controller2Link caller, int seq) {
-            Session2Link.this.onDisconnect(caller, seq);
+            if (caller == null) {
+                return;
+            }
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Session2Link.this.onDisconnect(caller, seq);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
 
         @Override
         public void sendSessionCommand(final Controller2Link caller, final int seq,
                 final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
-            Session2Link.this.onSessionCommand(caller, seq, command, args, resultReceiver);
+            if (caller == null) {
+                return;
+            }
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Session2Link.this.onSessionCommand(caller, seq, command, args, resultReceiver);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
 
         @Override
         public void cancelSessionCommand(final Controller2Link caller, final int seq) {
-            Session2Link.this.onCancelCommand(caller, seq);
+            if (caller == null) {
+                return;
+            }
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Session2Link.this.onCancelCommand(caller, seq);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
     }
 }
diff --git a/media/java/android/media/Session2Token.java b/media/java/android/media/Session2Token.java
index e1fff38..c7b8911 100644
--- a/media/java/android/media/Session2Token.java
+++ b/media/java/android/media/Session2Token.java
@@ -34,7 +34,7 @@
 import java.util.Objects;
 
 /**
- * Represents an ongoing {@link MediaSession2} or a {@link MediaSession2Service}.
+ * Represents an ongoing {@link MediaSession2} or a MediaSession2Service.
  * If it's representing a session service, it may not be ongoing.
  * <p>
  * This API is not generally intended for third party application developers.
@@ -45,9 +45,8 @@
  * This may be passed to apps by the session owner to allow them to create a
  * {@link MediaController2} to communicate with the session.
  * <p>
- * It can be also obtained by {@link MediaSessionManager}.
+ * It can be also obtained by {@link android.media.session.MediaSessionManager}.
  *
- * @hide
  */
 // New version of MediaSession2.Token for following reasons
 //   - Stop implementing Parcelable for updatable support
@@ -56,6 +55,7 @@
 //     This helps controller apps to keep target of dispatching media key events in uniform way.
 //     For details about the reason, see following. (Android O+)
 //         android.media.session.MediaSessionManager.Callback#onAddressedPlayerChanged
+// TODO: use @link for MediaSession2Service
 public final class Session2Token implements Parcelable {
     private static final String TAG = "Session2Token";
 
@@ -75,7 +75,7 @@
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "TYPE_", value = {TYPE_SESSION, TYPE_SESSION_SERVICE, TYPE_LIBRARY_SERVICE})
+    @IntDef(prefix = "TYPE_", value = {TYPE_SESSION, TYPE_SESSION_SERVICE})
     public @interface TokenType {
     }
 
@@ -85,15 +85,10 @@
     public static final int TYPE_SESSION = 0;
 
     /**
-     * Type for {@link MediaSession2Service}.
+     * Type for MediaSession2Service.
      */
     public static final int TYPE_SESSION_SERVICE = 1;
 
-    /**
-     * Type for {@link MediaLibrary2Service}.
-     */
-    public static final int TYPE_LIBRARY_SERVICE = 2;
-
     private final int mUid;
     private final @TokenType int mType;
     private final String mPackageName;
@@ -102,8 +97,7 @@
     private final ComponentName mComponentName;
 
     /**
-     * Constructor for the token with type {@link #TYPE_SESSION_SERVICE} or
-     * {@link #TYPE_LIBRARY_SERVICE}.
+     * Constructor for the token with type {@link #TYPE_SESSION_SERVICE}.
      *
      * @param context The context.
      * @param serviceComponent The component name of the service.
@@ -158,9 +152,7 @@
         mType = in.readInt();
         mPackageName = in.readString();
         mServiceName = in.readString();
-        // TODO: Uncomment below and stop hardcode mSessionLink
-        mSessionLink = null;
-        //mSessionLink = ISession.Stub.asInterface(in.readStrongBinder());
+        mSessionLink = Session2Link.CREATOR.createFromParcel(in);
         mComponentName = ComponentName.unflattenFromString(in.readString());
     }
 
@@ -170,8 +162,7 @@
         dest.writeInt(mType);
         dest.writeString(mPackageName);
         dest.writeString(mServiceName);
-        // TODO: Uncomment below
-        //dest.writeStrongBinder(mSessionLink.getBinder());
+        mSessionLink.writeToParcel(dest, flags);
         dest.writeString(mComponentName == null ? "" : mComponentName.flattenToString());
     }
 
@@ -239,7 +230,6 @@
      * @return type of the token
      * @see #TYPE_SESSION
      * @see #TYPE_SESSION_SERVICE
-     * @see #TYPE_LIBRARY_SERVICE
      */
     public @TokenType int getType() {
         return mType;
diff --git a/media/java/android/media/session/MediaSessionProviderService.java b/media/java/android/media/session/MediaSessionProviderService.java
new file mode 100644
index 0000000..9a346ff
--- /dev/null
+++ b/media/java/android/media/session/MediaSessionProviderService.java
@@ -0,0 +1,35 @@
+/*
+ * 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.media.session;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Abstract class for mainline module services.
+ *
+ * @hide  // TODO: Make it as a @SystemApi
+ */
+public abstract class MediaSessionProviderService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        // TODO: Return IMediaSessionProviderService.Stub()
+        return null;
+    }
+}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index d6b6339..0198470 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -34,7 +34,6 @@
         "libutils",
         "libbinder",
         "libmedia",
-        "libmediaextractor",
         "libmedia_omx",
         "libmediametrics",
         "libmediadrm",
@@ -85,7 +84,7 @@
 }
 
 cc_library_shared {
-    name: "libmedia2_jni",
+    name: "libmediaplayer2_jni",
 
     srcs: [
         "android_media_DataSourceCallback.cpp",
@@ -117,7 +116,10 @@
         "libz",
     ],
 
-    header_libs: ["libhardware_headers"],
+    header_libs: [
+        "libhardware_headers",
+        "libnativewindow_headers",
+    ],
 
     static_libs: [
         "libbase",
@@ -125,12 +127,12 @@
         "libcutils",
         "libmedia_helper",
         "libmedia_player2_util",
-        "libmediaextractor",
         "libmediaplayer2",
         "libmediaplayer2-protos",
         "libmediandk_utils",
         "libmediautils",
         "libprotobuf-cpp-lite",
+        "libstagefright",
         "libstagefright_esds",
         "libstagefright_foundation",
         "libstagefright_httplive",
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
new file mode 100644
index 0000000..1d7d6de
--- /dev/null
+++ b/media/jni/Android.mk
@@ -0,0 +1,30 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_SRC_FILES := \
+    Media2Jni.cpp \
+
+# TODO: Move libmedia2_jni from system to media apex. Currently, libraries defined in
+#       Android.mk is not visible in apex build.
+LOCAL_MODULE:= libmedia2_jni
+LOCAL_SHARED_LIBRARIES := libdl liblog
+
+sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
+  $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+  $(UBSAN_RUNTIME_LIBRARY) \
+  $(TSAN_RUNTIME_LIBRARY)))
+
+# $(info Sanitizer:  $(sanitizer_runtime_libraries))
+
+ndk_libraries := $(call normalize-path-list,$(addprefix lib,$(addsuffix .so,\
+  $(NDK_PREBUILT_SHARED_LIBRARIES))))
+
+# $(info NDK:  $(ndk_libraries))
+
+LOCAL_CFLAGS += -DLINKED_LIBRARIES='"$(sanitizer_runtime_libraries):$(ndk_libraries)"'
+
+sanitizer_runtime_libraries :=
+ndk_libraries :=
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/Media2Jni.cpp b/media/jni/Media2Jni.cpp
new file mode 100644
index 0000000..6c0a65c
--- /dev/null
+++ b/media/jni/Media2Jni.cpp
@@ -0,0 +1,89 @@
+/*
+**
+** 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.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaPlayer2-JNI"
+#include "utils/Log.h"
+
+#include "jni.h"
+#include <android/dlext.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+
+extern "C" {
+  // Copied from GraphicsEnv.cpp
+  // TODO(b/37049319) Get this from a header once one exists
+  android_namespace_t* android_create_namespace(const char* name,
+                                                const char* ld_library_path,
+                                                const char* default_library_path,
+                                                uint64_t type,
+                                                const char* permitted_when_isolated_path,
+                                                android_namespace_t* parent);
+  bool android_link_namespaces(android_namespace_t* from,
+                               android_namespace_t* to,
+                               const char* shared_libs_sonames);
+  enum {
+     ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+  };
+
+}  // extern "C"
+
+static const char kApexLibPath[] =  "/apex/com.android.media/lib"
+#ifdef __LP64__
+    "64"
+#endif
+    "/";
+static const char kMediaPlayer2LibPath[] =  "/apex/com.android.media/lib"
+#ifdef __LP64__
+    "64"
+#endif
+    "/libmediaplayer2_jni.so";
+
+typedef jint (*Media2JniOnLoad)(JavaVM*, void*);
+
+JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+    android_namespace_t *media2Ns = android_create_namespace("media2",
+            nullptr,  // ld_library_path
+            kApexLibPath,
+            ANDROID_NAMESPACE_TYPE_ISOLATED,
+            nullptr,  // permitted_when_isolated_path
+            nullptr); // parent
+    if (!android_link_namespaces(media2Ns, nullptr, LINKED_LIBRARIES)) {
+        ALOGE("Failed to link namespace. Failed to load extractor plug-ins in apex.");
+        return -1;
+    }
+    const android_dlextinfo dlextinfo = {
+        .flags = ANDROID_DLEXT_USE_NAMESPACE,
+        .library_namespace = media2Ns,
+    };
+    // load libmediaplayer2_jni and call JNI_OnLoad.
+    void *libHandle = android_dlopen_ext(kMediaPlayer2LibPath, RTLD_NOW | RTLD_LOCAL, &dlextinfo);
+    if (libHandle == NULL) {
+        ALOGW("couldn't dlopen(%s) %s", kMediaPlayer2LibPath, strerror(errno));
+        return -1;
+    }
+    Media2JniOnLoad media2JniOnLoad = (Media2JniOnLoad) dlsym(libHandle, "JNI_OnLoad");
+    if (!media2JniOnLoad) {
+        ALOGW("%s does not contain JNI_OnLoad()", kMediaPlayer2LibPath);
+        dlclose(libHandle);
+        return -1;
+    }
+    return media2JniOnLoad(vm, reserved);
+}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 7b07bea3..406f9dd 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -648,7 +648,6 @@
 
     capabilities->getSupportedColorFormats(&colorFormats);
     capabilities->getSupportedProfileLevels(&profileLevels);
-    uint32_t flags = capabilities->getFlags();
     sp<AMessage> details = capabilities->getDetails();
 
     jobject defaultFormatObj = NULL;
@@ -687,7 +686,7 @@
 
     return env->NewObject(
             gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
-            profileLevelArray.get(), colorFormatsArray.get(), isEncoder, flags,
+            profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
             defaultFormatRef.get(), detailsRef.get());
 }
 
@@ -700,23 +699,28 @@
         return err;
     }
 
+    // TODO: get alias
     ScopedLocalRef<jstring> nameObject(env,
             env->NewStringUTF(codecInfo->getCodecName()));
 
+    ScopedLocalRef<jstring> canonicalNameObject(env,
+            env->NewStringUTF(codecInfo->getCodecName()));
+
+    MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
     bool isEncoder = codecInfo->isEncoder();
 
-    Vector<AString> mimes;
-    codecInfo->getSupportedMimes(&mimes);
+    Vector<AString> mediaTypes;
+    codecInfo->getSupportedMediaTypes(&mediaTypes);
 
     ScopedLocalRef<jobjectArray> capsArrayObj(env,
-        env->NewObjectArray(mimes.size(), gCodecInfo.capsClazz, NULL));
+        env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
 
-    for (size_t i = 0; i < mimes.size(); i++) {
+    for (size_t i = 0; i < mediaTypes.size(); i++) {
         const sp<MediaCodecInfo::Capabilities> caps =
-                codecInfo->getCapabilitiesFor(mimes[i].c_str());
+                codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
 
         ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
-                env, mimes[i].c_str(), isEncoder, caps));
+                env, mediaTypes[i].c_str(), isEncoder, caps));
 
         env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
     }
@@ -726,10 +730,10 @@
     CHECK(codecInfoClazz.get() != NULL);
 
     jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
-            "(Ljava/lang/String;Z[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
+            "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
 
     *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
-            nameObject.get(), isEncoder, capsArrayObj.get());
+            nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
 
     return OK;
 }
@@ -2079,7 +2083,7 @@
     gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
 
     method = env->GetMethodID(clazz.get(), "<init>",
-            "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZI"
+            "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
             "Ljava/util/Map;Ljava/util/Map;)V");
     CHECK(method != NULL);
     gCodecInfo.capsCtorId = method;
@@ -2217,7 +2221,7 @@
     { "getImage", "(ZI)Landroid/media/Image;",
       (void *)android_media_MediaCodec_getImage },
 
-    { "getName", "()Ljava/lang/String;",
+    { "getCanonicalName", "()Ljava/lang/String;",
       (void *)android_media_MediaCodec_getName },
 
     { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 8de11ca..cf14942 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -41,6 +41,21 @@
     return mcl;
 }
 
+static sp<MediaCodecInfo> getCodecInfo(JNIEnv *env, jint index) {
+    sp<IMediaCodecList> mcl = getCodecList(env);
+    if (mcl == NULL) {
+        // Runtime exception already pending.
+        return NULL;
+    }
+
+    sp<MediaCodecInfo> info = mcl->getCodecInfo(index);
+    if (info == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+    }
+
+    return info;
+}
+
 static jint android_media_MediaCodecList_getCodecCount(
         JNIEnv *env, jobject /* thiz */) {
     sp<IMediaCodecList> mcl = getCodecList(env);
@@ -53,15 +68,22 @@
 
 static jstring android_media_MediaCodecList_getCodecName(
         JNIEnv *env, jobject /* thiz */, jint index) {
-    sp<IMediaCodecList> mcl = getCodecList(env);
-    if (mcl == NULL) {
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
+    if (info == NULL) {
         // Runtime exception already pending.
         return NULL;
     }
 
-    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
+    // TODO: support aliases
+    const char *name = info->getCodecName();
+    return env->NewStringUTF(name);
+}
+
+static jstring android_media_MediaCodecList_getCanonicalName(
+        JNIEnv *env, jobject /* thiz */, jint index) {
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
     if (info == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        // Runtime exception already pending.
         return NULL;
     }
 
@@ -94,39 +116,27 @@
     return ret;
 }
 
-static jboolean android_media_MediaCodecList_isEncoder(
+static jboolean android_media_MediaCodecList_getAttributes(
         JNIEnv *env, jobject /* thiz */, jint index) {
-    sp<IMediaCodecList> mcl = getCodecList(env);
-    if (mcl == NULL) {
-        // Runtime exception already pending.
-        return false;
-    }
-
-    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
     if (info == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return false;
+        // Runtime exception already pending.
+        return 0;
     }
 
-    return info->isEncoder();
+    return info->getAttributes();
 }
 
 static jarray android_media_MediaCodecList_getSupportedTypes(
         JNIEnv *env, jobject /* thiz */, jint index) {
-    sp<IMediaCodecList> mcl = getCodecList(env);
-    if (mcl == NULL) {
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
+    if (info == NULL) {
         // Runtime exception already pending.
         return NULL;
     }
 
-    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
-    if (info == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return NULL;
-    }
-
     Vector<AString> types;
-    info->getSupportedMimes(&types);
+    info->getSupportedMediaTypes(&types);
 
     jclass clazz = env->FindClass("java/lang/String");
     CHECK(clazz != NULL);
@@ -150,17 +160,12 @@
         return NULL;
     }
 
-    sp<IMediaCodecList> mcl = getCodecList(env);
-    if (mcl == NULL) {
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
+    if (info == NULL) {
         // Runtime exception already pending.
         return NULL;
     }
 
-    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
-    if (info == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return NULL;
-    }
 
     const char *typeStr = env->GetStringUTFChars(type, NULL);
     if (typeStr == NULL) {
@@ -186,7 +191,6 @@
 
     capabilities->getSupportedColorFormats(&colorFormats);
     capabilities->getSupportedProfileLevels(&profileLevels);
-    uint32_t flags = capabilities->getFlags();
     sp<AMessage> details = capabilities->getDetails();
     bool isEncoder = info->isEncoder();
 
@@ -240,11 +244,11 @@
     }
 
     jmethodID capsConstructID = env->GetMethodID(capsClazz, "<init>",
-            "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZI"
+            "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
             "Ljava/util/Map;Ljava/util/Map;)V");
 
     jobject caps = env->NewObject(capsClazz, capsConstructID,
-            profileLevelArray, colorFormatsArray, isEncoder, flags,
+            profileLevelArray, colorFormatsArray, isEncoder,
             defaultFormatObj, infoObj);
 
     env->DeleteLocalRef(profileLevelArray);
@@ -288,9 +292,15 @@
 
 static const JNINativeMethod gMethods[] = {
     { "native_getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount },
+
+    { "getCanonicalName", "(I)Ljava/lang/String;",
+      (void *)android_media_MediaCodecList_getCanonicalName },
+
     { "getCodecName", "(I)Ljava/lang/String;",
       (void *)android_media_MediaCodecList_getCodecName },
-    { "isEncoder", "(I)Z", (void *)android_media_MediaCodecList_isEncoder },
+
+    { "getAttributes", "(I)I", (void *)android_media_MediaCodecList_getAttributes },
+
     { "getSupportedTypes", "(I)[Ljava/lang/String;",
       (void *)android_media_MediaCodecList_getSupportedTypes },
 
diff --git a/media/packages/MediaCore/Android.bp b/media/packages/MediaCore/Android.bp
new file mode 100644
index 0000000..c7fd58b
--- /dev/null
+++ b/media/packages/MediaCore/Android.bp
@@ -0,0 +1,21 @@
+android_app {
+    name: "MediaCore",
+
+    srcs: [
+        "src/**/*.java",
+    ],
+
+    static_libs: [
+        // TODO: Temporarily statically linked. Should go into "libs"
+        "media1",
+    ],
+
+    // System app
+    platform_apis: true,
+
+    // Privileged app
+    privileged: true,
+
+    // Make sure that the implementation only relies on SDK or system APIs.
+    sdk_version: "system_current",
+}
diff --git a/media/packages/MediaCore/AndroidManifest.xml b/media/packages/MediaCore/AndroidManifest.xml
new file mode 100644
index 0000000..4e2b274
--- /dev/null
+++ b/media/packages/MediaCore/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/AndroidManifest.xml
+**
+** 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.
+*/
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.media" coreApp="true" android:sharedUserId="android.uid.system"
+    android:sharedUserLabel="@string/android_system_label">
+    <application android:process="system"
+        android:persistent="true"
+        android:directBootAware="true">
+        <service android:name="AmlMediaSessionProviderService" android:singleUser="true">
+            <intent-filter>
+                <action android:name="android.media.session.MediaSessionProviderService"/>
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
diff --git a/media/packages/MediaCore/res/values/strings.xml b/media/packages/MediaCore/res/values/strings.xml
new file mode 100644
index 0000000..59fd635
--- /dev/null
+++ b/media/packages/MediaCore/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+    <!-- Label for the Android system components when they are shown to the user. -->
+    <string name="android_system_label" translatable="false">Android System</string>
+</resources>
+
diff --git a/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java b/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java
new file mode 100644
index 0000000..43b95ab
--- /dev/null
+++ b/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java
@@ -0,0 +1,37 @@
+/*
+ * 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 com.android.media;
+
+import android.content.Context;
+import android.media.session.MediaSessionProviderService;
+import android.os.PowerManager;
+import android.util.Log;
+
+/**
+ * System implementation of MediaSessionProviderService
+ */
+public class AmlMediaSessionProviderService extends MediaSessionProviderService {
+    private static final String TAG = "AmlMediaSessionProviderS";
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private Context mContext;
+
+    public AmlMediaSessionProviderService(Context context) {
+        mContext = context;
+        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+    }
+}
diff --git a/native/android/Android.bp b/native/android/Android.bp
index fdcfc44..73d4c45 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -49,6 +49,7 @@
         "sharedmem.cpp",
         "storage_manager.cpp",
         "surface_texture.cpp",
+        "surface_control.cpp",
         "system_fonts.cpp",
         "trace.cpp",
     ],
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 537aed4..8be8eda 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -205,6 +205,9 @@
     AStorageManager_mountObb;
     AStorageManager_new;
     AStorageManager_unmountObb;
+    ASurfaceControl_create; # introduced=29
+    ASurfaceControl_createFromWindow; # introduced=29
+    ASurfaceControl_destroy; # introduced=29
     ASurfaceTexture_acquireANativeWindow; # introduced=28
     ASurfaceTexture_attachToGLContext; # introduced=28
     ASurfaceTexture_detachFromGLContext; # introduced=28
@@ -213,6 +216,16 @@
     ASurfaceTexture_getTransformMatrix; # introduced=28
     ASurfaceTexture_release; # introduced=28
     ASurfaceTexture_updateTexImage; # introduced=28
+    ASurfaceTransaction_apply; # introduced=29
+    ASurfaceTransaction_create; # introduced=29
+    ASurfaceTransaction_delete; # introduced=29
+    ASurfaceTransaction_setBuffer; # introduced=29
+    ASurfaceTransaction_setBufferTransparency; # introduced=29
+    ASurfaceTransaction_setDamageRegion; # introduced=29
+    ASurfaceTransaction_setGeometry; # introduced=29
+    ASurfaceTransaction_setOnComplete; # introduced=29
+    ASurfaceTransaction_setVisibility; # introduced=29
+    ASurfaceTransaction_setZOrder; # introduced=29
     ASystemFontIterator_open; # introduced=29
     ASystemFontIterator_close; # introduced=29
     ASystemFontIterator_next; # introduced=29
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 8e58210..c3b2e25 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -342,3 +342,8 @@
     RETURN_IF_SENSOR_IS_NULL(ASENSOR_DIRECT_RATE_STOP);
     return static_cast<Sensor const *>(sensor)->getHighestDirectReportRateLevel();
 }
+
+int ASensor_getHandle(ASensor const* sensor) {
+    RETURN_IF_SENSOR_IS_NULL(ASENSOR_INVALID);
+    return static_cast<Sensor const*>(sensor)->getHandle();
+}
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
new file mode 100644
index 0000000..ead5b0b
--- /dev/null
+++ b/native/android/surface_control.cpp
@@ -0,0 +1,232 @@
+/*
+ * 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.
+ */
+
+#include <android/native_window.h>
+#include <android/surface_control.h>
+
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+
+using namespace android;
+
+using Transaction = SurfaceComposerClient::Transaction;
+
+#define CHECK_NOT_NULL(name) \
+    LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument");
+
+#define CHECK_VALID_RECT(name)                                     \
+    LOG_ALWAYS_FATAL_IF(!static_cast<const Rect&>(name).isValid(), \
+                        "invalid arg passed as " #name " argument");
+
+Transaction* ASurfaceTransaction_to_Transaction(ASurfaceTransaction* aSurfaceTransaction) {
+    return reinterpret_cast<Transaction*>(aSurfaceTransaction);
+}
+
+SurfaceControl* ASurfaceControl_to_SurfaceControl(ASurfaceControl* aSurfaceControl) {
+    return reinterpret_cast<SurfaceControl*>(aSurfaceControl);
+}
+
+void SurfaceControl_acquire(SurfaceControl* surfaceControl) {
+    // incStrong/decStrong token must be the same, doesn't matter what it is
+    surfaceControl->incStrong((void*)SurfaceControl_acquire);
+}
+
+void SurfaceControl_release(SurfaceControl* surfaceControl) {
+    // incStrong/decStrong token must be the same, doesn't matter what it is
+    surfaceControl->decStrong((void*)SurfaceControl_acquire);
+}
+
+ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* window, const char* debug_name) {
+    CHECK_NOT_NULL(window);
+    CHECK_NOT_NULL(debug_name);
+
+    sp<SurfaceComposerClient> client = new SurfaceComposerClient();
+    if (client->initCheck() != NO_ERROR) {
+        return nullptr;
+    }
+
+    uint32_t flags = ISurfaceComposerClient::eFXSurfaceBufferState;
+    sp<SurfaceControl> surfaceControl =
+            client->createWithSurfaceParent(String8(debug_name), 0 /* width */, 0 /* height */,
+                                            // Format is only relevant for buffer queue layers.
+                                            PIXEL_FORMAT_UNKNOWN /* format */, flags,
+                                            static_cast<Surface*>(window));
+    if (!surfaceControl) {
+        return nullptr;
+    }
+
+    SurfaceControl_acquire(surfaceControl.get());
+    return reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
+}
+
+ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* debug_name) {
+    CHECK_NOT_NULL(parent);
+    CHECK_NOT_NULL(debug_name);
+
+    SurfaceComposerClient* client = ASurfaceControl_to_SurfaceControl(parent)->getClient().get();
+
+    SurfaceControl* surfaceControlParent = ASurfaceControl_to_SurfaceControl(parent);
+
+    uint32_t flags = ISurfaceComposerClient::eFXSurfaceBufferState;
+    sp<SurfaceControl> surfaceControl =
+            client->createSurface(String8(debug_name), 0 /* width */, 0 /* height */,
+                                  // Format is only relevant for buffer queue layers.
+                                  PIXEL_FORMAT_UNKNOWN /* format */, flags,
+                                  surfaceControlParent);
+    if (!surfaceControl) {
+        return nullptr;
+    }
+
+    SurfaceControl_acquire(surfaceControl.get());
+    return reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
+}
+
+void ASurfaceControl_destroy(ASurfaceControl* aSurfaceControl) {
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+
+    Transaction().reparent(surfaceControl, nullptr).apply();
+    SurfaceControl_release(surfaceControl.get());
+}
+
+ASurfaceTransaction* ASurfaceTransaction_create() {
+    Transaction* transaction = new Transaction;
+    return reinterpret_cast<ASurfaceTransaction*>(transaction);
+}
+
+void ASurfaceTransaction_delete(ASurfaceTransaction* aSurfaceTransaction) {
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+    delete transaction;
+}
+
+void ASurfaceTransaction_apply(ASurfaceTransaction* aSurfaceTransaction) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    transaction->apply();
+}
+
+void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* aSurfaceTransaction, void* context,
+                                       ASurfaceTransaction_OnComplete func) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(context);
+    CHECK_NOT_NULL(func);
+
+    TransactionCompletedCallbackTakesContext callback = [func](void* callback_context,
+                                                               const TransactionStats& stats) {
+        int fence = (stats.presentFence) ? stats.presentFence->dup() : -1;
+        (*func)(callback_context, fence);
+    };
+
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    transaction->addTransactionCompletedCallback(callback, context);
+}
+
+void ASurfaceTransaction_setVisibility(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl,
+                                       int8_t visibility) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    switch (visibility) {
+    case ASURFACE_TRANSACTION_VISIBILITY_SHOW:
+        transaction->show(surfaceControl);
+        break;
+    case ASURFACE_TRANSACTION_VISIBILITY_HIDE:
+        transaction->hide(surfaceControl);
+        break;
+    default:
+        LOG_ALWAYS_FATAL("invalid visibility %d", visibility);
+    }
+}
+
+void ASurfaceTransaction_setZOrder(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl,
+                                   int32_t z_order) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    transaction->setLayer(surfaceControl, z_order);
+}
+
+void ASurfaceTransaction_setBuffer(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl,
+                                   AHardwareBuffer* buffer, int fence_fd) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    sp<GraphicBuffer> graphic_buffer(reinterpret_cast<GraphicBuffer*>(buffer));
+
+    transaction->setBuffer(surfaceControl, graphic_buffer);
+    if (fence_fd != -1) {
+        sp<Fence> fence = new Fence(fence_fd);
+        transaction->setAcquireFence(surfaceControl, fence);
+    }
+}
+
+void ASurfaceTransaction_setGeometry(ASurfaceTransaction* aSurfaceTransaction,
+                                     ASurfaceControl* aSurfaceControl, const ARect& source,
+                                     const ARect& destination, int32_t transform) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+    CHECK_VALID_RECT(source);
+    CHECK_VALID_RECT(destination);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    transaction->setCrop(surfaceControl, static_cast<const Rect&>(source));
+    transaction->setFrame(surfaceControl, static_cast<const Rect&>(destination));
+    transaction->setTransform(surfaceControl, transform);
+}
+
+void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* aSurfaceTransaction,
+                                               ASurfaceControl* aSurfaceControl,
+                                               int8_t transparency) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    uint32_t flags = (transparency == ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE) ?
+                      layer_state_t::eLayerOpaque : 0;
+    transaction->setFlags(surfaceControl, flags, layer_state_t::eLayerOpaque);
+}
+
+void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl,
+                                         const ARect rects[], uint32_t count) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    Region region;
+    for (uint32_t i = 0; i < count; ++i) {
+        region.merge(static_cast<const Rect&>(rects[i]));
+    }
+
+    transaction->setSurfaceDamageRegion(surfaceControl, region);
+}
diff --git a/native/webview/plat_support/draw_fn.h b/native/webview/plat_support/draw_fn.h
index 6afd883..0490e65 100644
--- a/native/webview/plat_support/draw_fn.h
+++ b/native/webview/plat_support/draw_fn.h
@@ -74,7 +74,10 @@
   VkQueue queue;
   uint32_t graphics_queue_index;
   uint32_t instance_version;
-  const char* const* enabled_extension_names;
+  const char* const* enabled_instance_extension_names;
+  uint32_t enabled_instance_extension_names_length;
+  const char* const* enabled_device_extension_names;
+  uint32_t enabled_device_extension_names_length;
   // Only one of device_features and device_features_2 should be non-null.
   // If both are null then no features are enabled.
   VkPhysicalDeviceFeatures* device_features;
@@ -109,8 +112,15 @@
   // Input: Format of the destination surface.
   VkFormat format;
 
-  // Input: Color space transformation from linear RGB to D50-adapted XYZ
-  float matrix[9];
+  // Input: Color space parameters.
+  float transfer_function_g;
+  float transfer_function_a;
+  float transfer_function_b;
+  float transfer_function_c;
+  float transfer_function_d;
+  float transfer_function_e;
+  float transfer_function_f;
+  float color_space_toXYZD50[9];
 
   // Input: current clip rect
   int clip_left;
@@ -121,15 +131,13 @@
 
 struct AwDrawFn_PostDrawVkParams {
   int version;
-
-  // Input: Fence for the composite command buffer to signal it has finished its
-  // work on the GPU.
-  int fd;
 };
 
 // Called on render thread while UI thread is blocked. Called for both GL and
 // VK.
-typedef void AwDrawFn_OnSync(int functor, void* data, AwDrawFn_OnSyncParams* params);
+typedef void AwDrawFn_OnSync(int functor,
+                             void* data,
+                             AwDrawFn_OnSyncParams* params);
 
 // Called on render thread when either the context is destroyed _or_ when the
 // functor's last reference goes away. Will always be called with an active
@@ -143,17 +151,24 @@
 typedef void AwDrawFn_OnDestroyed(int functor, void* data);
 
 // Only called for GL.
-typedef void AwDrawFn_DrawGL(int functor, void* data, AwDrawFn_DrawGLParams* params);
+typedef void AwDrawFn_DrawGL(int functor,
+                             void* data,
+                             AwDrawFn_DrawGLParams* params);
 
 // Initialize vulkan state. Needs to be called again after any
 // OnContextDestroyed. Only called for Vulkan.
-typedef void AwDrawFn_InitVk(int functor, void* data, AwDrawFn_InitVkParams* params);
+typedef void AwDrawFn_InitVk(int functor,
+                             void* data,
+                             AwDrawFn_InitVkParams* params);
 
 // Only called for Vulkan.
-typedef void AwDrawFn_DrawVk(int functor, void* data, AwDrawFn_DrawVkParams* params);
+typedef void AwDrawFn_DrawVk(int functor,
+                             void* data,
+                             AwDrawFn_DrawVkParams* params);
 
 // Only called for Vulkan.
-typedef void AwDrawFn_PostDrawVk(int functor, void* data,
+typedef void AwDrawFn_PostDrawVk(int functor,
+                                 void* data,
                                  AwDrawFn_PostDrawVkParams* params);
 
 struct AwDrawFnFunctorCallbacks {
@@ -176,7 +191,8 @@
 typedef AwDrawFnRenderMode AwDrawFn_QueryRenderMode(void);
 
 // Create a functor. |functor_callbacks| should be valid until OnDestroyed.
-typedef int AwDrawFn_CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks);
+typedef int AwDrawFn_CreateFunctor(void* data,
+                                   AwDrawFnFunctorCallbacks* functor_callbacks);
 
 // May be called on any thread to signal that the functor should be destroyed.
 // The functor will receive an onDestroyed when the last usage of it is
diff --git a/native/webview/plat_support/draw_functor.cpp b/native/webview/plat_support/draw_functor.cpp
index 6c1ceab..b97bbc3 100644
--- a/native/webview/plat_support/draw_functor.cpp
+++ b/native/webview/plat_support/draw_functor.cpp
@@ -74,6 +74,79 @@
   support->callbacks.draw_gl(functor, support->data, &params);
 }
 
+void initializeVk(int functor, void* data,
+                  const uirenderer::VkFunctorInitParams& init_vk_params) {
+  SupportData* support = static_cast<SupportData*>(data);
+  VkPhysicalDeviceFeatures2 device_features_2;
+  if (init_vk_params.device_features_2)
+    device_features_2 = *init_vk_params.device_features_2;
+
+  AwDrawFn_InitVkParams params{
+      .version = kAwDrawFnVersion,
+      .instance = init_vk_params.instance,
+      .physical_device = init_vk_params.physical_device,
+      .device = init_vk_params.device,
+      .queue = init_vk_params.queue,
+      .graphics_queue_index = init_vk_params.graphics_queue_index,
+      .instance_version = init_vk_params.instance_version,
+      .enabled_instance_extension_names =
+          init_vk_params.enabled_instance_extension_names,
+      .enabled_instance_extension_names_length =
+          init_vk_params.enabled_instance_extension_names_length,
+      .enabled_device_extension_names =
+          init_vk_params.enabled_device_extension_names,
+      .enabled_device_extension_names_length =
+          init_vk_params.enabled_device_extension_names_length,
+      .device_features = nullptr,
+      .device_features_2 =
+          init_vk_params.device_features_2 ? &device_features_2 : nullptr,
+  };
+  support->callbacks.init_vk(functor, support->data, &params);
+}
+
+void drawVk(int functor, void* data, const uirenderer::VkFunctorDrawParams& draw_vk_params) {
+  SupportData* support = static_cast<SupportData*>(data);
+  float gabcdef[7];
+  draw_vk_params.color_space_ptr->transferFn(gabcdef);
+  AwDrawFn_DrawVkParams params{
+      .version = kAwDrawFnVersion,
+      .width = draw_vk_params.width,
+      .height = draw_vk_params.height,
+      .is_layer = draw_vk_params.is_layer,
+      .secondary_command_buffer = draw_vk_params.secondary_command_buffer,
+      .color_attachment_index = draw_vk_params.color_attachment_index,
+      .compatible_render_pass = draw_vk_params.compatible_render_pass,
+      .format = draw_vk_params.format,
+      .transfer_function_g = gabcdef[0],
+      .transfer_function_a = gabcdef[1],
+      .transfer_function_b = gabcdef[2],
+      .transfer_function_c = gabcdef[3],
+      .transfer_function_d = gabcdef[4],
+      .transfer_function_e = gabcdef[5],
+      .transfer_function_f = gabcdef[6],
+      .clip_left = draw_vk_params.clip_left,
+      .clip_top = draw_vk_params.clip_top,
+      .clip_right = draw_vk_params.clip_right,
+      .clip_bottom = draw_vk_params.clip_bottom,
+  };
+  COMPILE_ASSERT(sizeof(params.color_space_toXYZD50) == sizeof(skcms_Matrix3x3),
+                 gamut_transform_size_mismatch);
+  draw_vk_params.color_space_ptr->toXYZD50(
+      reinterpret_cast<skcms_Matrix3x3*>(&params.color_space_toXYZD50));
+  COMPILE_ASSERT(NELEM(params.transform) == NELEM(draw_vk_params.transform),
+                 mismatched_transform_matrix_sizes);
+  for (int i = 0; i < NELEM(params.transform); ++i) {
+    params.transform[i] = draw_vk_params.transform[i];
+  }
+  support->callbacks.draw_vk(functor, support->data, &params);
+}
+
+void postDrawVk(int functor, void* data) {
+  SupportData* support = static_cast<SupportData*>(data);
+  AwDrawFn_PostDrawVkParams params{.version = kAwDrawFnVersion};
+  support->callbacks.post_draw_vk(functor, support->data, &params);
+}
+
 int CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks) {
   static bool callbacks_initialized = false;
   static uirenderer::WebViewFunctorCallbacks webview_functor_callbacks = {
@@ -82,9 +155,19 @@
       .onDestroyed = &onDestroyed,
   };
   if (!callbacks_initialized) {
-    // Under uirenderer::RenderMode::Vulkan, whether gles or vk union should
-    // be populated should match whether the vk-gl interop is used.
-    webview_functor_callbacks.gles.draw = &draw_gl;
+    switch (uirenderer::WebViewFunctor_queryPlatformRenderMode()) {
+      case uirenderer::RenderMode::OpenGL_ES:
+        webview_functor_callbacks.gles.draw = &draw_gl;
+        break;
+      case uirenderer::RenderMode::Vulkan:
+        webview_functor_callbacks.vk.initialize = &initializeVk;
+        webview_functor_callbacks.vk.draw = &drawVk;
+        webview_functor_callbacks.vk.postDraw = &postDrawVk;
+        // TODO(boliu): Remove this once SkiaRecordingCanvas::drawWebViewFunctor
+        // no longer uses GL interop.
+        webview_functor_callbacks.gles.draw = &draw_gl;
+        break;
+    }
     callbacks_initialized = true;
   }
   SupportData* support = new SupportData{
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index a9d8f62..95df5f2 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -27,6 +27,7 @@
 import android.service.notification.NotificationAssistantService;
 import android.text.TextUtils;
 import android.util.LruCache;
+import android.view.textclassifier.ConversationAction;
 import android.view.textclassifier.ConversationActions;
 import android.view.textclassifier.TextClassification;
 import android.view.textclassifier.TextClassificationContext;
@@ -65,13 +66,13 @@
     private static final int MAX_MESSAGES_TO_EXTRACT = 5;
     private static final int MAX_RESULT_ID_TO_CACHE = 20;
 
-    private static final ConversationActions.TypeConfig TYPE_CONFIG =
-            new ConversationActions.TypeConfig.Builder().setIncludedTypes(
-                    Collections.singletonList(ConversationActions.TYPE_TEXT_REPLY))
+    private static final TextClassifier.EntityConfig TYPE_CONFIG =
+            new TextClassifier.EntityConfig.Builder().setIncludedTypes(
+                    Collections.singletonList(ConversationAction.TYPE_TEXT_REPLY))
                     .includeTypesFromTextClassifier(false)
                     .build();
     private static final List<String> HINTS =
-            Collections.singletonList(ConversationActions.HINT_FOR_NOTIFICATION);
+            Collections.singletonList(ConversationActions.Request.HINT_FOR_NOTIFICATION);
 
     private Context mContext;
     @Nullable
@@ -137,7 +138,7 @@
 
         ConversationActions conversationActionsResult =
                 mTextClassifier.suggestConversationActions(request);
-        List<ConversationActions.ConversationAction> conversationActions =
+        List<ConversationAction> conversationActions =
                 conversationActionsResult.getConversationActions();
         ArrayList<CharSequence> replies = conversationActions.stream()
                 .map(conversationAction -> conversationAction.getTextReply())
@@ -193,7 +194,7 @@
         }
         TextClassifierEvent textClassifierEvent =
                 createTextClassifierEventBuilder(TextClassifierEvent.TYPE_SMART_ACTION, resultId)
-                        .setEntityType(ConversationActions.TYPE_TEXT_REPLY)
+                        .setEntityType(ConversationAction.TYPE_TEXT_REPLY)
                         .build();
         mTextClassifier.onTextClassifierEvent(textClassifierEvent);
     }
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
index 7d74788..7b7ce3d 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
@@ -32,6 +32,7 @@
 import android.service.notification.StatusBarNotification;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.textclassifier.ConversationAction;
 import android.view.textclassifier.ConversationActions;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textclassifier.TextClassifier;
@@ -65,9 +66,10 @@
     private static final String NOTIFICATION_KEY = "key";
     private static final String RESULT_ID = "id";
 
-    private static final ConversationActions.ConversationAction REPLY_ACTION =
-            new ConversationActions.ConversationAction.Builder(
-                    ConversationActions.TYPE_TEXT_REPLY).setTextReply("Home").build();
+    private static final ConversationAction REPLY_ACTION =
+            new ConversationAction.Builder(ConversationAction.TYPE_TEXT_REPLY)
+            .setTextReply("Home")
+            .build();
 
     private SmartActionsHelper mSmartActionsHelper;
     private Context mContext;
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index 0b0f1ec..7f8bb93 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -20,6 +20,7 @@
           package="com.android.mainline.networkstack"
           android:sharedUserId="android.uid.networkstack">
     <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 94ea1b9..4077d93 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -545,7 +545,9 @@
                     return HANDLED;
                 case CMD_FORCE_REEVALUATION:
                 case CMD_CAPTIVE_PORTAL_RECHECK:
-                    log("Forcing reevaluation for UID " + message.arg1);
+                    final int dnsCount = mDnsStallDetector.getConsecutiveTimeoutCount();
+                    validationLog("Forcing reevaluation for UID " + message.arg1
+                            + ". Dns signal count: " + dnsCount);
                     mUidResponsibleForReeval = message.arg1;
                     transitionTo(mEvaluatingState);
                     return HANDLED;
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 03c6205..16bfcc9 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -99,8 +99,12 @@
     <string name="connected_via_network_scorer_default">Automatically connected via network rating provider</string>
     <!-- Status message of Wi-Fi when it is connected by Passpoint configuration. [CHAR LIMIT=NONE] -->
     <string name="connected_via_passpoint">Connected via %1$s</string>
+    <!-- Status message of Wi-Fi when it is connected by Passpoint configuration. [CHAR LIMIT=NONE] -->
+    <string name="ssid_by_passpoint_provider"><xliff:g id="ssid" example="Cafe Wifi">%1$s</xliff:g> by <xliff:g id="passpointProvider" example="Passpoint Provider">%2$s</xliff:g></string>
     <!-- Status message of Wi-Fi when network has matching passpoint credentials. [CHAR LIMIT=NONE] -->
     <string name="available_via_passpoint">Available via %1$s</string>
+    <!-- Status message of OSU Provider network when not connected. [CHAR LIMIT=NONE] -->
+    <string name="tap_to_set_up">Tap to set up</string>
     <!-- Package name for Settings app-->
     <string name="settings_package" translatable="false">com.android.settings</string>
     <!-- Package name for Certinstaller app-->
@@ -123,6 +127,79 @@
     <!-- Status message of Wi-Fi when an available network is a carrier network. [CHAR LIMIT=NONE] -->
     <string name="available_via_carrier">Available via %1$s</string>
 
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_AP_CONNECTION. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_ap_connection">Connection failed</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_SERVER_URL_INVALID. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_server_url_invalid">Invalid OSU server URL</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_SERVER_CONNECTION. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_server_connection">OSU server connection failed</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_SERVER_VALIDATION. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_server_validation">OSU server validation failed</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_service_provider_verification">Invalid OSU server certificate</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_PROVISIONING_ABORTED. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_provisioning_aborted">Provisioning aborted</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_PROVISIONING_NOT_AVAILABLE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_provisioning_not_available">Provisioning not available</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_INVALID_SERVER_URL. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_invalid_server_url">Invalid OSU server URL</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_UNEXPECTED_COMMAND_TYPE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_unexpected_command_type">Unexpected command type</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_unexpected_soap_message_type">Unexpected SOAP message type</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_SOAP_MESSAGE_EXCHANGE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_soap_message_exchange">SOAP message exchange failed</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_START_REDIRECT_LISTENER. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_start_redirect_listener">Redirect listener failed to start</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_timed_out_redirect_listener">Timed out waiting for redirect</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_OSU_ACTIVITY_FOUND. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_no_osu_activity_found">No OSU activity found</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_unexpected_soap_message_status">Unexpected SOAP message status</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_PPS_MO. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_no_pps_mo">Failed to find PPS-MO</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_no_aaa_server_trust_root_node">Failed to find trust root node for AAA server</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_no_remediation_server_trust_root_node">Failed to find trust root node for remediation server</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_no_policy_server_trust_root_node">Failed to find trust root node for policy server</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_retrieve_trust_root_certificates">Failed to retrieve trust root certificates</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_no_aaa_trust_root_certificate">Failed to find trust root certificate for AAA server</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_add_passpoint_configuration">Failed to add PassPoint configuration</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_OSU_PROVIDER_NOT_FOUND. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_osu_provider_not_found">Failed to find an OSU provider</string>
+
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_AP_CONNECTING. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_ap_connecting">Connecting</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_AP_CONNECTED. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_ap_connected">Connected</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_SERVER_CONNECTING. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_server_connecting">Connecting to OSU server</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_SERVER_VALIDATED. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_server_validated">OSU server validated</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_SERVER_CONNECTED. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_server_connected">Connected to OSU server</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_INIT_SOAP_EXCHANGE. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_init_soap_exchange">Initial SOAP exchange</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_WAITING_FOR_REDIRECT_RESPONSE. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_waiting_for_redirect_response">Waiting for redirect response</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_REDIRECT_RESPONSE_RECEIVED. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_redirect_response_received">Received redirect response</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_SECOND_SOAP_EXCHANGE. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_second_soap_exchange">Second SOAP exchange</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_THIRD_SOAP_EXCHANGE. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_third_soap_exchange">Third SOAP exchange</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_RETRIEVING_TRUST_ROOT_CERTS. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_retrieving_trust_root_certs">Retrieving trust root certificates</string>
+
+    <!-- Status message of OSU Provider on completing provisioning. [CHAR LIMIT=NONE] -->
+    <string name="osu_provisioning_complete">Provisioning complete</string>
+
     <!-- Speed label for very slow network speed -->
     <string name="speed_label_very_slow">Very Slow</string>
     <!-- Speed label for slow network speed -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 595aeb3..c751c39 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -38,8 +38,8 @@
     private static final String CURRENT_MODE_KEY = "CURRENT_MODE";
     private static final String NEW_MODE_KEY = "NEW_MODE";
     @VisibleForTesting
-    static final String STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY =
-            "ro.storage_manager.show_opt_in";
+    static final String STORAGE_MANAGER_ENABLED_PROPERTY =
+            "ro.storage_manager.enabled";
 
     private static Signature[] sSystemSignature;
     private static String sPermissionControllerPackageName;
@@ -373,8 +373,7 @@
     public static boolean isStorageManagerEnabled(Context context) {
         boolean isDefaultOn;
         try {
-            // Turn off by default if the opt-in was shown.
-            isDefaultOn = !SystemProperties.getBoolean(STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY, true);
+            isDefaultOn = SystemProperties.getBoolean(STORAGE_MANAGER_ENABLED_PROPERTY, false);
         } catch (Resources.NotFoundException e) {
             isDefaultOn = false;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index 12b8efb..4ab9a9a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -55,6 +55,12 @@
             "com.android.settings.category.ia.privacy";
     public static final String CATEGORY_ENTERPRISE_PRIVACY =
             "com.android.settings.category.ia.enterprise_privacy";
+    public static final String CATEGORY_ABOUT_LEGAL =
+            "com.android.settings.category.ia.about_legal";
+    public static final String CATEGORY_MY_DEVICE_INFO =
+            "com.android.settings.category.ia.my_device_info";
+    public static final String CATEGORY_BATTERY_SAVER_SETTINGS =
+            "com.android.settings.category.ia.battery_saver_settings";
 
     public static final Map<String, String> KEY_COMPAT_MAP;
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index af5a24f..27dc628 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -41,7 +41,9 @@
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiNetworkScoreCache;
+import android.net.wifi.hotspot2.OsuProvider;
 import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.ProvisioningCallback;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.RemoteException;
@@ -182,6 +184,10 @@
 
     public static final int UNREACHABLE_RSSI = Integer.MIN_VALUE;
 
+    public static final String KEY_PREFIX_AP = "AP:";
+    public static final String KEY_PREFIX_FQDN = "FQDN:";
+    public static final String KEY_PREFIX_OSU = "OSU:";
+
     private final Context mContext;
 
     private String ssid;
@@ -204,9 +210,6 @@
     @Speed private int mSpeed = Speed.NONE;
     private boolean mIsScoredNetworkMetered = false;
 
-    // used to co-relate internal vs returned accesspoint.
-    int mId;
-
     /**
      * Information associated with the {@link PasspointConfiguration}.  Only maintaining
      * the relevant info to preserve spaces.
@@ -215,6 +218,13 @@
     private String mProviderFriendlyName;
 
     private boolean mIsCarrierAp = false;
+
+    private OsuProvider mOsuProvider;
+
+    private String mOsuStatus;
+    private String mOsuFailure;
+    private boolean mOsuProvisioningComplete = false;
+
     /**
      * The EAP type {@link WifiEnterpriseConfig.Eap} associated with this AP if it is a carrier AP.
      */
@@ -280,14 +290,18 @@
         // Calculate required fields
         updateKey();
         updateRssi();
-
-        mId = sLastId.incrementAndGet();
     }
 
+    /**
+     * Creates an AccessPoint with only a WifiConfiguration. This is used for the saved networks
+     * page.
+     *
+     * Passpoint Credential AccessPoints should be created with this.
+     * Make sure to call setScanResults after constructing with this.
+     */
     public AccessPoint(Context context, WifiConfiguration config) {
         mContext = context;
         loadConfig(config);
-        mId = sLastId.incrementAndGet();
     }
 
     /**
@@ -298,7 +312,17 @@
         mContext = context;
         mFqdn = config.getHomeSp().getFqdn();
         mProviderFriendlyName = config.getHomeSp().getFriendlyName();
-        mId = sLastId.incrementAndGet();
+    }
+
+    /**
+     * Initialize an AccessPoint object for a Passpoint OSU Provider.
+     * Make sure to call setScanResults after constructing with this.
+     */
+    public AccessPoint(Context context, OsuProvider provider) {
+        mContext = context;
+        mOsuProvider = provider;
+        ssid = provider.getFriendlyName();
+        updateKey();
     }
 
     AccessPoint(Context context, Collection<ScanResult> results) {
@@ -324,8 +348,6 @@
         mIsCarrierAp = firstResult.isCarrierAp;
         mCarrierApEapType = firstResult.carrierApEapType;
         mCarrierName = firstResult.carrierName;
-
-        mId = sLastId.incrementAndGet();
     }
 
     @VisibleForTesting void loadConfig(WifiConfiguration config) {
@@ -340,19 +362,13 @@
     /** Updates {@link #mKey} and should only called upon object creation/initialization. */
     private void updateKey() {
         // TODO(sghuman): Consolidate Key logic on ScanResultMatchInfo
-
-        StringBuilder builder = new StringBuilder();
-
         if (isPasspoint()) {
-            builder.append(mConfig.FQDN);
-        } else if (TextUtils.isEmpty(getSsidStr())) {
-            builder.append(getBssid());
-        } else {
-            builder.append(getSsidStr());
+            mKey = getKey(mConfig);
+        } else if (isOsuProvider()) {
+            mKey = getKey(mOsuProvider);
+        } else { // Non-Passpoint AP
+            mKey = getKey(getSsidStr(), getBssid(), getSecurity());
         }
-
-        builder.append(',').append(getSecurity());
-        mKey = builder.toString();
     }
 
     /**
@@ -396,8 +412,8 @@
             return difference;
         }
 
-        // Sort by ssid.
-        difference = getSsidStr().compareToIgnoreCase(other.getSsidStr());
+        // Sort by title.
+        difference = getTitle().compareToIgnoreCase(other.getTitle());
         if (difference != 0) {
             return difference;
         }
@@ -593,30 +609,46 @@
     }
 
     public static String getKey(ScanResult result) {
-        StringBuilder builder = new StringBuilder();
-
-        if (TextUtils.isEmpty(result.SSID)) {
-            builder.append(result.BSSID);
-        } else {
-            builder.append(result.SSID);
-        }
-
-        builder.append(',').append(getSecurity(result));
-        return builder.toString();
+        return getKey(result.SSID, result.BSSID, getSecurity(result));
     }
 
+    /**
+     * Returns the AccessPoint key for a WifiConfiguration.
+     * This will return a special Passpoint key if the config is for Passpoint.
+     */
     public static String getKey(WifiConfiguration config) {
-        StringBuilder builder = new StringBuilder();
-
         if (config.isPasspoint()) {
-            builder.append(config.FQDN);
-        } else if (TextUtils.isEmpty(config.SSID)) {
-            builder.append(config.BSSID);
+            return new StringBuilder()
+                    .append(KEY_PREFIX_FQDN)
+                    .append(config.FQDN).toString();
         } else {
-            builder.append(removeDoubleQuotes(config.SSID));
+            return getKey(config.SSID, config.BSSID, getSecurity(config));
         }
+    }
 
-        builder.append(',').append(getSecurity(config));
+    /**
+     * Returns the AccessPoint key corresponding to the OsuProvider.
+     */
+    public static String getKey(OsuProvider provider) {
+        return new StringBuilder()
+                .append(KEY_PREFIX_OSU)
+                .append(provider.getFriendlyName())
+                .append(',')
+                .append(provider.getServerUri()).toString();
+    }
+
+    /**
+     * Returns the AccessPoint key for a normal non-Passpoint network by ssid/bssid and security.
+     */
+    private static String getKey(String ssid, String bssid, int security) {
+        StringBuilder builder = new StringBuilder();
+        builder.append(KEY_PREFIX_AP);
+        if (TextUtils.isEmpty(ssid)) {
+            builder.append(bssid);
+        } else {
+            builder.append(ssid);
+        }
+        builder.append(',').append(security);
         return builder.toString();
     }
 
@@ -839,91 +871,105 @@
     public String getTitle() {
         if (isPasspoint()) {
             return mConfig.providerFriendlyName;
+        } else if (isOsuProvider()) {
+            return mOsuProvider.getFriendlyName();
         } else {
             return getSsidStr();
         }
     }
 
     public String getSummary() {
-        return getSettingsSummary(mConfig);
+        return getSettingsSummary();
     }
 
     public String getSettingsSummary() {
-        return getSettingsSummary(mConfig);
-    }
-
-    private String getSettingsSummary(WifiConfiguration config) {
         // Update to new summary
         StringBuilder summary = new StringBuilder();
 
-        if (isActive() && config != null && config.isPasspoint()) {
-            // This is the active connection on passpoint
-            summary.append(getSummary(mContext, getDetailedState(),
-                    false, config.providerFriendlyName));
-        } else if (isActive() && config != null && getDetailedState() == DetailedState.CONNECTED
-                && mIsCarrierAp) {
-            summary.append(String.format(mContext.getString(R.string.connected_via_carrier), mCarrierName));
-        } else if (isActive()) {
-            // This is the active connection on non-passpoint network
-            summary.append(getSummary(mContext, getDetailedState(),
-                    mInfo != null && mInfo.isEphemeral()));
-        } else if (config != null && config.isPasspoint()
-                && config.getNetworkSelectionStatus().isNetworkEnabled()) {
-            String format = mContext.getString(R.string.available_via_passpoint);
-            summary.append(String.format(format, config.providerFriendlyName));
-        } else if (config != null && config.hasNoInternetAccess()) {
-            int messageID = config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()
-                    ? R.string.wifi_no_internet_no_reconnect
-                    : R.string.wifi_no_internet;
-            summary.append(mContext.getString(messageID));
-        } else if (config != null && !config.getNetworkSelectionStatus().isNetworkEnabled()) {
-            WifiConfiguration.NetworkSelectionStatus networkStatus =
-                    config.getNetworkSelectionStatus();
-            switch (networkStatus.getNetworkSelectionDisableReason()) {
-                case WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE:
-                    summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
-                    break;
-                case WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD:
-                    summary.append(mContext.getString(R.string.wifi_check_password_try_again));
-                    break;
-                case WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE:
-                case WifiConfiguration.NetworkSelectionStatus.DISABLED_DNS_FAILURE:
-                    summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
-                    break;
-                case WifiConfiguration.NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION:
-                    summary.append(mContext.getString(R.string.wifi_disabled_generic));
-                    break;
+        if (isOsuProvider()) {
+            if (mOsuProvisioningComplete) {
+                summary.append(mContext.getString(R.string.osu_provisioning_complete));
+            } else if (mOsuFailure != null) {
+                summary.append(mOsuFailure);
+            } else if (mOsuStatus != null) {
+                summary.append(mOsuStatus);
+            } else {
+                summary.append(mContext.getString(R.string.tap_to_set_up));
             }
-        } else if (config != null && config.getNetworkSelectionStatus().isNotRecommended()) {
-            summary.append(mContext.getString(R.string.wifi_disabled_by_recommendation_provider));
-        } else if (mIsCarrierAp) {
-            summary.append(String.format(mContext.getString(R.string.available_via_carrier), mCarrierName));
-        } else if (!isReachable()) { // Wifi out of range
-            summary.append(mContext.getString(R.string.wifi_not_in_range));
-        } else { // In range, not disabled.
-            if (config != null) { // Is saved network
-                // Last attempt to connect to this failed. Show reason why
-                switch (config.recentFailure.getAssociationStatus()) {
-                    case WifiConfiguration.RecentFailure.STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
-                        summary.append(mContext.getString(
-                                R.string.wifi_ap_unable_to_handle_new_sta));
+        } else if (isActive()) {
+            if (isPasspoint()) {
+                // This is the active connection on passpoint
+                summary.append(getSummary(mContext, ssid, getDetailedState(),
+                        false, mConfig.providerFriendlyName));
+            } else if (mConfig != null && getDetailedState() == DetailedState.CONNECTED
+                    && mIsCarrierAp) {
+                // This is the active connection on a carrier AP
+                summary.append(String.format(mContext.getString(R.string.connected_via_carrier),
+                        mCarrierName));
+            } else {
+                // This is the active connection on non-passpoint network
+                summary.append(getSummary(mContext, getDetailedState(),
+                        mInfo != null && mInfo.isEphemeral()));
+            }
+        } else { // not active
+            if (mConfig != null && mConfig.hasNoInternetAccess()) {
+                int messageID = mConfig.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()
+                        ? R.string.wifi_no_internet_no_reconnect
+                        : R.string.wifi_no_internet;
+                summary.append(mContext.getString(messageID));
+            } else if (mConfig != null && !mConfig.getNetworkSelectionStatus().isNetworkEnabled()) {
+                WifiConfiguration.NetworkSelectionStatus networkStatus =
+                        mConfig.getNetworkSelectionStatus();
+                switch (networkStatus.getNetworkSelectionDisableReason()) {
+                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE:
+                        summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
                         break;
-                    default:
-                        // "Saved"
-                        summary.append(mContext.getString(R.string.wifi_remembered));
+                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD:
+                        summary.append(mContext.getString(R.string.wifi_check_password_try_again));
                         break;
+                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE:
+                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_DNS_FAILURE:
+                        summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
+                        break;
+                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION:
+                        summary.append(mContext.getString(R.string.wifi_disabled_generic));
+                        break;
+                }
+            } else if (mConfig != null && mConfig.getNetworkSelectionStatus().isNotRecommended()) {
+                summary.append(mContext.getString(
+                        R.string.wifi_disabled_by_recommendation_provider));
+            } else if (mIsCarrierAp) {
+                summary.append(String.format(mContext.getString(
+                        R.string.available_via_carrier), mCarrierName));
+            } else if (!isReachable()) { // Wifi out of range
+                summary.append(mContext.getString(R.string.wifi_not_in_range));
+            } else { // In range, not disabled.
+                if (mConfig != null) { // Is saved network
+                    // Last attempt to connect to this failed. Show reason why
+                    switch (mConfig.recentFailure.getAssociationStatus()) {
+                        case WifiConfiguration.RecentFailure.STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
+                            summary.append(mContext.getString(
+                                    R.string.wifi_ap_unable_to_handle_new_sta));
+                            break;
+                        default:
+                            // "Saved"
+                            summary.append(mContext.getString(R.string.wifi_remembered));
+                            break;
+                    }
                 }
             }
         }
 
+
+
         if (isVerboseLoggingEnabled()) {
-            summary.append(WifiUtils.buildLoggingSummary(this, config));
+            summary.append(WifiUtils.buildLoggingSummary(this, mConfig));
         }
 
-        if (config != null && (WifiUtils.isMeteredOverridden(config) || config.meteredHint)) {
+        if (mConfig != null && (WifiUtils.isMeteredOverridden(mConfig) || mConfig.meteredHint)) {
             return mContext.getResources().getString(
                     R.string.preference_summary_default_combination,
-                    WifiUtils.getMeteredLabel(mContext, config),
+                    WifiUtils.getMeteredLabel(mContext, mConfig),
                     summary.toString());
         }
 
@@ -976,11 +1022,33 @@
     }
 
     /**
+     * Return true if this AccessPoint represents an OSU Provider.
+     */
+    public boolean isOsuProvider() {
+        return mOsuProvider != null;
+    }
+
+    /**
+     * Starts the OSU Provisioning flow.
+     */
+    public void startOsuProvisioning() {
+        mContext.getSystemService(WifiManager.class).startSubscriptionProvisioning(
+                mOsuProvider,
+                new AccessPointProvisioningCallback(),
+                ThreadUtils.getUiThreadHandler()
+        );
+    }
+
+    /**
      * Return whether the given {@link WifiInfo} is for this access point.
      * If the current AP does not have a network Id then the config is used to
      * match based on SSID and security.
      */
     private boolean isInfoForThisAccessPoint(WifiConfiguration config, WifiInfo info) {
+        if (info.isOsuAp()) {
+            return (mOsuStatus != null);
+        }
+
         if (isPasspoint() == false && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
             return networkId == info.getNetworkId();
         } else if (config != null) {
@@ -1065,8 +1133,8 @@
     void setScanResults(Collection<ScanResult> scanResults) {
 
         // Validate scan results are for current AP only by matching SSID/BSSID
-        // Passpoint R1 networks are not bound to a specific SSID/BSSID, so skip this for passpoint.
-        if (!isPasspoint()) {
+        // Passpoint networks are not bound to a specific SSID/BSSID, so skip this for passpoint.
+        if (!isPasspoint() && !isOsuProvider()) {
             String key = getKey();
             for (ScanResult result : scanResults) {
                 String scanResultKey = AccessPoint.getKey(result);
@@ -1119,7 +1187,17 @@
         }
     }
 
-    /** Attempt to update the AccessPoint and return true if an update occurred. */
+    /**
+     * Attempt to update the AccessPoint with the current connection info.
+     * This is used to set an AccessPoint to the active one if the connection info matches, or
+     * conversely to set an AccessPoint to inactive if the connection info does not match. The RSSI
+     * is also updated upon a match. Listeners will be notified if an update occurred.
+     *
+     * This is called in {@link WifiTracker#updateAccessPoints} as well as in callbacks for handling
+     * NETWORK_STATE_CHANGED_ACTION, RSSI_CHANGED_ACTION, and onCapabilitiesChanged in WifiTracker.
+     *
+     * Returns true if an update occurred.
+     */
     public boolean update(
             @Nullable WifiConfiguration config, WifiInfo info, NetworkInfo networkInfo) {
 
@@ -1246,11 +1324,11 @@
 
     public static String getSummary(Context context, String ssid, DetailedState state,
             boolean isEphemeral, String passpointProvider) {
-        if (state == DetailedState.CONNECTED && ssid == null) {
-            if (TextUtils.isEmpty(passpointProvider) == false) {
+        if (state == DetailedState.CONNECTED) {
+            if (!TextUtils.isEmpty(passpointProvider)) {
                 // Special case for connected + passpoint networks.
-                String format = context.getString(R.string.connected_via_passpoint);
-                return String.format(format, passpointProvider);
+                String format = context.getString(R.string.ssid_by_passpoint_provider);
+                return String.format(format, ssid, passpointProvider);
             } else if (isEphemeral) {
                 // Special case for connected + ephemeral networks.
                 final NetworkScoreManager networkScoreManager = context.getSystemService(
@@ -1443,4 +1521,166 @@
     private static boolean isVerboseLoggingEnabled() {
         return WifiTracker.sVerboseLogging || Log.isLoggable(TAG, Log.VERBOSE);
     }
+
+    /**
+     * Callbacks relaying changes to the OSU provisioning status started in startOsuProvisioning().
+     *
+     * All methods are invoked on the Main Thread
+     */
+    private class AccessPointProvisioningCallback extends ProvisioningCallback {
+        // TODO: Remove logs and implement summary changing logic for these provisioning callbacks.
+        @Override
+        @MainThread public void onProvisioningFailure(int status) {
+            switch (status) {
+                case OSU_FAILURE_AP_CONNECTION:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_ap_connection);
+                    break;
+                case OSU_FAILURE_SERVER_URL_INVALID:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_server_url_invalid);
+                    break;
+                case OSU_FAILURE_SERVER_CONNECTION:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_server_connection);
+                    break;
+                case OSU_FAILURE_SERVER_VALIDATION:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_server_validation);
+                    break;
+                case OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_service_provider_verification);
+                    break;
+                case OSU_FAILURE_PROVISIONING_ABORTED:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_provisioning_aborted);
+                    break;
+                case OSU_FAILURE_PROVISIONING_NOT_AVAILABLE:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_provisioning_not_available);
+                    break;
+                case OSU_FAILURE_INVALID_SERVER_URL:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_invalid_server_url);
+                    break;
+                case OSU_FAILURE_UNEXPECTED_COMMAND_TYPE:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_unexpected_command_type);
+                    break;
+                case OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_unexpected_soap_message_type);
+                    break;
+                case OSU_FAILURE_SOAP_MESSAGE_EXCHANGE:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_soap_message_exchange);
+                    break;
+                case OSU_FAILURE_START_REDIRECT_LISTENER:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_start_redirect_listener);
+                    break;
+                case OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_timed_out_redirect_listener);
+                    break;
+                case OSU_FAILURE_NO_OSU_ACTIVITY_FOUND:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_no_osu_activity_found);
+                    break;
+                case OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_unexpected_soap_message_status);
+                    break;
+                case OSU_FAILURE_NO_PPS_MO:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_no_pps_mo);
+                    break;
+                case OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_no_aaa_server_trust_root_node);
+                    break;
+                case OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_no_remediation_server_trust_root_node);
+                    break;
+                case OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_no_policy_server_trust_root_node);
+                    break;
+                case OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_retrieve_trust_root_certificates);
+                    break;
+                case OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_no_aaa_trust_root_certificate);
+                    break;
+                case OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_add_passpoint_configuration);
+                    break;
+                case OSU_FAILURE_OSU_PROVIDER_NOT_FOUND:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_osu_provider_not_found);
+                    break;
+            }
+            mOsuStatus = null;
+            mOsuProvisioningComplete = false;
+            ThreadUtils.postOnMainThread(() -> {
+                if (mAccessPointListener != null) {
+                    mAccessPointListener.onAccessPointChanged(AccessPoint.this);
+                }
+            });
+        }
+
+        @Override
+        @MainThread public void onProvisioningStatus(int status) {
+            switch (status) {
+                case OSU_STATUS_AP_CONNECTING:
+                    mOsuStatus = mContext.getString(R.string.osu_status_ap_connecting);
+                    break;
+                case OSU_STATUS_AP_CONNECTED:
+                    mOsuStatus = mContext.getString(R.string.osu_status_ap_connected);
+                    break;
+                case OSU_STATUS_SERVER_CONNECTING:
+                    mOsuStatus = mContext.getString(R.string.osu_status_server_connecting);
+                    break;
+                case OSU_STATUS_SERVER_VALIDATED:
+                    mOsuStatus = mContext.getString(R.string.osu_status_server_validated);
+                    break;
+                case OSU_STATUS_SERVER_CONNECTED:
+                    mOsuStatus = mContext.getString(R.string.osu_status_server_connected);
+                    break;
+                case OSU_STATUS_INIT_SOAP_EXCHANGE:
+                    mOsuStatus = mContext.getString(R.string.osu_status_init_soap_exchange);
+                    break;
+                case OSU_STATUS_WAITING_FOR_REDIRECT_RESPONSE:
+                    mOsuStatus = mContext.getString(
+                            R.string.osu_status_waiting_for_redirect_response);
+                    break;
+                case OSU_STATUS_REDIRECT_RESPONSE_RECEIVED:
+                    mOsuStatus = mContext.getString(R.string.osu_status_redirect_response_received);
+                    break;
+                case OSU_STATUS_SECOND_SOAP_EXCHANGE:
+                    mOsuStatus = mContext.getString(R.string.osu_status_second_soap_exchange);
+                    break;
+                case OSU_STATUS_THIRD_SOAP_EXCHANGE:
+                    mOsuStatus = mContext.getString(R.string.osu_status_third_soap_exchange);
+                    break;
+                case OSU_STATUS_RETRIEVING_TRUST_ROOT_CERTS:
+                    mOsuStatus = mContext.getString(
+                            R.string.osu_status_retrieving_trust_root_certs);
+                    break;
+            }
+            mOsuFailure = null;
+            mOsuProvisioningComplete = false;
+            ThreadUtils.postOnMainThread(() -> {
+                if (mAccessPointListener != null) {
+                    mAccessPointListener.onAccessPointChanged(AccessPoint.this);
+                }
+            });
+        }
+
+        @Override
+        @MainThread public void onProvisioningComplete() {
+            mOsuProvisioningComplete = true;
+            mOsuFailure = null;
+            mOsuStatus = null;
+            ThreadUtils.postOnMainThread(() -> {
+                if (mAccessPointListener != null) {
+                    mAccessPointListener.onAccessPointChanged(AccessPoint.this);
+                }
+            });
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 79a7240..b9a5f23 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -35,6 +35,7 @@
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiNetworkScoreCache;
 import android.net.wifi.WifiNetworkScoreCache.CacheListener;
+import android.net.wifi.hotspot2.OsuProvider;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
@@ -67,6 +68,7 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -584,7 +586,6 @@
                     Map<Integer, List<ScanResult>>> pairing : passpointConfigsAndScans) {
                 WifiConfiguration config = pairing.first;
 
-                // TODO: Prioritize home networks before roaming networks
                 List<ScanResult> scanResults = new ArrayList<>();
 
                 List<ScanResult> homeScans =
@@ -599,8 +600,12 @@
                     roamingScans = new ArrayList<>();
                 }
 
-                scanResults.addAll(homeScans);
-                scanResults.addAll(roamingScans);
+                // TODO(b/118705403): Differentiate home network vs roaming network for summary info
+                if (!homeScans.isEmpty()) {
+                    scanResults.addAll(homeScans);
+                } else {
+                    scanResults.addAll(roamingScans);
+                }
 
                 if (seenFQDNs.add(config.FQDN)) {
                     int bestRssi = Integer.MIN_VALUE;
@@ -611,13 +616,30 @@
                         }
                     }
 
-                    AccessPoint accessPoint = new AccessPoint(mContext, config);
-                    accessPoint.setScanResults(scanResults);
+                    AccessPoint accessPoint =
+                            getCachedOrCreatePasspoint(scanResults, cachedAccessPoints, config);
                     accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
                     accessPoints.add(accessPoint);
                 }
             }
 
+            // Add Passpoint OSU Provider AccessPoints
+            Map<OsuProvider, List<ScanResult>> providersAndScans =
+                    mWifiManager.getMatchingOsuProviders(cachedScanResults);
+            Set<OsuProvider> alreadyProvisioned = mWifiManager
+                    .getMatchingPasspointConfigsForOsuProviders(
+                            providersAndScans.keySet()).keySet();
+            for (OsuProvider provider : providersAndScans.keySet()) {
+                if (!alreadyProvisioned.contains(provider)) {
+                    AccessPoint accessPointOsu =
+                            getCachedOrCreateOsu(providersAndScans.get(provider),
+                                    cachedAccessPoints, provider);
+                    accessPointOsu.update(connectionConfig, mLastInfo, mLastNetworkInfo);
+                    accessPoints.add(accessPointOsu);
+                }
+            }
+
+
             // If there were no scan results, create an AP for the currently connected network (if
             // it exists).
             if (accessPoints.isEmpty() && connectionConfig != null) {
@@ -667,16 +689,49 @@
     AccessPoint getCachedOrCreate(
             List<ScanResult> scanResults,
             List<AccessPoint> cache) {
-        final int N = cache.size();
-        for (int i = 0; i < N; i++) {
-            if (cache.get(i).getKey().equals(AccessPoint.getKey(scanResults.get(0)))) {
-                AccessPoint ret = cache.remove(i);
-                ret.setScanResults(scanResults);
-                return ret;
+        AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(scanResults.get(0)));
+        if (accessPoint == null) {
+            accessPoint = new AccessPoint(mContext, scanResults);
+        } else {
+            accessPoint.setScanResults(scanResults);
+        }
+        return accessPoint;
+    }
+
+    private AccessPoint getCachedOrCreatePasspoint(
+            List<ScanResult> scanResults,
+            List<AccessPoint> cache,
+            WifiConfiguration config) {
+        AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(config));
+        if (accessPoint == null) {
+            accessPoint = new AccessPoint(mContext, config);
+        }
+        accessPoint.setScanResults(scanResults);
+        return accessPoint;
+    }
+
+    private AccessPoint getCachedOrCreateOsu(
+            List<ScanResult> scanResults,
+            List<AccessPoint> cache,
+            OsuProvider provider) {
+        AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(provider));
+        if (accessPoint == null) {
+            accessPoint = new AccessPoint(mContext, provider);
+        }
+        accessPoint.setScanResults(scanResults);
+        return accessPoint;
+    }
+
+    private AccessPoint getCachedByKey(List<AccessPoint> cache, String key) {
+        ListIterator<AccessPoint> lit = cache.listIterator();
+        while (lit.hasNext()) {
+            AccessPoint currentAccessPoint = lit.next();
+            if (currentAccessPoint.getKey().equals(key)) {
+                lit.remove();
+                return currentAccessPoint;
             }
         }
-        final AccessPoint accessPoint = new AccessPoint(mContext, scanResults);
-        return accessPoint;
+        return null;
     }
 
     private void updateNetworkInfo(NetworkInfo networkInfo) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 86f0438..92ebe44 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -17,7 +17,7 @@
 
 import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
 
-import static com.android.settingslib.Utils.STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY;
+import static com.android.settingslib.Utils.STORAGE_MANAGER_ENABLED_PROPERTY;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -159,7 +159,7 @@
 
     @Test
     public void testIsStorageManagerEnabled_UsesSystemProperties() {
-        SystemProperties.set(STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY, "false");
+        SystemProperties.set(STORAGE_MANAGER_ENABLED_PROPERTY, "true");
         assertThat(Utils.isStorageManagerEnabled(mContext)).isTrue();
     }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index bcf37ff..e843eb4 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -705,14 +705,17 @@
                 Settings.Global.GPU_DEBUG_LAYERS_GLES,
                 GlobalSettingsProto.Gpu.DEBUG_LAYERS_GLES);
         dumpSetting(s, p,
+                Settings.Global.GUP_DEV_ALL_APPS,
+                GlobalSettingsProto.Gpu.GUP_DEV_ALL_APPS);
+        dumpSetting(s, p,
                 Settings.Global.GUP_DEV_OPT_IN_APPS,
                 GlobalSettingsProto.Gpu.GUP_DEV_OPT_IN_APPS);
         dumpSetting(s, p,
                 Settings.Global.GUP_DEV_OPT_OUT_APPS,
                 GlobalSettingsProto.Gpu.GUP_DEV_OPT_OUT_APPS);
         dumpSetting(s, p,
-                Settings.Global.GUP_BLACK_LIST,
-                GlobalSettingsProto.Gpu.GUP_BLACK_LIST);
+                Settings.Global.GUP_BLACKLIST,
+                GlobalSettingsProto.Gpu.GUP_BLACKLIST);
         p.end(gpuToken);
 
         final long hdmiToken = p.start(GlobalSettingsProto.HDMI);
@@ -1879,6 +1882,9 @@
         dumpSetting(s, p,
                 Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
                 SecureSettingsProto.Doze.PULSE_ON_DOUBLE_TAP);
+        dumpSetting(s, p,
+                Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
+                SecureSettingsProto.Doze.PULSE_ON_TAP);
         p.end(dozeToken);
 
         dumpSetting(s, p,
@@ -2363,6 +2369,14 @@
                 SecureSettingsProto.Zen.SETTINGS_SUGGESTION_VIEWED);
         p.end(zenToken);
 
+        dumpSetting(s, p,
+                Settings.Secure.SKIP_GESTURE,
+                SecureSettingsProto.SKIP_GESTURE_ENABLED);
+
+        dumpSetting(s, p,
+                Settings.Secure.SILENCE_GESTURE,
+                SecureSettingsProto.SILENCE_GESTURE_ENABLED);
+
         // Please insert new settings using the same order as in SecureSettingsProto.
         p.end(token);
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index bce5593..5153f9e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1052,7 +1052,7 @@
         }
 
         // TODO(b/117663715): Ensure the caller can access the setting.
-        // enforceSettingReadable(name, SETTINGS_TYPE_CONFIG, UserHandle.getCallingUserId());
+        // enforceReadPermission(READ_DEVICE_CONFIG);
 
         // Get the value.
         synchronized (mLock) {
@@ -1088,8 +1088,9 @@
 
     private boolean mutateConfigSetting(String name, String value, String prefix,
             boolean makeDefault, int operation, int mode) {
-        // TODO(b/117663715): check the new permission when it's added.
-        // enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
+
+        // TODO(b/117663715): Ensure the caller can access the setting.
+        // enforceReadPermission(WRITE_DEVICE_CONFIG);
 
         // Perform the mutation.
         synchronized (mLock) {
diff --git a/packages/SettingsProvider/test/AndroidManifest.xml b/packages/SettingsProvider/test/AndroidManifest.xml
index 87a4f60..ebdf9b1 100644
--- a/packages/SettingsProvider/test/AndroidManifest.xml
+++ b/packages/SettingsProvider/test/AndroidManifest.xml
@@ -20,6 +20,8 @@
     <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
 
     <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/>
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
     <uses-permission android:name="android.permission.MANAGE_USERS"/>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index fa95bf2..b903142 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -57,6 +57,8 @@
     <uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
     <uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY" />
     <!-- Development tool permissions granted to the shell. -->
@@ -129,6 +131,7 @@
     <uses-permission android:name="android.permission.VIBRATE" />
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
     <uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" />
+    <uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
     <uses-permission android:name="android.permission.ACTIVITY_EMBEDDING" />
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 2530abc..2d7471d 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -56,6 +56,7 @@
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.annotation.MainThread;
+import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.app.AlertDialog;
 import android.app.Notification;
@@ -799,6 +800,18 @@
             Log.wtf(TAG, "Missing " + EXTRA_BUGREPORT + " on intent " + intent);
             return;
         }
+        final int max = intent.getIntExtra(EXTRA_MAX, -1);
+        final File screenshotFile = getFileExtra(intent, EXTRA_SCREENSHOT);
+        final String shareTitle = intent.getStringExtra(EXTRA_TITLE);
+        final String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION);
+        onBugreportFinished(id, bugreportFile, screenshotFile, shareTitle, shareDescription, max);
+    }
+
+    /**
+     * Wraps up bugreport generation and triggers a notification to share the bugreport.
+     */
+    private void onBugreportFinished(int id, File bugreportFile, @Nullable File screenshotFile,
+        String shareTitle, String shareDescription, int max) {
         mInfoDialog.onBugreportFinished();
         BugreportInfo info = getInfo(id);
         if (info == null) {
@@ -809,22 +822,17 @@
         }
         info.renameScreenshots(mScreenshotsDir);
         info.bugreportFile = bugreportFile;
+        if (screenshotFile != null) {
+            info.addScreenshot(screenshotFile);
+        }
 
-        final int max = intent.getIntExtra(EXTRA_MAX, -1);
         if (max != -1) {
             MetricsLogger.histogram(this, "dumpstate_duration", max);
             info.max = max;
         }
 
-        final File screenshot = getFileExtra(intent, EXTRA_SCREENSHOT);
-        if (screenshot != null) {
-            info.addScreenshot(screenshot);
-        }
-
-        final String shareTitle = intent.getStringExtra(EXTRA_TITLE);
         if (!TextUtils.isEmpty(shareTitle)) {
             info.title = shareTitle;
-            final String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION);
             if (!TextUtils.isEmpty(shareDescription)) {
                 info.shareDescription= shareDescription;
             }
@@ -1944,6 +1952,22 @@
         }
 
         @Override
+        public void onProgress(int progress) throws RemoteException {
+            updateProgressInfo(progress, 100 /* progress is already a percentage; so max = 100 */);
+        }
+
+        @Override
+        public void onError(int errorCode) throws RemoteException {
+            // TODO(b/111441001): implement
+        }
+
+        @Override
+        public void onFinished(long durationMs, String title, String description)
+                throws RemoteException {
+            // TODO(b/111441001): implement
+        }
+
+        @Override
         public void onProgressUpdated(int progress) throws RemoteException {
             /*
              * Checks whether the progress changed in a way that should be displayed to the user:
@@ -1964,21 +1988,7 @@
             }
 
             if (newPercentage > oldPercentage) {
-                if (DEBUG) {
-                    if (progress != info.progress) {
-                        Log.v(TAG, "Updating progress for PID " + info.pid + "(id: " + info.id
-                                + ") from " + info.progress + " to " + progress);
-                    }
-                    if (max != info.max) {
-                        Log.v(TAG, "Updating max progress for PID " + info.pid + "(id: " + info.id
-                                + ") from " + info.max + " to " + max);
-                    }
-                }
-                info.progress = progress;
-                info.max = max;
-                info.lastUpdate = System.currentTimeMillis();
-
-                updateProgress(info);
+                updateProgressInfo(progress, max);
             }
         }
 
@@ -2000,5 +2010,23 @@
         public void dump(String prefix, PrintWriter pw) {
             pw.print(prefix); pw.print("token: "); pw.println(token);
         }
+
+        private void updateProgressInfo(int progress, int max) {
+            if (DEBUG) {
+                if (progress != info.progress) {
+                    Log.v(TAG, "Updating progress for PID " + info.pid + "(id: " + info.id
+                            + ") from " + info.progress + " to " + progress);
+                }
+                if (max != info.max) {
+                    Log.v(TAG, "Updating max progress for PID " + info.pid + "(id: " + info.id
+                            + ") from " + info.max + " to " + max);
+                }
+            }
+            info.progress = progress;
+            info.max = max;
+            info.lastUpdate = System.currentTimeMillis();
+
+            updateProgress(info);
+        }
     }
 }
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 1c1a140..b4f2711 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -87,6 +87,7 @@
     <uses-permission android:name="android.permission.STOP_APP_SWITCHES" />
     <uses-permission android:name="android.permission.SET_SCREEN_COMPATIBILITY" />
     <uses-permission android:name="android.permission.START_ANY_ACTIVITY" />
+    <uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" />
diff --git a/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml b/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml
new file mode 100644
index 0000000..d3c3a51
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="200dp"
+    android:width="200dp"
+    android:viewportHeight="100"
+    android:viewportWidth="100">
+    <path
+        android:fillColor="#000000"
+        android:pathData="M50.082,14.199m-13.985,0a13.985,13.985 0,1 1,27.97 0a13.985,13.985 0,1 1,-27.97 0"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml b/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml
new file mode 100644
index 0000000..a4417fb
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="200dp"
+    android:width="200dp"
+    android:viewportHeight="100"
+    android:viewportWidth="100" >
+    <path
+        android:fillColor="#000000"
+        android:pathData="M50.082,0.025L50.082,0.025A13.985,15.63 0,0 1,64.067 15.656L64.067,49.029A13.985,15.63 0,0 1,50.082 64.659L50.082,64.659A13.985,15.63 0,0 1,36.097 49.029L36.097,15.656A13.985,15.63 0,0 1,50.082 0.025z"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
new file mode 100644
index 0000000..6f7f398
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<com.android.keyguard.clock.ClockLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+  >
+  <include
+      android:id="@+id/digital_clock"
+      layout="@layout/text_clock"
+  />
+  <com.android.keyguard.clock.ImageClock
+      android:id="@+id/analog_clock"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+  >
+    <ImageView
+        android:id="@+id/minute_hand"
+        android:layout_width="300dp"
+        android:layout_height="300dp"
+        android:src="@drawable/bubble_minute_hand"
+        android:tint="@color/bubbleMinuteHandColor"
+    />
+    <ImageView
+        android:id="@+id/hour_hand"
+        android:layout_width="300dp"
+        android:layout_height="300dp"
+        android:src="@drawable/bubble_hour_hand"
+        android:tint="@color/bubbleHourHandColor"
+    />
+  </com.android.keyguard.clock.ImageClock>
+</com.android.keyguard.clock.ClockLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/digital_clock.xml b/packages/SystemUI/res-keyguard/layout/digital_clock.xml
new file mode 100644
index 0000000..e88e2c9
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/digital_clock.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_horizontal"
+    android:layout_alignParentTop="true">
+  <include
+      android:id="@+id/lock_screen_clock"
+      layout="@layout/text_clock"
+  />
+</FrameLayout>
+
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index d52866f..463367b 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -30,17 +30,9 @@
          android:layout_height="wrap_content"
          android:layout_gravity="center_horizontal"
          android:layout_alignParentTop="true">
-        <TextClock
+        <include
              android:id="@+id/default_clock_view"
-             android:layout_width="wrap_content"
-             android:layout_height="wrap_content"
-             android:layout_gravity="center_horizontal"
-             android:letterSpacing="0.03"
-             android:textColor="?attr/wallpaperTextColor"
-             android:singleLine="true"
-             style="@style/widget_big"
-             android:format12Hour="@string/keyguard_widget_12_hours_format"
-             android:format24Hour="@string/keyguard_widget_24_hours_format" />
+             layout="@layout/text_clock" />
     </FrameLayout>
     <include layout="@layout/keyguard_status_area"
         android:id="@+id/keyguard_status_area"
diff --git a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
new file mode 100644
index 0000000..64b676f5
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<com.android.keyguard.clock.ClockLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+  >
+  <include
+      android:id="@+id/digital_clock"
+      layout="@layout/text_clock"
+  />
+  <com.android.keyguard.clock.StretchAnalogClock
+      android:id="@+id/analog_clock"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+  />
+</com.android.keyguard.clock.ClockLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/text_clock.xml b/packages/SystemUI/res-keyguard/layout/text_clock.xml
new file mode 100644
index 0000000..b61ad9c
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/text_clock.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<TextClock
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_horizontal"
+    android:letterSpacing="0.03"
+    android:textColor="?attr/wallpaperTextColor"
+    android:singleLine="true"
+    style="@style/widget_big"
+    android:format12Hour="@string/keyguard_widget_12_hours_format"
+    android:format24Hour="@string/keyguard_widget_24_hours_format"
+    android:elegantTextHeight="false"
+/>
diff --git a/packages/SystemUI/res-keyguard/layout/type_clock.xml b/packages/SystemUI/res-keyguard/layout/type_clock.xml
new file mode 100644
index 0000000..21c64e9
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/type_clock.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<com.android.keyguard.clock.ClockLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+  >
+  <com.android.keyguard.clock.TypographicClock
+      android:id="@+id/type_clock"
+      android:orientation="vertical"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+    >
+    <TextView
+        android:id="@+id/header"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="50dp"
+        style="@style/widget_big"
+        android:textColor="@color/typeClockAccentColor"
+        android:text="@string/type_clock_header"
+        android:textSize="40dp"
+    />
+    <TextView
+        android:id="@+id/hour"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="50dp"
+        style="@style/widget_big"
+        android:textSize="40dp"
+    />
+    <TextView
+        android:id="@+id/minute"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="50dp"
+        style="@style/widget_big"
+        android:textSize="40dp"
+    />
+  </com.android.keyguard.clock.TypographicClock>
+</com.android.keyguard.clock.ClockLayout>
diff --git a/packages/SystemUI/res-keyguard/values/colors.xml b/packages/SystemUI/res-keyguard/values/colors.xml
new file mode 100644
index 0000000..74ee7ff
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/values/colors.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<resources>
+  <!-- Default color for hour hand of Bubble clock. -->
+  <color name="bubbleHourHandColor">#C97343</color>
+  <!-- Default color for minute hand of Bubble clock. -->
+  <color name="bubbleMinuteHandColor">#F5C983</color>
+  <!-- Accent color for Typographic clock. -->
+  <color name="typeClockAccentColor">#F5C983</color>
+</resources>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 1d5aa6d..7432f9c 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -402,4 +402,87 @@
 number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item>
     </plurals>
 
+    <!-- Header for typographic clock face. [CHAR LIMIT=8] -->
+    <string name="type_clock_header">It\u2019s</string>
+
+    <!-- Hour displayed in words on the typographic clock face. [CHAR LIMIT=8] -->
+    <string-array name="type_clock_hours">
+        <item>Twelve</item>
+        <item>One</item>
+        <item>Two</item>
+        <item>Three</item>
+        <item>Four</item>
+        <item>Five</item>
+        <item>Six</item>
+        <item>Seven</item>
+        <item>Eight</item>
+        <item>Nine</item>
+        <item>Ten</item>
+        <item>Eleven</item>
+    </string-array>
+
+    <!-- Minutes displayed in words on the typographic clock face. [CHAR LIMIT=16] -->
+    <string-array name="type_clock_minutes">
+        <item>O\u2019Clock</item>
+        <item>O\u2019One</item>
+        <item>O\u2019Two</item>
+        <item>O\u2019Three</item>
+        <item>O\u2019Four</item>
+        <item>O\u2019Five</item>
+        <item>O\u2019Six</item>
+        <item>O\u2019Seven</item>
+        <item>O\u2019Eight</item>
+        <item>O\u2019Nine</item>
+        <item>Ten</item>
+        <item>Eleven</item>
+        <item>Twelve</item>
+        <item>Thirteen</item>
+        <item>Fourteen</item>
+        <item>Fifteen</item>
+        <item>Sixteen</item>
+        <item>Seventeen</item>
+        <item>Eighteen</item>
+        <item>Nineteen</item>
+        <item>Twenty</item>
+        <item>Twenty\nOne</item>
+        <item>Twenty\nTwo</item>
+        <item>Twenty\nThree</item>
+        <item>Twenty\nFour</item>
+        <item>Twenty\nFive</item>
+        <item>Twenty\nSix</item>
+        <item>Twenty\nSeven</item>
+        <item>Twenty\nEight</item>
+        <item>Twenty\nNine</item>
+        <item>Thirty</item>
+        <item>Thirty\nOne</item>
+        <item>Thirty\nTwo</item>
+        <item>Thirty\nThree</item>
+        <item>Thirty\nFour</item>
+        <item>Thirty\nFive</item>
+        <item>Thirty\nSix</item>
+        <item>Thirty\nSeven</item>
+        <item>Thirty\nEight</item>
+        <item>Thirty\nNine</item>
+        <item>Forty</item>
+        <item>Forty\nOne</item>
+        <item>Forty\nTwo</item>
+        <item>Forty\nThree</item>
+        <item>Forty\nFour</item>
+        <item>Forty\nFive</item>
+        <item>Forty\nSix</item>
+        <item>Forty\nSeven</item>
+        <item>Forty\nEight</item>
+        <item>Forty\nNine</item>
+        <item>Fifty</item>
+        <item>Fifty\nOne</item>
+        <item>Fifty\nTwo</item>
+        <item>Fifty\nThree</item>
+        <item>Fifty\nFour</item>
+        <item>Fifty\nFive</item>
+        <item>Fifty\nSix</item>
+        <item>Fifty\nSeven</item>
+        <item>Fifty\nEight</item>
+        <item>Fifty\nNine</item>
+    </string-array>
+
 </resources>
diff --git a/packages/SystemUI/res/layout/global_actions_wrapped.xml b/packages/SystemUI/res/layout/global_actions_wrapped.xml
index 7f4e0d2..f932303 100644
--- a/packages/SystemUI/res/layout/global_actions_wrapped.xml
+++ b/packages/SystemUI/res/layout/global_actions_wrapped.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <com.android.systemui.HardwareUiLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@id/global_actions_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_gravity="top|right"
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml b/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml
index ecfbfb4..c8e0845 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml
@@ -25,12 +25,18 @@
     android:focusable="true"
     android:layout_gravity="center_vertical">
 
-    <ImageView
-        android:id="@+id/app_icon"
+    <FrameLayout
         android:layout_height="@dimen/ongoing_appops_dialog_app_icon_size"
         android:layout_width="@dimen/ongoing_appops_dialog_app_icon_size"
-        android:layout_gravity="start|center_vertical"
-    />
+        android:layout_gravity="start|center_vertical">
+
+        <ImageView
+            android:id="@+id/app_icon"
+            android:layout_height="@dimen/ongoing_appops_dialog_app_icon_size"
+            android:layout_width="@dimen/ongoing_appops_dialog_app_icon_size"
+            android:layout_gravity="center"
+            />
+    </FrameLayout>
 
     <TextView
         android:id="@+id/app_name"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 476089a..98f0cbe 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -106,7 +106,7 @@
 
     <!-- The default tiles to display in QuickSettings -->
     <string name="quick_settings_tiles_default" translatable="false">
-        wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast
+        wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast,sensorprivacy
     </string>
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ef16bca..5a00b45 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -952,6 +952,8 @@
     <dimen name="ongoing_appops_dialog_icon_margin">8dp</dimen>
     <!-- Height and width of Application icons in Ongoing App Ops dialog -->
     <dimen name="ongoing_appops_dialog_app_icon_size">32dp</dimen>
+    <!-- Height and width of Plus sign in Ongoing App Ops dialog -->
+    <dimen name="ongoing_appops_dialog_app_plus_size">24dp</dimen>
     <!-- Height of line in Ongoing App Ops dialog-->
     <dimen name="ongoing_appops_dialog_line_height">48dp</dimen>
     <!-- Side margin of title in Ongoing App Ops dialog -->
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 633f868..bd34bea 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -114,5 +114,8 @@
     <item type="id" name="aod_mask_transition_progress_tag" />
     <item type="id" name="aod_mask_transition_progress_end_tag" />
     <item type="id" name="aod_mask_transition_progress_start_tag" />
+
+    <!-- Global Actions Menu -->
+    <item type="id" name="global_actions_view" />
 </resources>
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
index 523720d5..1a684a0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
@@ -323,7 +323,7 @@
                     return null;
                 }
                 // Create our own ClassLoader so we can use our own code as the parent.
-                ClassLoader classLoader = mManager.getClassLoader(info.sourceDir, info.packageName);
+                ClassLoader classLoader = mManager.getClassLoader(info);
                 Context pluginContext = new PluginContextWrapper(
                         mContext.createApplicationContext(info, 0), classLoader);
                 Class<?> pluginClass = Class.forName(cls, true, classLoader);
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index da143f9..7139708 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -14,6 +14,7 @@
 
 package com.android.systemui.shared.plugins;
 
+import android.app.LoadedApk;
 import android.app.Notification;
 import android.app.Notification.Action;
 import android.app.NotificationManager;
@@ -44,15 +45,17 @@
 import com.android.systemui.plugins.Plugin;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
-import com.android.systemui.shared.plugins.PluginInstanceManager.PluginContextWrapper;
 import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;
 
 import dalvik.system.PathClassLoader;
 
+import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 /**
  * @see Plugin
@@ -117,6 +120,7 @@
         return mPluginEnabler;
     }
 
+    // TODO(mankoff): This appears to be only called from tests. Remove?
     public <T extends Plugin> T getOneShotPlugin(Class<T> cls) {
         ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
         if (info == null) {
@@ -282,17 +286,25 @@
         }
     }
 
-    public ClassLoader getClassLoader(String sourceDir, String pkg) {
-        if (!isDebuggable && !mWhitelistedPlugins.contains(pkg)) {
-            Log.w(TAG, "Cannot get class loader for non-whitelisted plugin. Src:" + sourceDir +
-                    ", pkg: " + pkg);
+    /** Returns class loader specific for the given plugin. */
+    public ClassLoader getClassLoader(ApplicationInfo appInfo) {
+        if (!isDebuggable && !mWhitelistedPlugins.contains(appInfo.packageName)) {
+            Log.w(TAG, "Cannot get class loader for non-whitelisted plugin. Src:"
+                    + appInfo.sourceDir + ", pkg: " + appInfo.packageName);
             return null;
         }
-        if (mClassLoaders.containsKey(pkg)) {
-            return mClassLoaders.get(pkg);
+        if (mClassLoaders.containsKey(appInfo.packageName)) {
+            return mClassLoaders.get(appInfo.packageName);
         }
-        ClassLoader classLoader = new PathClassLoader(sourceDir, getParentClassLoader());
-        mClassLoaders.put(pkg, classLoader);
+
+        List<String> zipPaths = new ArrayList<>();
+        List<String> libPaths = new ArrayList<>();
+        LoadedApk.makePaths(null, true, appInfo, zipPaths, libPaths);
+        ClassLoader classLoader = new PathClassLoader(
+                TextUtils.join(File.pathSeparator, zipPaths),
+                TextUtils.join(File.pathSeparator, libPaths),
+                getParentClassLoader());
+        mClassLoaders.put(appInfo.packageName, classLoader);
         return classLoader;
     }
 
@@ -309,11 +321,6 @@
         return mParentClassLoader;
     }
 
-    public Context getContext(ApplicationInfo info, String pkg) throws NameNotFoundException {
-        ClassLoader classLoader = getClassLoader(info.sourceDir, pkg);
-        return new PluginContextWrapper(mContext.createApplicationContext(info, 0), classLoader);
-    }
-
     public <T> boolean dependsOn(Plugin p, Class<T> cls) {
         for (int i = 0; i < mPluginMap.size(); i++) {
             if (mPluginMap.valueAt(i).dependsOn(p, cls)) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 41e9eba..a055950 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -46,6 +46,7 @@
     protected View mEcaView;
     protected boolean mEnableHaptics;
     private boolean mDismissing;
+    protected boolean mResumed;
     private CountDownTimer mCountdownTimer = null;
 
     // To avoid accidental lockout due to events while the device in in the pocket, ignore
@@ -263,6 +264,8 @@
 
     @Override
     public void onPause() {
+        mResumed = false;
+
         if (mCountdownTimer != null) {
             mCountdownTimer.cancel();
             mCountdownTimer = null;
@@ -276,6 +279,7 @@
 
     @Override
     public void onResume(int reason) {
+        mResumed = true;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 3cfd6a9..1aff394 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -1,9 +1,15 @@
 package com.android.keyguard;
 
+import android.content.ContentResolver;
 import android.content.Context;
+import android.database.ContentObserver;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
 import android.util.AttributeSet;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
@@ -12,6 +18,9 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.keyguard.clock.BubbleClockController;
+import com.android.keyguard.clock.StretchAnalogClockController;
+import com.android.keyguard.clock.TypeClockController;
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.ClockPlugin;
 import com.android.systemui.statusbar.StatusBarState;
@@ -19,13 +28,19 @@
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.ExtensionController.Extension;
 
+import java.util.Objects;
 import java.util.TimeZone;
 import java.util.function.Consumer;
+import java.util.function.Supplier;
 
 /**
  * Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
  */
 public class KeyguardClockSwitch extends RelativeLayout {
+
+    private LayoutInflater mLayoutInflater;
+
+    private final ContentResolver mContentResolver;
     /**
      * Optional/alternative clock injected via plugin.
      */
@@ -79,12 +94,25 @@
                 }
     };
 
+    private final ContentObserver mContentObserver =
+            new ContentObserver(new Handler(Looper.getMainLooper())) {
+                @Override
+                public void onChange(boolean selfChange) {
+                    super.onChange(selfChange);
+                    if (mClockExtension != null) {
+                        mClockExtension.reload();
+                    }
+                }
+    };
+
     public KeyguardClockSwitch(Context context) {
         this(context, null);
     }
 
     public KeyguardClockSwitch(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mLayoutInflater = LayoutInflater.from(context);
+        mContentResolver = context.getContentResolver();
     }
 
     /**
@@ -108,7 +136,34 @@
         mClockExtension = Dependency.get(ExtensionController.class).newExtension(ClockPlugin.class)
                 .withPlugin(ClockPlugin.class)
                 .withCallback(mClockPluginConsumer)
+                // Using withDefault even though this isn't the default as a workaround.
+                // ExtensionBulider doesn't provide the ability to supply a ClockPlugin
+                // instance based off of the value of a setting. Since multiple "default"
+                // can be provided, using a supplier that changes the settings value.
+                // A null return will cause Extension#reload to look at the next "default"
+                // supplier.
+                .withDefault(
+                        new SettingsGattedSupplier(
+                                mContentResolver,
+                                Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
+                                BubbleClockController.class.getName(),
+                                () -> BubbleClockController.build(mLayoutInflater)))
+                .withDefault(
+                        new SettingsGattedSupplier(
+                                mContentResolver,
+                                Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
+                                StretchAnalogClockController.class.getName(),
+                                () -> StretchAnalogClockController.build(mLayoutInflater)))
+                .withDefault(
+                        new SettingsGattedSupplier(
+                                mContentResolver,
+                                Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
+                                TypeClockController.class.getName(),
+                                () -> TypeClockController.build(mLayoutInflater)))
                 .build();
+        mContentResolver.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
+                false, mContentObserver);
         Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
     }
 
@@ -116,6 +171,7 @@
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         mClockExtension.destroy();
+        mContentResolver.unregisterContentObserver(mContentObserver);
         Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
     }
 
@@ -199,10 +255,6 @@
         mClockView.setShowCurrentUserTime(showCurrentUserTime);
     }
 
-    public void setElegantTextHeight(boolean elegant) {
-        mClockView.setElegantTextHeight(elegant);
-    }
-
     public void setTextSize(int unit, float size) {
         mClockView.setTextSize(unit, size);
     }
@@ -269,4 +321,44 @@
     StatusBarStateController.StateListener getStateListener() {
         return mStateListener;
     }
+
+    /**
+     * Supplier that only gets an instance when a settings value matches expected value.
+     */
+    private static class SettingsGattedSupplier implements Supplier<ClockPlugin> {
+
+        private final ContentResolver mContentResolver;
+        private final String mKey;
+        private final String mValue;
+        private final Supplier<ClockPlugin> mSupplier;
+
+        /**
+         * Constructs a supplier that changes secure setting key against value.
+         *
+         * @param contentResolver Used to look up settings value.
+         * @param key Settings key.
+         * @param value If the setting matches this values that get supplies a ClockPlugin
+         *        instance.
+         * @param supplier Supplier of ClockPlugin instance, only used if the setting
+         *        matches value.
+         */
+        SettingsGattedSupplier(ContentResolver contentResolver, String key, String value,
+                Supplier<ClockPlugin> supplier) {
+            mContentResolver = contentResolver;
+            mKey = key;
+            mValue = value;
+            mSupplier = supplier;
+        }
+
+        /**
+         * Returns null if the settings value doesn't match the expected value.
+         *
+         * A null return causes Extension#reload to skip this supplier and move to the next.
+         */
+        @Override
+        public ClockPlugin get() {
+            final String currentValue = Settings.Secure.getString(mContentResolver, mKey);
+            return Objects.equals(currentValue, mValue) ? mSupplier.get() : null;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 41afa9a..3296c10 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -81,6 +81,11 @@
     protected void resetState() {
         mSecurityMessageDisplay.setMessage("");
         final boolean wasDisabled = mPasswordEntry.isEnabled();
+        // Don't set enabled password entry & showSoftInput when PasswordEntry is invisible or in
+        // pausing stage.
+        if (!mResumed || !mPasswordEntry.isVisibleToUser()) {
+            return;
+        }
         setPasswordEntryEnabled(true);
         setPasswordEntryInputEnabled(true);
         if (wasDisabled) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index f0cdc89..7ae4c41 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -202,10 +202,6 @@
         updateOwnerInfo();
         updateLogoutView();
         updateDark();
-
-        // Disable elegant text height because our fancy colon makes the ymin value huge for no
-        // reason.
-        mClockView.setElegantTextHeight(false);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
new file mode 100644
index 0000000..db6127f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
@@ -0,0 +1,114 @@
+/*
+ * 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.keyguard.clock;
+
+import android.graphics.Paint.Style;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextClock;
+
+import com.android.keyguard.R;
+import com.android.systemui.plugins.ClockPlugin;
+
+import java.util.TimeZone;
+
+/**
+ * Controller for Bubble clock that can appear on lock screen and AOD.
+ */
+public class BubbleClockController implements ClockPlugin {
+
+    /**
+     * Custom clock shown on AOD screen and behind stack scroller on lock.
+     */
+    private View mView;
+    private TextClock mDigitalClock;
+    private ImageClock mAnalogClock;
+
+    /**
+     * Small clock shown on lock screen above stack scroller.
+     */
+    private View mLockClockContainer;
+    private TextClock mLockClock;
+
+    /**
+     * Controller for transition to dark state.
+     */
+    private CrossFadeDarkController mDarkController;
+
+    private BubbleClockController() { }
+
+    /**
+     * Create a BubbleClockController instance.
+     *
+     * @param layoutInflater Inflater used to inflate custom clock views.
+     */
+    public static BubbleClockController build(LayoutInflater layoutInflater) {
+        BubbleClockController controller = new BubbleClockController();
+        controller.createViews(layoutInflater);
+        return controller;
+    }
+
+    private void createViews(LayoutInflater layoutInflater) {
+        mView = layoutInflater.inflate(R.layout.bubble_clock, null);
+        mDigitalClock = (TextClock) mView.findViewById(R.id.digital_clock);
+        mAnalogClock = (ImageClock) mView.findViewById(R.id.analog_clock);
+
+        mLockClockContainer = layoutInflater.inflate(R.layout.digital_clock, null);
+        mLockClock = (TextClock) mLockClockContainer.findViewById(R.id.lock_screen_clock);
+        mLockClock.setVisibility(View.GONE);
+
+        mDarkController = new CrossFadeDarkController(mDigitalClock, mLockClock);
+    }
+
+    @Override
+    public View getView() {
+        return mLockClockContainer;
+    }
+
+    @Override
+    public View getBigClockView() {
+        return mView;
+    }
+
+    @Override
+    public void setStyle(Style style) {}
+
+    @Override
+    public void setTextColor(int color) {
+        mLockClock.setTextColor(color);
+        mDigitalClock.setTextColor(color);
+    }
+
+    @Override
+    public void dozeTimeTick() {
+        mAnalogClock.onTimeChanged();
+    }
+
+    @Override
+    public void setDarkAmount(float darkAmount) {
+        mDarkController.setDarkAmount(darkAmount);
+    }
+
+    @Override
+    public void onTimeZoneChanged(TimeZone timeZone) {
+        mAnalogClock.onTimeZoneChanged(timeZone);
+    }
+
+    @Override
+    public boolean shouldShowStatusArea() {
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
new file mode 100644
index 0000000..3591dc8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
@@ -0,0 +1,101 @@
+/*
+ * 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.keyguard.clock;
+
+import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.keyguard.R;
+
+/**
+ * Positions clock faces (analog, digital, typographic) and handles pixel shifting
+ * to prevent screen burn-in.
+ */
+public class ClockLayout extends FrameLayout {
+
+    /**
+     * Clock face views.
+     */
+    private View mDigitalClock;
+    private View mAnalogClock;
+    private View mTypeClock;
+
+    /**
+     * Pixel shifting amplitidues used to prevent screen burn-in.
+     */
+    private int mBurnInPreventionOffsetX;
+    private int mBurnInPreventionOffsetY;
+
+    public ClockLayout(Context context) {
+        this(context, null);
+    }
+
+    public ClockLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ClockLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mDigitalClock = findViewById(R.id.digital_clock);
+        mAnalogClock = findViewById(R.id.analog_clock);
+        mTypeClock = findViewById(R.id.type_clock);
+
+        // Get pixel shifting X, Y amplitudes from resources.
+        Resources resources = getResources();
+        mBurnInPreventionOffsetX = resources.getDimensionPixelSize(
+            R.dimen.burn_in_prevention_offset_x);
+        mBurnInPreventionOffsetY = resources.getDimensionPixelSize(
+            R.dimen.burn_in_prevention_offset_y);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        final float offsetX = getBurnInOffset(mBurnInPreventionOffsetX, true);
+        final float offsetY = getBurnInOffset(mBurnInPreventionOffsetY, false);
+
+        // Put digital clock in two left corner of the screen.
+        if (mDigitalClock != null) {
+            mDigitalClock.setX(0.1f * getWidth() + offsetX);
+            mDigitalClock.setY(0.1f * getHeight() + offsetY);
+        }
+
+        // Put the analog clock in the middle of the screen.
+        if (mAnalogClock != null) {
+            mAnalogClock.setX(Math.max(0f, 0.5f * (getWidth() - mAnalogClock.getWidth()))
+                    + offsetX);
+            mAnalogClock.setY(Math.max(0f, 0.5f * (getHeight() - mAnalogClock.getHeight()))
+                    + offsetY);
+        }
+
+        // Put the typographic clock part way down the screen.
+        if (mTypeClock != null) {
+            mTypeClock.setX(offsetX);
+            mTypeClock.setY(0.2f * getHeight() + offsetY);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java b/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java
new file mode 100644
index 0000000..3c3f475
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.view.View;
+
+/**
+ * Controls transition to dark state by cross fading between views.
+ */
+final class CrossFadeDarkController {
+
+    private final View mFadeInView;
+    private final View mFadeOutView;
+
+    /**
+     * Creates a new controller that fades between views.
+     *
+     * @param fadeInView View to fade in when transitioning to AOD.
+     * @param fadeOutView View to fade out when transitioning to AOD.
+     */
+    CrossFadeDarkController(View fadeInView, View fadeOutView) {
+        mFadeInView = fadeInView;
+        mFadeOutView = fadeOutView;
+    }
+
+    /**
+     * Sets the amount the system has transitioned to the dark state.
+     *
+     * @param darkAmount Amount of transition to dark state: 1f for AOD and 0f for lock screen.
+     */
+    void setDarkAmount(float darkAmount) {
+        mFadeInView.setAlpha(Math.max(0f, 2f * darkAmount - 1f));
+        if (darkAmount == 0f) {
+            mFadeInView.setVisibility(View.GONE);
+        } else {
+            if (mFadeInView.getVisibility() == View.GONE) {
+                mFadeInView.setVisibility(View.VISIBLE);
+            }
+        }
+        mFadeOutView.setAlpha(Math.max(0f, 1f - 2f * darkAmount));
+        if (darkAmount == 1f) {
+            mFadeOutView.setVisibility(View.GONE);
+        } else {
+            if (mFadeOutView.getVisibility() == View.GONE) {
+                mFadeOutView.setVisibility(View.VISIBLE);
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
new file mode 100644
index 0000000..2c709e0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.content.Context;
+import android.text.format.DateFormat;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.keyguard.R;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * Clock composed of two images that rotate with the time.
+ *
+ * The images are the clock hands. ImageClock expects two child ImageViews
+ * with ids hour_hand and minute_hand.
+ */
+public class ImageClock extends FrameLayout {
+
+    private ImageView mHourHand;
+    private ImageView mMinuteHand;
+    private Calendar mTime;
+    private String mDescFormat;
+    private TimeZone mTimeZone;
+
+    public ImageClock(Context context) {
+        this(context, null);
+    }
+
+    public ImageClock(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ImageClock(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mTime = Calendar.getInstance();
+        mDescFormat = ((SimpleDateFormat) DateFormat.getTimeFormat(context)).toLocalizedPattern();
+    }
+
+    /**
+     * Call when the time changes to update the rotation of the clock hands.
+     */
+    public void onTimeChanged() {
+        mTime.setTimeInMillis(System.currentTimeMillis());
+        final float hourAngle = mTime.get(Calendar.HOUR) * 30f;
+        mHourHand.setRotation(hourAngle);
+        final float minuteAngle = mTime.get(Calendar.MINUTE) * 6f;
+        mMinuteHand.setRotation(minuteAngle);
+        setContentDescription(DateFormat.format(mDescFormat, mTime));
+        invalidate();
+    }
+
+    /**
+     * Call when the time zone has changed to update clock hands.
+     *
+     * @param timeZone The updated time zone that will be used.
+     */
+    public void onTimeZoneChanged(TimeZone timeZone) {
+        mTimeZone = timeZone;
+        mTime.setTimeZone(timeZone);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mHourHand = findViewById(R.id.hour_hand);
+        mMinuteHand = findViewById(R.id.minute_hand);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mTime = Calendar.getInstance(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
+        onTimeChanged();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
new file mode 100644
index 0000000..87347545
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
@@ -0,0 +1,142 @@
+/*
+ * 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.keyguard.clock;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * Analog clock where the minute hand extends off of the screen.
+ */
+public class StretchAnalogClock extends View {
+
+    private static final int DEFAULT_COLOR = Color.parseColor("#F5C983");
+    private static final float HOUR_STROKE_WIDTH = 60f;
+    private static final float MINUTE_STROKE_WIDTH = 20f;
+    private static final float CENTER_GAP_AND_CIRCLE_RADIUS = 80f;
+
+    private final Paint mHourPaint = new Paint();
+    private final Paint mMinutePaint = new Paint();
+    private Calendar mTime;
+    private TimeZone mTimeZone;
+
+    public StretchAnalogClock(Context context) {
+        this(context, null);
+    }
+
+    public StretchAnalogClock(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public StretchAnalogClock(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public StretchAnalogClock(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+
+    /**
+     * Call when the time changes to update the clock hands.
+     */
+    public void onTimeChanged() {
+        mTime.setTimeInMillis(System.currentTimeMillis());
+        invalidate();
+    }
+
+    /**
+     * Call when the time zone has changed to update clock hands.
+     *
+     * @param timeZone The updated time zone that will be used.
+     */
+    public void onTimeZoneChanged(TimeZone timeZone) {
+        mTime.setTimeZone(timeZone);
+    }
+
+    /**
+     * Set the color of the minute hand.
+     */
+    public void setMinuteHandColor(int color) {
+        mMinutePaint.setColor(color);
+        invalidate();
+    }
+
+    private void init() {
+        mHourPaint.setColor(DEFAULT_COLOR);
+        mHourPaint.setStrokeWidth(HOUR_STROKE_WIDTH);
+        mHourPaint.setAntiAlias(true);
+        mHourPaint.setStrokeCap(Paint.Cap.ROUND);
+
+        mMinutePaint.setColor(Color.WHITE);
+        mMinutePaint.setStrokeWidth(MINUTE_STROKE_WIDTH);
+        mMinutePaint.setAntiAlias(true);
+        mMinutePaint.setStrokeCap(Paint.Cap.ROUND);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        final float centerX = getWidth() / 2f;
+        final float centerY = getHeight() / 2f;
+
+        final float minutesRotation = mTime.get(Calendar.MINUTE) * 6f;
+        final float hoursRotation = (mTime.get(Calendar.HOUR) * 30);
+
+        // Compute length of clock hands. Hour hand is 60% the length from center to edge
+        // and minute hand is twice the length to make sure it extends past screen edge.
+        double sMinuteHandLengthFactor = Math.sin(2d * Math.PI * minutesRotation / 360d);
+        float sMinuteHandLength = (float) (2d * (centerY + (centerX - centerY)
+                * sMinuteHandLengthFactor * sMinuteHandLengthFactor));
+        double sHourHandLengthFactor = Math.sin(2d * Math.PI * hoursRotation / 360d);
+        float sHourHandLength = (float) (0.6d * (centerY + (centerX - centerY)
+                * sHourHandLengthFactor * sHourHandLengthFactor));
+
+        canvas.save();
+
+        canvas.rotate(minutesRotation, centerX, centerY);
+        canvas.drawLine(
+                centerX,
+                centerY + CENTER_GAP_AND_CIRCLE_RADIUS,
+                centerX,
+                centerY - sMinuteHandLength,
+                mMinutePaint);
+
+        canvas.rotate(hoursRotation - minutesRotation, centerX, centerY);
+        canvas.drawLine(
+                centerX,
+                centerY + CENTER_GAP_AND_CIRCLE_RADIUS,
+                centerX,
+                centerY - sHourHandLength,
+                mHourPaint);
+
+        canvas.restore();
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mTime = Calendar.getInstance(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
+        onTimeChanged();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
new file mode 100644
index 0000000..0a39158
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.graphics.Paint.Style;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextClock;
+
+import com.android.keyguard.R;
+import com.android.systemui.plugins.ClockPlugin;
+
+import java.util.TimeZone;
+
+/**
+ * Controller for Stretch clock that can appear on lock screen and AOD.
+ */
+public class StretchAnalogClockController implements ClockPlugin {
+
+    /**
+     * Custom clock shown on AOD screen and behind stack scroller on lock.
+     */
+    private View mBigClockView;
+    private TextClock mDigitalClock;
+    private StretchAnalogClock mAnalogClock;
+
+    /**
+     * Small clock shown on lock screen above stack scroller.
+     */
+    private View mView;
+    private TextClock mLockClock;
+
+    /**
+     * Controller for transition to dark state.
+     */
+    private CrossFadeDarkController mDarkController;
+
+    private StretchAnalogClockController() { }
+
+    /**
+     * Create a BubbleClockController instance.
+     *
+     * @param layoutInflater Inflater used to inflate custom clock views.
+     */
+    public static StretchAnalogClockController build(LayoutInflater layoutInflater) {
+        StretchAnalogClockController controller = new StretchAnalogClockController();
+        controller.createViews(layoutInflater);
+        return controller;
+    }
+
+    private void createViews(LayoutInflater layoutInflater) {
+        mBigClockView = layoutInflater.inflate(R.layout.stretchanalog_clock, null);
+        mAnalogClock = mBigClockView.findViewById(R.id.analog_clock);
+        mDigitalClock = mBigClockView.findViewById(R.id.digital_clock);
+
+        mView = layoutInflater.inflate(R.layout.digital_clock, null);
+        mLockClock = mView.findViewById(R.id.lock_screen_clock);
+        mLockClock.setVisibility(View.GONE);
+
+        mDarkController = new CrossFadeDarkController(mDigitalClock, mLockClock);
+    }
+
+    @Override
+    public View getView() {
+        return mView;
+    }
+
+    @Override
+    public View getBigClockView() {
+        return mBigClockView;
+    }
+
+    @Override
+    public void setStyle(Style style) {}
+
+    @Override
+    public void setTextColor(int color) {
+        mLockClock.setTextColor(color);
+        mDigitalClock.setTextColor(color);
+        mAnalogClock.setMinuteHandColor(color);
+    }
+
+    @Override
+    public void dozeTimeTick() {
+        mAnalogClock.onTimeChanged();
+    }
+
+    @Override
+    public void setDarkAmount(float darkAmount) {
+        mDarkController.setDarkAmount(darkAmount);
+    }
+
+    @Override
+    public void onTimeZoneChanged(TimeZone timeZone) {
+        mAnalogClock.onTimeZoneChanged(timeZone);
+    }
+
+    @Override
+    public boolean shouldShowStatusArea() {
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
new file mode 100644
index 0000000..17d929d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
@@ -0,0 +1,106 @@
+/*
+ * 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.keyguard.clock;
+
+import android.graphics.Paint.Style;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.keyguard.R;
+import com.android.systemui.plugins.ClockPlugin;
+
+import java.util.TimeZone;
+
+/**
+ * Plugin for a custom Typographic clock face that displays the time in words.
+ */
+public class TypeClockController implements ClockPlugin {
+
+    /**
+     * Custom clock shown on AOD screen and behind stack scroller on lock.
+     */
+    private View mView;
+    private TypographicClock mTypeClock;
+
+    /**
+     * Small clock shown on lock screen above stack scroller.
+     */
+    private View mLockClockContainer;
+
+    /**
+     * Controller for transition into dark state.
+     */
+    private CrossFadeDarkController mDarkController;
+
+    private TypeClockController() {}
+
+    /**
+     * Create a TypeClockController instance.
+     *
+     * @param inflater Inflater used to inflate custom clock views.
+     */
+    public static TypeClockController build(LayoutInflater inflater) {
+        TypeClockController controller = new TypeClockController();
+        controller.createViews(inflater);
+        return controller;
+    }
+
+    private void createViews(LayoutInflater inflater) {
+        mView = inflater.inflate(R.layout.type_clock, null);
+        mTypeClock = mView.findViewById(R.id.type_clock);
+
+        // For now, this view is used to hide the default digital clock.
+        // Need better transition to lock screen.
+        mLockClockContainer = inflater.inflate(R.layout.digital_clock, null);
+        mLockClockContainer.setVisibility(View.GONE);
+    }
+
+    @Override
+    public View getView() {
+        return mLockClockContainer;
+    }
+
+    @Override
+    public View getBigClockView() {
+        return mView;
+    }
+
+    @Override
+    public void setStyle(Style style) {}
+
+    @Override
+    public void setTextColor(int color) {
+        mTypeClock.setTextColor(color);
+    }
+
+    @Override
+    public void dozeTimeTick() {
+        mTypeClock.onTimeChanged();
+    }
+
+    @Override
+    public void setDarkAmount(float darkAmount) {}
+
+    @Override
+    public void onTimeZoneChanged(TimeZone timeZone) {
+        mTypeClock.onTimeZoneChanged(timeZone);
+    }
+
+    @Override
+    public boolean shouldShowStatusArea() {
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
new file mode 100644
index 0000000..5f9da3e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.text.format.DateFormat;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.keyguard.R;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * Clock that presents the time in words.
+ */
+public class TypographicClock extends LinearLayout {
+
+    private final String[] mHours;
+    private final String[] mMinutes;
+    private TextView mHeaderText;
+    private TextView mHourText;
+    private TextView mMinuteText;
+    private Calendar mTime;
+    private String mDescFormat;
+    private TimeZone mTimeZone;
+
+    public TypographicClock(Context context) {
+        this(context, null);
+    }
+
+    public TypographicClock(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public TypographicClock(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mTime = Calendar.getInstance();
+        mDescFormat = ((SimpleDateFormat) DateFormat.getTimeFormat(context)).toLocalizedPattern();
+        Resources res = context.getResources();
+        mHours = res.getStringArray(R.array.type_clock_hours);
+        mMinutes = res.getStringArray(R.array.type_clock_minutes);
+    }
+
+    /**
+     * Call when the time changes to update the text of the time.
+     */
+    public void onTimeChanged() {
+        mTime.setTimeInMillis(System.currentTimeMillis());
+        setContentDescription(DateFormat.format(mDescFormat, mTime));
+        final int hour = mTime.get(Calendar.HOUR);
+        mHourText.setText(mHours[hour % 12]);
+        final int minute = mTime.get(Calendar.MINUTE);
+        mMinuteText.setText(mMinutes[minute % 60]);
+        invalidate();
+    }
+
+    /**
+     * Call when the time zone has changed to update clock time.
+     *
+     * @param timeZone The updated time zone that will be used.
+     */
+    public void onTimeZoneChanged(TimeZone timeZone) {
+        mTimeZone = timeZone;
+        mTime.setTimeZone(timeZone);
+    }
+
+    /**
+     * Set the color of the text used to display the time.
+     *
+     * This is necessary when the wallpaper shown behind the clock on the
+     * lock screen changes.
+     */
+    public void setTextColor(int color) {
+        mHourText.setTextColor(color);
+        mMinuteText.setTextColor(color);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mHeaderText = findViewById(R.id.header);
+        mHourText = findViewById(R.id.hour);
+        mMinuteText = findViewById(R.id.minute);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mTime = Calendar.getInstance(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
+        onTimeChanged();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index 16e869e..e28aa9d 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -37,23 +37,25 @@
 import com.android.systemui.tuner.TunerService.Tunable;
 import com.android.systemui.util.leak.RotationUtils;
 
-public class HardwareUiLayout extends LinearLayout implements Tunable {
+/**
+ * Layout for placing two containers at a specific physical position on the device, relative to the
+ * device's hardware, regardless of screen rotation.
+ */
+public class HardwareUiLayout extends MultiListLayout implements Tunable {
 
     private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
     private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";
     private final int[] mTmp2 = new int[2];
-    private View mList;
-    private View mSeparatedView;
+    private ViewGroup mList;
+    private ViewGroup mSeparatedView;
     private int mOldHeight;
     private boolean mAnimating;
     private AnimatorSet mAnimation;
     private View mDivision;
-    private boolean mHasOutsideTouch;
     private HardwareBgDrawable mListBackground;
     private HardwareBgDrawable mSeparatedViewBackground;
     private Animator mAnimator;
     private boolean mCollapse;
-    private boolean mHasSeparatedButton;
     private int mEndPoint;
     private boolean mEdgeBleed;
     private boolean mRoundedDivider;
@@ -67,6 +69,35 @@
     }
 
     @Override
+    protected ViewGroup getSeparatedView() {
+        return findViewById(com.android.systemui.R.id.separated_button);
+    }
+
+    @Override
+    protected ViewGroup getListView() {
+        return findViewById(android.R.id.list);
+    }
+
+    @Override
+    public void removeAllItems() {
+        if (mList != null) {
+            mList.removeAllViews();
+        }
+        if (mSeparatedView != null) {
+            mSeparatedView.removeAllViews();
+        }
+    }
+
+    @Override
+    public ViewGroup getParentView(boolean separated, int index) {
+        if (separated) {
+            return getSeparatedView();
+        } else {
+            return getListView();
+        }
+    }
+
+    @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         updateSettings();
@@ -137,9 +168,9 @@
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         if (mList == null) {
             if (getChildCount() != 0) {
-                mList = getChildAt(0);
+                mList = getListView();
                 mList.setBackground(mListBackground);
-                mSeparatedView = getChildAt(1);
+                mSeparatedView = getSeparatedView();
                 mSeparatedView.setBackground(mSeparatedViewBackground);
                 updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
                 mOldHeight = mList.getMeasuredHeight();
@@ -187,7 +218,7 @@
         } else {
             rotateLeft();
         }
-        if (mHasSeparatedButton) {
+        if (mHasSeparatedView) {
             if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
                 // Separated view has top margin, so seascape separated view need special rotation,
                 // not a full left or right rotation.
@@ -408,8 +439,8 @@
         if (mList == null) return;
         // If got separated button, setRotatedBackground to false,
         // all items won't get white background.
-        mListBackground.setRotatedBackground(mHasSeparatedButton);
-        mSeparatedViewBackground.setRotatedBackground(mHasSeparatedButton);
+        mListBackground.setRotatedBackground(mHasSeparatedView);
+        mSeparatedViewBackground.setRotatedBackground(mHasSeparatedView);
         if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
             int index = mRotatedBackground ? 0 : 1;
             mDivision.getLocationOnScreen(mTmp2);
@@ -460,21 +491,21 @@
             case RotationUtils.ROTATION_LANDSCAPE:
                 defaultTopPadding = getPaddingLeft();
                 viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
-                separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0;
+                separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0;
                 screenHeight = getMeasuredWidth();
                 targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
                 break;
             case RotationUtils.ROTATION_SEASCAPE:
                 defaultTopPadding = getPaddingRight();
                 viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
-                separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0;
+                separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0;
                 screenHeight = getMeasuredWidth();
                 targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
                 break;
             default: // Portrait
                 defaultTopPadding = getPaddingTop();
                 viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight();
-                separatedViewTopMargin = mHasSeparatedButton ? params.topMargin : 0;
+                separatedViewTopMargin = mHasSeparatedView ? params.topMargin : 0;
                 screenHeight = getMeasuredHeight();
                 targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT;
                 break;
@@ -491,30 +522,10 @@
         return super.getOutlineProvider();
     }
 
-    public void setOutsideTouchListener(OnClickListener onClickListener) {
-        mHasOutsideTouch = true;
-        requestLayout();
-        setOnClickListener(onClickListener);
-        setClickable(true);
-        setFocusable(true);
-    }
-
     public void setCollapse() {
         mCollapse = true;
     }
 
-    public void setHasSeparatedButton(boolean hasSeparatedButton) {
-        mHasSeparatedButton = hasSeparatedButton;
-    }
-
-    public static HardwareUiLayout get(View v) {
-        if (v instanceof HardwareUiLayout) return (HardwareUiLayout) v;
-        if (v.getParent() instanceof View) {
-            return get((View) v.getParent());
-        }
-        return null;
-    }
-
     private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
         if (mHasOutsideTouch || (mList == null)) {
             inoutInfo.setTouchableInsets(
diff --git a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
new file mode 100644
index 0000000..0c7a9a9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+/**
+ * Layout class representing the Global Actions menu which appears when the power button is held.
+ */
+public abstract class MultiListLayout extends LinearLayout {
+    boolean mHasOutsideTouch;
+    boolean mHasSeparatedView;
+
+    int mExpectedSeparatedItemCount;
+    int mExpectedListItemCount;
+
+    public MultiListLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    protected abstract ViewGroup getSeparatedView();
+
+    protected abstract ViewGroup getListView();
+
+    /**
+     * Removes all child items from the separated and list views, if they exist.
+     */
+    public abstract void removeAllItems();
+
+    /**
+     * Get the parent view which will be used to contain the item at the specified index.
+     * @param separated Whether or not this index refers to a position in the separated or list
+     *                  container.
+     * @param index The index of the item within the container.
+     * @return The parent ViewGroup which will be used to contain the specified item
+     * after it has been added to the layout.
+     */
+    public abstract ViewGroup getParentView(boolean separated, int index);
+
+    /**
+     * Sets the divided view, which may have a differently-colored background.
+     */
+    public abstract void setDivisionView(View v);
+
+    /**
+     * Set the view accessibility delegate for the list view container.
+     */
+    public void setListViewAccessibilityDelegate(View.AccessibilityDelegate delegate) {
+        getListView().setAccessibilityDelegate(delegate);
+    }
+
+    protected void setSeparatedViewVisibility(boolean visible) {
+        getSeparatedView().setVisibility(visible ? View.VISIBLE : View.GONE);
+    }
+
+    /**
+     * Sets the number of items expected to be rendered in the separated container. This allows the
+     * layout to correctly determine which parent containers will be used for items before they have
+     * beenadded to the layout.
+     * @param count The number of items expected.
+     */
+    public void setExpectedSeparatedItemCount(int count) {
+        mExpectedSeparatedItemCount = count;
+    }
+
+    /**
+     * Sets the number of items expected to be rendered in the list container. This allows the
+     * layout to correctly determine which parent containers will be used for items before they have
+     * beenadded to the layout.
+     * @param count The number of items expected.
+     */
+    public void setExpectedListItemCount(int count) {
+        mExpectedListItemCount = count;
+    }
+
+    /**
+     * Sets whether the separated view should be shown, and handles updating visibility on
+     * that view.
+     */
+    public void setHasSeparatedView(boolean hasSeparatedView) {
+        mHasSeparatedView = hasSeparatedView;
+        setSeparatedViewVisibility(hasSeparatedView);
+    }
+
+    /**
+     * Sets this layout to respond to an outside touch listener.
+     */
+    public void setOutsideTouchListener(OnClickListener onClickListener) {
+        mHasOutsideTouch = true;
+        requestLayout();
+        setOnClickListener(onClickListener);
+        setClickable(true);
+        setFocusable(true);
+    }
+
+    /**
+     * Retrieve the MultiListLayout associated with the given view.
+     */
+    public static MultiListLayout get(View v) {
+        if (v instanceof MultiListLayout) return (MultiListLayout) v;
+        if (v.getParent() instanceof View) {
+            return get((View) v.getParent());
+        }
+        return null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index d7bf77d..957d772 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -284,8 +284,9 @@
     @Nullable
     private PendingIntent getAppOverlayIntent(NotificationEntry notif) {
         Notification notification = notif.notification.getNotification();
-        if (canLaunchInActivityView(notification.getAppOverlayIntent())) {
-            return notification.getAppOverlayIntent();
+        if (canLaunchInActivityView(notification.getBubbleMetadata() != null
+                ? notification.getBubbleMetadata().getIntent() : null)) {
+            return notification.getBubbleMetadata().getIntent();
         } else if (shouldUseContentIntent(mContext)
                 && canLaunchInActivityView(notification.contentIntent)) {
             Log.d(TAG, "[addBubble " + notif.key
@@ -446,15 +447,16 @@
         StatusBarNotification n = entry.notification;
         boolean canAppOverlay = false;
         try {
-            canAppOverlay = mNotificationManagerService.areAppOverlaysAllowedForPackage(
+            canAppOverlay = mNotificationManagerService.areBubblesAllowedForPackage(
                     n.getPackageName(), n.getUid());
         } catch (RemoteException e) {
             Log.w(TAG, "Error calling NoMan to determine if app can overlay", e);
         }
 
         boolean canChannelOverlay = mNotificationEntryManager.getNotificationData().getChannel(
-                entry.key).canOverlayApps();
-        boolean hasOverlayIntent = n.getNotification().getAppOverlayIntent() != null;
+                entry.key).canBubble();
+        boolean hasOverlayIntent = n.getNotification().getBubbleMetadata() != null
+                && n.getNotification().getBubbleMetadata().getIntent() != null;
         return hasOverlayIntent && canChannelOverlay && canAppOverlay;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 4cb1fee..bd7a421 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -38,7 +38,13 @@
     void setAnimateWakeup(boolean animateWakeup);
     void setAnimateScreenOff(boolean animateScreenOff);
 
-    void onDoubleTap(float x, float y);
+    /**
+     * Reports that a tap event happend on the Sensors Low Power Island.
+     *
+     * @param x Touch X, or -1 if sensor doesn't support touch location.
+     * @param y Touch Y, or -1 if sensor doesn't support touch location.
+     */
+    void onSlpiTap(float x, float y);
 
     default void setAodDimmingScrim(float scrimOpacity) {}
     void setDozeScreenBrightness(int value);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 50003e3..a784773 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -35,7 +35,7 @@
     private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50;
     static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
 
-    private static final int REASONS = 9;
+    private static final int REASONS = 10;
 
     public static final int PULSE_REASON_NONE = -1;
     public static final int PULSE_REASON_INTENT = 0;
@@ -47,6 +47,7 @@
     public static final int PULSE_REASON_DOCKING = 6;
     public static final int REASON_SENSOR_WAKE_UP = 7;
     public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8;
+    public static final int PULSE_REASON_SENSOR_TAP = 9;
 
     private static boolean sRegisterKeyguardCallback = true;
 
@@ -207,6 +208,7 @@
             case PULSE_REASON_DOCKING: return "docking";
             case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakelockscreen";
             case REASON_SENSOR_WAKE_UP: return "wakeup";
+            case PULSE_REASON_SENSOR_TAP: return "tap";
             default: throw new IllegalArgumentException("bad reason: " + pulseReason);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index b6fc355..78374a0 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -107,6 +107,13 @@
                         dozeParameters.doubleTapReportsTouchCoordinates(),
                         true /* touchscreen */),
                 new TriggerSensor(
+                        findSensorWithType(config.tapSensorType()),
+                        Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
+                        true /* configured */,
+                        DozeLog.PULSE_REASON_SENSOR_TAP,
+                        false /* reports touch coordinates */,
+                        true /* touchscreen */),
+                new TriggerSensor(
                         findSensorWithType(config.longPressSensorType()),
                         Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
                         false /* settingDef */,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 6a9b689..e2e448b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -132,6 +132,7 @@
     private void onSensor(int pulseReason, boolean sensorPerformedProxCheck,
             float screenX, float screenY, float[] rawValues) {
         boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
+        boolean isTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_TAP;
         boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
         boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS;
         boolean isWakeDisplay = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP;
@@ -148,8 +149,10 @@
                     // In pocket, drop event.
                     return;
                 }
-                if (isDoubleTap) {
-                    mDozeHost.onDoubleTap(screenX, screenY);
+                if (isDoubleTap || isTap) {
+                    if (screenX != -1 && screenY != -1) {
+                        mDozeHost.onSlpiTap(screenX, screenY);
+                    }
                     mMachine.wakeUp();
                 } else if (isPickup) {
                     mMachine.wakeUp();
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 268245b..7b18fad 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -67,10 +67,8 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.AdapterView.OnItemLongClickListener;
 import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.internal.R;
@@ -86,8 +84,8 @@
 import com.android.internal.util.ScreenshotHelper;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.Dependency;
-import com.android.systemui.HardwareUiLayout;
 import com.android.systemui.Interpolators;
+import com.android.systemui.MultiListLayout;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
 import com.android.systemui.statusbar.phone.ScrimController;
@@ -490,6 +488,11 @@
         public boolean showBeforeProvisioning() {
             return true;
         }
+
+        @Override
+        public boolean shouldBeSeparated() {
+            return true;
+        }
     }
 
     private final class RestartAction extends SinglePressAction implements LongPressAction {
@@ -926,6 +929,34 @@
             return getItem(position).isEnabled();
         }
 
+        public ArrayList<Action> getSeparatedActions(boolean shouldUseSeparatedView) {
+            ArrayList<Action> separatedActions = new ArrayList<Action>();
+            if (!shouldUseSeparatedView) {
+                return separatedActions;
+            }
+            for (int i = 0; i < mItems.size(); i++) {
+                final Action action = mItems.get(i);
+                if (action.shouldBeSeparated()) {
+                    separatedActions.add(action);
+                }
+            }
+            return separatedActions;
+        }
+
+        public ArrayList<Action> getListActions(boolean shouldUseSeparatedView) {
+            if (!shouldUseSeparatedView) {
+                return new ArrayList<Action>(mItems);
+            }
+            ArrayList<Action> listActions = new ArrayList<Action>();
+            for (int i = 0; i < mItems.size(); i++) {
+                final Action action = mItems.get(i);
+                if (!action.shouldBeSeparated()) {
+                    listActions.add(action);
+                }
+            }
+            return listActions;
+        }
+
         @Override
         public boolean areAllItemsEnabled() {
             return false;
@@ -965,7 +996,7 @@
             View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
             // Everything but screenshot, the last item, gets white background.
             if (position == getCount() - 1) {
-                HardwareUiLayout.get(parent).setDivisionView(view);
+                MultiListLayout.get(parent).setDivisionView(view);
             }
             return view;
         }
@@ -1004,6 +1035,10 @@
         boolean showBeforeProvisioning();
 
         boolean isEnabled();
+
+        default boolean shouldBeSeparated() {
+            return false;
+        }
     }
 
     /**
@@ -1423,9 +1458,7 @@
 
         private final Context mContext;
         private final MyAdapter mAdapter;
-        private final LinearLayout mListView;
-        private final FrameLayout mSeparatedView;
-        private final HardwareUiLayout mHardwareLayout;
+        private final MultiListLayout mGlobalActionsLayout;
         private final OnClickListener mClickListener;
         private final OnItemLongClickListener mLongClickListener;
         private final GradientDrawable mGradientDrawable;
@@ -1466,16 +1499,11 @@
             window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
 
             setContentView(com.android.systemui.R.layout.global_actions_wrapped);
-            mListView = findViewById(android.R.id.list);
-            mSeparatedView = findViewById(com.android.systemui.R.id.separated_button);
-            if (!mShouldDisplaySeparatedButton) {
-                mSeparatedView.setVisibility(View.GONE);
-            }
-            mHardwareLayout = HardwareUiLayout.get(mListView);
-            mHardwareLayout.setOutsideTouchListener(view -> dismiss());
-            mHardwareLayout.setHasSeparatedButton(mShouldDisplaySeparatedButton);
-            setTitle(R.string.global_actions);
-            mListView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+            mGlobalActionsLayout = (MultiListLayout)
+                    findViewById(com.android.systemui.R.id.global_actions_view);
+            mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
+            mGlobalActionsLayout.setHasSeparatedView(mShouldDisplaySeparatedButton);
+            mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
                 @Override
                 public boolean dispatchPopulateAccessibilityEvent(
                         View host, AccessibilityEvent event) {
@@ -1484,20 +1512,33 @@
                     return true;
                 }
             });
+            setTitle(R.string.global_actions);
         }
 
         private void updateList() {
-            mListView.removeAllViews();
-            mSeparatedView.removeAllViews();
+            mGlobalActionsLayout.removeAllItems();
+            ArrayList<Action> separatedActions =
+                    mAdapter.getSeparatedActions(mShouldDisplaySeparatedButton);
+            ArrayList<Action> listActions = mAdapter.getListActions(mShouldDisplaySeparatedButton);
+            mGlobalActionsLayout.setExpectedListItemCount(listActions.size());
+            mGlobalActionsLayout.setExpectedSeparatedItemCount(separatedActions.size());
+
             for (int i = 0; i < mAdapter.getCount(); i++) {
-                ViewGroup parentView = mShouldDisplaySeparatedButton && i == mAdapter.getCount() - 1
-                        ? mSeparatedView : mListView;
-                View v = mAdapter.getView(i, null, parentView);
+                Action action = mAdapter.getItem(i);
+                int separatedIndex = separatedActions.indexOf(action);
+                ViewGroup parent;
+                if (separatedIndex != -1) {
+                    parent = mGlobalActionsLayout.getParentView(true, separatedIndex);
+                } else {
+                    int listIndex = listActions.indexOf(action);
+                    parent = mGlobalActionsLayout.getParentView(false, listIndex);
+                }
+                View v = mAdapter.getView(i, null, parent);
                 final int pos = i;
                 v.setOnClickListener(view -> mClickListener.onClick(this, pos));
                 v.setOnLongClickListener(view ->
                         mLongClickListener.onItemLongClick(null, v, pos, 0));
-                parentView.addView(v);
+                parent.addView(v);
             }
         }
 
@@ -1543,9 +1584,9 @@
             super.show();
             mShowing = true;
             mGradientDrawable.setAlpha(0);
-            mHardwareLayout.setTranslationX(getAnimTranslation());
-            mHardwareLayout.setAlpha(0);
-            mHardwareLayout.animate()
+            mGlobalActionsLayout.setTranslationX(getAnimTranslation());
+            mGlobalActionsLayout.setAlpha(0);
+            mGlobalActionsLayout.animate()
                     .alpha(1)
                     .translationX(0)
                     .setDuration(300)
@@ -1564,9 +1605,9 @@
                 return;
             }
             mShowing = false;
-            mHardwareLayout.setTranslationX(0);
-            mHardwareLayout.setAlpha(1);
-            mHardwareLayout.animate()
+            mGlobalActionsLayout.setTranslationX(0);
+            mGlobalActionsLayout.setAlpha(1);
+            mGlobalActionsLayout.animate()
                     .alpha(0)
                     .translationX(getAnimTranslation())
                     .setDuration(300)
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
index 6ed1eba..77e25e3 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.util.IconDrawableFactory
 import android.view.Gravity
 import android.view.LayoutInflater
 import android.view.View
@@ -37,11 +38,22 @@
 
     private val iconSize = context.resources.getDimensionPixelSize(
             R.dimen.ongoing_appops_dialog_icon_size)
+    private val plusSize = context.resources.getDimensionPixelSize(
+            R.dimen.ongoing_appops_dialog_app_plus_size)
     private val iconColor = context.resources.getColor(
             com.android.internal.R.color.text_color_primary, context.theme)
+    private val plusColor: Int
     private val iconMargin = context.resources.getDimensionPixelSize(
             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)
+
+    init {
+        val a = context.theme.obtainStyledAttributes(
+                intArrayOf(com.android.internal.R.attr.colorAccent))
+        plusColor = a.getColor(0, 0)
+        a.recycle()
+    }
 
     fun createDialog(): Dialog {
         val builder = AlertDialog.Builder(context).apply {
@@ -87,9 +99,15 @@
                     numItems - MAX_ITEMS
             )
             val overflowPlus = overflow.findViewById(R.id.app_icon) as ImageView
+            val lp = overflowPlus.layoutParams.apply {
+                height = plusSize
+                width = plusSize
+            }
+            overflowPlus.layoutParams = lp
             overflowPlus.apply {
-                imageTintList = ColorStateList.valueOf(iconColor)
-                setImageDrawable(context.getDrawable(R.drawable.plus))
+                val plus = context.getDrawable(R.drawable.plus)
+                imageTintList = ColorStateList.valueOf(plusColor)
+                setImageDrawable(plus)
             }
         }
 
@@ -114,7 +132,7 @@
         }
 
         app.icon.let {
-            appIcon.setImageDrawable(it)
+            appIcon.setImageDrawable(iconFactory.getShadowedIcon(it))
         }
 
         appName.text = app.applicationName
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
index 5230cea..7ee37d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
@@ -84,7 +84,7 @@
 
     @Override
     public Intent getLongClickIntent() {
-        return null;
+        return new Intent();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index eea4490..839b06c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -33,6 +33,13 @@
     default void onPendingEntryAdded(NotificationEntry entry) {
     }
 
+    // TODO: Combine this with onPreEntryUpdated into "onBeforeEntryFiltered" or similar
+    /**
+     * Called when a new entry is created but before it has been filtered or displayed to the user.
+     */
+    default void onBeforeNotificationAdded(NotificationEntry entry) {
+    }
+
     /**
      * Called when a new entry is created.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 45db002..989e781 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -18,11 +18,9 @@
 import android.annotation.Nullable;
 import android.app.Notification;
 import android.content.Context;
-import android.os.UserHandle;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -41,7 +39,6 @@
 import com.android.systemui.statusbar.notification.row.NotificationInflater;
 import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.leak.LeakDetector;
 
@@ -68,8 +65,6 @@
     @VisibleForTesting
     protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>();
 
-    private final DeviceProvisionedController mDeviceProvisionedController =
-            Dependency.get(DeviceProvisionedController.class);
     private final ForegroundServiceController mForegroundServiceController =
             Dependency.get(ForegroundServiceController.class);
 
@@ -81,25 +76,12 @@
     private NotificationListenerService.RankingMap mLatestRankingMap;
     @VisibleForTesting
     protected NotificationData mNotificationData;
-    private NotificationListContainer mListContainer;
+
     @VisibleForTesting
     final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders
             = new ArrayList<>();
     private final List<NotificationEntryListener> mNotificationEntryListeners = new ArrayList<>();
 
-    private final DeviceProvisionedController.DeviceProvisionedListener
-            mDeviceProvisionedListener =
-            new DeviceProvisionedController.DeviceProvisionedListener() {
-                @Override
-                public void onDeviceProvisionedChanged() {
-                    updateNotifications();
-                }
-            };
-
-    public void destroy() {
-        mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
-    }
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("NotificationEntryManager state:");
@@ -151,9 +133,6 @@
             HeadsUpManager headsUpManager) {
         mPresenter = presenter;
         mNotificationData.setHeadsUpManager(headsUpManager);
-        mListContainer = listContainer;
-
-        mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
     }
 
     /** Adds multiple {@link NotificationLifetimeExtender}s. */
@@ -227,7 +206,9 @@
                     listener.onEntryInflated(entry, inflatedFlags);
                 }
                 mNotificationData.add(entry);
-                tagForeground(entry.notification);
+                for (NotificationEntryListener listener : mNotificationEntryListeners) {
+                    listener.onBeforeNotificationAdded(entry);
+                }
                 updateNotifications();
                 for (NotificationEntryListener listener : mNotificationEntryListeners) {
                     listener.onNotificationAdded(entry);
@@ -283,7 +264,6 @@
 
                 if (entry.rowExists()) {
                     entry.removeRow();
-                    mListContainer.cleanUpViewStateForEntry(entry);
                 }
 
                 // Let's remove the children if this was a summary
@@ -368,19 +348,6 @@
         }
     }
 
-    @VisibleForTesting
-    void tagForeground(StatusBarNotification notification) {
-        ArraySet<Integer> activeOps = mForegroundServiceController.getAppOps(
-                notification.getUserId(), notification.getPackageName());
-        if (activeOps != null) {
-            int N = activeOps.size();
-            for (int i = 0; i < N; i++) {
-                updateNotificationsForAppOp(activeOps.valueAt(i), notification.getUid(),
-                        notification.getPackageName(), true);
-            }
-        }
-    }
-
     @Override
     public void addNotification(StatusBarNotification notification,
             NotificationListenerService.RankingMap ranking) {
@@ -391,15 +358,6 @@
         }
     }
 
-    public void updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon) {
-        String foregroundKey = mForegroundServiceController.getStandardLayoutKey(
-                UserHandle.getUserId(uid), pkg);
-        if (foregroundKey != null) {
-            mNotificationData.updateAppOp(appOp, uid, pkg, foregroundKey, showIcon);
-            updateNotifications();
-        }
-    }
-
     private void updateNotificationInternal(StatusBarNotification notification,
             NotificationListenerService.RankingMap ranking) throws InflationException {
         if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
@@ -452,8 +410,9 @@
 
     public void updateNotifications() {
         mNotificationData.filterAndSort();
-
-        mPresenter.updateNotificationViews();
+        if (mPresenter != null) {
+            mPresenter.updateNotificationViews();
+        }
     }
 
     public void updateNotificationRanking(NotificationListenerService.RankingMap rankingMap) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
new file mode 100644
index 0000000..88f4ca2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+
+/**
+ * Root controller for the list of notifications in the shade.
+ *
+ * TODO: Much of the code in NotificationPresenter should eventually move in here. It will proxy
+ * domain-specific behavior (ARC, etc) to subcontrollers.
+ */
+public class NotificationListController {
+    private final NotificationEntryManager mEntryManager;
+    private final NotificationListContainer mListContainer;
+    private final ForegroundServiceController mForegroundServiceController;
+    private final DeviceProvisionedController mDeviceProvisionedController;
+
+    public NotificationListController(
+            NotificationEntryManager entryManager,
+            NotificationListContainer listContainer,
+            ForegroundServiceController foregroundServiceController,
+            DeviceProvisionedController deviceProvisionedController) {
+        mEntryManager = checkNotNull(entryManager);
+        mListContainer = checkNotNull(listContainer);
+        mForegroundServiceController = checkNotNull(foregroundServiceController);
+        mDeviceProvisionedController = checkNotNull(deviceProvisionedController);
+    }
+
+    /**
+     * Causes the controller to register listeners on its dependencies. This method must be called
+     * before the controller is ready to perform its duties.
+     */
+    public void bind() {
+        mEntryManager.addNotificationEntryListener(mEntryListener);
+        mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
+    }
+
+    /** Should be called when the list controller is being destroyed. */
+    public void destroy() {
+        mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
+    }
+
+    @SuppressWarnings("FieldCanBeLocal")
+    private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
+        @Override
+        public void onEntryRemoved(
+                NotificationEntry entry,
+                NotificationVisibility visibility,
+                boolean removedByUser) {
+            mListContainer.cleanUpViewStateForEntry(entry);
+        }
+
+        @Override
+        public void onBeforeNotificationAdded(NotificationEntry entry) {
+            tagForeground(entry.notification);
+        }
+    };
+
+    private final DeviceProvisionedListener mDeviceProvisionedListener =
+            new DeviceProvisionedListener() {
+                @Override
+                public void onDeviceProvisionedChanged() {
+                    mEntryManager.updateNotifications();
+                }
+            };
+
+    // TODO: This method is horrifically inefficient
+    private void tagForeground(StatusBarNotification notification) {
+        ArraySet<Integer> activeOps =
+                mForegroundServiceController.getAppOps(
+                        notification.getUserId(), notification.getPackageName());
+        if (activeOps != null) {
+            int len = activeOps.size();
+            for (int i = 0; i < len; i++) {
+                updateNotificationsForAppOp(activeOps.valueAt(i), notification.getUid(),
+                        notification.getPackageName(), true);
+            }
+        }
+    }
+
+    /** When an app op changes, propagate that change to notifications. */
+    public void updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon) {
+        String foregroundKey =
+                mForegroundServiceController.getStandardLayoutKey(UserHandle.getUserId(uid), pkg);
+        if (foregroundKey != null) {
+            mEntryManager
+                    .getNotificationData().updateAppOp(appOp, uid, pkg, foregroundKey, showIcon);
+            mEntryManager.updateNotifications();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java
index ebcd39b..323e776 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java
@@ -43,6 +43,11 @@
     }
 
     @Override
+    public boolean disableProxyEvents() {
+        return true;
+    }
+
+    @Override
     public void onGestureStart(MotionEvent event) {
         mAssistManager.startAssist(new Bundle());
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
index 93605ad..7a42b03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
@@ -95,6 +95,11 @@
         }
     }
 
+    @Override
+    public boolean disableProxyEvents() {
+        return true;
+    }
+
     private void performBack() {
         sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
         sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
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 31310f5..32cc0e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -141,6 +141,7 @@
     private KeyguardAffordanceHelper mAffordanceHelper;
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
     private KeyguardStatusBarView mKeyguardStatusBar;
+    private ViewGroup mBigClockContainer;
     private QS mQs;
     private FrameLayout mQsFrame;
     @VisibleForTesting
@@ -348,8 +349,8 @@
         mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
 
         KeyguardClockSwitch keyguardClockSwitch = findViewById(R.id.keyguard_clock_container);
-        ViewGroup bigClockContainer = findViewById(R.id.big_clock_container);
-        keyguardClockSwitch.setBigClockContainer(bigClockContainer);
+        mBigClockContainer = findViewById(R.id.big_clock_container);
+        keyguardClockSwitch.setBigClockContainer(mBigClockContainer);
 
         mNotificationContainerParent = findViewById(R.id.notification_container_parent);
         mNotificationStackScroller = findViewById(R.id.notification_stack_scroller);
@@ -585,6 +586,11 @@
                     mClockPositionResult.clockX, CLOCK_ANIMATION_PROPERTIES, animateClock);
             PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.Y,
                     mClockPositionResult.clockY, CLOCK_ANIMATION_PROPERTIES, animateClock);
+            // Move big clock up while pulling up the bouncer
+            PropertyAnimator.setProperty(mBigClockContainer, AnimatableProperty.Y,
+                    MathUtils.lerp(-mBigClockContainer.getHeight(), 0,
+                          Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(getExpandedFraction())),
+                    CLOCK_ANIMATION_PROPERTIES, animateClock);
             updateClock();
             stackScrollerPadding = mClockPositionResult.stackScrollerPadding;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 853d7ab..3568f28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -612,9 +612,11 @@
         anim.setStartDelay(mAnimationDelay);
         anim.setDuration(mAnimationDuration);
         anim.addListener(new AnimatorListenerAdapter() {
+            private Callback lastCallback = mCallback;
+
             @Override
             public void onAnimationEnd(Animator animation) {
-                onFinished();
+                onFinished(lastCallback);
 
                 scrim.setTag(TAG_KEY_ANIM, null);
                 dispatchScrimsVisible();
@@ -672,14 +674,23 @@
     }
 
     private void onFinished() {
+        onFinished(mCallback);
+    }
+
+    private void onFinished(Callback callback) {
         if (mWakeLockHeld) {
             mWakeLock.release();
             mWakeLockHeld = false;
         }
-        if (mCallback != null) {
-            mCallback.onFinished();
-            mCallback = null;
+
+        if (callback != null) {
+            callback.onFinished();
+
+            if (callback == mCallback) {
+                mCallback = null;
+            }
         }
+
         // When unlocking with fingerprint, we'll fade the scrims from black to transparent.
         // At the end of the animation we need to remove the tint.
         if (mState == ScrimState.UNLOCKED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 514bb22..ed71598 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -196,6 +196,7 @@
 import com.android.systemui.statusbar.notification.NotificationClicker;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.NotificationListController;
 import com.android.systemui.statusbar.notification.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -387,6 +388,7 @@
     private NotificationGutsManager mGutsManager;
     protected NotificationLogger mNotificationLogger;
     protected NotificationEntryManager mEntryManager;
+    private NotificationListController mNotificationListController;
     private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
     private NotificationRowBinder mNotificationRowBinder;
     protected NotificationViewHierarchyManager mViewHierarchyManager;
@@ -593,7 +595,7 @@
     public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
         mForegroundServiceController.onAppOpChanged(code, uid, packageName, active);
         Dependency.get(Dependency.MAIN_HANDLER).post(() -> {
-            mEntryManager.updateNotificationsForAppOp(code, uid, packageName, active);
+            mNotificationListController.updateNotificationsForAppOp(code, uid, packageName, active);
         });
     }
 
@@ -1044,6 +1046,13 @@
                 mScrimController, mActivityLaunchAnimator, mStatusBarKeyguardViewManager,
                 mNotificationAlertingManager);
 
+        mNotificationListController =
+                new NotificationListController(
+                        mEntryManager,
+                        (NotificationListContainer) mStackScroller,
+                        mForegroundServiceController,
+                        mDeviceProvisionedController);
+
         mAppOpsController.addCallback(APP_OPS, this);
         mNotificationListener.setUpWithPresenter(mPresenter);
         mNotificationShelf.setOnActivatedListener(mPresenter);
@@ -1056,6 +1065,7 @@
                 this, Dependency.get(BubbleController.class), mNotificationActivityStarter));
 
         mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager);
+        mNotificationListController.bind();
     }
 
     /**
@@ -2831,7 +2841,7 @@
         } catch (RemoteException e) {
             // Ignore.
         }
-        mEntryManager.destroy();
+        mNotificationListController.destroy();
         // End old BaseStatusBar.destroy().
         if (mStatusBarWindow != null) {
             mWindowManager.removeViewImmediate(mStatusBarWindow);
@@ -3999,7 +4009,7 @@
         }
 
         @Override
-        public void onDoubleTap(float screenX, float screenY) {
+        public void onSlpiTap(float screenX, float screenY) {
             if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
                 && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
                 mAmbientIndicationContainer.getLocationOnScreen(mTmpInt2);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 04d24dc..4f61009 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -346,7 +346,7 @@
     }
 
     private void handleFullScreenIntent(NotificationEntry entry) {
-        boolean isHeadsUped = mNotificationInterruptionStateProvider.canHeadsUpCommon(entry);
+        boolean isHeadsUped = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
         if (!isHeadsUped && entry.notification.getNotification().fullScreenIntent != null) {
             if (shouldSuppressFullScreenIntent(entry)) {
                 if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 9422101..f79ad71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -541,7 +541,8 @@
 
     @VisibleForTesting
     void doUpdateMobileControllers() {
-        List<SubscriptionInfo> subscriptions = mSubscriptionManager.getActiveSubscriptionInfoList();
+        List<SubscriptionInfo> subscriptions = mSubscriptionManager
+                .getActiveSubscriptionInfoList(true);
         if (subscriptions == null) {
             subscriptions = Collections.emptyList();
         }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
new file mode 100644
index 0000000..9e946fa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.keyguard.clock;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public final class BubbleClockControllerTest extends SysuiTestCase {
+
+    private BubbleClockController mClockController;
+
+    @Before
+    public void setUp() {
+        LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+        mClockController = BubbleClockController.build(layoutInflater);
+    }
+
+    @Test
+    public void setDarkAmount_fadeIn() {
+        ViewGroup smallClockFrame = (ViewGroup) mClockController.getView();
+        View smallClock = smallClockFrame.getChildAt(0);
+        // WHEN dark amount is set to AOD
+        mClockController.setDarkAmount(1f);
+        // THEN small clock should not be shown.
+        assertThat(smallClock.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void setTextColor_setDigitalClock() {
+        ViewGroup smallClock = (ViewGroup) mClockController.getView();
+        // WHEN text color is set
+        mClockController.setTextColor(42);
+        // THEN child of small clock should have text color set.
+        TextView digitalClock = (TextView) smallClock.getChildAt(0);
+        assertThat(digitalClock.getCurrentTextColor()).isEqualTo(42);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java
new file mode 100644
index 0000000..fd7657f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public final class CrossFadeDarkControllerTest extends SysuiTestCase {
+
+    private View mViewFadeIn;
+    private View mViewFadeOut;
+    private CrossFadeDarkController mDarkController;
+
+    @Before
+    public void setUp() {
+        mViewFadeIn = new TextView(getContext());
+        mViewFadeIn.setVisibility(View.VISIBLE);
+        mViewFadeIn.setAlpha(1f);
+        mViewFadeOut = new TextView(getContext());
+        mViewFadeOut.setVisibility(View.VISIBLE);
+        mViewFadeOut.setAlpha(1f);
+
+        mDarkController = new CrossFadeDarkController(mViewFadeIn, mViewFadeOut);
+    }
+
+    @Test
+    public void setDarkAmount_fadeIn() {
+        // WHEN dark amount corresponds to AOD
+        mDarkController.setDarkAmount(1f);
+        // THEN fade in view should be faded in and fade out view faded out.
+        assertThat(mViewFadeIn.getAlpha()).isEqualTo(1f);
+        assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mViewFadeOut.getAlpha()).isEqualTo(0f);
+        assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void setDarkAmount_fadeOut() {
+        // WHEN dark amount corresponds to lock screen
+        mDarkController.setDarkAmount(0f);
+        // THEN fade out view should bed faded out and fade in view faded in.
+        assertThat(mViewFadeIn.getAlpha()).isEqualTo(0f);
+        assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mViewFadeOut.getAlpha()).isEqualTo(1f);
+        assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void setDarkAmount_partialFadeIn() {
+        // WHEN dark amount corresponds to a partial transition
+        mDarkController.setDarkAmount(0.9f);
+        // THEN views should have intermediate alpha value.
+        assertThat(mViewFadeIn.getAlpha()).isGreaterThan(0f);
+        assertThat(mViewFadeIn.getAlpha()).isLessThan(1f);
+        assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void setDarkAmount_partialFadeOut() {
+        // WHEN dark amount corresponds to a partial transition
+        mDarkController.setDarkAmount(0.1f);
+        // THEN views should have intermediate alpha value.
+        assertThat(mViewFadeOut.getAlpha()).isGreaterThan(0f);
+        assertThat(mViewFadeOut.getAlpha()).isLessThan(1f);
+        assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java
new file mode 100644
index 0000000..8de8f3d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.keyguard.clock;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public final class StretchAnalogClockControllerTest extends SysuiTestCase {
+
+    private StretchAnalogClockController mClockController;
+
+    @Before
+    public void setUp() {
+        LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+        mClockController = StretchAnalogClockController.build(layoutInflater);
+    }
+
+    @Test
+    public void setDarkAmount_fadeIn() {
+        ViewGroup smallClockFrame = (ViewGroup) mClockController.getView();
+        View smallClock = smallClockFrame.getChildAt(0);
+        // WHEN dark amount is set to AOD
+        mClockController.setDarkAmount(1f);
+        // THEN small clock should not be shown.
+        assertThat(smallClock.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void setTextColor_setDigitalClock() {
+        ViewGroup smallClock = (ViewGroup) mClockController.getView();
+        // WHEN text color is set
+        mClockController.setTextColor(42);
+        // THEN child of small clock should have text color set.
+        TextView digitalClock = (TextView) smallClock.getChildAt(0);
+        assertThat(digitalClock.getCurrentTextColor()).isEqualTo(42);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
index ce28b50..dc42872 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
@@ -104,7 +104,7 @@
     }
 
     @Override
-    public void onDoubleTap(float x, float y) {
+    public void onSlpiTap(float x, float y) {
         doubleTapX = y;
         doubleTapY = y;
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
index 4583770..3415c72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
@@ -91,7 +91,7 @@
         mMockPm = mock(PackageManager.class);
         mMockListener = mock(PluginListener.class);
         mMockManager = mock(PluginManagerImpl.class);
-        when(mMockManager.getClassLoader(any(), any())).thenReturn(getClass().getClassLoader());
+        when(mMockManager.getClassLoader(any())).thenReturn(getClass().getClassLoader());
         mMockEnabler = mock(PluginEnabler.class);
         when(mMockManager.getPluginEnabler()).thenReturn(mMockEnabler);
         mMockVersionInfo = mock(VersionInfo.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
index 76e68f1..536c043 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
@@ -25,6 +25,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -135,9 +136,13 @@
         });
         resetExceptionHandler();
 
+        String sourceDir = "myPlugin";
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.sourceDir = sourceDir;
+        applicationInfo.packageName = WHITELISTED_PACKAGE;
         mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
-        assertNull(mPluginManager.getOneShotPlugin("myPlugin", TestPlugin.class));
-        assertNull(mPluginManager.getClassLoader("myPlugin", WHITELISTED_PACKAGE));
+        assertNull(mPluginManager.getOneShotPlugin(sourceDir, TestPlugin.class));
+        assertNull(mPluginManager.getClassLoader(applicationInfo));
     }
 
     @Test
@@ -152,9 +157,16 @@
         });
         resetExceptionHandler();
 
+        String sourceDir = "myPlugin";
+        ApplicationInfo whiteListedApplicationInfo = new ApplicationInfo();
+        whiteListedApplicationInfo.sourceDir = sourceDir;
+        whiteListedApplicationInfo.packageName = WHITELISTED_PACKAGE;
+        ApplicationInfo invalidApplicationInfo = new ApplicationInfo();
+        invalidApplicationInfo.sourceDir = sourceDir;
+        invalidApplicationInfo.packageName = "com.android.invalidpackage";
         mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
-        assertNotNull(mPluginManager.getClassLoader("myPlugin", WHITELISTED_PACKAGE));
-        assertNull(mPluginManager.getClassLoader("myPlugin", "com.android.invalidpackage"));
+        assertNotNull(mPluginManager.getClassLoader(whiteListedApplicationInfo));
+        assertNull(mPluginManager.getClassLoader(invalidApplicationInfo));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 2b13f86..8952594 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -27,6 +27,7 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.drawable.Icon;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.support.test.InstrumentationRegistry;
@@ -220,8 +221,7 @@
             notificationBuilder.setGroup(groupKey);
         }
         if (isBubble) {
-            PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
-            notificationBuilder.setAppOverlayIntent(bubbleIntent);
+            notificationBuilder.setBubbleMetadata(makeBubbleMetadata());
         }
         return notificationBuilder.build();
     }
@@ -282,4 +282,14 @@
         mGroupManager.onEntryAdded(entry);
         return row;
     }
+
+    private Notification.BubbleMetadata makeBubbleMetadata() {
+        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        return new Notification.BubbleMetadata.Builder()
+                .setIntent(bubbleIntent)
+                .setTitle("bubble title")
+                .setIcon(Icon.createWithResource(mContext, 1))
+                .setDesiredHeight(314)
+                .build();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index d937f93..9ce6ae1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -22,19 +22,15 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
-import android.app.AppOpsManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -49,7 +45,6 @@
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
-import android.util.ArraySet;
 import android.widget.FrameLayout;
 
 import com.android.internal.logging.MetricsLogger;
@@ -79,8 +74,6 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
-import junit.framework.Assert;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -346,7 +339,6 @@
 
         verify(mEntryListener, never()).onInflationError(any(), any());
 
-        verify(mListContainer).cleanUpViewStateForEntry(mEntry);
         verify(mPresenter).updateNotificationViews();
         verify(mEntryListener).onEntryRemoved(
                 mEntry, null, false /* removedByUser */);
@@ -401,90 +393,6 @@
     }
 
     @Test
-    public void testUpdateAppOps_foregroundNoti() {
-        com.android.systemui.util.Assert.isNotMainThread();
-
-        when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
-                .thenReturn(mEntry.key);
-        mEntry.setRow(mRow);
-        mEntryManager.getNotificationData().add(mEntry);
-
-        mEntryManager.updateNotificationsForAppOp(
-                AppOpsManager.OP_CAMERA, mEntry.notification.getUid(),
-                mEntry.notification.getPackageName(), true);
-
-        verify(mPresenter, times(1)).updateNotificationViews();
-        assertTrue(mEntryManager.getNotificationData().get(mEntry.key).mActiveAppOps.contains(
-                AppOpsManager.OP_CAMERA));
-    }
-
-    @Test
-    public void testUpdateAppOps_otherNoti() {
-        com.android.systemui.util.Assert.isNotMainThread();
-
-        when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
-                .thenReturn(null);
-        mEntryManager.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true);
-
-        verify(mPresenter, never()).updateNotificationViews();
-    }
-
-    @Test
-    public void testAddNotificationExistingAppOps() {
-        mEntry.setRow(mRow);
-        mEntryManager.getNotificationData().add(mEntry);
-        ArraySet<Integer> expected = new ArraySet<>();
-        expected.add(3);
-        expected.add(235);
-        expected.add(1);
-
-        when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(expected);
-        when(mForegroundServiceController.getStandardLayoutKey(
-                mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(mEntry.key);
-
-        mEntryManager.tagForeground(mEntry.notification);
-
-        Assert.assertEquals(expected.size(), mEntry.mActiveAppOps.size());
-        for (int op : expected) {
-            assertTrue("Entry missing op " + op, mEntry.mActiveAppOps.contains(op));
-        }
-    }
-
-    @Test
-    public void testAdd_noExistingAppOps() {
-        mEntry.setRow(mRow);
-        mEntryManager.getNotificationData().add(mEntry);
-        when(mForegroundServiceController.getStandardLayoutKey(
-                mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(mEntry.key);
-        when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(null);
-
-        mEntryManager.tagForeground(mEntry.notification);
-        Assert.assertEquals(0, mEntry.mActiveAppOps.size());
-    }
-
-    @Test
-    public void testAdd_existingAppOpsNotForegroundNoti() {
-        mEntry.setRow(mRow);
-        mEntryManager.getNotificationData().add(mEntry);
-        ArraySet<Integer> ops = new ArraySet<>();
-        ops.add(3);
-        ops.add(235);
-        ops.add(1);
-        when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(ops);
-        when(mForegroundServiceController.getStandardLayoutKey(
-                mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn("something else");
-
-        mEntryManager.tagForeground(mEntry.notification);
-        Assert.assertEquals(0, mEntry.mActiveAppOps.size());
-    }
-
-    @Test
     public void testUpdateNotificationRanking() {
         when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
         when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
new file mode 100644
index 0000000..4b5037b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.Notification;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.util.ArraySet;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationListControllerTest extends SysuiTestCase {
+    private NotificationListController mController;
+
+    @Mock private NotificationEntryManager mEntryManager;
+    @Mock private NotificationListContainer mListContainer;
+    @Mock private ForegroundServiceController mForegroundServiceController;
+    @Mock private DeviceProvisionedController mDeviceProvisionedController;
+
+    @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
+    @Captor private ArgumentCaptor<DeviceProvisionedListener> mProvisionedCaptor;
+
+    private NotificationEntryListener mEntryListener;
+    private DeviceProvisionedListener mProvisionedListener;
+
+    // TODO: Remove this once EntryManager no longer needs to be mocked
+    private NotificationData mNotificationData = new NotificationData();
+
+    private int mNextNotifId = 0;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
+
+        mController = new NotificationListController(
+                mEntryManager,
+                mListContainer,
+                mForegroundServiceController,
+                mDeviceProvisionedController);
+        mController.bind();
+
+        // Capture callbacks passed to mocks
+        verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
+        mEntryListener = mEntryListenerCaptor.getValue();
+        verify(mDeviceProvisionedController).addCallback(mProvisionedCaptor.capture());
+        mProvisionedListener = mProvisionedCaptor.getValue();
+    }
+
+    @Test
+    public void testCleanUpViewStateOnEntryRemoved() {
+        final NotificationEntry entry = buildEntry();
+        mEntryListener.onEntryRemoved(
+                entry,
+                NotificationVisibility.obtain(entry.key, 0, 0, true),
+                false);
+        verify(mListContainer).cleanUpViewStateForEntry(entry);
+    }
+
+    @Test
+    public void testCallUpdateNotificationsOnDeviceProvisionedChange() {
+        mProvisionedListener.onDeviceProvisionedChanged();
+        verify(mEntryManager).updateNotifications();
+    }
+
+    @Test
+    public void testAppOps_appOpAddedToForegroundNotif() {
+        // GIVEN a notification associated with a foreground service
+        final NotificationEntry entry = buildEntry();
+        mNotificationData.add(entry);
+        when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
+                .thenReturn(entry.key);
+
+        // WHEN we are notified of a new app op
+        mController.updateNotificationsForAppOp(
+                AppOpsManager.OP_CAMERA,
+                entry.notification.getUid(),
+                entry.notification.getPackageName(),
+                true);
+
+        // THEN the app op is added to the entry
+        assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
+        // THEN updateNotifications() is called
+        verify(mEntryManager, times(1)).updateNotifications();
+    }
+
+    @Test
+    public void testAppOps_appOpAddedToUnrelatedNotif() {
+        // GIVEN No current foreground notifs
+        when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
+                .thenReturn(null);
+
+        // WHEN An unrelated notification gets a new app op
+        mController.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true);
+
+        // THEN We never call updateNotifications()
+        verify(mEntryManager, never()).updateNotifications();
+    }
+
+    @Test
+    public void testAppOps_addNotificationWithExistingAppOps() {
+        // GIVEN a notification with three associated app ops that is associated with a foreground
+        // service
+        final NotificationEntry entry = buildEntry();
+        mNotificationData.add(entry);
+        ArraySet<Integer> expected = new ArraySet<>();
+        expected.add(3);
+        expected.add(235);
+        expected.add(1);
+        when(mForegroundServiceController.getStandardLayoutKey(
+                entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(entry.key);
+        when(mForegroundServiceController.getAppOps(entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(expected);
+
+        // WHEN the notification is added
+        mEntryListener.onBeforeNotificationAdded(entry);
+
+        // THEN the entry is tagged with all three app ops
+        assertEquals(expected.size(), entry.mActiveAppOps.size());
+        for (int op : expected) {
+            assertTrue("Entry missing op " + op, entry.mActiveAppOps.contains(op));
+        }
+    }
+
+    @Test
+    public void testAdd_addNotificationWithNoExistingAppOps() {
+        // GIVEN a notification with NO associated app ops
+        final NotificationEntry entry = buildEntry();
+
+        mNotificationData.add(entry);
+        when(mForegroundServiceController.getStandardLayoutKey(
+                entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(entry.key);
+        when(mForegroundServiceController.getAppOps(entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(null);
+
+        // WHEN the notification is added
+        mEntryListener.onBeforeNotificationAdded(entry);
+
+        // THEN the entry doesn't have any app ops associated with it
+        assertEquals(0, entry.mActiveAppOps.size());
+    }
+
+    @Test
+    public void testAdd_addNonForegroundNotificationWithExistingAppOps() {
+        // GIVEN a notification with app ops that isn't associated with a foreground service
+        final NotificationEntry entry = buildEntry();
+        mNotificationData.add(entry);
+        ArraySet<Integer> ops = new ArraySet<>();
+        ops.add(3);
+        ops.add(235);
+        ops.add(1);
+        when(mForegroundServiceController.getAppOps(entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(ops);
+        when(mForegroundServiceController.getStandardLayoutKey(
+                entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn("something else");
+
+        // WHEN the notification is added
+        mEntryListener.onBeforeNotificationAdded(entry);
+
+        // THEN the entry doesn't have any app ops associated with it
+        assertEquals(0, entry.mActiveAppOps.size());
+    }
+
+    private NotificationEntry buildEntry() {
+        mNextNotifId++;
+
+        Notification.Builder n = new Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text");
+
+        StatusBarNotification notification =
+                new StatusBarNotification(
+                        TEST_PACKAGE_NAME,
+                        TEST_PACKAGE_NAME,
+                        mNextNotifId,
+                        null,
+                        TEST_UID,
+                        0,
+                        n.build(),
+                        new UserHandle(ActivityManager.getCurrentUser()),
+                        null,
+                        0);
+        return new NotificationEntry(notification);
+    }
+
+    private static final String TEST_PACKAGE_NAME = "test";
+    private static final int TEST_UID = 0;
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index fdbf090..c1f8885 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -182,6 +182,7 @@
             subs.add(subscription);
         }
         when(mMockSm.getActiveSubscriptionInfoList()).thenReturn(subs);
+        when(mMockSm.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(subs);
         mNetworkController.doUpdateMobileControllers();
     }
 
diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk
index 848f2bd..2fa1dde 100644
--- a/packages/WallpaperCropper/Android.mk
+++ b/packages/WallpaperCropper/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_PACKAGE_NAME := WallpaperCropper
 LOCAL_PRIVATE_PLATFORM_APIS := true
 LOCAL_CERTIFICATE := platform
+LOCAL_PRODUCT_MODULE := true
 LOCAL_PRIVILEGED_MODULE := true
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
diff --git a/packages/WallpaperCropper/CleanSpec.mk b/packages/WallpaperCropper/CleanSpec.mk
new file mode 100644
index 0000000..e6d8d5a
--- /dev/null
+++ b/packages/WallpaperCropper/CleanSpec.mk
@@ -0,0 +1,50 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/WallpaperCropper)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/packages/services/PacProcessor/Android.mk b/packages/services/PacProcessor/Android.mk
index 295b3d8b..be9ba43 100644
--- a/packages/services/PacProcessor/Android.mk
+++ b/packages/services/PacProcessor/Android.mk
@@ -26,6 +26,6 @@
 LOCAL_PRIVATE_PLATFORM_APIS := true
 LOCAL_CERTIFICATE := platform
 
-LOCAL_JNI_SHARED_LIBRARIES := libjni_pacprocessor libpac
+LOCAL_JNI_SHARED_LIBRARIES := libjni_pacprocessor
 
 include $(BUILD_PACKAGE)
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 44edb56..a07411d 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6801,8 +6801,20 @@
     // ACTION: Tap & Pay -> Default Application Setting -> Use Default
     // OS: Q
     ACTION_NFC_PAYMENT_ALWAYS_SETTING = 1623;
-    // ---- End Q Constants, all Q constants go above this line ----
 
+    // OPEN: Settings > System > Input & Gesture > Skip song gesture
+    // OS: Q
+    SETTINGS_GESTURE_SKIP_SONG = 1624;
+
+    // OPEN: Settings > System > Input & Gesture > Silence gesture
+    // OS: Q
+    SETTINGS_GESTURE_SILENCE = 1625;
+
+    // OPEN: Settings > System > Input & Gesture > Tap screen gesture
+    // OS: Q
+    SETTINGS_GESTURE_TAP_SCREEN = 1626;
+
+    // ---- 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/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index cf9f233..8ffadde 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -462,7 +462,7 @@
             return false;
         }
 
-        endGestureDetection();
+        endGestureDetection(true);
 
         mAms.onGesture(gestureId);
 
@@ -472,7 +472,7 @@
     @Override
     public boolean onGestureCancelled(MotionEvent event, int policyFlags) {
         if (mCurrentState == STATE_GESTURE_DETECTING) {
-            endGestureDetection();
+            endGestureDetection(event.getActionMasked() == MotionEvent.ACTION_UP);
             return true;
         } else if (mCurrentState == STATE_TOUCH_EXPLORING) {
             // If the finger is still moving, pass the event on.
@@ -804,13 +804,19 @@
         }
     }
 
-    private void endGestureDetection() {
+    private void endGestureDetection(boolean interactionEnd) {
         mAms.onTouchInteractionEnd();
 
         // Announce the end of the gesture recognition.
         sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
-        // Announce the end of a the touch interaction.
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
+        if (interactionEnd) {
+            // Announce the end of a the touch interaction.
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
+        } else {
+            // If gesture detection is end, but user doesn't release the finger, announce the
+            // transition to exploration state.
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
+        }
 
         mExitGestureDetectionModeDelayed.cancel();
         mCurrentState = STATE_TOUCH_EXPLORING;
@@ -889,7 +895,6 @@
         MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent();
         if (event != null && event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
             final int pointerIdBits = event.getPointerIdBits();
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
             sendMotionEvent(event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits, policyFlags);
         }
     }
@@ -1148,8 +1153,8 @@
             sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
             // Clearing puts is in touch exploration state with a finger already
             // down, so announce the transition to exploration state.
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
             clear();
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
         }
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 24fd7b9..c992da4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -252,9 +252,8 @@
     @Override // from AbstractMasterSystemService
     protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId,
             boolean disabled) {
-        return new AutofillManagerServiceImpl(this, mLock, mRequestsHistory,
-                mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi, mAutofillCompatState,
-                disabled);
+        return new AutofillManagerServiceImpl(this, mLock, mUiLatencyHistory,
+                mWtfHistory, resolvedUserId, mUi, mAutofillCompatState, disabled);
     }
 
     @Override // AbstractMasterSystemService
@@ -291,6 +290,13 @@
         return mSupportedSmartSuggestionModes;
     }
 
+    /**
+     * Logs a request so it's dumped later...
+     */
+    void logRequestLocked(@NonNull String historyItem) {
+        mRequestsHistory.log(historyItem);
+    }
+
     // Called by AutofillManagerServiceImpl, doesn't need to check permission
     boolean isInstantServiceAllowed() {
         return mAllowInstantService;
@@ -701,6 +707,11 @@
         public void onBackKeyPressed() {
             if (sDebug) Slog.d(TAG, "onBackKeyPressed()");
             mUi.hideAll(null);
+            synchronized (mLock) {
+                final AutofillManagerServiceImpl service =
+                        getServiceForUserLocked(UserHandle.getCallingUserId());
+                service.onBackKeyPressed();
+            }
         }
 
         @Override
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index a6bb049..954b67e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -108,7 +108,6 @@
 
     private static final Random sRandom = new Random();
 
-    private final LocalLog mRequestsHistory;
     private final LocalLog mUiLatencyHistory;
     private final LocalLog mWtfHistory;
     private final FieldClassificationStrategy mFieldClassificationStrategy;
@@ -166,12 +165,12 @@
     @Nullable
     private RemoteAugmentedAutofillService mRemoteAugmentedAutofillService;
 
-    AutofillManagerServiceImpl(AutofillManagerService master, Object lock, LocalLog requestsHistory,
+    AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
             LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
-            AutofillCompatState autofillCompatState, boolean disabled) {
+            AutofillCompatState autofillCompatState,
+            boolean disabled) {
         super(master, lock, userId);
 
-        mRequestsHistory = requestsHistory;
         mUiLatencyHistory = uiLatencyHistory;
         mWtfHistory = wtfHistory;
         mUi = ui;
@@ -187,6 +186,15 @@
     }
 
     @GuardedBy("mLock")
+    void onBackKeyPressed() {
+        final RemoteAugmentedAutofillService remoteService =
+                getRemoteAugmentedAutofillServiceLocked();
+        if (remoteService != null) {
+            remoteService.onDestroyAutofillWindowsRequest();
+        }
+    }
+
+    @GuardedBy("mLock")
     @Override // from PerUserSystemService
     protected boolean updateLocked(boolean disabled) {
         destroySessionsLocked();
@@ -301,7 +309,7 @@
                 + " s=" + mInfo.getServiceInfo().packageName
                 + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds
                 + " hc=" + hasCallback + " f=" + flags;
-        mRequestsHistory.log(historyItem);
+        mMaster.logRequestLocked(historyItem);
 
         newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags);
 
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index a8ff9b0..5d8d8fa 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -109,8 +109,8 @@
     /**
      * Called by {@link Session} when it's time to destroy all augmented autofill requests.
      */
-    public void onDestroyAutofillWindowsRequest(int sessionId) {
-        scheduleAsyncRequest((s) -> s.onDestroyFillWindowRequest(sessionId));
+    public void onDestroyAutofillWindowsRequest() {
+        scheduleAsyncRequest((s) -> s.onDestroyAllFillWindowsRequest());
     }
 
     // TODO(b/111330312): inline into PendingAutofillRequest if it doesn't have any other subclass
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index cf4963c..7dfd8fe 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2610,6 +2610,13 @@
                     + " when server returned null for session " + this.id);
         }
 
+        final String historyItem =
+                "aug:id=" + id + " u=" + uid + " m=" + mode
+                + " a=" + ComponentName.flattenToShortString(mComponentName)
+                + " f=" + mCurrentViewId
+                + " s=" + remoteService.getComponentName();
+        mService.getMaster().logRequestLocked(historyItem);
+
         final AutofillValue currentValue = mViewStates.get(mCurrentViewId).getCurrentValue();
 
         // TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize
@@ -2619,7 +2626,7 @@
                 currentValue);
 
         if (mAugmentedAutofillDestroyer == null) {
-            mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest(id);
+            mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest();
         }
         return mAugmentedAutofillDestroyer;
     }
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index 529430c..a7bada0 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -562,7 +562,7 @@
     private void registerTransportsFromPackage(
             String packageName, Predicate<ComponentName> transportComponentFilter) {
         try {
-            mPackageManager.getPackageInfo(packageName, 0);
+            mPackageManager.getPackageInfoAsUser(packageName, 0, mUserId);
         } catch (PackageManager.NameNotFoundException e) {
             Slog.e(TAG, "Trying to register transports from package not found " + packageName);
             return;
@@ -599,7 +599,8 @@
             return false;
         }
         try {
-            PackageInfo packInfo = mPackageManager.getPackageInfo(transport.getPackageName(), 0);
+            PackageInfo packInfo =
+                    mPackageManager.getPackageInfoAsUser(transport.getPackageName(), 0, mUserId);
             if ((packInfo.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
                     == 0) {
                 Slog.w(TAG, "Transport package " + transport.getPackageName() + " not privileged");
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 0412b0f..79f8a7e 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -249,11 +249,11 @@
     private final TransportManager mTransportManager;
     private final HandlerThread mUserBackupThread;
 
-    private Context mContext;
-    private PackageManager mPackageManager;
-    private IPackageManager mPackageManagerBinder;
-    private IActivityManager mActivityManager;
-    private ActivityManagerInternal mActivityManagerInternal;
+    private final Context mContext;
+    private final PackageManager mPackageManager;
+    private final IPackageManager mPackageManagerBinder;
+    private final IActivityManager mActivityManager;
+    private final ActivityManagerInternal mActivityManagerInternal;
     private PowerManager mPowerManager;
     private final AlarmManager mAlarmManager;
     private final IStorageManager mStorageManager;
@@ -494,20 +494,18 @@
                 mUserId);
 
         mBaseStateDir = checkNotNull(baseStateDir, "baseStateDir cannot be null");
-        mBaseStateDir.mkdirs();
-        if (!SELinux.restorecon(mBaseStateDir)) {
-            Slog.w(TAG, "SELinux restorecon failed on " + mBaseStateDir);
-        }
-
-        mDataDir = checkNotNull(dataDir, "dataDir cannot be null");
-        // TODO(b/120424138): Remove when the system user moves out of the cache dir. The cache dir
-        // is managed by init.rc so we don't have to create it below.
-        if (userId != UserHandle.USER_SYSTEM) {
-            mDataDir.mkdirs();
-            if (!SELinux.restorecon(mDataDir)) {
-                Slog.w(TAG, "SELinux restorecon failed on " + mDataDir);
+        // TODO (b/120424138): Remove once the system user is migrated to use the per-user CE
+        // directory. Per-user CE directories are managed by vold.
+        if (userId == UserHandle.USER_SYSTEM) {
+            mBaseStateDir.mkdirs();
+            if (!SELinux.restorecon(mBaseStateDir)) {
+                Slog.w(TAG, "SELinux restorecon failed on " + mBaseStateDir);
             }
         }
+
+        // TODO (b/120424138): The system user currently uses the cache which is managed by init.rc
+        // Initialization and restorecon is managed by vold for per-user CE directories.
+        mDataDir = checkNotNull(dataDir, "dataDir cannot be null");
         mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng);
 
         // Receivers for scheduled backups and transport initialization operations.
@@ -584,7 +582,7 @@
         mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);
 
         // Power management
-        mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
+        mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*-" + userId);
     }
 
     void initializeBackupEnableState() {
@@ -1352,7 +1350,7 @@
     private List<PackageInfo> allAgentPackages() {
         // !!! TODO: cache this and regenerate only when necessary
         int flags = PackageManager.GET_SIGNING_CERTIFICATES;
-        List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
+        List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(flags, mUserId);
         int numPackages = packages.size();
         for (int a = numPackages - 1; a >= 0; a--) {
             PackageInfo pkg = packages.get(a);
@@ -1366,8 +1364,8 @@
                     // we will need the shared library path, so look that up and store it here.
                     // This is used implicitly when we pass the PackageInfo object off to
                     // the Activity Manager to launch the app for backup/restore purposes.
-                    app = mPackageManager.getApplicationInfo(pkg.packageName,
-                            PackageManager.GET_SHARED_LIBRARY_FILES);
+                    app = mPackageManager.getApplicationInfoAsUser(pkg.packageName,
+                            PackageManager.GET_SHARED_LIBRARY_FILES, mUserId);
                     pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
                     pkg.applicationInfo.sharedLibraryInfos = app.sharedLibraryInfos;
                 }
@@ -1392,7 +1390,7 @@
             notification.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES
                     | Intent.FLAG_RECEIVER_FOREGROUND);
             notification.putExtra(BACKUP_FINISHED_PACKAGE_EXTRA, packageName);
-            mContext.sendBroadcastAsUser(notification, UserHandle.OWNER);
+            mContext.sendBroadcastAsUser(notification, UserHandle.of(mUserId));
         }
 
         mProcessedPackagesJournal.addPackage(packageName);
@@ -1466,11 +1464,7 @@
             }
         }
         if (agent == null) {
-            try {
-                mActivityManager.clearPendingBackup();
-            } catch (RemoteException e) {
-                // can't happen - ActivityManager is local
-            }
+            mActivityManagerInternal.clearPendingBackup(mUserId);
         }
         return agent;
     }
@@ -2212,11 +2206,10 @@
     /** Used by both incremental and full restore to restore widget data. */
     public void restoreWidgetData(String packageName, byte[] widgetData) {
         // Apply the restored widget state and generate the ID update for the app
-        // TODO: http://b/22388012
         if (MORE_DEBUG) {
             Slog.i(TAG, "Incorporating restored widget data");
         }
-        AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, UserHandle.USER_SYSTEM);
+        AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, mUserId);
     }
 
     // *****************************
@@ -2295,20 +2288,6 @@
 
     /** Sent from an app's backup agent to let the service know that there's new data to backup. */
     public void dataChanged(final String packageName) {
-        final int callingUserHandle = UserHandle.getCallingUserId();
-        if (callingUserHandle != UserHandle.USER_SYSTEM) {
-            // TODO: http://b/22388012
-            // App is running under a non-owner user profile.  For now, we do not back
-            // up data from secondary user profiles.
-            // TODO: backups for all user profiles although don't add backup for profiles
-            // without adding admin control in DevicePolicyManager.
-            if (MORE_DEBUG) {
-                Slog.v(TAG, "dataChanged(" + packageName + ") ignored because it's user "
-                        + callingUserHandle);
-            }
-            return;
-        }
-
         final HashSet<String> targets = dataChangedTargets(packageName);
         if (targets == null) {
             Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
@@ -2925,7 +2904,7 @@
         try {
             int transportUid =
                     mContext.getPackageManager()
-                            .getPackageUid(transportComponent.getPackageName(), 0);
+                            .getPackageUidAsUser(transportComponent.getPackageName(), 0, mUserId);
             if (callingUid != transportUid) {
                 throw new SecurityException("Only the transport can change its description");
             }
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index 862ca71..cfc129e 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -45,6 +45,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SELinux;
+import android.os.UserHandle;
 import android.os.WorkSource;
 
 import com.android.internal.annotations.GuardedBy;
@@ -686,8 +687,12 @@
                     ParcelFileDescriptor.open(
                             mNewStateFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
 
-            if (!SELinux.restorecon(mBackupDataFile)) {
-                mReporter.onRestoreconFailed(mBackupDataFile);
+            // TODO (b/120424138): Remove once the system user is migrated to use the per-user CE
+            // directory. Per-user CE directories are managed by vold.
+            if (mUserId == UserHandle.USER_SYSTEM) {
+                if (!SELinux.restorecon(mBackupDataFile)) {
+                    mReporter.onRestoreconFailed(mBackupDataFile);
+                }
             }
 
             IBackupTransport transport = mTransportClient.connectOrThrow("KVBT.extractAgentData()");
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index c7f3315..b3d9fbc 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -68,6 +68,8 @@
 public class FullRestoreEngine extends RestoreEngine {
 
     private final UserBackupManagerService mBackupManagerService;
+    private final int mUserId;
+
     // Task in charge of monitoring timeouts
     private final BackupRestoreTask mMonitorTask;
 
@@ -146,6 +148,7 @@
                 backupManagerService.getAgentTimeoutParameters(),
                 "Timeout parameters cannot be null");
         mIsAdbRestore = isAdbRestore;
+        mUserId = backupManagerService.getUserId();
     }
 
     public IBackupAgent getAgent() {
@@ -272,7 +275,7 @@
                                         instream, mBackupManagerService.getContext(),
                                         mDeleteObserver, mManifestSignatures,
                                         mPackagePolicies, info, installerPackageName,
-                                        bytesReadListener, mBackupManagerService.getUserId());
+                                        bytesReadListener, mUserId);
                                 // good to go; promote to ACCEPT
                                 mPackagePolicies.put(pkg, isSuccessfullyInstalled
                                         ? RestorePolicy.ACCEPT
@@ -329,9 +332,8 @@
                         }
 
                         try {
-                            mTargetApp =
-                                    mBackupManagerService.getPackageManager().getApplicationInfo(
-                                            pkg, 0);
+                            mTargetApp = mBackupManagerService.getPackageManager()
+                                    .getApplicationInfoAsUser(pkg, 0, mUserId);
 
                             // If we haven't sent any data to this app yet, we probably
                             // need to clear it first. Check that.
@@ -684,7 +686,7 @@
         String packageListString = Settings.Secure.getStringForUser(
                 mBackupManagerService.getContext().getContentResolver(),
                 Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE,
-                mBackupManagerService.getUserId());
+                mUserId);
         if (TextUtils.isEmpty(packageListString)) {
             return false;
         }
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 5284d94..d01f77b 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -360,7 +360,6 @@
 
         // If we're starting a full-system restore, set up to begin widget ID remapping
         if (mIsSystemRestore) {
-            // TODO: http://b/22388012
             AppWidgetBackupBridge.restoreStarting(mUserId);
         }
 
@@ -1079,7 +1078,6 @@
         }
 
         // Kick off any work that may be needed regarding app widget restores
-        // TODO: http://b/22388012
         AppWidgetBackupBridge.restoreFinished(mUserId);
 
         // If this was a full-system restore, record the ancestral
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index dc0f602..e4bbcd6 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -32,6 +32,7 @@
 import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.LocalLog;
 import android.util.Slog;
 import android.view.contentcapture.IContentCaptureManager;
 
@@ -69,6 +70,8 @@
 
     private final LocalService mLocalService = new LocalService();
 
+    private final LocalLog mRequestsHistory = new LocalLog(20);
+
     public ContentCaptureManagerService(@NonNull Context context) {
         super(context, new FrameworkResourcesServiceNameResolver(context,
                 com.android.internal.R.string.config_defaultContentCaptureService),
@@ -154,6 +157,13 @@
         }
     }
 
+    /**
+     * Logs a request so it's dumped later...
+     */
+    void logRequestLocked(@NonNull String historyItem) {
+        mRequestsHistory.log(historyItem);
+    }
+
     private ActivityManagerInternal getAmInternal() {
         synchronized (mLock) {
             if (mAm == null) {
@@ -217,9 +227,29 @@
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
 
+            boolean showHistory = true;
+            if (args != null) {
+                for (String arg : args) {
+                    switch(arg) {
+                        case "--no-history":
+                            showHistory = false;
+                            break;
+                        case "--help":
+                            pw.println("Usage: dumpsys content_capture [--no-history]");
+                            return;
+                        default:
+                            Slog.w(TAG, "Ignoring invalid dump arg: " + arg);
+                    }
+                }
+            }
+
             synchronized (mLock) {
                 dumpLocked("", pw);
             }
+            if (showHistory) {
+                pw.println(); pw.println("Requests history:"); pw.println();
+                mRequestsHistory.reverseDump(fd, pw, args);
+            }
         }
 
         @Override
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 09aa421..8d2c79b 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -17,6 +17,9 @@
 package com.android.server.contentcapture;
 
 import static android.service.contentcapture.ContentCaptureService.setClientState;
+import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
+import static android.view.contentcapture.ContentCaptureSession.STATE_DUPLICATED_ID;
+import static android.view.contentcapture.ContentCaptureSession.STATE_NO_SERVICE;
 
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
@@ -36,10 +39,11 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.service.contentcapture.ContentCaptureService;
+import android.service.contentcapture.IContentCaptureServiceCallback;
 import android.service.contentcapture.SnapshotData;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.util.Slog;
-import android.view.contentcapture.ContentCaptureSession;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.IResultReceiver;
@@ -48,6 +52,7 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Per-user instance of {@link ContentCaptureManagerService}.
@@ -72,12 +77,14 @@
     @GuardedBy("mLock")
     private RemoteContentCaptureService mRemoteService;
 
+    private final ContentCaptureServiceRemoteCallback mRemoteServiceCallback =
+            new ContentCaptureServiceRemoteCallback();
+
     // TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's
 
     ContentCapturePerUserService(@NonNull ContentCaptureManagerService master,
             @NonNull Object lock, boolean disabled, @UserIdInt int userId) {
         super(master, lock, userId);
-
         updateRemoteServiceLocked(disabled);
     }
 
@@ -100,10 +107,10 @@
         }
 
         if (!disabled) {
-            mRemoteService = new RemoteContentCaptureService(
-                  mMaster.getContext(),
-                  ContentCaptureService.SERVICE_INTERFACE, serviceComponentName, mUserId, this,
-                  mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
+            mRemoteService = new RemoteContentCaptureService(mMaster.getContext(),
+                    ContentCaptureService.SERVICE_INTERFACE, serviceComponentName,
+                    mRemoteServiceCallback, mUserId, this, mMaster.isBindInstantServiceAllowed(),
+                    mMaster.verbose);
         }
     }
 
@@ -162,14 +169,24 @@
             @NonNull ComponentName componentName, int taskId, int displayId,
             @NonNull String sessionId, int uid, int flags,
             @NonNull IResultReceiver clientReceiver) {
-        if (!isEnabledLocked()) {
+
+        final ComponentName serviceComponentName = getServiceComponentName();
+        final boolean enabled = isEnabledLocked();
+        final String historyItem =
+                "id=" + sessionId + " uid=" + uid
+                + " a=" + ComponentName.flattenToShortString(componentName)
+                + " t=" + taskId + " d=" + displayId
+                + " s=" + ComponentName.flattenToShortString(serviceComponentName)
+                + " u=" + mUserId + " f=" + flags + (enabled ? "" : " (disabled)");
+        mMaster.logRequestLocked(historyItem);
+
+        if (!enabled) {
             // TODO: it would be better to split in differet reasons, like
             // STATE_DISABLED_NO_SERVICE and STATE_DISABLED_BY_DEVICE_POLICY
-            setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED_NO_SERVICE,
+            setClientState(clientReceiver, STATE_DISABLED | STATE_NO_SERVICE,
                     /* binder= */ null);
             return;
         }
-        final ComponentName serviceComponentName = getServiceComponentName();
         if (serviceComponentName == null) {
             // TODO(b/111276913): this happens when the system service is starting, we should
             // probably handle it in a more elegant way (like waiting for boot_complete or
@@ -184,7 +201,7 @@
         if (existingSession != null) {
             Slog.w(TAG, "startSession(id=" + existingSession + ", token=" + activityToken
                     + ": ignoring because it already exists for " + existingSession.mActivityToken);
-            setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED_DUPLICATED_ID,
+            setClientState(clientReceiver, STATE_DISABLED | STATE_DUPLICATED_ID,
                     /* binder=*/ null);
             return;
         }
@@ -197,8 +214,7 @@
             // TODO(b/119613670): log metrics
             Slog.w(TAG, "startSession(id=" + existingSession + ", token=" + activityToken
                     + ": ignoring because service is not set");
-            // TODO(b/111276913): use a new disabled state?
-            setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED_NO_SERVICE,
+            setClientState(clientReceiver, STATE_DISABLED | STATE_NO_SERVICE,
                     /* binder= */ null);
             return;
         }
@@ -338,4 +354,50 @@
         }
         return null;
     }
+
+    private final class ContentCaptureServiceRemoteCallback extends
+            IContentCaptureServiceCallback.Stub {
+
+        @Override
+        public void setContentCaptureWhitelist(List<String> packages,
+                List<ComponentName> activities) {
+            if (mMaster.verbose) {
+                Log.v(TAG, "setContentCaptureWhitelist(packages=" + packages + ", activities="
+                        + activities + ")");
+            }
+            // TODO(b/122595322): implement
+            // TODO(b/119613670): log metrics
+        }
+
+        @Override
+        public void setActivityContentCaptureEnabled(ComponentName activity, boolean enabled) {
+            if (mMaster.verbose) {
+                Log.v(TAG, "setActivityContentCaptureEnabled(activity=" + activity + ", enabled="
+                        + enabled + ")");
+            }
+            // TODO(b/122595322): implement
+            // TODO(b/119613670): log metrics
+        }
+
+        @Override
+        public void setPackageContentCaptureEnabled(String packageName, boolean enabled) {
+            if (mMaster.verbose) {
+                Log.v(TAG,
+                        "setPackageContentCaptureEnabled(packageName=" + packageName + ", enabled="
+                                + enabled + ")");
+            }
+            // TODO(b/122595322): implement
+            // TODO(b/119613670): log metrics
+        }
+
+        @Override
+        public void getContentCaptureDisabledActivities(IResultReceiver receiver) {
+            // TODO(b/122595322): implement
+        }
+
+        @Override
+        public void getContentCaptureDisabledPackages(IResultReceiver receiver) {
+            // TODO(b/122595322): implement
+        }
+    }
 }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index ebe0083..3c52e17 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -83,6 +83,8 @@
      */
     @GuardedBy("mLock")
     public void sendActivitySnapshotLocked(@NonNull SnapshotData snapshotData) {
+        mService.getMaster().logRequestLocked("snapshot: id=" + mId);
+
         mRemoteService.onActivitySnapshotRequest(mId, snapshotData);
     }
 
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index 8241628..12742ca 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.os.IBinder;
 import android.service.contentcapture.IContentCaptureService;
+import android.service.contentcapture.IContentCaptureServiceCallback;
 import android.service.contentcapture.SnapshotData;
 import android.text.format.DateUtils;
 import android.util.Slog;
@@ -35,12 +36,15 @@
 
     private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
 
+    private final IBinder mServerCallback;
+
     RemoteContentCaptureService(Context context, String serviceInterface,
-            ComponentName componentName, int userId,
+            ComponentName serviceComponentName, IContentCaptureServiceCallback callback, int userId,
             ContentCaptureServiceCallbacks callbacks, boolean bindInstantServiceAllowed,
             boolean verbose) {
-        super(context, serviceInterface, componentName, userId, callbacks,
+        super(context, serviceInterface, serviceComponentName, userId, callbacks,
                 bindInstantServiceAllowed, verbose, /* initialCapacity= */ 2);
+        mServerCallback = callback.asBinder();
 
         // Bind right away, which will trigger a onConnected() on service's
         scheduleBind();
@@ -69,7 +73,11 @@
             scheduleUnbind();
         }
         try {
-            mService.onConnectedStateChanged(state);
+            if (state) {
+                mService.onConnected(mServerCallback);
+            } else {
+                mService.onDisconnected();
+            }
         } catch (Exception e) {
             Slog.w(mTag, "Exception calling onConnectedStateChanged(" + state + "): " + e);
         }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d0666b9..d6f3e2b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4879,7 +4879,7 @@
         final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
         final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
                 new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
-                mContext, mTrackerHandler, new NetworkMisc(networkMisc), this);
+                mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mNMS);
         // Make sure the network capabilities reflect what the agent info says.
         nai.networkCapabilities = mixInCapabilities(nai, nc);
         final String extraInfo = networkInfo.getExtraInfo();
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 869d564..0b4c01e 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -257,6 +257,9 @@
         packageManagerInternal.setLocationPackagesProvider(
                 userId -> mContext.getResources().getStringArray(
                         com.android.internal.R.array.config_locationProviderPackageNames));
+        packageManagerInternal.setLocationExtraPackagesProvider(
+                userId -> mContext.getResources().getStringArray(
+                      com.android.internal.R.array.config_locationExtraPackageNames));
 
         // most startup is deferred until systemRunning()
     }
@@ -1041,12 +1044,13 @@
 
         @Override
         public void onSetProperties(ProviderProperties properties) {
-            // move calls coming from below LMS onto a different thread to avoid deadlock
-            runInternal(() -> {
-                synchronized (mLock) {
-                    mProperties = properties;
-                }
-            });
+            // because this does not invoke any other methods which might result in calling back
+            // into the location provider, it is safe to run this on the calling thread. it is also
+            // currently necessary to run this on the calling thread to ensure that property changes
+            // are publicly visibly immediately, ie for mock providers which are created.
+            synchronized (mLock) {
+                mProperties = properties;
+            }
         }
 
         @GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index b0ca2df..aed0684 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -17,13 +17,11 @@
 package com.android.server;
 
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
-import static android.Manifest.permission.DUMP;
 import static android.Manifest.permission.NETWORK_SETTINGS;
 import static android.Manifest.permission.NETWORK_STACK;
 import static android.Manifest.permission.SHUTDOWN;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
@@ -40,6 +38,7 @@
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.TrafficStats.UID_TETHERING;
+
 import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
@@ -53,11 +52,9 @@
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.INetd;
-import android.net.TetherStatsParcel;
 import android.net.INetworkManagementEventObserver;
 import android.net.ITetheringStatsProvider;
 import android.net.InterfaceConfiguration;
@@ -69,18 +66,15 @@
 import android.net.NetworkStats;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
+import android.net.TetherStatsParcel;
 import android.net.UidRange;
-import android.net.UidRangeParcel;
 import android.net.util.NetdService;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.INetworkActivityListener;
 import android.os.INetworkManagementService;
-import android.os.PersistableBundle;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
@@ -91,12 +85,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
-import android.provider.Settings;
 import android.telephony.DataConnectionRealTimeInfo;
-import android.telephony.PhoneStateListener;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -110,13 +99,11 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.HexDump;
 import com.android.internal.util.Preconditions;
-import com.android.server.NativeDaemonConnector.Command;
-import com.android.server.NativeDaemonConnector.SensitiveArg;
+
 import com.google.android.collect.Maps;
 
 import java.io.BufferedReader;
 import java.io.DataInputStream;
-import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -124,15 +111,11 @@
 import java.io.PrintWriter;
 import java.net.InetAddress;
 import java.net.InterfaceAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.StringTokenizer;
 import java.util.concurrent.CountDownLatch;
 
 /**
@@ -2153,28 +2136,6 @@
     }
 
     @Override
-    public void startClatd(String interfaceName) throws IllegalStateException {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
-        try {
-            mNetdService.clatdStart(interfaceName);
-        } catch (RemoteException | ServiceSpecificException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    @Override
-    public void stopClatd(String interfaceName) throws IllegalStateException {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
-        try {
-            mNetdService.clatdStop(interfaceName);
-        } catch (RemoteException | ServiceSpecificException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    @Override
     public void registerNetworkActivityListener(INetworkActivityListener listener) {
         mNetworkActivityListeners.register(listener);
     }
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 93e1dd3..16b12f1 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -7,7 +7,7 @@
                   "include-annotation": "android.platform.test.annotations.Presubmit"
                 },
                 {
-                  "exclude-annotation": "android.support.test.filters.FlakyTest"
+                  "exclude-annotation": "androidx.test.filters.FlakyTest"
                 }
             ]
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 1c04a94..dd2b33a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -70,6 +70,12 @@
     static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
     static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
     static final String KEY_USE_COMPACTION = "use_compaction";
+    static final String KEY_COMPACT_ACTION_1 = "compact_action_1";
+    static final String KEY_COMPACT_ACTION_2 = "compact_action_2";
+    static final String KEY_COMPACT_THROTTLE_1 = "compact_throttle_1";
+    static final String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2";
+    static final String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3";
+    static final String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
     private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -101,6 +107,12 @@
     private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
     private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
     private static final boolean DEFAULT_USE_COMPACTION = false;
+    public static final int DEFAULT_COMPACT_ACTION_1 = 1;
+    public static final int DEFAULT_COMPACT_ACTION_2 = 3;
+    public static final long DEFAULT_COMPACT_THROTTLE_1 = 5000;
+    public static final long DEFAULT_COMPACT_THROTTLE_2 = 10000;
+    public static final long DEFAULT_COMPACT_THROTTLE_3 = 500;
+    public static final long DEFAULT_COMPACT_THROTTLE_4 = 10000;
 
     // Maximum number of cached processes we will allow.
     public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -223,6 +235,20 @@
     // Use compaction for background apps.
     public boolean USE_COMPACTION = DEFAULT_USE_COMPACTION;
 
+    // Action for compactAppSome.
+    public int COMPACT_ACTION_1 = DEFAULT_COMPACT_ACTION_1;
+    // Action for compactAppFull;
+    public int COMPACT_ACTION_2 = DEFAULT_COMPACT_ACTION_2;
+
+    // How long we'll skip second compactAppSome after first compactAppSome
+    public long COMPACT_THROTTLE_1 = DEFAULT_COMPACT_THROTTLE_1;
+    // How long we'll skip compactAppSome after compactAppFull
+    public long COMPACT_THROTTLE_2 = DEFAULT_COMPACT_THROTTLE_2;
+    // How long we'll skip compactAppFull after compactAppSome
+    public long COMPACT_THROTTLE_3 = DEFAULT_COMPACT_THROTTLE_3;
+    // How long we'll skip second compactAppFull after first compactAppFull
+    public long COMPACT_THROTTLE_4 = DEFAULT_COMPACT_THROTTLE_4;
+
     // Indicates whether the activity starts logging is enabled.
     // Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
     volatile boolean mFlagActivityStartsLoggingEnabled;
@@ -381,6 +407,12 @@
             TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION,
                     DEFAULT_TOP_TO_FGS_GRACE_DURATION);
             USE_COMPACTION = mParser.getBoolean(KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION);
+            COMPACT_ACTION_1 = mParser.getInt(KEY_COMPACT_ACTION_1, DEFAULT_COMPACT_ACTION_1);
+            COMPACT_ACTION_2 = mParser.getInt(KEY_COMPACT_ACTION_2, DEFAULT_COMPACT_ACTION_2);
+            COMPACT_THROTTLE_1 = mParser.getLong(KEY_COMPACT_THROTTLE_1, DEFAULT_COMPACT_THROTTLE_1);
+            COMPACT_THROTTLE_2 = mParser.getLong(KEY_COMPACT_THROTTLE_2, DEFAULT_COMPACT_THROTTLE_2);
+            COMPACT_THROTTLE_3 = mParser.getLong(KEY_COMPACT_THROTTLE_3, DEFAULT_COMPACT_THROTTLE_3);
+            COMPACT_THROTTLE_4 = mParser.getLong(KEY_COMPACT_THROTTLE_4, DEFAULT_COMPACT_THROTTLE_4);
 
             updateMaxCachedProcesses();
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3b08a00..089847d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -32,6 +32,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
 import static android.content.pm.PackageManager.GET_PROVIDERS;
+import static android.content.pm.PackageManager.MATCH_ALL;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
 import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -318,7 +319,6 @@
 import com.android.internal.util.function.QuadFunction;
 import com.android.internal.util.function.TriFunction;
 import com.android.server.AlarmManagerInternal;
-import com.android.server.appop.AppOpsService;
 import com.android.server.AttributeCache;
 import com.android.server.DeviceIdleController;
 import com.android.server.DisplayThread;
@@ -337,6 +337,7 @@
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
 import com.android.server.am.MemoryStatUtil.MemoryStat;
+import com.android.server.appop.AppOpsService;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.job.JobSchedulerInternal;
 import com.android.server.pm.Installer;
@@ -658,9 +659,47 @@
 
     /**
      * When an app has restrictions on the other apps that can have associations with it,
-     * it appears here with a set of the allowed apps.
+     * it appears here with a set of the allowed apps and also track debuggability of the app.
      */
-    ArrayMap<String, ArraySet<String>> mAllowedAssociations;
+    ArrayMap<String, PackageAssociationInfo> mAllowedAssociations;
+
+    /**
+     * Tracks association information for a particular package along with debuggability.
+     * <p> Associations for a package A are allowed to package B if B is part of the
+     *     allowed associations for A or if A is debuggable.
+     */
+    private final class PackageAssociationInfo {
+        private final String mSourcePackage;
+        private final ArraySet<String> mAllowedPackageAssociations;
+        private boolean mIsDebuggable;
+
+        PackageAssociationInfo(String sourcePackage, ArraySet<String> allowedPackages,
+                boolean isDebuggable) {
+            mSourcePackage = sourcePackage;
+            mAllowedPackageAssociations = allowedPackages;
+            mIsDebuggable = isDebuggable;
+        }
+
+        /**
+         * Returns true if {@code mSourcePackage} is allowed association with
+         * {@code targetPackage}.
+         */
+        boolean isPackageAssociationAllowed(String targetPackage) {
+            return mIsDebuggable || mAllowedPackageAssociations.contains(targetPackage);
+        }
+
+        boolean isDebuggable() {
+            return mIsDebuggable;
+        }
+
+        void setDebuggable(boolean isDebuggable) {
+            mIsDebuggable = isDebuggable;
+        }
+
+        ArraySet<String> getAllowedPackageAssociations() {
+            return mAllowedPackageAssociations;
+        }
+    }
 
     /**
      * All of the processes we currently have running organized by pid.
@@ -920,8 +959,8 @@
     /**
      * Backup/restore process management
      */
-    String mBackupAppName = null;
-    BackupRecord mBackupTarget = null;
+    @GuardedBy("this")
+    final SparseArray<BackupRecord> mBackupTargets = new SparseArray<>();
 
     final ProviderMap mProviderMap;
 
@@ -2392,12 +2431,10 @@
      * If it does not, give it an empty set.
      */
     void requireAllowedAssociationsLocked(String packageName) {
-        if (mAllowedAssociations == null) {
-            mAllowedAssociations = new ArrayMap<>(
-                    SystemConfig.getInstance().getAllowedAssociations());
-        }
+        ensureAllowedAssociations();
         if (mAllowedAssociations.get(packageName) == null) {
-            mAllowedAssociations.put(packageName, new ArraySet<>());
+            mAllowedAssociations.put(packageName, new PackageAssociationInfo(packageName,
+                    new ArraySet<>(), /* isDebuggable = */ false));
         }
     }
 
@@ -2408,10 +2445,7 @@
      * association is implicitly allowed.
      */
     boolean validateAssociationAllowedLocked(String pkg1, int uid1, String pkg2, int uid2) {
-        if (mAllowedAssociations == null) {
-            mAllowedAssociations = new ArrayMap<>(
-                    SystemConfig.getInstance().getAllowedAssociations());
-        }
+        ensureAllowedAssociations();
         // Interactions with the system uid are always allowed, since that is the core system
         // that everyone needs to be able to interact with. Also allow reflexive associations
         // within the same uid.
@@ -2419,24 +2453,57 @@
                 || UserHandle.getAppId(uid2) == SYSTEM_UID) {
             return true;
         }
-        // We won't allow this association if either pkg1 or pkg2 has a limit on the
-        // associations that are allowed with it, and the other package is not explicitly
-        // specified as one of those associations.
-        ArraySet<String> pkgs = mAllowedAssociations.get(pkg1);
-        if (pkgs != null) {
-            if (!pkgs.contains(pkg2)) {
-                return false;
-            }
+
+        // Check for association on both source and target packages.
+        PackageAssociationInfo pai = mAllowedAssociations.get(pkg1);
+        if (pai != null && !pai.isPackageAssociationAllowed(pkg2)) {
+            return false;
         }
-        pkgs = mAllowedAssociations.get(pkg2);
-        if (pkgs != null) {
-            return pkgs.contains(pkg1);
+        pai = mAllowedAssociations.get(pkg2);
+        if (pai != null && !pai.isPackageAssociationAllowed(pkg1)) {
+            return false;
         }
         // If no explicit associations are provided in the manifest, then assume the app is
         // allowed associations with any package.
         return true;
     }
 
+    /** Sets up allowed associations for system prebuilt packages from system config (if needed). */
+    private void ensureAllowedAssociations() {
+        if (mAllowedAssociations == null) {
+            ArrayMap<String, ArraySet<String>> allowedAssociations =
+                    SystemConfig.getInstance().getAllowedAssociations();
+            mAllowedAssociations = new ArrayMap<>(allowedAssociations.size());
+            PackageManagerInternal pm = getPackageManagerInternalLocked();
+            for (int i = 0; i < allowedAssociations.size(); i++) {
+                final String pkg = allowedAssociations.keyAt(i);
+                final ArraySet<String> asc = allowedAssociations.valueAt(i);
+
+                // Query latest debuggable flag from package-manager.
+                boolean isDebuggable = false;
+                try {
+                    ApplicationInfo ai = AppGlobals.getPackageManager()
+                            .getApplicationInfo(pkg, MATCH_ALL, 0);
+                    if (ai != null) {
+                        isDebuggable = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+                    }
+                } catch (RemoteException e) {
+                    /* ignore */
+                }
+                mAllowedAssociations.put(pkg, new PackageAssociationInfo(pkg, asc, isDebuggable));
+            }
+        }
+    }
+
+    /** Updates allowed associations for app info (specifically, based on debuggability).  */
+    private void updateAssociationForApp(ApplicationInfo appInfo) {
+        ensureAllowedAssociations();
+        PackageAssociationInfo pai = mAllowedAssociations.get(appInfo.packageName);
+        if (pai != null) {
+            pai.setDebuggable((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
+        }
+    }
+
     @Override
     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
             throws RemoteException {
@@ -4365,6 +4432,7 @@
         mProcessList.removeProcessLocked(app, false, true, "timeout publishing content providers");
     }
 
+    @GuardedBy("this")
     private final void processStartTimedOutLocked(ProcessRecord app) {
         final int pid = app.pid;
         boolean gone = mPidsSelfLocked.removeIfNoThread(pid);
@@ -4385,7 +4453,8 @@
                 mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
             }
             removeLruProcessLocked(app);
-            if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
+            final BackupRecord backupTarget = mBackupTargets.get(app.userId);
+            if (backupTarget != null && backupTarget.app.pid == pid) {
                 Slog.w(TAG, "Unattached app died before backup, skipping");
                 mHandler.post(new Runnable() {
                 @Override
@@ -4393,7 +4462,7 @@
                         try {
                             IBackupManager bm = IBackupManager.Stub.asInterface(
                                     ServiceManager.getService(Context.BACKUP_SERVICE));
-                            bm.agentDisconnected(app.info.packageName);
+                            bm.agentDisconnectedForUser(app.userId, app.info.packageName);
                         } catch (RemoteException e) {
                             // Can't happen; the backup manager is local
                         }
@@ -4516,6 +4585,7 @@
         if (DEBUG_ALL) Slog.v(
             TAG, "New app record " + app
             + " thread=" + thread.asBinder() + " pid=" + pid);
+        final BackupRecord backupTarget = mBackupTargets.get(app.userId);
         try {
             int testMode = ApplicationThreadConstants.DEBUG_OFF;
             if (mDebugApp != null && mDebugApp.equals(processName)) {
@@ -4537,11 +4607,11 @@
 
             // If the app is being launched for restore or full backup, set it up specially
             boolean isRestrictedBackupMode = false;
-            if (mBackupTarget != null && mBackupAppName.equals(processName)) {
-                isRestrictedBackupMode = mBackupTarget.appInfo.uid >= FIRST_APPLICATION_UID
-                        && ((mBackupTarget.backupMode == BackupRecord.RESTORE)
-                                || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
-                                || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
+            if (backupTarget != null && backupTarget.appInfo.packageName.equals(processName)) {
+                isRestrictedBackupMode = backupTarget.appInfo.uid >= FIRST_APPLICATION_UID
+                        && ((backupTarget.backupMode == BackupRecord.RESTORE)
+                                || (backupTarget.backupMode == BackupRecord.RESTORE_FULL)
+                                || (backupTarget.backupMode == BackupRecord.BACKUP_FULL));
             }
 
             final ActiveInstrumentation instr = app.getActiveInstrumentation();
@@ -4749,15 +4819,15 @@
         }
 
         // Check whether the next backup agent is in this process...
-        if (!badApp && mBackupTarget != null && mBackupTarget.app == app) {
+        if (!badApp && backupTarget != null && backupTarget.app == app) {
             if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
                     "New app is backup target, launching agent for " + app);
-            notifyPackageUse(mBackupTarget.appInfo.packageName,
+            notifyPackageUse(backupTarget.appInfo.packageName,
                              PackageManager.NOTIFY_PACKAGE_USE_BACKUP);
             try {
-                thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
-                        compatibilityInfoForPackage(mBackupTarget.appInfo),
-                        mBackupTarget.backupMode);
+                thread.scheduleCreateBackupAgent(backupTarget.appInfo,
+                        compatibilityInfoForPackage(backupTarget.appInfo),
+                        backupTarget.backupMode);
             } catch (Exception e) {
                 Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e);
                 badApp = true;
@@ -10625,7 +10695,6 @@
             ProtoUtils.toDuration(proto, ActivityManagerServiceDumpProcessesProto.LAST_IDLE_TIME, mLastIdleTime, now);
             proto.write(ActivityManagerServiceDumpProcessesProto.LOW_RAM_SINCE_LAST_IDLE_MS, getLowRamTimeSinceIdle(now));
         }
-
     }
 
     void writeProcessesToGcToProto(ProtoOutputStream proto, long fieldId, String dumpPackage) {
@@ -10907,14 +10976,14 @@
     void dumpAllowedAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage) {
         boolean needSep = false;
-        boolean printedAnything = false;
 
         pw.println("ACTIVITY MANAGER ALLOWED ASSOCIATION STATE (dumpsys activity allowed-associations)");
         boolean printed = false;
         if (mAllowedAssociations != null) {
             for (int i = 0; i < mAllowedAssociations.size(); i++) {
                 final String pkg = mAllowedAssociations.keyAt(i);
-                final ArraySet<String> asc = mAllowedAssociations.valueAt(i);
+                final ArraySet<String> asc =
+                        mAllowedAssociations.valueAt(i).getAllowedPackageAssociations();
                 boolean printedHeader = false;
                 for (int j = 0; j < asc.size(); j++) {
                     if (dumpPackage == null || pkg.equals(dumpPackage)
@@ -10923,7 +10992,6 @@
                             pw.println("  Allowed associations (by restricted package):");
                             printed = true;
                             needSep = true;
-                            printedAnything = true;
                         }
                         if (!printedHeader) {
                             pw.print("  * ");
@@ -10935,6 +11003,9 @@
                         pw.println(asc.valueAt(j));
                     }
                 }
+                if (mAllowedAssociations.valueAt(i).isDebuggable()) {
+                    pw.println("      (debuggable)");
+                }
             }
         }
         if (!printed) {
@@ -13224,16 +13295,17 @@
         app.receivers.clear();
 
         // If the app is undergoing backup, tell the backup manager about it
-        if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
+        final BackupRecord backupTarget = mBackupTargets.get(app.userId);
+        if (backupTarget != null && app.pid == backupTarget.app.pid) {
             if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App "
-                    + mBackupTarget.appInfo + " died during backup");
+                    + backupTarget.appInfo + " died during backup");
             mHandler.post(new Runnable() {
                 @Override
                 public void run(){
                     try {
                         IBackupManager bm = IBackupManager.Stub.asInterface(
                                 ServiceManager.getService(Context.BACKUP_SERVICE));
-                        bm.agentDisconnected(app.info.packageName);
+                        bm.agentDisconnectedForUser(app.userId, app.info.packageName);
                     } catch (RemoteException e) {
                         // can't happen; backup manager is local
                     }
@@ -13573,7 +13645,11 @@
     // instantiated.  The backup agent will invoke backupAgentCreated() on the
     // activity manager to announce its creation.
     public boolean bindBackupAgent(String packageName, int backupMode, int userId) {
-        if (DEBUG_BACKUP) Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode);
+        if (DEBUG_BACKUP) {
+            Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode="
+                    + backupMode + " userId=" + userId + " callingUid = " + Binder.getCallingUid()
+                    + " uid = " + Process.myUid());
+        }
         enforceCallingPermission("android.permission.CONFIRM_FULL_BACKUP", "bindBackupAgent");
 
         IPackageManager pm = AppGlobals.getPackageManager();
@@ -13625,10 +13701,10 @@
                 proc.inFullBackup = true;
             }
             r.app = proc;
-            oldBackupUid = mBackupTarget != null ? mBackupTarget.appInfo.uid : -1;
+            final BackupRecord backupTarget = mBackupTargets.get(userId);
+            oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1;
             newBackupUid = proc.inFullBackup ? r.appInfo.uid : -1;
-            mBackupTarget = r;
-            mBackupAppName = app.packageName;
+            mBackupTargets.put(userId, r);
 
             // Try not to kill the process during backup
             updateOomAdjLocked(proc, true);
@@ -13663,14 +13739,14 @@
         return true;
     }
 
-    @Override
-    public void clearPendingBackup() {
-        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "clearPendingBackup");
-        enforceCallingPermission("android.permission.BACKUP", "clearPendingBackup");
+    private void clearPendingBackup(int userId) {
+        if (DEBUG_BACKUP) {
+            Slog.v(TAG_BACKUP, "clearPendingBackup: userId = " + userId + " callingUid = "
+                    + Binder.getCallingUid() + " uid = " + Process.myUid());
+        }
 
         synchronized (this) {
-            mBackupTarget = null;
-            mBackupAppName = null;
+            mBackupTargets.delete(userId);
         }
 
         JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
@@ -13678,12 +13754,19 @@
     }
 
     // A backup agent has just come up
+    @Override
     public void backupAgentCreated(String agentPackageName, IBinder agent) {
-        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName
-                + " = " + agent);
+        final int callingUserId = UserHandle.getCallingUserId();
+        if (DEBUG_BACKUP) {
+            Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName + " = " + agent
+                    + " callingUserId = " + callingUserId + " callingUid = "
+                    + Binder.getCallingUid() + " uid = " + Process.myUid());
+        }
 
         synchronized(this) {
-            if (!agentPackageName.equals(mBackupAppName)) {
+            final BackupRecord backupTarget = mBackupTargets.get(callingUserId);
+            String backupAppName = backupTarget == null ? null : backupTarget.appInfo.packageName;
+            if (!agentPackageName.equals(backupAppName)) {
                 Slog.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
                 return;
             }
@@ -13693,7 +13776,7 @@
         try {
             IBackupManager bm = IBackupManager.Stub.asInterface(
                     ServiceManager.getService(Context.BACKUP_SERVICE));
-            bm.agentConnected(agentPackageName, agent);
+            bm.agentConnectedForUser(callingUserId, agentPackageName, agent);
         } catch (RemoteException e) {
             // can't happen; the backup manager service is local
         } catch (Exception e) {
@@ -13706,7 +13789,12 @@
 
     // done with this agent
     public void unbindBackupAgent(ApplicationInfo appInfo) {
-        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "unbindBackupAgent: " + appInfo);
+        if (DEBUG_BACKUP) {
+            Slog.v(TAG_BACKUP, "unbindBackupAgent: " + appInfo + " appInfo.uid = "
+                    + appInfo.uid + " callingUid = " + Binder.getCallingUid() + " uid = "
+                    + Process.myUid());
+        }
+
         enforceCallingPermission("android.permission.CONFIRM_FULL_BACKUP", "unbindBackupAgent");
         if (appInfo == null) {
             Slog.w(TAG, "unbind backup agent for null app");
@@ -13715,24 +13803,27 @@
 
         int oldBackupUid;
 
+        final int userId = UserHandle.getUserId(appInfo.uid);
         synchronized(this) {
+            final BackupRecord backupTarget = mBackupTargets.get(userId);
+            String backupAppName = backupTarget == null ? null : backupTarget.appInfo.packageName;
             try {
-                if (mBackupAppName == null) {
+                if (backupAppName == null) {
                     Slog.w(TAG, "Unbinding backup agent with no active backup");
                     return;
                 }
 
-                if (!mBackupAppName.equals(appInfo.packageName)) {
+                if (!backupAppName.equals(appInfo.packageName)) {
                     Slog.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
                     return;
                 }
 
                 // Not backing this app up any more; reset its OOM adjustment
-                final ProcessRecord proc = mBackupTarget.app;
+                final ProcessRecord proc = backupTarget.app;
                 updateOomAdjLocked(proc, true);
                 proc.inFullBackup = false;
 
-                oldBackupUid = mBackupTarget != null ? mBackupTarget.appInfo.uid : -1;
+                oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1;
 
                 // If the app crashed during backup, 'thread' will be null here
                 if (proc.thread != null) {
@@ -13745,8 +13836,7 @@
                     }
                 }
             } finally {
-                mBackupTarget = null;
-                mBackupAppName = null;
+                mBackupTargets.delete(userId);
             }
         }
 
@@ -14497,6 +14587,7 @@
                                     + " ssp=" + ssp + " data=" + data);
                             return ActivityManager.BROADCAST_SUCCESS;
                         }
+                        updateAssociationForApp(aInfo);
                         mAtmInternal.onPackageReplaced(aInfo);
                         mServices.updateServiceApplicationInfoLocked(aInfo);
                         sendPackageBroadcastLocked(ApplicationThreadConstants.PACKAGE_REPLACED,
@@ -17771,6 +17862,20 @@
         public boolean isAppForeground(int uid) {
             return ActivityManagerService.this.isAppForeground(uid);
         }
+
+        @Override
+        public void clearPendingBackup(int userId) {
+            ActivityManagerService.this.clearPendingBackup(userId);
+        }
+
+        /**
+         * When power button is very long pressed, call this interface to do some pre-shutdown work
+         * like persisting database etc.
+         */
+        @Override
+        public void prepareForPossibleShutdown() {
+            ActivityManagerService.this.prepareForPossibleShutdown();
+        }
     }
 
     long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
@@ -18027,6 +18132,18 @@
         }
     }
 
+    /**
+     * When power button is very long pressed, call this interface to do some pre-shutdown work
+     * like persisting database etc.
+     */
+    public void prepareForPossibleShutdown() {
+        synchronized (this) {
+            if (mUsageStatsService != null) {
+                mUsageStatsService.prepareForPossibleShutdown();
+            }
+        }
+    }
+
     @VisibleForTesting
     public static class Injector {
         private NetworkManagementInternal mNmi;
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index aee16c3..fe27c49 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -44,7 +44,11 @@
      */
     final ArrayList<ProcessRecord> mPendingCompactionProcesses = new ArrayList<ProcessRecord>();
 
-    /*
+    static final int COMPACT_PROCESS_SOME = 1;
+    static final int COMPACT_PROCESS_FULL = 2;
+    static final int COMPACT_PROCESS_MSG = 1;
+
+    /**
      * This thread must be moved to the system background cpuset.
      * If that doesn't happen, it's probably going to draw a lot of power.
      * However, this has to happen after the first updateOomAdjLocked, because
@@ -53,13 +57,22 @@
      */
     final ServiceThread mCompactionThread;
 
-    static final int COMPACT_PROCESS_SOME = 1;
-    static final int COMPACT_PROCESS_FULL = 2;
-    static final int COMPACT_PROCESS_MSG = 1;
-    final Handler mCompactionHandler;
+    final private Handler mCompactionHandler;
 
-    final ActivityManagerService mAm;
-    final ActivityManagerConstants mConstants;
+    final private ActivityManagerService mAm;
+    final private ActivityManagerConstants mConstants;
+
+    final private String COMPACT_ACTION_FILE = "file";
+    final private String COMPACT_ACTION_ANON = "anon";
+    final private String COMPACT_ACTION_FULL = "full";
+
+    final private String compactActionSome;
+    final private String compactActionFull;
+
+    final private long throttleSomeSome;
+    final private long throttleSomeFull;
+    final private long throttleFullSome;
+    final private long throttleFullFull;
 
     public AppCompactor(ActivityManagerService am) {
         mAm = am;
@@ -69,6 +82,41 @@
                 THREAD_PRIORITY_FOREGROUND, true);
         mCompactionThread.start();
         mCompactionHandler = new MemCompactionHandler(this);
+
+        switch(mConstants.COMPACT_ACTION_1) {
+            case 1:
+                compactActionSome = COMPACT_ACTION_FILE;
+                break;
+            case 2:
+                compactActionSome = COMPACT_ACTION_ANON;
+                break;
+            case 3:
+                compactActionSome = COMPACT_ACTION_FULL;
+                break;
+            default:
+                compactActionSome = COMPACT_ACTION_FILE;
+                break;
+        }
+
+        switch(mConstants.COMPACT_ACTION_2) {
+            case 1:
+                compactActionFull = COMPACT_ACTION_FILE;
+                break;
+            case 2:
+                compactActionFull = COMPACT_ACTION_ANON;
+                break;
+            case 3:
+                compactActionFull = COMPACT_ACTION_FULL;
+                break;
+            default:
+                compactActionFull = COMPACT_ACTION_FULL;
+                break;
+        }
+
+        throttleSomeSome = mConstants.COMPACT_THROTTLE_1;
+        throttleSomeFull = mConstants.COMPACT_THROTTLE_2;
+        throttleFullSome = mConstants.COMPACT_THROTTLE_3;
+        throttleFullFull = mConstants.COMPACT_THROTTLE_4;
     }
 
     // Must be called while holding AMS lock.
@@ -128,18 +176,16 @@
                 }
 
                 // basic throttling
+                // use the ActivityManagerConstants knobs to determine whether current/prevous
+                // compaction combo should be throtted or not
                 if (pendingAction == COMPACT_PROCESS_SOME) {
-                    // if we're compacting some, then compact if >10s after last full
-                    // or >5s after last some
-                    if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < 5000)) ||
-                        (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < 10000))) {
+                    if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < throttleSomeSome)) ||
+                        (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < throttleSomeFull))) {
                         return;
                     }
                 } else {
-                    // if we're compacting full, then compact if >10s after last full
-                    // or >.5s after last some
-                    if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < 500)) ||
-                        (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < 10000))) {
+                    if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < throttleFullSome)) ||
+                        (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < throttleFullFull))) {
                         return;
                     }
                 }
@@ -151,9 +197,9 @@
                     long[] rssBefore = Process.getRss(pid);
                     FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim");
                     if (pendingAction == COMPACT_PROCESS_SOME) {
-                        action = "file";
+                        action = compactActionSome;
                     } else {
-                        action = "all";
+                        action = compactActionFull;
                     }
                     fos.write(action.getBytes());
                     fos.close();
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index d7cb2bd..d3953b5 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -67,9 +67,10 @@
         sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS_GLES, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYER_APP, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, int.class);
+        sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_ALL_APPS, int.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_OPT_IN_APPS, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_OPT_OUT_APPS, String.class);
-        sGlobalSettingToTypeMap.put(Settings.Global.GUP_BLACK_LIST, String.class);
+        sGlobalSettingToTypeMap.put(Settings.Global.GUP_BLACKLIST, String.class);
         // add other global settings here...
     }
 
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index cb4cac9..1f9362e 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1024,7 +1024,8 @@
         app.hasStartedServices = false;
         app.adjSeq = mAdjSeq;
 
-        if (mService.mBackupTarget != null && app == mService.mBackupTarget.app) {
+        final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId);
+        if (backupTarget != null && app == backupTarget.app) {
             // If possible we want to avoid killing apps while they're being backed up
             if (adj > ProcessList.BACKUP_APP_ADJ) {
                 if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 8d7811f..714a807 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -1454,8 +1454,8 @@
                 if (accessCount > 0) {
                     if (!printedUidState) {
                         mWriter.print(mUidStatePrefix);
-                        mWriter.print(AppOpsManager.uidStateToString(uidState));
-                        mWriter.print("[");
+                        mWriter.print(AppOpsService.UID_STATE_NAMES[uidState]);
+                        mWriter.print(" = ");
                         printedUidState = true;
                     }
                     mWriter.print("access=");
@@ -1465,11 +1465,11 @@
                 if (rejectCount > 0) {
                     if (!printedUidState) {
                         mWriter.print(mUidStatePrefix);
-                        mWriter.print(AppOpsManager.uidStateToString(uidState));
-                        mWriter.print("[");
+                        mWriter.print(AppOpsService.UID_STATE_NAMES[uidState]);
+                        mWriter.print(" = ");
                         printedUidState = true;
                     } else {
-                        mWriter.print(",");
+                        mWriter.print(", ");
                     }
                     mWriter.print("reject=");
                     mWriter.print(rejectCount);
@@ -1478,16 +1478,17 @@
                 if (accessDuration > 0) {
                     if (!printedUidState) {
                         mWriter.print(mUidStatePrefix);
-                        mWriter.print(AppOpsManager.uidStateToString(uidState));
+                        mWriter.print(AppOpsService.UID_STATE_NAMES[uidState]);
+                        mWriter.print(" = ");
                         printedUidState = true;
                     } else {
-                        mWriter.print(",");
+                        mWriter.print(", ");
                     }
                     mWriter.print("duration=");
-                    mWriter.print(accessDuration);
+                    TimeUtils.formatDuration(accessDuration, mWriter);
                 }
                 if (printedUidState) {
-                    mWriter.println("]");
+                    mWriter.println("");
                 }
             }
         }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d704a3e..9a4ca1f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -7824,8 +7824,10 @@
 
     /** see AudioPolicy.setUidDeviceAffinity() */
     public int setUidDeviceAffinity(IAudioPolicyCallback pcb, int uid,
-            @NonNull int[] deviceTypes,
-            @NonNull String[] deviceAddresses) {
+            @NonNull int[] deviceTypes, @NonNull String[] deviceAddresses) {
+        if (DEBUG_AP) {
+            Log.d(TAG, "setUidDeviceAffinity for " + pcb.asBinder() + " uid:" + uid);
+        }
         synchronized (mAudioPolicies) {
             final AudioPolicyProxy app =
                     checkUpdateForPolicy(pcb, "Cannot change device affinity in audio policy");
@@ -7835,21 +7837,23 @@
             if (!app.hasMixRoutedToDevices(deviceTypes, deviceAddresses)) {
                 return AudioManager.ERROR;
             }
+            return app.setUidDeviceAffinities(uid, deviceTypes, deviceAddresses);
         }
-        return AudioManager.SUCCESS;
     }
 
     /** see AudioPolicy.removeUidDeviceAffinity() */
     public int removeUidDeviceAffinity(IAudioPolicyCallback pcb, int uid) {
+        if (DEBUG_AP) {
+            Log.d(TAG, "removeUidDeviceAffinity for " + pcb.asBinder() + " uid:" + uid);
+        }
         synchronized (mAudioPolicies) {
             final AudioPolicyProxy app =
                     checkUpdateForPolicy(pcb, "Cannot remove device affinity in audio policy");
             if (app == null) {
                 return AudioManager.ERROR;
             }
-
+            return app.removeUidDeviceAffinities(uid);
         }
-        return AudioManager.SUCCESS;
     }
 
     public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
@@ -8160,27 +8164,41 @@
             Binder.restoreCallingIdentity(identity);
         }
 
-        void setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
+        int setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
             final Integer Uid = new Integer(uid);
+            int res;
             if (mUidDeviceAffinities.remove(Uid) != null) {
                 final long identity = Binder.clearCallingIdentity();
-                AudioSystem.removeUidDeviceAffinities(uid);
+                res = AudioSystem.removeUidDeviceAffinities(uid);
                 Binder.restoreCallingIdentity(identity);
+                if (res != AudioSystem.SUCCESS) {
+                    Log.e(TAG, "AudioSystem. removeUidDeviceAffinities(" + uid + ") failed, "
+                            + " cannot call AudioSystem.setUidDeviceAffinities");
+                    return AudioManager.ERROR;
+                }
             }
             final long identity = Binder.clearCallingIdentity();
-            final int res = AudioSystem.setUidDeviceAffinities(uid, types, addresses);
+            res = AudioSystem.setUidDeviceAffinities(uid, types, addresses);
             Binder.restoreCallingIdentity(identity);
             if (res == AudioSystem.SUCCESS) {
                 mUidDeviceAffinities.put(Uid, new AudioDeviceArray(types, addresses));
+                return AudioManager.SUCCESS;
             }
+            Log.e(TAG, "AudioSystem. setUidDeviceAffinities(" + uid + ") failed");
+            return AudioManager.ERROR;
         }
 
-        void removeUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
+        int removeUidDeviceAffinities(int uid) {
             if (mUidDeviceAffinities.remove(new Integer(uid)) != null) {
                 final long identity = Binder.clearCallingIdentity();
-                AudioSystem.removeUidDeviceAffinities(uid);
+                final int res = AudioSystem.removeUidDeviceAffinities(uid);
                 Binder.restoreCallingIdentity(identity);
+                if (res == AudioSystem.SUCCESS) {
+                    return AudioManager.SUCCESS;
+                }
             }
+            Log.e(TAG, "AudioSystem. removeUidDeviceAffinities failed");
+            return AudioManager.ERROR;
         }
     };
 
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index ecc3d2d..174ecfa 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -116,6 +116,7 @@
     protected HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
     // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
     protected HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
+    protected int mHALDeathCount;
 
     protected class PerformanceStats {
         public int accept; // number of accepted biometrics
@@ -596,6 +597,7 @@
     public void serviceDied(long cookie) {
         Slog.e(getTag(), "HAL died");
         mMetricsLogger.count(getMetrics().tagHalDied(), 1);
+        mHALDeathCount++;
         handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
                 0 /*vendorCode */);
     }
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 5a9c1ac..a2aacdd 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -675,6 +675,12 @@
     }
 
     @Override
+    public void serviceDied(long cookie) {
+        super.serviceDied(cookie);
+        mDaemon = null;
+    }
+
+    @Override
     protected void updateActiveGroup(int userId, String clientPackage) {
         IBiometricsFace daemon = getFaceDaemon();
 
@@ -864,6 +870,8 @@
             Slog.e(TAG, "dump formatting failure", e);
         }
         pw.println(dump);
+        pw.println("HAL Deaths: " + mHALDeathCount);
+        mHALDeathCount = 0;
     }
 
     private void dumpProto(FileDescriptor fd) {
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 1613dc9..3db6a74 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -777,6 +777,12 @@
     }
 
     @Override
+    public void serviceDied(long cookie) {
+        super.serviceDied(cookie);
+        mDaemon = null;
+    }
+
+    @Override
     protected void updateActiveGroup(int userId, String clientPackage) {
         IBiometricsFingerprint daemon = getFingerprintDaemon();
 
@@ -1074,6 +1080,8 @@
             Slog.e(TAG, "dump formatting failure", e);
         }
         pw.println(dump);
+        pw.println("HAL Deaths: " + mHALDeathCount);
+        mHALDeathCount = 0;
     }
 
     private void dumpProto(FileDescriptor fd) {
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 6596d27..9d9b1cf 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -16,8 +16,9 @@
 
 package com.android.server.connectivity;
 
-import android.net.InterfaceConfiguration;
 import android.net.ConnectivityManager;
+import android.net.INetd;
+import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
@@ -59,6 +60,7 @@
         NetworkInfo.State.SUSPENDED,
     };
 
+    private final INetd mNetd;
     private final INetworkManagementService mNMService;
 
     // The network we're running on, and its type.
@@ -76,7 +78,8 @@
     private String mIface;
     private State mState = State.IDLE;
 
-    public Nat464Xlat(INetworkManagementService nmService, NetworkAgentInfo nai) {
+    public Nat464Xlat(NetworkAgentInfo nai, INetd netd, INetworkManagementService nmService) {
+        mNetd = netd;
         mNMService = nmService;
         mNetwork = nai;
     }
@@ -140,7 +143,7 @@
             return;
         }
         try {
-            mNMService.startClatd(baseIface);
+            mNetd.clatdStart(baseIface);
         } catch(RemoteException|IllegalStateException e) {
             Slog.e(TAG, "Error starting clatd on " + baseIface, e);
         }
@@ -162,7 +165,7 @@
      */
     private void enterStoppingState() {
         try {
-            mNMService.stopClatd(mBaseIface);
+            mNetd.clatdStop(mBaseIface);
         } catch(RemoteException|IllegalStateException e) {
             Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e);
         }
@@ -204,7 +207,7 @@
             Slog.e(TAG, "startClat: Can't start clat on null interface");
             return;
         }
-        // TODO: should we only do this if mNMService.startClatd() succeeds?
+        // TODO: should we only do this if mNetd.clatdStart() succeeds?
         Slog.i(TAG, "Starting clatd on " + baseIface);
         enterStartingState(baseIface);
     }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 54c89aa..9ea73fb 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -17,6 +17,7 @@
 package com.android.server.connectivity;
 
 import android.content.Context;
+import android.net.INetd;
 import android.net.INetworkMonitor;
 import android.net.LinkProperties;
 import android.net.Network;
@@ -239,12 +240,15 @@
     private static final String TAG = ConnectivityService.class.getSimpleName();
     private static final boolean VDBG = false;
     private final ConnectivityService mConnService;
+    private final INetd mNetd;
+    private final INetworkManagementService mNMS;
     private final Context mContext;
     private final Handler mHandler;
 
     public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
             LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
-            NetworkMisc misc, ConnectivityService connService) {
+            NetworkMisc misc, ConnectivityService connService, INetd netd,
+            INetworkManagementService nms) {
         this.messenger = messenger;
         asyncChannel = ac;
         network = net;
@@ -253,6 +257,8 @@
         networkCapabilities = nc;
         currentScore = score;
         mConnService = connService;
+        mNetd = netd;
+        mNMS = nms;
         mContext = context;
         mHandler = handler;
         networkMisc = misc;
@@ -587,18 +593,18 @@
 
     public void updateClat(INetworkManagementService netd) {
         if (Nat464Xlat.requiresClat(this)) {
-            maybeStartClat(netd);
+            maybeStartClat();
         } else {
             maybeStopClat();
         }
     }
 
     /** Ensure clat has started for this network. */
-    public void maybeStartClat(INetworkManagementService netd) {
+    public void maybeStartClat() {
         if (clatd != null && clatd.isStarted()) {
             return;
         }
-        clatd = new Nat464Xlat(netd, this);
+        clatd = new Nat464Xlat(this, mNetd, mNMS);
         clatd.start();
     }
 
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 3ea9810..9789688 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -282,6 +282,7 @@
     private void setCurrentProxyScript(String script) {
         if (mProxyService == null) {
             Log.e(TAG, "setCurrentProxyScript: no proxy service");
+            return;
         }
         try {
             mProxyService.setPacFile(script);
diff --git a/services/core/java/com/android/server/content/SyncJobService.java b/services/core/java/com/android/server/content/SyncJobService.java
index bfcc629..aaf9cbc 100644
--- a/services/core/java/com/android/server/content/SyncJobService.java
+++ b/services/core/java/com/android/server/content/SyncJobService.java
@@ -141,10 +141,7 @@
             final long runtime = nowUptime - startUptime;
 
 
-            if (startUptime == 0) {
-                wtf("Job " + jobId + " start uptime not found: "
-                        + " params=" + jobParametersToString(params));
-            } else if (runtime > 60 * 1000) {
+            if (runtime > 60 * 1000) {
                 // WTF if startSyncH() hasn't happened, *unless* onStopJob() was called too soon.
                 // (1 minute threshold.)
                 // Also don't wtf when it's not ready to sync.
diff --git a/services/core/java/com/android/server/content/SyncLogger.java b/services/core/java/com/android/server/content/SyncLogger.java
index 5cbe5b9..fc20ef20 100644
--- a/services/core/java/com/android/server/content/SyncLogger.java
+++ b/services/core/java/com/android/server/content/SyncLogger.java
@@ -16,6 +16,7 @@
 
 package com.android.server.content;
 
+import android.accounts.Account;
 import android.app.job.JobParameters;
 import android.os.Build;
 import android.os.Environment;
@@ -31,6 +32,8 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IntPair;
 import com.android.server.IoThread;
+import com.android.server.content.SyncManager.ActiveSyncContext;
+import com.android.server.content.SyncStorageEngine.EndPoint;
 
 import libcore.io.IoUtils;
 
@@ -309,4 +312,20 @@
             }
         }
     }
+
+    static String logSafe(Account account) {
+        return account == null ? "[null]" : account.toSafeString();
+    }
+
+    static String logSafe(EndPoint endPoint) {
+        return endPoint == null ? "[null]" : endPoint.toSafeString();
+    }
+
+    static String logSafe(SyncOperation operation) {
+        return operation == null ? "[null]" : operation.toSafeString();
+    }
+
+    static String logSafe(ActiveSyncContext asc) {
+        return asc == null ? "[null]" : asc.toSafeString();
+    }
 }
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 8b93e04..7096477 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -16,6 +16,8 @@
 
 package com.android.server.content;
 
+import static com.android.server.content.SyncLogger.logSafe;
+
 import android.accounts.Account;
 import android.accounts.AccountAndUser;
 import android.accounts.AccountManager;
@@ -1140,7 +1142,7 @@
             /* ignore - local call */
         }
         if (checkAccountAccess && !canAccessAccount(account, owningPackage, owningUid)) {
-            Log.w(TAG, "Access to " + account + " denied for package "
+            Log.w(TAG, "Access to " + logSafe(account) + " denied for package "
                     + owningPackage + " in UID " + syncAdapterInfo.uid);
             return AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS;
         }
@@ -1474,7 +1476,8 @@
         if (!syncOperation.ignoreBackoff()) {
             Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(syncOperation.target);
             if (backoff == null) {
-                Slog.e(TAG, "Couldn't find backoff values for " + syncOperation.target);
+                Slog.e(TAG, "Couldn't find backoff values for "
+                        + logSafe(syncOperation.target));
                 backoff = new Pair<Long, Long>(SyncStorageEngine.NOT_IN_BACKOFF_MODE,
                         SyncStorageEngine.NOT_IN_BACKOFF_MODE);
             }
@@ -1745,8 +1748,8 @@
             scheduleSyncOperationH(operation);
         } else {
             // Otherwise do not reschedule.
-            Log.d(TAG, "not retrying sync operation because the error is a hard error: "
-                    + operation);
+            Log.e(TAG, "not retrying sync operation because the error is a hard error: "
+                    + logSafe(operation));
         }
     }
 
@@ -1881,11 +1884,12 @@
             sendSyncFinishedOrCanceledMessage(this, result);
         }
 
-        public void toString(StringBuilder sb) {
+        public void toString(StringBuilder sb, boolean logSafe) {
             sb.append("startTime ").append(mStartTime)
                     .append(", mTimeoutStartTime ").append(mTimeoutStartTime)
                     .append(", mHistoryRowId ").append(mHistoryRowId)
-                    .append(", syncOperation ").append(mSyncOperation);
+                    .append(", syncOperation ").append(
+                        logSafe ? logSafe(mSyncOperation) : mSyncOperation);
         }
 
         public void onServiceConnected(ComponentName name, IBinder service) {
@@ -1947,7 +1951,13 @@
 
         public String toString() {
             StringBuilder sb = new StringBuilder();
-            toString(sb);
+            toString(sb, false);
+            return sb.toString();
+        }
+
+        public String toSafeString() {
+            StringBuilder sb = new StringBuilder();
+            toString(sb, true);
             return sb.toString();
         }
 
@@ -2036,7 +2046,7 @@
         int count = 0;
         for (SyncOperation op: pendingSyncs) {
             if (!op.isPeriodic) {
-                pw.println(op.dump(null, false, buckets));
+                pw.println(op.dump(null, false, buckets, /*logSafe=*/ false));
                 count++;
             }
         }
@@ -2053,7 +2063,7 @@
         int count = 0;
         for (SyncOperation op: pendingSyncs) {
             if (op.isPeriodic) {
-                pw.println(op.dump(null, false, buckets));
+                pw.println(op.dump(null, false, buckets, /*logSafe=*/ false));
                 count++;
             }
         }
@@ -2186,7 +2196,7 @@
             sb.setLength(0);
             pw.print(formatDurationHMS(sb, durationInSeconds));
             pw.print(" - ");
-            pw.print(activeSyncContext.mSyncOperation.dump(pm, false, buckets));
+            pw.print(activeSyncContext.mSyncOperation.dump(pm, false, buckets, /*logSafe=*/ false));
             pw.println();
         }
         pw.println();
@@ -2974,7 +2984,7 @@
                     case SyncHandler.MESSAGE_CANCEL:
                         SyncStorageEngine.EndPoint endpoint = (SyncStorageEngine.EndPoint) msg.obj;
                         Bundle extras = msg.peekData();
-                        if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        if (isLoggable) {
                             Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_CANCEL: "
                                     + endpoint + " bundle: " + extras);
                         }
@@ -2985,9 +2995,11 @@
                         SyncFinishedOrCancelledMessagePayload payload =
                                 (SyncFinishedOrCancelledMessagePayload) msg.obj;
                         if (!isSyncStillActiveH(payload.activeSyncContext)) {
-                            Log.d(TAG, "handleSyncHandlerMessage: dropping since the "
-                                    + "sync is no longer active: "
-                                    + payload.activeSyncContext);
+                            if (isLoggable) {
+                                Log.d(TAG, "handleSyncHandlerMessage: dropping since the "
+                                        + "sync is no longer active: "
+                                        + payload.activeSyncContext);
+                            }
                             break;
                         }
                         if (isLoggable) {
@@ -3002,7 +3014,7 @@
 
                     case SyncHandler.MESSAGE_SERVICE_CONNECTED: {
                         ServiceConnectionData msgData = (ServiceConnectionData) msg.obj;
-                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        if (isLoggable) {
                             Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CONNECTED: "
                                     + msgData.activeSyncContext);
                         }
@@ -3018,7 +3030,7 @@
                     case SyncHandler.MESSAGE_SERVICE_DISCONNECTED: {
                         final ActiveSyncContext currentSyncContext =
                                 ((ServiceConnectionData) msg.obj).activeSyncContext;
-                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        if (isLoggable) {
                             Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_DISCONNECTED: "
                                     + currentSyncContext);
                         }
@@ -3053,7 +3065,7 @@
 
                     case SyncHandler.MESSAGE_MONITOR_SYNC:
                         ActiveSyncContext monitoredSyncContext = (ActiveSyncContext) msg.obj;
-                        if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        if (isLoggable) {
                             Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_MONITOR_SYNC: " +
                                     monitoredSyncContext.mSyncOperation.target);
                         }
@@ -3061,7 +3073,7 @@
                         if (isSyncNotUsingNetworkH(monitoredSyncContext)) {
                             Log.w(TAG, String.format(
                                     "Detected sync making no progress for %s. cancelling.",
-                                    monitoredSyncContext));
+                                    logSafe(monitoredSyncContext)));
                             SyncJobService.callJobFinished(
                                     monitoredSyncContext.mSyncOperation.jobId, false,
                                     "no network activity");
@@ -3558,7 +3570,8 @@
             } catch (RuntimeException exc) {
                 mLogger.log("Sync failed with RuntimeException: ", exc.toString());
                 closeActiveSyncContext(activeSyncContext);
-                Slog.e(TAG, "Caught RuntimeException while starting the sync " + syncOperation, exc);
+                Slog.e(TAG, "Caught RuntimeException while starting the sync "
+                        + logSafe(syncOperation), exc);
             }
         }
 
@@ -3658,7 +3671,8 @@
                         reschedulePeriodicSyncH(syncOperation);
                     }
                 } else {
-                    Log.w(TAG, "failed sync operation " + syncOperation + ", " + syncResult);
+                    Log.w(TAG, "failed sync operation "
+                            + logSafe(syncOperation) + ", " + syncResult);
 
                     syncOperation.retries++;
                     if (syncOperation.retries > mConstants.getMaxRetriesWithAppStandbyExemption()) {
@@ -4042,11 +4056,6 @@
         getJobScheduler().cancel(op.jobId);
     }
 
-    private void wtfWithLog(String message) {
-        Slog.wtf(TAG, message);
-        mLogger.log("WTF: ", message);
-    }
-
     public void resetTodayStats() {
         mSyncStorageEngine.resetTodayStats(/*force=*/ true);
     }
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index 25edf40..2abc2e6 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -363,14 +363,19 @@
 
     @Override
     public String toString() {
-        return dump(null, true, null);
+        return dump(null, true, null, false);
     }
 
-    String dump(PackageManager pm, boolean shorter, SyncAdapterStateFetcher appStates) {
+    public String toSafeString() {
+        return dump(null, true, null, true);
+    }
+
+    String dump(PackageManager pm, boolean shorter, SyncAdapterStateFetcher appStates,
+            boolean logSafe) {
         StringBuilder sb = new StringBuilder();
         sb.append("JobId=").append(jobId)
                 .append(" ")
-                .append(target.account.name)
+                .append(logSafe ? "***" : target.account.name)
                 .append("/")
                 .append(target.account.type)
                 .append(" u")
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index bfd1791..6b441a0 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -16,6 +16,8 @@
 
 package com.android.server.content;
 
+import static com.android.server.content.SyncLogger.logSafe;
+
 import android.accounts.Account;
 import android.accounts.AccountAndUser;
 import android.accounts.AccountManager;
@@ -225,6 +227,15 @@
             sb.append(":u" + userId);
             return sb.toString();
         }
+
+        public String toSafeString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(account == null ? "ALL ACCS" : logSafe(account))
+                    .append("/")
+                    .append(provider == null ? "ALL PDRS" : provider);
+            sb.append(":u" + userId);
+            return sb.toString();
+        }
     }
 
     public static class AuthorityInfo {
@@ -1861,8 +1872,8 @@
 
                 }
             } else {
-                Slog.w(TAG, "Failure adding authority: account="
-                        + accountName + " auth=" + authorityName
+                Slog.w(TAG, "Failure adding authority:"
+                        + " auth=" + authorityName
                         + " enabled=" + enabled
                         + " syncable=" + syncable);
             }
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index b332c47..2fe17d8 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -34,8 +34,10 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.hardware.display.ColorDisplayManager;
+import android.graphics.ColorSpace;
 import android.hardware.display.IColorDisplayManager;
 import android.net.Uri;
 import android.opengl.Matrix;
@@ -59,6 +61,7 @@
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
 
+import java.io.PrintWriter;
 import java.time.DateTimeException;
 import java.time.Instant;
 import java.time.LocalDateTime;
@@ -148,26 +151,204 @@
     };
 
     private final TintController mDisplayWhiteBalanceTintController = new TintController() {
+        // Three chromaticity coordinates per color: X, Y, and Z
+        private final int NUM_VALUES_PER_PRIMARY = 3;
+        // Four colors: red, green, blue, and white
+        private final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY;
 
+        private final Object mLock = new Object();
+        private int mTemperatureMin;
+        private int mTemperatureMax;
+        private int mTemperatureDefault;
+        private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+        private ColorSpace.Rgb mDisplayColorSpaceRGB;
+        private float[] mChromaticAdaptationMatrix;
+        private int mCurrentColorTemperature;
+        private float[] mCurrentColorTemperatureXYZ;
+        private boolean mSetUp = false;
         private float[] mMatrixDisplayWhiteBalance = new float[16];
 
         @Override
         public void setUp(Context context, boolean needsLinear) {
+            mSetUp = false;
+
+            final Resources res = getContext().getResources();
+            final String[] displayPrimariesValues = res.getStringArray(
+                    R.array.config_displayWhiteBalanceDisplayPrimaries);
+            final String[] nominalWhiteValues = res.getStringArray(
+                    R.array.config_displayWhiteBalanceDisplayNominalWhite);
+
+            if (displayPrimariesValues.length != NUM_DISPLAY_PRIMARIES_VALS) {
+                Slog.e(TAG, "Unexpected display white balance primaries resource length " +
+                        displayPrimariesValues.length);
+                return;
+            }
+
+            if (nominalWhiteValues.length != NUM_VALUES_PER_PRIMARY) {
+                Slog.e(TAG, "Unexpected display white balance nominal white resource length " +
+                        nominalWhiteValues.length);
+                return;
+            }
+
+            float[] displayRedGreenBlueXYZ =
+                new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY];
+            float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+            for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) {
+                displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]);
+            }
+            for (int i = 0; i < displayWhiteXYZ.length; i++) {
+                displayWhiteXYZ[i] = Float.parseFloat(
+                        displayPrimariesValues[displayRedGreenBlueXYZ.length + i]);
+            }
+
+            final ColorSpace.Rgb displayColorSpaceRGB = new ColorSpace.Rgb(
+                "Display Color Space",
+                displayRedGreenBlueXYZ,
+                displayWhiteXYZ,
+                2.2f // gamma, unused for display white balance
+            );
+
+            float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+            for (int i = 0; i < nominalWhiteValues.length; i++) {
+                displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
+            }
+
+            final int colorTemperatureMin = res.getInteger(
+                    R.integer.config_displayWhiteBalanceColorTemperatureMin);
+            if (colorTemperatureMin <= 0) {
+                Slog.e(TAG, "display white balance minimum temperature must be greater than 0");
+                return;
+            }
+
+            final int colorTemperatureMax = res.getInteger(
+                    R.integer.config_displayWhiteBalanceColorTemperatureMax);
+            if (colorTemperatureMax < colorTemperatureMin) {
+                Slog.e(TAG, "display white balance max temp must be greater or equal to min");
+                return;
+            }
+
+            final int colorTemperature = res.getInteger(
+                    R.integer.config_displayWhiteBalanceColorTemperatureDefault);
+
+            synchronized (mLock) {
+                mDisplayColorSpaceRGB = displayColorSpaceRGB;
+                mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
+                mTemperatureMin = colorTemperatureMin;
+                mTemperatureMax = colorTemperatureMax;
+                mTemperatureDefault = colorTemperature;
+                mSetUp = true;
+            }
+
+            setMatrix(mTemperatureDefault);
         }
 
         @Override
         public float[] getMatrix() {
-            return isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
+            return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
         }
 
         @Override
         public void setMatrix(int cct) {
+            if (!mSetUp) {
+                Slog.w(TAG, "Can't set display white balance temperature: uninitialized");
+                return;
+            }
+
+            if (cct < mTemperatureMin) {
+                Slog.w(TAG, "Requested display color temperature is below allowed minimum");
+                cct = mTemperatureMin;
+            } else if (cct > mTemperatureMax) {
+                Slog.w(TAG, "Requested display color temperature is above allowed maximum");
+                cct = mTemperatureMax;
+            }
+
+            Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct);
+
+            synchronized (mLock) {
+                mCurrentColorTemperature = cct;
+
+                // Adapt the display's nominal white point to match the requested CCT value
+                mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
+
+                mChromaticAdaptationMatrix =
+                    ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
+                            mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
+
+                // Convert the adaptation matrix to RGB space
+                float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix,
+                        mDisplayColorSpaceRGB.getTransform());
+                result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
+
+                // Normalize the transform matrix to peak white value in RGB space
+                final float adaptedMaxR = result[0] + result[3] + result[6];
+                final float adaptedMaxG = result[1] + result[4] + result[7];
+                final float adaptedMaxB = result[2] + result[5] + result[8];
+                final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
+                for (int i = 0; i < result.length; i++) {
+                    result[i] /= denum;
+                }
+
+                Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
+                java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
+                java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
+                java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
+            }
         }
 
         @Override
         public int getLevel() {
             return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
         }
+
+        /**
+         * Format a given matrix into a string.
+         *
+         * @param matrix the matrix to format
+         * @param cols number of columns in the matrix
+         */
+        private String matrixToString(float[] matrix, int cols) {
+            if (matrix == null || cols <= 0) {
+                Slog.e(TAG, "Invalid arguments when formatting matrix to string");
+                return "";
+            }
+
+            StringBuilder sb = new StringBuilder("");
+            for (int i = 0; i < matrix.length; i++) {
+                if (i % cols == 0) {
+                    sb.append("\n    ");
+                }
+                sb.append(String.format("%9.6f ", matrix[i]));
+            }
+            return sb.toString();
+        }
+
+        @Override
+        public void dump(PrintWriter pw) {
+            synchronized (mLock) {
+                pw.println("ColorDisplayService");
+                pw.println("  mSetUp = " + mSetUp);
+
+                if (!mSetUp) {
+                    return;
+                }
+
+                pw.println("  isActivated = " + isActivated());
+                pw.println("  mTemperatureMin = " + mTemperatureMin);
+                pw.println("  mTemperatureMax = " + mTemperatureMax);
+                pw.println("  mTemperatureDefault = " + mTemperatureDefault);
+                pw.println("  mCurrentColorTemperature = " + mCurrentColorTemperature);
+                pw.println("  mCurrentColorTemperatureXYZ = " +
+                        matrixToString(mCurrentColorTemperatureXYZ, 3));
+                pw.println("  mDisplayColorSpaceRGB RGB-to-XYZ = " +
+                        matrixToString(mDisplayColorSpaceRGB.getTransform(), 3));
+                pw.println("  mChromaticAdaptationMatrix = " +
+                        matrixToString(mChromaticAdaptationMatrix, 3));
+                pw.println("  mDisplayColorSpaceRGB XYZ-to-RGB = " +
+                        matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3));
+                pw.println("  mMatrixDisplayWhiteBalance = " +
+                        matrixToString(mMatrixDisplayWhiteBalance, 4));
+            }
+        }
     };
 
     private final TintController mGlobalSaturationTintController = new TintController() {
@@ -230,8 +411,6 @@
 
     private NightDisplayAutoMode mNightDisplayAutoMode;
 
-    private Integer mDisplayWhiteBalanceColorTemperature;
-
     public ColorDisplayService(Context context) {
         super(context);
         mHandler = new TintHandler(Looper.getMainLooper());
@@ -363,7 +542,7 @@
                                 onAccessibilityTransformChanged();
                                 break;
                             case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
-                                onDisplayWhiteBalanceEnabled(isDisplayWhiteBalanceSettingEnabled());
+                                updateDisplayWhiteBalanceStatus();
                                 break;
                         }
                     }
@@ -416,14 +595,9 @@
 
         if (ColorDisplayManager.isDisplayWhiteBalanceAvailable(getContext())) {
             // Prepare the display white balance transform matrix.
-            mDisplayWhiteBalanceTintController
-                    .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
-            if (mDisplayWhiteBalanceColorTemperature != null) {
-                mDisplayWhiteBalanceTintController
-                        .setMatrix(mDisplayWhiteBalanceColorTemperature);
-            }
+            mDisplayWhiteBalanceTintController.setUp(getContext(), true /* needsLinear */);
 
-            onDisplayWhiteBalanceEnabled(isDisplayWhiteBalanceSettingEnabled());
+            updateDisplayWhiteBalanceStatus();
         }
     }
 
@@ -460,6 +634,8 @@
                 mNightDisplayAutoMode.onActivated(activated);
             }
 
+            updateDisplayWhiteBalanceStatus();
+
             applyTint(mNightDisplayTintController, false);
         }
     }
@@ -516,11 +692,7 @@
                 .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
         mNightDisplayTintController.setMatrix(mNightDisplayController.getColorTemperature());
 
-        mDisplayWhiteBalanceTintController
-                .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
-        if (mDisplayWhiteBalanceColorTemperature != null) {
-            mDisplayWhiteBalanceTintController.setMatrix(mDisplayWhiteBalanceColorTemperature);
-        }
+        updateDisplayWhiteBalanceStatus();
 
         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
         dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
@@ -611,10 +783,15 @@
         return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
     }
 
-    private void onDisplayWhiteBalanceEnabled(boolean enabled) {
-        mDisplayWhiteBalanceTintController.setActivated(enabled);
-        if (mDisplayWhiteBalanceListener != null) {
-            mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(enabled);
+    private void updateDisplayWhiteBalanceStatus() {
+        boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated();
+        mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled() &&
+                !mNightDisplayTintController.isActivated() &&
+                DisplayTransformManager.needsLinearColorMatrix());
+        boolean activated = mDisplayWhiteBalanceTintController.isActivated();
+
+        if (mDisplayWhiteBalanceListener != null && oldActivated != activated) {
+            mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(activated);
         }
     }
 
@@ -896,6 +1073,12 @@
         }
 
         /**
+         * Dump debug information.
+         */
+        public void dump(PrintWriter pw) {
+        }
+
+        /**
          * Set up any constants needed for computing the matrix.
          */
         public abstract void setUp(Context context, boolean needsLinear);
@@ -929,11 +1112,10 @@
          */
         public boolean setDisplayWhiteBalanceColorTemperature(int cct) {
             // Update the transform matrix even if it can't be applied.
-            mDisplayWhiteBalanceColorTemperature = cct;
             mDisplayWhiteBalanceTintController.setMatrix(cct);
 
             if (mDisplayWhiteBalanceTintController.isActivated()) {
-                applyTint(mDisplayWhiteBalanceTintController, true);
+                applyTint(mDisplayWhiteBalanceTintController, false);
                 return true;
             }
             return false;
@@ -946,6 +1128,10 @@
             mDisplayWhiteBalanceListener = listener;
             return mDisplayWhiteBalanceTintController.isActivated();
         }
+
+        public void dump(PrintWriter pw) {
+            mDisplayWhiteBalanceTintController.dump(pw);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 4a17c65..cb3f91b 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -95,6 +95,7 @@
 import com.android.server.UiThread;
 import com.android.server.wm.SurfaceAnimationThread;
 import com.android.server.wm.WindowManagerInternal;
+import com.android.server.display.ColorDisplayService.ColorDisplayServiceInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -791,6 +792,16 @@
         }
     }
 
+    private void setVirtualDisplayStateInternal(IBinder appToken, boolean isOn) {
+        synchronized (mSyncRoot) {
+            if (mVirtualDisplayAdapter == null) {
+                return;
+            }
+
+            mVirtualDisplayAdapter.setVirtualDisplayStateLocked(appToken, isOn);
+        }
+    }
+
     private void registerDefaultDisplayAdapters() {
         // Register default display adapters.
         synchronized (mSyncRoot) {
@@ -1459,6 +1470,13 @@
 
             pw.println();
             mPersistentDataStore.dump(pw);
+
+            final ColorDisplayServiceInternal cds = LocalServices.getService(
+                    ColorDisplayServiceInternal.class);
+            if (cds != null) {
+                pw.println();
+                cds.dump(pw);
+            }
         }
     }
 
@@ -1922,6 +1940,16 @@
         }
 
         @Override // Binder call
+        public void setVirtualDisplayState(IVirtualDisplayCallback callback, boolean isOn) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                setVirtualDisplayStateInternal(callback.asBinder(), isOn);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
         public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 5aa585f..1ca8dd3 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -147,6 +147,13 @@
         return device;
     }
 
+    void setVirtualDisplayStateLocked(IBinder appToken, boolean isOn) {
+        VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
+        if (device != null) {
+            device.setDisplayState(isOn);
+        }
+    }
+
     /**
      * Returns the next unique index for the uniqueIdPrefix
      */
@@ -206,6 +213,7 @@
         private int mPendingChanges;
         private int mUniqueIndex;
         private Display.Mode mMode;
+        private boolean mIsDisplayOn;
 
         public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
                 int ownerUid, String ownerPackageName,
@@ -226,6 +234,7 @@
             mDisplayState = Display.STATE_UNKNOWN;
             mPendingChanges |= PENDING_SURFACE_CHANGE;
             mUniqueIndex = uniqueIndex;
+            mIsDisplayOn = surface != null;
         }
 
         @Override
@@ -304,6 +313,14 @@
             }
         }
 
+        void setDisplayState(boolean isOn) {
+            if (mIsDisplayOn != isOn) {
+                mIsDisplayOn = isOn;
+                mInfo = null;
+                sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
+            }
+        }
+
         public void stopLocked() {
             setSurfaceLocked(null);
             mStopped = true;
@@ -375,7 +392,9 @@
                 mInfo.type = Display.TYPE_VIRTUAL;
                 mInfo.touch = ((mFlags & VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH) == 0) ?
                         DisplayDeviceInfo.TOUCH_NONE : DisplayDeviceInfo.TOUCH_VIRTUAL;
-                mInfo.state = mSurface != null ? Display.STATE_ON : Display.STATE_OFF;
+
+                mInfo.state = mIsDisplayOn ? Display.STATE_ON : Display.STATE_OFF;
+
                 mInfo.ownerUid = mOwnerUid;
                 mInfo.ownerPackageName = mOwnerPackageName;
             }
diff --git a/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
index 18d328d..137833c 100644
--- a/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
@@ -51,6 +51,13 @@
         }
         switch (cmd.getOpcode()) {
             case Constants.MESSAGE_FEATURE_ABORT:
+                if ((cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_INITIATE_ARC) {
+                    audioSystem().setArcStatus(false);
+                    finish();
+                    return true;
+                } else {
+                    return false;
+                }
             case Constants.MESSAGE_REPORT_ARC_TERMINATED:
                 audioSystem().setArcStatus(false);
                 finish();
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index ff029c1..297a418 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -17,6 +17,7 @@
 package com.android.server.hdmi;
 
 import android.annotation.IntDef;
+import android.annotation.StringDef;
 import android.hardware.hdmi.HdmiDeviceInfo;
 
 import java.lang.annotation.Retention;
@@ -222,6 +223,15 @@
     static final int AUDIO_CODEC_WMAPRO = 0xE; // Support WMA-Pro
     static final int AUDIO_CODEC_MAX = 0xF;
 
+    @StringDef({
+        AUDIO_DEVICE_ARC_IN,
+        AUDIO_DEVICE_SPDIF,
+    })
+    public @interface AudioDevice {}
+
+    static final String AUDIO_DEVICE_ARC_IN = "ARC_IN";
+    static final String AUDIO_DEVICE_SPDIF = "SPDIF";
+
     // Bit mask used to get the routing path of the top level device.
     // When &'d with the path 1.2.2.0 (0x1220), for instance, gives 1.0.0.0.
     static final int ROUTING_PATH_TOP_MASK = 0xF000;
diff --git a/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java b/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java
index 0495ff8..7187319 100644
--- a/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java
+++ b/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java
@@ -50,8 +50,10 @@
             if (mState != STATE_WAITING_FOR_FEATURE_ABORT) {
                 return false;
             }
-            finishAction(false);
-            return true;
+            if ((cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE) {
+                finishAction(false);
+                return true;
+            }
         }
         return false;
     }
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index ba21b78..df0dc77 100755
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -16,6 +16,7 @@
 
 package com.android.server.hdmi;
 
+import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.util.Slog;
 
@@ -51,6 +52,10 @@
     private static final int STATE_WAITING_FOR_OSD_NAME = 3;
     // State in which the action is waiting for gathering vendor id of non-local devices.
     private static final int STATE_WAITING_FOR_VENDOR_ID = 4;
+    // State in which the action is waiting for devices to be ready.
+    private static final int STATE_WAITING_FOR_DEVICES = 5;
+    // State in which the action is waiting for gathering power status of non-local devices.
+    private static final int STATE_WAITING_FOR_POWER = 6;
 
     /**
      * Interface used to report result of device discovery.
@@ -72,6 +77,7 @@
         private int mPhysicalAddress = Constants.INVALID_PHYSICAL_ADDRESS;
         private int mPortId = Constants.INVALID_PORT_ID;
         private int mVendorId = Constants.UNKNOWN_VENDOR_ID;
+        private int mPowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
         private String mDisplayName = "";
         private int mDeviceType = HdmiDeviceInfo.DEVICE_INACTIVE;
 
@@ -81,7 +87,7 @@
 
         private HdmiDeviceInfo toHdmiDeviceInfo() {
             return new HdmiDeviceInfo(mLogicalAddress, mPhysicalAddress, mPortId, mDeviceType,
-                    mVendorId, mDisplayName);
+                    mVendorId, mDisplayName, mPowerStatus);
         }
     }
 
@@ -89,7 +95,20 @@
     private final DeviceDiscoveryCallback mCallback;
     private int mProcessedDeviceCount = 0;
     private int mTimeoutRetry = 0;
-    private boolean mIsTvDevice = source().mService.isTvDevice();
+    private boolean mIsTvDevice = localDevice().mService.isTvDevice();
+    private final int mDelayPeriod;
+
+    /**
+     * Constructor.
+     *
+     * @param source an instance of {@link HdmiCecLocalDevice}.
+     * @param delay delay action for this period between query Physical Address and polling
+     */
+    DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback, int delay) {
+        super(source);
+        mCallback = Preconditions.checkNotNull(callback);
+        mDelayPeriod = delay;
+    }
 
     /**
      * Constructor.
@@ -97,8 +116,7 @@
      * @param source an instance of {@link HdmiCecLocalDevice}.
      */
     DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback) {
-        super(source);
-        mCallback = Preconditions.checkNotNull(callback);
+        this(source, callback, 0);
     }
 
     @Override
@@ -117,7 +135,11 @@
 
                 Slog.v(TAG, "Device detected: " + ackedAddress);
                 allocateDevices(ackedAddress);
-                startPhysicalAddressStage();
+                if (mDelayPeriod > 0) {
+                    startToDelayAction();
+                } else {
+                    startPhysicalAddressStage();
+                }
             }
         }, Constants.POLL_ITERATION_REVERSE_ORDER
             | Constants.POLL_STRATEGY_REMOTES_DEVICES, HdmiConfig.DEVICE_POLLING_RETRY);
@@ -131,6 +153,13 @@
         }
     }
 
+    private void startToDelayAction() {
+        Slog.v(TAG, "Waiting for connected devices to be ready");
+        mState = STATE_WAITING_FOR_DEVICES;
+
+        checkAndProceedStage();
+    }
+
     private void startPhysicalAddressStage() {
         Slog.v(TAG, "Start [Physical Address Stage]:" + mDevices.size());
         mProcessedDeviceCount = 0;
@@ -159,6 +188,11 @@
         addTimer(mState, HdmiConfig.TIMEOUT_MS);
     }
 
+    private void delayActionWithTimePeriod(int timeDelay) {
+        mActionTimer.clearTimerMessage();
+        addTimer(mState, timeDelay);
+    }
+
     private void startOsdNameStage() {
         Slog.v(TAG, "Start [Osd Name Stage]:" + mDevices.size());
         mProcessedDeviceCount = 0;
@@ -207,6 +241,29 @@
         addTimer(mState, HdmiConfig.TIMEOUT_MS);
     }
 
+    private void startPowerStatusStage() {
+        Slog.v(TAG, "Start [Power Status Stage]:" + mDevices.size());
+        mProcessedDeviceCount = 0;
+        mState = STATE_WAITING_FOR_POWER;
+
+        checkAndProceedStage();
+    }
+
+    private void queryPowerStatus(int address) {
+        if (!verifyValidLogicalAddress(address)) {
+            checkAndProceedStage();
+            return;
+        }
+
+        mActionTimer.clearTimerMessage();
+
+        if (mayProcessMessageIfCached(address, Constants.MESSAGE_REPORT_POWER_STATUS)) {
+            return;
+        }
+        sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), address));
+        addTimer(mState, HdmiConfig.TIMEOUT_MS);
+    }
+
     private boolean mayProcessMessageIfCached(int address, int opcode) {
         HdmiCecMessage message = getCecMessageCache().getMessage(address, opcode);
         if (message != null) {
@@ -245,6 +302,16 @@
                     return true;
                 }
                 return false;
+            case STATE_WAITING_FOR_POWER:
+                if (cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) {
+                    handleReportPowerStatus(cmd);
+                    return true;
+                } else if ((cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT)
+                        && ((cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_REPORT_POWER_STATUS)) {
+                    handleReportPowerStatus(cmd);
+                    return true;
+                }
+                return false;
             case STATE_WAITING_FOR_DEVICE_POLLING:
                 // Fall through.
             default:
@@ -266,6 +333,7 @@
         current.mPhysicalAddress = HdmiUtils.twoBytesToInt(params);
         current.mPortId = getPortId(current.mPhysicalAddress);
         current.mDeviceType = params[2] & 0xFF;
+        current.mDisplayName = HdmiUtils.getDefaultDeviceName(current.mDeviceType);
 
         // TODO(amyjojo): check if non-TV device needs to update cec switch info.
         // This is to manager CEC device separately in case they don't have address.
@@ -329,6 +397,26 @@
         checkAndProceedStage();
     }
 
+    private void handleReportPowerStatus(HdmiCecMessage cmd) {
+        Preconditions.checkState(mProcessedDeviceCount < mDevices.size());
+
+        DeviceInfo current = mDevices.get(mProcessedDeviceCount);
+        if (current.mLogicalAddress != cmd.getSource()) {
+            Slog.w(TAG, "Unmatched address[expected:" + current.mLogicalAddress + ", actual:"
+                    + cmd.getSource());
+            return;
+        }
+
+        if (cmd.getOpcode() != Constants.MESSAGE_FEATURE_ABORT) {
+            byte[] params = cmd.getParams();
+            int powerStatus = params[0] & 0xFF;
+            current.mPowerStatus = powerStatus;
+        }
+
+        increaseProcessedDeviceCount();
+        checkAndProceedStage();
+    }
+
     private void increaseProcessedDeviceCount() {
         mProcessedDeviceCount++;
         mTimeoutRetry = 0;
@@ -372,6 +460,9 @@
                     startVendorIdStage();
                     return;
                 case STATE_WAITING_FOR_VENDOR_ID:
+                    startPowerStatusStage();
+                    return;
+                case STATE_WAITING_FOR_POWER:
                     wrapUpAndFinish();
                     return;
                 default:
@@ -385,6 +476,9 @@
     private void sendQueryCommand() {
         int address = mDevices.get(mProcessedDeviceCount).mLogicalAddress;
         switch (mState) {
+            case STATE_WAITING_FOR_DEVICES:
+                delayActionWithTimePeriod(mDelayPeriod);
+                return;
             case STATE_WAITING_FOR_PHYSICAL_ADDRESS:
                 queryPhysicalAddress(address);
                 return;
@@ -394,6 +488,9 @@
             case STATE_WAITING_FOR_VENDOR_ID:
                 queryVendorId(address);
                 return;
+            case STATE_WAITING_FOR_POWER:
+                queryPowerStatus(address);
+                return;
             default:
                 return;
         }
@@ -405,13 +502,24 @@
             return;
         }
 
+        if (mState == STATE_WAITING_FOR_DEVICES) {
+            startPhysicalAddressStage();
+            return;
+        }
         if (++mTimeoutRetry < HdmiConfig.TIMEOUT_RETRY) {
             sendQueryCommand();
             return;
         }
         mTimeoutRetry = 0;
         Slog.v(TAG, "Timeout[State=" + mState + ", Processed=" + mProcessedDeviceCount);
-        removeDevice(mProcessedDeviceCount);
+        if (mState != STATE_WAITING_FOR_POWER && mState != STATE_WAITING_FOR_OSD_NAME) {
+            // We don't need to remove the device info if the power status is unknown.
+            // Some device does not have preferred OSD name and does not respond to Give OSD name.
+            // Like LG TV. We can give it default device name and not remove it.
+            removeDevice(mProcessedDeviceCount);
+        } else {
+            increaseProcessedDeviceCount();
+        }
         checkAndProceedStage();
     }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index e777ce8..86be585 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -77,7 +77,7 @@
 
     private static final int NUM_LOGICAL_ADDRESS = 16;
 
-    private static final int MAX_CEC_MESSAGE_HISTORY = 20;
+    private static final int MAX_CEC_MESSAGE_HISTORY = 200;
 
     // Predicate for whether the given logical address is remote device's one or not.
     private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() {
@@ -682,7 +682,7 @@
 
     void dump(final IndentingPrintWriter pw) {
         for (int i = 0; i < mLocalDevices.size(); ++i) {
-            pw.println("HdmiCecLocalDevice #" + i + ":");
+            pw.println("HdmiCecLocalDevice #" + mLocalDevices.keyAt(i) + ":");
             pw.increaseIndent();
             mLocalDevices.valueAt(i).dump(pw);
             pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 32dc0261..414f6bb 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -56,16 +56,12 @@
     // Within the timer, a received <User Control Pressed> will start "Press and Hold" behavior.
     // When it expires, we can assume <User Control Release> is received.
     private static final int FOLLOWER_SAFETY_TIMEOUT = 550;
-    /**
-     * Return value of {@link #getLocalPortFromPhysicalAddress(int)}
-     */
-    private static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
-    private static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;
 
     protected final HdmiControlService mService;
     protected final int mDeviceType;
     protected int mAddress;
     protected int mPreferredAddress;
+    @GuardedBy("mLock")
     protected HdmiDeviceInfo mDeviceInfo;
     protected int mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE;
     protected int mLastKeyRepeatCount = 0;
@@ -717,16 +713,18 @@
         return mDeviceType;
     }
 
-    @ServiceThreadOnly
+    @GuardedBy("mLock")
     HdmiDeviceInfo getDeviceInfo() {
-        assertRunOnServiceThread();
-        return mDeviceInfo;
+        synchronized (mLock) {
+            return mDeviceInfo;
+        }
     }
 
-    @ServiceThreadOnly
+    @GuardedBy("mLock")
     void setDeviceInfo(HdmiDeviceInfo info) {
-        assertRunOnServiceThread();
-        mDeviceInfo = info;
+        synchronized (mLock) {
+            mDeviceInfo = info;
+        }
     }
 
     // Returns true if the logical address is same as the argument.
@@ -1058,47 +1056,6 @@
         pw.println(String.format("mActiveRoutingPath: 0x%04x", mActiveRoutingPath));
     }
 
-    /**
-     * Method to parse target physical address to the port number on the current device.
-     *
-     * <p>This check assumes target address is valid.
-     * @param targetPhysicalAddress is the physical address of the target device
-     * @return
-     * If the target device is under the current device, return the port number of current device
-     * that the target device is connected to.
-     *
-     * <p>If the target device has the same physical address as the current device, return
-     * {@link #TARGET_SAME_PHYSICAL_ADDRESS}.
-     *
-     * <p>If the target device is not under the current device, return
-     * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}.
-     */
-    protected int getLocalPortFromPhysicalAddress(int targetPhysicalAddress) {
-        int myPhysicalAddress = mService.getPhysicalAddress();
-        if (myPhysicalAddress == targetPhysicalAddress) {
-            return TARGET_SAME_PHYSICAL_ADDRESS;
-        }
-        int finalMask = 0xF000;
-        int mask;
-        int port = 0;
-        for (mask = 0x0F00; mask > 0x000F;  mask >>= 4) {
-            if ((myPhysicalAddress & mask) == 0)  {
-                port = mask & targetPhysicalAddress;
-                break;
-            } else {
-                finalMask |= mask;
-            }
-        }
-        if (finalMask != 0xFFFF && (finalMask & targetPhysicalAddress) == myPhysicalAddress) {
-            while (mask != 0x000F) {
-                mask >>= 4;
-                port >>= 4;
-            }
-            return port;
-        }
-        return TARGET_NOT_UNDER_LOCAL_DEVICE;
-    }
-
     /** Calculates the physical address for {@code activePortId}.
      *
      * <p>This method assumes current device physical address is valid.
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 0e4e334..63214ed 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -26,22 +26,38 @@
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.media.AudioDeviceInfo;
+import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.tv.TvContract;
 import android.os.SystemProperties;
+import android.provider.Settings.Global;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.hdmi.Constants.AudioCodec;
 import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
+import com.android.server.hdmi.HdmiUtils.CodecSad;
+import com.android.server.hdmi.HdmiUtils.DeviceConfig;
 
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.stream.Collectors;
+
 
 /**
  * Represent a logical device of type {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM} residing in Android
@@ -77,25 +93,28 @@
     // processing.
     private final HashMap<Integer, String> mTvInputs = new HashMap<>();
 
+    // Copy of mDeviceInfos to guarantee thread-safety.
+    @GuardedBy("mLock")
+    private List<HdmiDeviceInfo> mSafeAllDeviceInfos = Collections.emptyList();
+
     // Map-like container of all cec devices.
     // device id is used as key of container.
     private final SparseArray<HdmiDeviceInfo> mDeviceInfos = new SparseArray<>();
 
     protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
         super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
-        mSystemAudioControlFeatureEnabled = true;
-        // TODO(amyjojo) make System Audio Control controllable by users
-        /*mSystemAudioControlFeatureEnabled =
-        mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);*/
-        // TODO(amyjojo): make the map ro property.
-        mTvInputs.put(Constants.CEC_SWITCH_HDMI1,
-                "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5");
-        mTvInputs.put(Constants.CEC_SWITCH_HDMI2,
-                "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6");
-        mTvInputs.put(Constants.CEC_SWITCH_HDMI3,
-                "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7");
+        mRoutingControlFeatureEnabled =
+            mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, false);
+        mSystemAudioControlFeatureEnabled =
+            mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);
+        // TODO(amyjojo): Maintain a portId to TvinputId map.
+        mTvInputs.put(2, "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5");
+        mTvInputs.put(4, "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6");
+        mTvInputs.put(1, "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7");
     }
 
+    private static final String SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH = "/vendor/etc/sadConfig.xml";
+
     /**
      * Called when a device is newly added or a new device is detected or
      * an existing device is updated.
@@ -167,6 +186,7 @@
             removeDeviceInfo(deviceInfo.getId());
         }
         mDeviceInfos.append(deviceInfo.getId(), deviceInfo);
+        updateSafeDeviceInfoList();
         return oldDeviceInfo;
     }
 
@@ -184,6 +204,7 @@
         if (deviceInfo != null) {
             mDeviceInfos.remove(id);
         }
+        updateSafeDeviceInfoList();
         return deviceInfo;
     }
 
@@ -200,6 +221,24 @@
         return mDeviceInfos.get(HdmiDeviceInfo.idForCecDevice(logicalAddress));
     }
 
+    @ServiceThreadOnly
+    private void updateSafeDeviceInfoList() {
+        assertRunOnServiceThread();
+        List<HdmiDeviceInfo> copiedDevices = HdmiUtils.sparseArrayToList(mDeviceInfos);
+        synchronized (mLock) {
+            mSafeAllDeviceInfos = copiedDevices;
+        }
+    }
+
+    @GuardedBy("mLock")
+    List<HdmiDeviceInfo> getSafeCecDevicesLocked() {
+        ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>();
+        for (HdmiDeviceInfo info : mSafeAllDeviceInfos) {
+            infoList.add(info);
+        }
+        return infoList;
+    }
+
     private void invokeDeviceEventListener(HdmiDeviceInfo info, int status) {
         mService.invokeDeviceEventListeners(info, status);
     }
@@ -229,7 +268,7 @@
         mTvSystemAudioModeSupport = false;
         // Record the last state of System Audio Control before going to standby
         synchronized (mLock) {
-            SystemProperties.set(
+            mService.writeStringSetting(
                     Constants.PROPERTY_LAST_SYSTEM_AUDIO_CONTROL,
                     mSystemAudioActivated ? "true" : "false");
         }
@@ -240,6 +279,10 @@
     @ServiceThreadOnly
     protected void onAddressAllocated(int logicalAddress, int reason) {
         assertRunOnServiceThread();
+        if (reason == mService.INITIATED_BY_ENABLE_CEC) {
+            mService.setAndBroadcastActiveSource(mService.getPhysicalAddress(),
+                    getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST);
+        }
         mService.sendCecCommand(
                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
                         mAddress, mService.getPhysicalAddress(), mDeviceType));
@@ -259,7 +302,10 @@
 
     @Override
     protected int findKeyReceiverAddress() {
-        return Constants.ADDR_TV;
+        if (getActiveSource().isValid()) {
+            return getActiveSource().logicalAddress;
+        }
+        return Constants.ADDR_INVALID;
     }
 
     @VisibleForTesting
@@ -267,7 +313,7 @@
             int systemAudioOnPowerOnProp, boolean lastSystemAudioControlStatus) {
         if ((systemAudioOnPowerOnProp == ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON)
                 || ((systemAudioOnPowerOnProp == USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON)
-                && lastSystemAudioControlStatus)) {
+                && lastSystemAudioControlStatus && isSystemAudioControlFeatureEnabled())) {
             addAndStartAction(new SystemAudioInitiationActionFromAvr(this));
         }
     }
@@ -284,7 +330,7 @@
     @ServiceThreadOnly
     protected void setPreferredAddress(int addr) {
         assertRunOnServiceThread();
-        SystemProperties.set(
+        mService.writeStringSetting(
                 Constants.PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM, String.valueOf(addr));
     }
 
@@ -400,8 +446,11 @@
     @ServiceThreadOnly
     protected boolean handleGiveAudioStatus(HdmiCecMessage message) {
         assertRunOnServiceThread();
-
-        reportAudioStatus(message);
+        if (isSystemAudioControlFeatureEnabled()) {
+            reportAudioStatus(message.getSource());
+        } else {
+            mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+        }
         return true;
     }
 
@@ -420,7 +469,7 @@
     protected boolean handleRequestArcInitiate(HdmiCecMessage message) {
         assertRunOnServiceThread();
         removeAction(ArcInitiationActionFromAvr.class);
-        if (!SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)) {
+        if (!mService.readBooleanSetting(Constants.PROPERTY_ARC_SUPPORT, true)) {
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNRECOGNIZED_OPCODE);
         } else if (!isDirectConnectToTv()) {
             HdmiLogger.debug("AVR device is not directly connected with TV");
@@ -459,13 +508,35 @@
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE);
             return true;
         }
-        AudioDeviceInfo deviceInfo = getSystemAudioDeviceInfo();
-        if (deviceInfo == null) {
-            mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNABLE_TO_DETERMINE);
-            return true;
+
+        List<DeviceConfig> config = null;
+        File file = new File(SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH);
+        if (file.exists()) {
+            try {
+                InputStream in = new FileInputStream(file);
+                config = HdmiUtils.ShortAudioDescriptorXmlParser.parse(in);
+                in.close();
+            } catch (IOException e) {
+                Slog.e(TAG, "Error reading file: " + file, e);
+            } catch (XmlPullParserException e) {
+                Slog.e(TAG, "Unable to parse file: " + file, e);
+            }
         }
+
         @AudioCodec int[] audioFormatCodes = parseAudioFormatCodes(message.getParams());
-        byte[] sadBytes = getSupportedShortAudioDescriptors(deviceInfo, audioFormatCodes);
+        byte[] sadBytes;
+        if (config != null && config.size() > 0) {
+            sadBytes = getSupportedShortAudioDescriptorsFromConfig(config, audioFormatCodes);
+        } else {
+            AudioDeviceInfo deviceInfo = getSystemAudioDeviceInfo();
+            if (deviceInfo == null) {
+                mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNABLE_TO_DETERMINE);
+                return true;
+            }
+
+            sadBytes = getSupportedShortAudioDescriptors(deviceInfo, audioFormatCodes);
+        }
+
         if (sadBytes.length == 0) {
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_INVALID_OPERAND);
         } else {
@@ -478,14 +549,127 @@
 
     private byte[] getSupportedShortAudioDescriptors(
             AudioDeviceInfo deviceInfo, @AudioCodec int[] audioFormatCodes) {
-        // TODO(b/80297701) implement
-        return new byte[] {};
+        ArrayList<byte[]> sads = new ArrayList<>(audioFormatCodes.length);
+        for (@AudioCodec int audioFormatCode : audioFormatCodes) {
+            byte[] sad = getSupportedShortAudioDescriptor(deviceInfo, audioFormatCode);
+            if (sad != null) {
+                if (sad.length == 3) {
+
+                    sads.add(sad);
+                } else {
+                    HdmiLogger.warning(
+                            "Dropping Short Audio Descriptor with length %d for requested codec %x",
+                            sad.length, audioFormatCode);
+                }
+            }
+        }
+        return getShortAudioDescriptorBytes(sads);
+    }
+
+    private byte[] getSupportedShortAudioDescriptorsFromConfig(
+            List<DeviceConfig> deviceConfig, @AudioCodec int[] audioFormatCodes) {
+        DeviceConfig deviceConfigToUse = null;
+        for (DeviceConfig device : deviceConfig) {
+            // TODO(amyjojo) use PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT to get the audio device name
+            if (device.name.equals("VX_AUDIO_DEVICE_IN_HDMI_ARC")) {
+                deviceConfigToUse = device;
+                break;
+            }
+        }
+        if (deviceConfigToUse == null) {
+            // TODO(amyjojo) use PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT to get the audio device name
+            Slog.w(TAG, "sadConfig.xml does not have required device info for "
+                        + "VX_AUDIO_DEVICE_IN_HDMI_ARC");
+            return new byte[0];
+        }
+        HashMap<Integer, byte[]> map = new HashMap<>();
+        ArrayList<byte[]> sads = new ArrayList<>(audioFormatCodes.length);
+        for (CodecSad codecSad : deviceConfigToUse.supportedCodecs) {
+            map.put(codecSad.audioCodec, codecSad.sad);
+        }
+        for (int i = 0; i < audioFormatCodes.length; i++) {
+            if (map.containsKey(audioFormatCodes[i])) {
+                byte[] sad = map.get(audioFormatCodes[i]);
+                if (sad != null && sad.length == 3) {
+                    sads.add(sad);
+                }
+            }
+        }
+        return getShortAudioDescriptorBytes(sads);
+    }
+
+    private byte[] getShortAudioDescriptorBytes(ArrayList<byte[]> sads) {
+        // Short Audio Descriptors are always 3 bytes long.
+        byte[] bytes = new byte[sads.size() * 3];
+        int index = 0;
+        for (byte[] sad : sads) {
+            System.arraycopy(sad, 0, bytes, index, 3);
+            index += 3;
+        }
+        return bytes;
+    }
+
+    /**
+     * Returns a 3 byte short audio descriptor as described in CEC 1.4 table 29 or null if the
+     * audioFormatCode is not supported.
+     */
+    @Nullable
+    private byte[] getSupportedShortAudioDescriptor(
+            AudioDeviceInfo deviceInfo, @AudioCodec int audioFormatCode) {
+        switch (audioFormatCode) {
+            case Constants.AUDIO_CODEC_NONE: {
+                return null;
+            }
+            case Constants.AUDIO_CODEC_LPCM: {
+                return getLpcmShortAudioDescriptor(deviceInfo);
+            }
+            // TODO(b/80297701): implement the rest of the codecs
+            case Constants.AUDIO_CODEC_DD:
+            case Constants.AUDIO_CODEC_MPEG1:
+            case Constants.AUDIO_CODEC_MP3:
+            case Constants.AUDIO_CODEC_MPEG2:
+            case Constants.AUDIO_CODEC_AAC:
+            case Constants.AUDIO_CODEC_DTS:
+            case Constants.AUDIO_CODEC_ATRAC:
+            case Constants.AUDIO_CODEC_ONEBITAUDIO:
+            case Constants.AUDIO_CODEC_DDP:
+            case Constants.AUDIO_CODEC_DTSHD:
+            case Constants.AUDIO_CODEC_TRUEHD:
+            case Constants.AUDIO_CODEC_DST:
+            case Constants.AUDIO_CODEC_WMAPRO:
+            default: {
+                return null;
+            }
+        }
+    }
+
+    @Nullable
+    private byte[] getLpcmShortAudioDescriptor(AudioDeviceInfo deviceInfo) {
+        // TODO(b/80297701): implement
+        return null;
     }
 
     @Nullable
     private AudioDeviceInfo getSystemAudioDeviceInfo() {
-        // TODO(b/80297701) implement
-        // Get the audio device used for system audio mode.
+        AudioManager audioManager = mService.getContext().getSystemService(AudioManager.class);
+        if (audioManager == null) {
+            HdmiLogger.error(
+                    "Error getting system audio device because AudioManager not available.");
+            return null;
+        }
+        AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
+        HdmiLogger.debug("Found %d audio input devices", devices.length);
+        for (AudioDeviceInfo device : devices) {
+            HdmiLogger.debug("%s at port %s", device.getProductName(), device.getPort());
+            HdmiLogger.debug("Supported encodings are %s",
+                    Arrays.stream(device.getEncodings()).mapToObj(
+                            AudioFormat::toLogFriendlyEncoding
+                    ).collect(Collectors.joining(", ")));
+            // TODO(b/80297701) use the actual device type that system audio mode is connected to.
+            if (device.getType() == AudioDeviceInfo.TYPE_HDMI_ARC) {
+                return device;
+            }
+        }
         return null;
     }
 
@@ -583,17 +767,20 @@
             .setWiredDeviceConnectionState(AudioSystem.DEVICE_IN_HDMI, enabled ? 1 : 0, "", "");
     }
 
-    private void reportAudioStatus(HdmiCecMessage message) {
+    void reportAudioStatus(int source) {
         assertRunOnServiceThread();
 
         int volume = mService.getAudioManager().getStreamVolume(AudioManager.STREAM_MUSIC);
         boolean mute = mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC);
         int maxVolume = mService.getAudioManager().getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        int minVolume = mService.getAudioManager().getStreamMinVolume(AudioManager.STREAM_MUSIC);
         int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume);
+        HdmiLogger.debug("Reporting volume %i (%i-%i) as CEC volume %i", volume,
+                minVolume, maxVolume, scaledVolume);
 
         mService.sendCecCommand(
                 HdmiCecMessageBuilder.buildReportAudioStatus(
-                        mAddress, message.getSource(), scaledVolume, mute));
+                        mAddress, source, scaledVolume, mute));
     }
 
     /**
@@ -633,7 +820,7 @@
      */
     private void setSystemAudioMode(boolean newSystemAudioMode) {
         int targetPhysicalAddress = getActiveSource().physicalAddress;
-        int port = getLocalPortFromPhysicalAddress(targetPhysicalAddress);
+        int port = mService.pathToPortId(targetPhysicalAddress);
         if (newSystemAudioMode && port >= 0) {
             switchToAudioInput();
         }
@@ -641,16 +828,18 @@
         // PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE is false when device never needs to be muted.
         boolean currentMuteStatus =
                 mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC);
-        if (SystemProperties.getBoolean(
-                Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, true)
-                && currentMuteStatus == newSystemAudioMode) {
-            mService.getAudioManager()
-                    .adjustStreamVolume(
-                            AudioManager.STREAM_MUSIC,
-                            newSystemAudioMode
-                                    ? AudioManager.ADJUST_UNMUTE
-                                    : AudioManager.ADJUST_MUTE,
-                                    0);
+        if (currentMuteStatus == newSystemAudioMode) {
+            if (mService.readBooleanSetting(
+                    Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, true)
+                            || newSystemAudioMode) {
+                mService.getAudioManager()
+                        .adjustStreamVolume(
+                                AudioManager.STREAM_MUSIC,
+                                newSystemAudioMode
+                                        ? AudioManager.ADJUST_UNMUTE
+                                        : AudioManager.ADJUST_MUTE,
+                                0);
+            }
         }
         updateAudioManagerForSystemAudio(newSystemAudioMode);
         synchronized (mLock) {
@@ -688,6 +877,13 @@
         HdmiLogger.debug("[A]UpdateSystemAudio mode[on=%b] output=[%X]", on, device);
     }
 
+    void onSystemAduioControlFeatureSupportChanged(boolean enabled) {
+        setSystemAudioControlFeatureEnabled(enabled);
+        if (enabled) {
+            addAndStartAction(new SystemAudioInitiationActionFromAvr(this));
+        }
+    }
+
     @ServiceThreadOnly
     void setSystemAudioControlFeatureEnabled(boolean enabled) {
         assertRunOnServiceThread();
@@ -697,6 +893,14 @@
     }
 
     @ServiceThreadOnly
+    void setRoutingControlFeatureEnables(boolean enabled) {
+        assertRunOnServiceThread();
+        synchronized (mLock) {
+            mRoutingControlFeatureEnabled = enabled;
+        }
+    }
+
+    @ServiceThreadOnly
     void doManualPortSwitching(int portId, IHdmiControlCallback callback) {
         assertRunOnServiceThread();
         // TODO: validate port ID
@@ -817,7 +1021,7 @@
 
     @Override
     protected void switchInputOnReceivingNewActivePath(int physicalAddress) {
-        int port = getLocalPortFromPhysicalAddress(physicalAddress);
+        int port = mService.pathToPortId(physicalAddress);
         if (isSystemAudioActivated() && port < 0) {
             // If system audio mode is on and the new active source is not under the current device,
             // Will switch to ARC input.
@@ -831,6 +1035,10 @@
     }
 
     protected void routeToInputFromPortId(int portId) {
+        if (!isRoutingControlFeatureEnabled()) {
+            HdmiLogger.debug("Routing Control Feature is not enabled.");
+            return;
+        }
         if (mArcIntentUsed) {
             routeToTvInputFromPortId(portId);
         } else {
@@ -885,7 +1093,7 @@
 
     @Override
     protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
-        int port = getLocalPortFromPhysicalAddress(physicalAddress);
+        int port = mService.pathToPortId(physicalAddress);
         // Routing change or information sent from switches under the current device can be ignored.
         if (port > 0) {
             return;
@@ -918,8 +1126,7 @@
             return;
         }
 
-        int routingInformationPath =
-                getActivePathOnSwitchFromActivePortId(getRoutingPort());
+        int routingInformationPath = mService.portIdToPath(getRoutingPort());
         // If current device is already the leaf of the whole HDMI system, will do nothing.
         if (routingInformationPath == mService.getPhysicalAddress()) {
             HdmiLogger.debug("Current device can't assign valid physical address"
@@ -954,6 +1161,10 @@
     @ServiceThreadOnly
     private void launchDeviceDiscovery() {
         assertRunOnServiceThread();
+        if (hasAction(DeviceDiscoveryAction.class)) {
+            Slog.i(TAG, "Device Discovery Action is in progress. Restarting.");
+            removeAction(DeviceDiscoveryAction.class);
+        }
         DeviceDiscoveryAction action = new DeviceDiscoveryAction(this,
                 new DeviceDiscoveryCallback() {
                     @Override
@@ -977,5 +1188,25 @@
             invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
         }
         mDeviceInfos.clear();
+        updateSafeDeviceInfoList();
     }
+
+    @Override
+    protected void dump(IndentingPrintWriter pw) {
+        pw.println("HdmiCecLocalDeviceAudioSystem:");
+        pw.increaseIndent();
+        pw.println("mSystemAudioActivated: " + mSystemAudioActivated);
+        pw.println("isRoutingFeatureEnabled " + isRoutingControlFeatureEnabled());
+        pw.println("mSystemAudioControlFeatureEnabled: " + mSystemAudioControlFeatureEnabled);
+        pw.println("mTvSystemAudioModeSupport: " + mTvSystemAudioModeSupport);
+        pw.println("mArcEstablished: " + mArcEstablished);
+        pw.println("mArcIntentUsed: " + mArcIntentUsed);
+        pw.println("mRoutingPort: " + getRoutingPort());
+        pw.println("mLocalActivePort: " + getLocalActivePort());
+        HdmiUtils.dumpMap(pw, "mTvInputs:", mTvInputs);
+        HdmiUtils.dumpSparseArray(pw, "mDeviceInfos:", mDeviceInfos);
+        pw.decreaseIndent();
+        super.dump(pw);
+    }
+
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 07db971..7a0c279 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -77,6 +77,10 @@
     @ServiceThreadOnly
     protected void onAddressAllocated(int logicalAddress, int reason) {
         assertRunOnServiceThread();
+        if (reason == mService.INITIATED_BY_ENABLE_CEC) {
+            mService.setAndBroadcastActiveSource(mService.getPhysicalAddress(),
+                    getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST);
+        }
         mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
                 mAddress, mService.getPhysicalAddress(), mDeviceType));
         mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
@@ -96,7 +100,7 @@
     @ServiceThreadOnly
     protected void setPreferredAddress(int addr) {
         assertRunOnServiceThread();
-        SystemProperties.set(Constants.PROPERTY_PREFERRED_ADDRESS_PLAYBACK,
+        mService.writeStringSetting(Constants.PROPERTY_PREFERRED_ADDRESS_PLAYBACK,
                 String.valueOf(addr));
     }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index a95f7f1..ae008b4 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -66,6 +66,10 @@
     @LocalActivePort
     protected int mLocalActivePort = Constants.CEC_SWITCH_HOME;
 
+    // Whether the Routing Coutrol feature is enabled or not. False by default.
+    @GuardedBy("mLock")
+    protected boolean mRoutingControlFeatureEnabled;
+
     protected HdmiCecLocalDeviceSource(HdmiControlService service, int deviceType) {
         super(service, deviceType);
     }
@@ -123,7 +127,9 @@
         }
         setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
         updateDevicePowerStatus(logicalAddress, HdmiControlManager.POWER_STATUS_ON);
-        switchInputOnReceivingNewActivePath(physicalAddress);
+        if (isRoutingControlFeatureEnabled()) {
+            switchInputOnReceivingNewActivePath(physicalAddress);
+        }
         return true;
     }
 
@@ -153,6 +159,10 @@
     @ServiceThreadOnly
     protected boolean handleRoutingChange(HdmiCecMessage message) {
         assertRunOnServiceThread();
+        if (!isRoutingControlFeatureEnabled()) {
+            mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+            return true;
+        }
         int newPath = HdmiUtils.twoBytesToInt(message.getParams(), 2);
         // if the current device is a pure playback device
         if (!mIsSwitchDevice
@@ -168,6 +178,10 @@
     @ServiceThreadOnly
     protected boolean handleRoutingInformation(HdmiCecMessage message) {
         assertRunOnServiceThread();
+        if (!isRoutingControlFeatureEnabled()) {
+            mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+            return true;
+        }
         int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
         // if the current device is a pure playback device
         if (!mIsSwitchDevice
@@ -204,7 +218,7 @@
     // This method should only be called when the device can be the active source.
     protected void setAndBroadcastActiveSource(HdmiCecMessage message, int physicalAddress) {
         mService.setAndBroadcastActiveSource(
-                message, physicalAddress, getDeviceInfo().getDeviceType());
+                physicalAddress, getDeviceInfo().getDeviceType(), message.getSource());
     }
 
     @ServiceThreadOnly
@@ -279,6 +293,12 @@
         }
     }
 
+    boolean isRoutingControlFeatureEnabled() {
+        synchronized (mLock) {
+            return mRoutingControlFeatureEnabled;
+        }
+    }
+
     // Check if the device is trying to switch to the same input that is active right now.
     // This can help avoid redundant port switching.
     protected boolean isSwitchingToTheSameInput(@LocalActivePort int activePort) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
index c005615..f8b3962 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
@@ -17,6 +17,7 @@
 package com.android.server.hdmi;
 
 import android.annotation.Nullable;
+
 import libcore.util.EmptyArray;
 
 import java.util.Arrays;
@@ -111,12 +112,11 @@
     @Override
     public String toString() {
         StringBuffer s = new StringBuffer();
-        s.append(String.format("<%s> src: %d, dst: %d",
-                opcodeToString(mOpcode), mSource, mDestination));
+        s.append(String.format("<%s> %X%X:%02X",
+                opcodeToString(mOpcode), mSource, mDestination, mOpcode));
         if (mParams.length > 0) {
-            s.append(", params:");
             for (byte data : mParams) {
-                s.append(String.format(" %02X", data));
+                s.append(String.format(":%02X", data));
             }
         }
         return s.toString();
@@ -133,7 +133,7 @@
             case Constants.MESSAGE_TUNER_STEP_DECREMENT:
                 return "Tuner Step Decrement";
             case Constants.MESSAGE_TUNER_DEVICE_STATUS:
-                return "Tuner Device Staus";
+                return "Tuner Device Status";
             case Constants.MESSAGE_GIVE_TUNER_DEVICE_STATUS:
                 return "Give Tuner Device Status";
             case Constants.MESSAGE_RECORD_ON:
@@ -207,7 +207,7 @@
             case Constants.MESSAGE_DEVICE_VENDOR_ID:
                 return "Device Vendor Id";
             case Constants.MESSAGE_VENDOR_COMMAND:
-                return "Vendor Commandn";
+                return "Vendor Command";
             case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN:
                 return "Vendor Remote Button Down";
             case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP:
@@ -215,7 +215,7 @@
             case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID:
                 return "Give Device Vendor Id";
             case Constants.MESSAGE_MENU_REQUEST:
-                return "Menu REquest";
+                return "Menu Request";
             case Constants.MESSAGE_MENU_STATUS:
                 return "Menu Status";
             case Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS:
@@ -247,7 +247,7 @@
             case Constants.MESSAGE_SET_EXTERNAL_TIMER:
                 return "Set External Timer";
             case Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR:
-                return "Repot Short Audio Descriptor";
+                return "Report Short Audio Descriptor";
             case Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR:
                 return "Request Short Audio Descriptor";
             case Constants.MESSAGE_INITIATE_ARC:
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 2d6e762..46219d5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -20,12 +20,14 @@
 import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE;
 
 import static com.android.internal.os.RoSystemProperties.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH;
+import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
 import static com.android.server.hdmi.Constants.DISABLED;
 import static com.android.server.hdmi.Constants.ENABLED;
 import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE;
 import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING;
 import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE;
 import static com.android.server.hdmi.Constants.OPTION_MHL_SERVICE_CONTROL;
+import static com.android.server.power.ShutdownThread.SHUTDOWN_ACTION_PROPERTY;
 
 import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
@@ -184,9 +186,10 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             assertRunOnServiceThread();
+            boolean isReboot = SystemProperties.get(SHUTDOWN_ACTION_PROPERTY).contains("1");
             switch (intent.getAction()) {
                 case Intent.ACTION_SCREEN_OFF:
-                    if (isPowerOnOrTransient()) {
+                    if (isPowerOnOrTransient() && !isReboot) {
                         onStandby(STANDBY_SCREEN_OFF);
                     }
                     break;
@@ -202,7 +205,7 @@
                     }
                     break;
                 case Intent.ACTION_SHUTDOWN:
-                    if (isPowerOnOrTransient()) {
+                    if (isPowerOnOrTransient() && !isReboot) {
                         onStandby(STANDBY_SHUTDOWN);
                     }
                     break;
@@ -345,6 +348,10 @@
     @Nullable
     private Looper mIoLooper;
 
+    // Thread safe physical address
+    @GuardedBy("mLock")
+    private int mPhysicalAddress = Constants.INVALID_PHYSICAL_ADDRESS;
+
     // Last input port before switching to the MHL port. Should switch back to this port
     // when the mobile device sends the request one touch play with off.
     // Gets invalidated if we go to other port/input.
@@ -564,7 +571,8 @@
                 Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
                 Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
                 Global.MHL_INPUT_SWITCHING_ENABLED,
-                Global.MHL_POWER_CHARGE_ENABLED
+                Global.MHL_POWER_CHARGE_ENABLED,
+                Global.HDMI_CEC_SWITCH_ENABLED
         };
         for (String s : settings) {
             resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver,
@@ -605,6 +613,24 @@
                     if (isTvDeviceEnabled()) {
                         tv().setSystemAudioControlFeatureEnabled(enabled);
                     }
+                    if (isAudioSystemDevice()) {
+                        if (audioSystem() == null) {
+                            Slog.e(TAG, "Audio System device has not registered yet."
+                                    + " Can't turn system audio mode on.");
+                            break;
+                        }
+                        audioSystem().onSystemAduioControlFeatureSupportChanged(enabled);
+                    }
+                    break;
+                case Global.HDMI_CEC_SWITCH_ENABLED:
+                    if (isAudioSystemDevice()) {
+                        if (audioSystem() == null) {
+                            Slog.w(TAG, "Switch device has not registered yet."
+                                    + " Can't turn routing on.");
+                            break;
+                        }
+                        audioSystem().setRoutingControlFeatureEnables(enabled);
+                    }
                     break;
                 case Global.MHL_INPUT_SWITCHING_ENABLED:
                     setMhlInputChangeEnabled(enabled);
@@ -620,6 +646,7 @@
         return enabled ? ENABLED : DISABLED;
     }
 
+    @VisibleForTesting
     boolean readBooleanSetting(String key, boolean defVal) {
         ContentResolver cr = getContext().getContentResolver();
         return Global.getInt(cr, key, toInt(defVal)) == ENABLED;
@@ -630,6 +657,11 @@
         Global.putInt(cr, key, toInt(value));
     }
 
+    void writeStringSetting(String key, String value) {
+        ContentResolver cr = getContext().getContentResolver();
+        Global.putString(cr, key, value);
+    }
+
     private void initializeCec(int initiatedBy) {
         mAddressAllocated = false;
         mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
@@ -734,6 +766,10 @@
         assertRunOnServiceThread();
         HdmiPortInfo[] cecPortInfo = null;
 
+        synchronized (mLock) {
+            mPhysicalAddress = getPhysicalAddress();
+        }
+
         // CEC HAL provides majority of the info while MHL does only MHL support flag for
         // each port. Return empty array if CEC HAL didn't provide the info.
         if (mCecController != null) {
@@ -827,7 +863,10 @@
     int pathToPortId(int path) {
         int mask = 0xF000;
         int finalMask = 0xF000;
-        int physicalAddress = getPhysicalAddress();
+        int physicalAddress;
+        synchronized (mLock) {
+            physicalAddress = mPhysicalAddress;
+        }
         int maskedAddress = physicalAddress;
 
         while (maskedAddress != 0) {
@@ -1135,7 +1174,7 @@
         String displayName = Build.MODEL;
         return new HdmiDeviceInfo(logicalAddress,
                 getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType,
-                getVendorId(), displayName);
+                getVendorId(), displayName, powerStatus);
     }
 
     @ServiceThreadOnly
@@ -1354,6 +1393,33 @@
             HdmiCecLocalDeviceTv tv = tv();
             if (tv == null) {
                 Slog.w(TAG, "Local tv device not available");
+                if (isPlaybackDevice()) {
+                    // if playback device itself is the active source,
+                    // return its own device info.
+                    if (playback() != null && playback().mIsActiveSource) {
+                        return playback().getDeviceInfo();
+                    }
+                    // Otherwise get the active source and look for it from the device list
+                    ActiveSource activeSource = mActiveSource;
+                    // If the active source is not set yet, return null
+                    if (!activeSource.isValid()) {
+                        return null;
+                    }
+                    if (audioSystem() != null) {
+                        HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+                        for (HdmiDeviceInfo info : audioSystem.getSafeCecDevicesLocked()) {
+                            if (info.getLogicalAddress() == activeSource.logicalAddress) {
+                                return info;
+                            }
+                        }
+                    }
+                    // If the device info is not in the list yet, return a device info with minimum
+                    // information from mActiveSource.
+                    return new HdmiDeviceInfo(activeSource.logicalAddress,
+                        activeSource.physicalAddress, pathToPortId(activeSource.physicalAddress),
+                        HdmiUtils.getTypeFromAddress(activeSource.logicalAddress), 0,
+                        HdmiUtils.getDefaultDeviceName(activeSource.logicalAddress));
+                }
                 return null;
             }
             ActiveSource activeSource = tv.getActiveSource();
@@ -1532,6 +1598,14 @@
         }
 
         @Override
+        public int getPhysicalAddress() {
+            enforceAccessPermission();
+            synchronized (mLock) {
+                return mPhysicalAddress;
+            }
+        }
+
+        @Override
         public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) {
             enforceAccessPermission();
             runOnServiceThread(new Runnable() {
@@ -1588,14 +1662,62 @@
         public List<HdmiDeviceInfo> getDeviceList() {
             enforceAccessPermission();
             HdmiCecLocalDeviceTv tv = tv();
-            synchronized (mLock) {
-                return (tv == null)
+            if (tv != null) {
+                synchronized (mLock) {
+                    return tv.getSafeCecDevicesLocked();
+                }
+            } else {
+                HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+                synchronized (mLock) {
+                    return (audioSystem == null)
                         ? Collections.<HdmiDeviceInfo>emptyList()
-                        : tv.getSafeCecDevicesLocked();
+                        : audioSystem.getSafeCecDevicesLocked();
+                }
             }
         }
 
         @Override
+        public void powerOffRemoteDevice(int logicalAddress, int powerStatus) {
+            enforceAccessPermission();
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    Slog.w(TAG, "Device "
+                            + logicalAddress + " power status is " + powerStatus
+                            + " before standby command sent out");
+                    sendCecCommand(HdmiCecMessageBuilder.buildStandby(
+                            getRemoteControlSourceAddress(), logicalAddress));
+                }
+            });
+        }
+
+        @Override
+        public void powerOnRemoteDevice(int logicalAddress, int powerStatus) {
+            // TODO(amyjojo): implement the method
+        }
+
+        @Override
+        // TODO(AMYJOJO): add a result callback
+        public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) {
+            enforceAccessPermission();
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(
+                            getRemoteControlSourceAddress(), physicalAddress);
+                    if (pathToPortId(physicalAddress) != Constants.INVALID_PORT_ID) {
+                        if (getSwitchDevice() != null) {
+                            getSwitchDevice().handleSetStreamPath(setStreamPath);
+                        } else {
+                            Slog.e(TAG, "Can't get the correct local device to handle routing.");
+                        }
+                    }
+                    sendCecCommand(setStreamPath);
+                }
+            });
+        }
+
+        @Override
         public void setSystemAudioVolume(final int oldIndex, final int newIndex,
                 final int maxIndex) {
             enforceAccessPermission();
@@ -1834,14 +1956,32 @@
                         Slog.w(TAG, "audio system is not in system audio mode");
                         return;
                     }
-                    int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume);
+                    audioSystem().reportAudioStatus(Constants.ADDR_TV);
+                }
+            });
+        }
 
-                    sendCecCommand(HdmiCecMessageBuilder
-                            .buildReportAudioStatus(
-                                    device.getDeviceInfo().getLogicalAddress(),
-                                    Constants.ADDR_TV,
-                                    scaledVolume,
-                                    isMute));
+        @Override
+        public void setSystemAudioModeOnForAudioOnlySource() {
+            enforceAccessPermission();
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    if (!isAudioSystemDevice()) {
+                        Slog.e(TAG, "Not an audio system device. Won't set system audio mode on");
+                        return;
+                    }
+                    if (audioSystem() == null) {
+                        Slog.e(TAG, "Audio System local device is not registered");
+                        return;
+                    }
+                    if (!audioSystem().checkSupportAndSetSystemAudioMode(true)) {
+                        Slog.e(TAG, "System Audio Mode is not supported.");
+                        return;
+                    }
+                    sendCecCommand(
+                            HdmiCecMessageBuilder.buildSetSystemAudioMode(
+                                    audioSystem().mAddress, Constants.ADDR_BROADCAST, true));
                 }
             });
         }
@@ -1851,30 +1991,54 @@
             if (!DumpUtils.checkDumpPermission(getContext(), TAG, writer)) return;
             final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
 
-            pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled);
             pw.println("mProhibitMode: " + mProhibitMode);
-            if (mCecController != null) {
-                pw.println("mCecController: ");
-                pw.increaseIndent();
-                mCecController.dump(pw);
-                pw.decreaseIndent();
-            }
+            pw.println("mPowerStatus: " + mPowerStatus);
+
+            // System settings
+            pw.println("System_settings:");
+            pw.increaseIndent();
+            pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled);
+            pw.println("mMhlInputChangeEnabled: " + mMhlInputChangeEnabled);
+            pw.decreaseIndent();
 
             pw.println("mMhlController: ");
             pw.increaseIndent();
             mMhlController.dump(pw);
             pw.decreaseIndent();
 
-            pw.println("mPortInfo: ");
-            pw.increaseIndent();
-            for (HdmiPortInfo hdmiPortInfo : mPortInfo) {
-                pw.println("- " + hdmiPortInfo);
+            HdmiUtils.dumpIterable(pw, "mPortInfo:", mPortInfo);
+            if (mCecController != null) {
+                pw.println("mCecController: ");
+                pw.increaseIndent();
+                mCecController.dump(pw);
+                pw.decreaseIndent();
             }
-            pw.decreaseIndent();
-            pw.println("mPowerStatus: " + mPowerStatus);
         }
     }
 
+    // Get the source address to send out commands to devices connected to the current device
+    // when other services interact with HdmiControlService.
+    private int getRemoteControlSourceAddress() {
+        if (isAudioSystemDevice()) {
+            return audioSystem().getDeviceInfo().getLogicalAddress();
+        } else if (isPlaybackDevice()) {
+            return playback().getDeviceInfo().getLogicalAddress();
+        }
+        return ADDR_UNREGISTERED;
+    }
+
+    // Get the switch device to do CEC routing control
+    @Nullable
+    private HdmiCecLocalDeviceSource getSwitchDevice() {
+        if (isAudioSystemDevice()) {
+            return audioSystem();
+        }
+        if (isPlaybackDevice()) {
+            return playback();
+        }
+        return null;
+    }
+
     @ServiceThreadOnly
     private void oneTouchPlay(final IHdmiControlCallback callback) {
         assertRunOnServiceThread();
@@ -2549,14 +2713,14 @@
     // For example, when receiving broadcast messages, all the device types will call this
     // method but only one of them will be the Active Source.
     protected void setAndBroadcastActiveSource(
-            HdmiCecMessage message, int physicalAddress, int deviceType) {
+            int physicalAddress, int deviceType, int source) {
         // If the device has both playback and audio system logical addresses,
         // playback will claim active source. Otherwise audio system will.
         if (deviceType == HdmiDeviceInfo.DEVICE_PLAYBACK) {
             HdmiCecLocalDevicePlayback playback = playback();
             playback.setIsActiveSource(true);
             playback.wakeUpIfActiveSource();
-            playback.maySendActiveSource(message.getSource());
+            playback.maySendActiveSource(source);
             setActiveSource(playback.mAddress, physicalAddress);
         }
 
@@ -2567,7 +2731,7 @@
             } else {
                 audioSystem.setIsActiveSource(true);
                 audioSystem.wakeUpIfActiveSource();
-                audioSystem.maySendActiveSource(message.getSource());
+                audioSystem.maySendActiveSource(source);
                 setActiveSource(audioSystem.mAddress, physicalAddress);
             }
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index 2a8117f..e44f1d1 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -16,19 +16,35 @@
 
 package com.android.server.hdmi;
 
+import android.annotation.Nullable;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.Xml;
 
+import com.android.internal.util.HexDump;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.hdmi.Constants.AudioCodec;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 /**
  * Various utilities to handle HDMI CEC messages.
  */
 final class HdmiUtils {
 
+    private static final String TAG = "HdmiUtils";
+
     private static final int[] ADDRESS_TO_TYPE = {
         HdmiDeviceInfo.DEVICE_TV,  // ADDR_TV
         HdmiDeviceInfo.DEVICE_RECORDER,  // ADDR_RECORDER_1
@@ -65,6 +81,12 @@
         "Secondary_TV",
     };
 
+    /**
+     * Return value of {@link #getLocalPortFromPhysicalAddress(int, int)}
+     */
+    static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
+    static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;
+
     private HdmiUtils() { /* cannot be instantiated */ }
 
     /**
@@ -317,4 +339,339 @@
                 info.getPhysicalAddress(), info.getPortId(), info.getDeviceType(),
                 info.getVendorId(), info.getDisplayName(), newPowerStatus);
     }
+
+    /**
+     * Dump a {@link SparseArray} to the print writer.
+     *
+     * <p>The dump is formatted:
+     * <pre>
+     *     name:
+     *        key = value
+     *        key = value
+     *        ...
+     * </pre>
+     */
+    static <T> void dumpSparseArray(IndentingPrintWriter pw, String name,
+            SparseArray<T> sparseArray) {
+        printWithTrailingColon(pw, name);
+        pw.increaseIndent();
+        int size = sparseArray.size();
+        for (int i = 0; i < size; i++) {
+            int key = sparseArray.keyAt(i);
+            T value = sparseArray.get(key);
+            pw.printPair(Integer.toString(key), value);
+            pw.println();
+        }
+        pw.decreaseIndent();
+    }
+
+    private static void printWithTrailingColon(IndentingPrintWriter pw, String name) {
+        pw.println(name.endsWith(":") ? name : name.concat(":"));
+    }
+
+    /**
+     * Dump a {@link Map} to the print writer.
+     *
+     * <p>The dump is formatted:
+     * <pre>
+     *     name:
+     *        key = value
+     *        key = value
+     *        ...
+     * </pre>
+     */
+    static <K, V> void dumpMap(IndentingPrintWriter pw, String name, Map<K, V> map) {
+        printWithTrailingColon(pw, name);
+        pw.increaseIndent();
+        for (Map.Entry<K, V> entry: map.entrySet()) {
+            pw.printPair(entry.getKey().toString(), entry.getValue());
+            pw.println();
+        }
+        pw.decreaseIndent();
+    }
+
+    /**
+     * Dump a {@link Map} to the print writer.
+     *
+     * <p>The dump is formatted:
+     * <pre>
+     *     name:
+     *        value
+     *        value
+     *        ...
+     * </pre>
+     */
+    static <T> void dumpIterable(IndentingPrintWriter pw, String name, Iterable<T> values) {
+        printWithTrailingColon(pw, name);
+        pw.increaseIndent();
+        for (T value : values) {
+            pw.println(value);
+        }
+        pw.decreaseIndent();
+    }
+
+    /**
+     * Method to parse target physical address to the port number on the current device.
+     *
+     * <p>This check assumes target address is valid.
+     *
+     * @param targetPhysicalAddress is the physical address of the target device
+     * @param myPhysicalAddress is the physical address of the current device
+     * @return
+     * If the target device is under the current device, return the port number of current device
+     * that the target device is connected to. This also applies to the devices that are indirectly
+     * connected to the current device.
+     *
+     * <p>If the target device has the same physical address as the current device, return
+     * {@link #TARGET_SAME_PHYSICAL_ADDRESS}.
+     *
+     * <p>If the target device is not under the current device, return
+     * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}.
+     */
+    public static int getLocalPortFromPhysicalAddress(
+            int targetPhysicalAddress, int myPhysicalAddress) {
+        if (myPhysicalAddress == targetPhysicalAddress) {
+            return TARGET_SAME_PHYSICAL_ADDRESS;
+        }
+
+        int mask = 0xF000;
+        int finalMask = 0xF000;
+        int maskedAddress = myPhysicalAddress;
+
+        while (maskedAddress != 0) {
+            maskedAddress = myPhysicalAddress & mask;
+            finalMask |= mask;
+            mask >>= 4;
+        }
+
+        int portAddress = targetPhysicalAddress & finalMask;
+        if ((portAddress & (finalMask << 4)) != myPhysicalAddress) {
+            return TARGET_NOT_UNDER_LOCAL_DEVICE;
+        }
+
+        mask <<= 4;
+        int port = portAddress & mask;
+        while ((port >> 4) != 0) {
+            port >>= 4;
+        }
+        return port;
+    }
+
+    public static class ShortAudioDescriptorXmlParser {
+        // We don't use namespaces
+        private static final String NS = null;
+
+        // return a list of devices config
+        public static List<DeviceConfig> parse(InputStream in)
+                throws XmlPullParserException, IOException {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
+            parser.setInput(in, null);
+            parser.nextTag();
+            return readDevices(parser);
+        }
+
+        private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                throw new IllegalStateException();
+            }
+            int depth = 1;
+            while (depth != 0) {
+                switch (parser.next()) {
+                    case XmlPullParser.END_TAG:
+                        depth--;
+                        break;
+                    case XmlPullParser.START_TAG:
+                        depth++;
+                        break;
+                }
+            }
+        }
+
+        private static List<DeviceConfig> readDevices(XmlPullParser parser)
+                throws XmlPullParserException, IOException {
+            List<DeviceConfig> devices = new ArrayList<>();
+
+            parser.require(XmlPullParser.START_TAG, NS, "config");
+            while (parser.next() != XmlPullParser.END_TAG) {
+                if (parser.getEventType() != XmlPullParser.START_TAG) {
+                    continue;
+                }
+                String name = parser.getName();
+                // Starts by looking for the device tag
+                if (name.equals("device")) {
+                    String deviceType = parser.getAttributeValue(null, "type");
+                    DeviceConfig config = null;
+                    if (deviceType != null) {
+                        config = readDeviceConfig(parser, deviceType);
+                    }
+                    if (config != null) {
+                        devices.add(config);
+                    }
+                } else {
+                    skip(parser);
+                }
+            }
+            return devices;
+        }
+
+        // Processes device tags in the config.
+        @Nullable
+        private static DeviceConfig readDeviceConfig(XmlPullParser parser, String deviceType)
+                throws XmlPullParserException, IOException {
+            List<CodecSad> codecSads = new ArrayList<>();
+            int format;
+            byte[] descriptor;
+
+            parser.require(XmlPullParser.START_TAG, NS, "device");
+            while (parser.next() != XmlPullParser.END_TAG) {
+                if (parser.getEventType() != XmlPullParser.START_TAG) {
+                    continue;
+                }
+                String tagName = parser.getName();
+
+                // Starts by looking for the supportedFormat tag
+                if (tagName.equals("supportedFormat")) {
+                    String codecAttriValue = parser.getAttributeValue(null, "format");
+                    String sadAttriValue = parser.getAttributeValue(null, "descriptor");
+                    format = (codecAttriValue) == null
+                            ? Constants.AUDIO_CODEC_NONE : formatNameToNum(codecAttriValue);
+                    descriptor = readSad(sadAttriValue);
+                    if (format != Constants.AUDIO_CODEC_NONE && descriptor != null) {
+                        codecSads.add(new CodecSad(format, descriptor));
+                    }
+                    parser.nextTag();
+                    parser.require(XmlPullParser.END_TAG, NS, "supportedFormat");
+                } else {
+                    skip(parser);
+                }
+            }
+            if (codecSads.size() == 0) {
+                return null;
+            }
+            return new DeviceConfig(deviceType, codecSads);
+        }
+
+        // Processes sad attribute in the supportedFormat.
+        @Nullable
+        private static byte[] readSad(String sad) {
+            if (sad == null || sad.length() == 0) {
+                return null;
+            }
+            byte[] sadBytes = HexDump.hexStringToByteArray(sad);
+            if (sadBytes.length != 3) {
+                Slog.w(TAG, "SAD byte array length is not 3. Length = " + sadBytes.length);
+                return null;
+            }
+            return sadBytes;
+        }
+
+        @AudioCodec
+        private static int formatNameToNum(String codecAttriValue) {
+            switch (codecAttriValue) {
+                case "AUDIO_FORMAT_NONE":
+                    return Constants.AUDIO_CODEC_NONE;
+                case "AUDIO_FORMAT_LPCM":
+                    return Constants.AUDIO_CODEC_LPCM;
+                case "AUDIO_FORMAT_DD":
+                    return Constants.AUDIO_CODEC_DD;
+                case "AUDIO_FORMAT_MPEG1":
+                    return Constants.AUDIO_CODEC_MPEG1;
+                case "AUDIO_FORMAT_MP3":
+                    return Constants.AUDIO_CODEC_MP3;
+                case "AUDIO_FORMAT_MPEG2":
+                    return Constants.AUDIO_CODEC_MPEG2;
+                case "AUDIO_FORMAT_AAC":
+                    return Constants.AUDIO_CODEC_AAC;
+                case "AUDIO_FORMAT_DTS":
+                    return Constants.AUDIO_CODEC_DTS;
+                case "AUDIO_FORMAT_ATRAC":
+                    return Constants.AUDIO_CODEC_ATRAC;
+                case "AUDIO_FORMAT_ONEBITAUDIO":
+                    return Constants.AUDIO_CODEC_ONEBITAUDIO;
+                case "AUDIO_FORMAT_DDP":
+                    return Constants.AUDIO_CODEC_DDP;
+                case "AUDIO_FORMAT_DTSHD":
+                    return Constants.AUDIO_CODEC_DTSHD;
+                case "AUDIO_FORMAT_TRUEHD":
+                    return Constants.AUDIO_CODEC_TRUEHD;
+                case "AUDIO_FORMAT_DST":
+                    return Constants.AUDIO_CODEC_DST;
+                case "AUDIO_FORMAT_WMAPRO":
+                    return Constants.AUDIO_CODEC_WMAPRO;
+                case "AUDIO_FORMAT_MAX":
+                    return Constants.AUDIO_CODEC_MAX;
+                default:
+                    return Constants.AUDIO_CODEC_NONE;
+            }
+        }
+    }
+
+    // Device configuration of its supported Codecs and their Short Audio Descriptors.
+    public static class DeviceConfig {
+        /** Name of the device. Should be {@link Constants.AudioDevice}. **/
+        public final String name;
+        /** List of a {@link CodecSad}. **/
+        public final List<CodecSad> supportedCodecs;
+
+        public DeviceConfig(String name, List<CodecSad> supportedCodecs) {
+            this.name = name;
+            this.supportedCodecs = supportedCodecs;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof DeviceConfig) {
+                DeviceConfig that = (DeviceConfig) obj;
+                return that.name.equals(this.name)
+                    && that.supportedCodecs.equals(this.supportedCodecs);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(
+                name,
+                supportedCodecs.hashCode());
+        }
+    }
+
+    // Short Audio Descriptor of a specific Codec
+    public static class CodecSad {
+        /** Audio Codec. Should be {@link Constants.AudioCodec}. **/
+        public final int audioCodec;
+        /**
+         * Three-byte Short Audio Descriptor. See HDMI Specification 1.4b CEC 13.15.3 and
+         * ANSI-CTA-861-F-FINAL 7.5.2 Audio Data Block for more details.
+         */
+        public final byte[] sad;
+
+        public CodecSad(int audioCodec, byte[] sad) {
+            this.audioCodec = audioCodec;
+            this.sad = sad;
+        }
+
+        public CodecSad(int audioCodec, String sad) {
+            this.audioCodec = audioCodec;
+            this.sad = HexDump.hexStringToByteArray(sad);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof CodecSad) {
+                CodecSad that = (CodecSad) obj;
+                return that.audioCodec == this.audioCodec
+                    && Arrays.equals(that.sad, this.sad);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(
+                audioCodec,
+                Arrays.hashCode(sad));
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 41bf01f..354d8d1 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -92,6 +92,9 @@
         if (source.mService.audioSystem() != null) {
             source = source.mService.audioSystem();
         }
+        if (source.getLocalActivePort() != Constants.CEC_SWITCH_HOME) {
+            source.switchInputOnReceivingNewActivePath(getSourcePath());
+        }
         source.setRoutingPort(Constants.CEC_SWITCH_HOME);
         source.setLocalActivePort(Constants.CEC_SWITCH_HOME);
     }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 979de66..669ff2b 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -138,6 +138,9 @@
     private final Context mContext;
     private final InputManagerHandler mHandler;
 
+    // Context cache used for loading pointer resources.
+    private Context mDisplayContext;
+
     private final File mDoubleTouchGestureEnableFile;
 
     private WindowManagerCallbacks mWindowManagerCallbacks;
@@ -1923,8 +1926,25 @@
     }
 
     // Native callback.
-    private PointerIcon getPointerIcon() {
-        return PointerIcon.getDefaultIcon(mContext);
+    private PointerIcon getPointerIcon(int displayId) {
+        return PointerIcon.getDefaultIcon(getContextForDisplay(displayId));
+    }
+
+    private Context getContextForDisplay(int displayId) {
+        if (mDisplayContext != null && mDisplayContext.getDisplay().getDisplayId() == displayId) {
+            return mDisplayContext;
+        }
+
+        if (mContext.getDisplay().getDisplayId() == displayId) {
+            mDisplayContext = mContext;
+            return mDisplayContext;
+        }
+
+        // Create and cache context for non-default display.
+        final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+        final Display display = displayManager.getDisplay(displayId);
+        mDisplayContext = mContext.createDisplayContext(display);
+        return mDisplayContext;
     }
 
     // Native callback.
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 5fa3f52..7ff6a2f 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -89,6 +89,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.provider.Settings;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
@@ -309,6 +310,7 @@
     private final HardKeyboardListener mHardKeyboardListener;
     private final AppOpsManager mAppOpsManager;
     private final UserManager mUserManager;
+    private final UserManagerInternal mUserManagerInternal;
 
     // All known input methods.  mMethodMap also serves as the global
     // lock for this class.
@@ -1405,6 +1407,7 @@
         }, true /*asyncHandler*/);
         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
         mUserManager = mContext.getSystemService(UserManager.class);
+        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
         mHardKeyboardListener = new HardKeyboardListener();
         mHasFeature = context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_INPUT_METHODS);
@@ -1489,7 +1492,7 @@
         // If the system is not ready or the device is not yed unlocked by the user, then we use
         // copy-on-write settings.
         final boolean useCopyOnWriteSettings =
-                !mSystemReady || !mUserManager.isUserUnlockingOrUnlocked(newUserId);
+                !mSystemReady || !mUserManagerInternal.isUserUnlockingOrUnlocked(newUserId);
         mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
         updateCurrentProfileIds();
         // Additional subtypes should be reset when the user is changed
@@ -1562,7 +1565,7 @@
                 mLastSystemLocales = mRes.getConfiguration().getLocales();
                 final int currentUserId = mSettings.getCurrentUserId();
                 mSettings.switchCurrentUser(currentUserId,
-                        !mUserManager.isUserUnlockingOrUnlocked(currentUserId));
+                        !mUserManagerInternal.isUserUnlockingOrUnlocked(currentUserId));
                 mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
                 mNotificationManager = mContext.getSystemService(NotificationManager.class);
                 mStatusBar = statusBar;
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java
index ac2dbdf..c16d1b4 100644
--- a/services/core/java/com/android/server/job/controllers/QuotaController.java
+++ b/services/core/java/com/android/server/job/controllers/QuotaController.java
@@ -26,7 +26,10 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
+import android.app.IUidObserver;
 import android.app.usage.UsageStatsManagerInternal;
 import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
 import android.content.BroadcastReceiver;
@@ -38,12 +41,14 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -69,6 +74,11 @@
  * bucket, it will be eligible to run. When a job's bucket changes, its new quota is immediately
  * applied to it.
  *
+ * Jobs are throttled while an app is not in a foreground state. All jobs are allowed to run
+ * freely when an app enters the foreground state and are restricted when the app leaves the
+ * foreground state. However, jobs that are started while the app is in the TOP state are not
+ * restricted regardless of the app's state change.
+ *
  * Test: atest com.android.server.job.controllers.QuotaControllerTest
  */
 public final class QuotaController extends StateController {
@@ -97,6 +107,12 @@
             data.put(packageName, obj);
         }
 
+        public void clear() {
+            for (int i = 0; i < mData.size(); ++i) {
+                mData.valueAt(i).clear();
+            }
+        }
+
         /** Removes all the data for the user, if there was any. */
         public void delete(int userId) {
             mData.delete(userId);
@@ -119,6 +135,11 @@
             return null;
         }
 
+        /** @see SparseArray#indexOfKey */
+        public int indexOfKey(int userId) {
+            return mData.indexOfKey(userId);
+        }
+
         /** Returns the userId at the given index. */
         public int keyAt(int index) {
             return mData.keyAt(index);
@@ -294,6 +315,17 @@
     /** Cached calculation results for each app, with the standby buckets as the array indices. */
     private final UserPackageMap<ExecutionStats[]> mExecutionStatsCache = new UserPackageMap<>();
 
+    /** List of UIDs currently in the foreground. */
+    private final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
+
+    /**
+     * List of jobs that started while the UID was in the TOP state. There will be no more than
+     * 16 ({@link JobSchedulerService.MAX_JOB_CONTEXTS_COUNT}) running at once, so an ArraySet is
+     * fine.
+     */
+    private final ArraySet<JobStatus> mTopStartedJobs = new ArraySet<>();
+
+    private final ActivityManagerInternal mActivityManagerInternal;
     private final AlarmManager mAlarmManager;
     private final ChargingTracker mChargeTracker;
     private final Handler mHandler;
@@ -343,6 +375,29 @@
                 }
             };
 
+    private final IUidObserver mUidObserver = new IUidObserver.Stub() {
+        @Override
+        public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+            mHandler.obtainMessage(MSG_UID_PROCESS_STATE_CHANGED, uid, procState).sendToTarget();
+        }
+
+        @Override
+        public void onUidGone(int uid, boolean disabled) {
+        }
+
+        @Override
+        public void onUidActive(int uid) {
+        }
+
+        @Override
+        public void onUidIdle(int uid, boolean disabled) {
+        }
+
+        @Override
+        public void onUidCachedChanged(int uid, boolean cached) {
+        }
+    };
+
     /**
      * The rolling window size for each standby bucket. Within each window, an app will have 10
      * minutes to run its jobs.
@@ -363,12 +418,15 @@
     private static final int MSG_CLEAN_UP_SESSIONS = 1;
     /** Check if a package is now within its quota. */
     private static final int MSG_CHECK_PACKAGE = 2;
+    /** Process state for a UID has changed. */
+    private static final int MSG_UID_PROCESS_STATE_CHANGED = 3;
 
     public QuotaController(JobSchedulerService service) {
         super(service);
         mHandler = new QcHandler(mContext.getMainLooper());
         mChargeTracker = new ChargingTracker();
         mChargeTracker.startTracking();
+        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
 
         // Set up the app standby bucketing tracker
@@ -376,6 +434,14 @@
                 UsageStatsManagerInternal.class);
         usageStats.addAppIdleStateChangeListener(new StandbyTracker());
 
+        try {
+            ActivityManager.getService().registerUidObserver(mUidObserver,
+                    ActivityManager.UID_OBSERVER_PROCSTATE,
+                    ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, null);
+        } catch (RemoteException e) {
+            // ignored; both services live in system_server
+        }
+
         onConstantsUpdatedLocked();
     }
 
@@ -399,11 +465,15 @@
         if (DEBUG) Slog.d(TAG, "Prepping for " + jobStatus.toShortString());
         final int userId = jobStatus.getSourceUserId();
         final String packageName = jobStatus.getSourcePackageName();
+        final int uid = jobStatus.getSourceUid();
         Timer timer = mPkgTimers.get(userId, packageName);
         if (timer == null) {
-            timer = new Timer(userId, packageName);
+            timer = new Timer(uid, userId, packageName);
             mPkgTimers.add(userId, packageName, timer);
         }
+        if (mActivityManagerInternal.getUidProcessState(uid) == ActivityManager.PROCESS_STATE_TOP) {
+            mTopStartedJobs.add(jobStatus);
+        }
         timer.startTrackingJob(jobStatus);
     }
 
@@ -421,6 +491,7 @@
             if (jobs != null) {
                 jobs.remove(jobStatus);
             }
+            mTopStartedJobs.remove(jobStatus);
         }
     }
 
@@ -511,6 +582,7 @@
             mInQuotaAlarmListeners.delete(userId, packageName);
         }
         mExecutionStatsCache.delete(userId, packageName);
+        mForegroundUids.delete(uid);
     }
 
     @Override
@@ -522,6 +594,20 @@
         mExecutionStatsCache.delete(userId);
     }
 
+    private boolean isUidInForeground(int uid) {
+        if (UserHandle.isCore(uid)) {
+            return true;
+        }
+        synchronized (mLock) {
+            return mForegroundUids.get(uid);
+        }
+    }
+
+    /** @return true if the job was started while the app was in the TOP state. */
+    private boolean isTopStartedJob(@NonNull final JobStatus jobStatus) {
+        return mTopStartedJobs.contains(jobStatus);
+    }
+
     /**
      * Returns an appropriate standby bucket for the job, taking into account any standby
      * exemptions.
@@ -537,9 +623,15 @@
 
     private boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) {
         final int standbyBucket = getEffectiveStandbyBucket(jobStatus);
-        // Jobs for the active app should always be able to run.
-        return jobStatus.uidActive || isWithinQuotaLocked(
-                jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket);
+        Timer timer = mPkgTimers.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
+        // A job is within quota if one of the following is true:
+        //   1. it was started while the app was in the TOP state
+        //   2. the app is currently in the foreground
+        //   3. the app overall is within its quota
+        return isTopStartedJob(jobStatus)
+                || isUidInForeground(jobStatus.getSourceUid())
+                || isWithinQuotaLocked(
+                      jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket);
     }
 
     private boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName,
@@ -800,7 +892,7 @@
         final boolean isCharging = mChargeTracker.isCharging();
         if (DEBUG) Slog.d(TAG, "handleNewChargingStateLocked: " + isCharging);
         // Deal with Timers first.
-        mPkgTimers.forEach((t) -> t.onChargingChanged(nowElapsed, isCharging));
+        mPkgTimers.forEach((t) -> t.onStateChanged(nowElapsed, isCharging));
         // Now update jobs.
         maybeUpdateAllConstraintsLocked();
     }
@@ -837,10 +929,15 @@
         boolean changed = false;
         for (int i = jobs.size() - 1; i >= 0; --i) {
             final JobStatus js = jobs.valueAt(i);
-            if (js.uidActive) {
-                // Jobs for the active app should always be able to run.
+            if (isTopStartedJob(js)) {
+                // Job was started while the app was in the TOP state so we should allow it to
+                // finish.
                 changed |= js.setQuotaConstraintSatisfied(true);
-            } else if (realStandbyBucket == getEffectiveStandbyBucket(js)) {
+            } else if (realStandbyBucket != ACTIVE_INDEX
+                    && realStandbyBucket == getEffectiveStandbyBucket(js)) {
+                // An app in the ACTIVE bucket may be out of quota while the job could be in quota
+                // for some reason. Therefore, avoid setting the real value here and check each job
+                // individually.
                 changed |= js.setQuotaConstraintSatisfied(realInQuota);
             } else {
                 // This job is somehow exempted. Need to determine its own quota status.
@@ -854,7 +951,7 @@
             maybeScheduleStartAlarmLocked(userId, packageName, realStandbyBucket);
         } else {
             QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName);
-            if (alarmListener != null) {
+            if (alarmListener != null && alarmListener.isWaiting()) {
                 mAlarmManager.cancel(alarmListener);
                 // Set the trigger time to 0 so that the alarm doesn't think it's still waiting.
                 alarmListener.setTriggerTime(0);
@@ -863,6 +960,56 @@
         return changed;
     }
 
+    private class UidConstraintUpdater implements Consumer<JobStatus> {
+        private final UserPackageMap<Integer> mToScheduleStartAlarms = new UserPackageMap<>();
+        public boolean wasJobChanged;
+
+        @Override
+        public void accept(JobStatus jobStatus) {
+            wasJobChanged |= jobStatus.setQuotaConstraintSatisfied(isWithinQuotaLocked(jobStatus));
+            final int userId = jobStatus.getSourceUserId();
+            final String packageName = jobStatus.getSourcePackageName();
+            final int realStandbyBucket = jobStatus.getStandbyBucket();
+            if (isWithinQuotaLocked(userId, packageName, realStandbyBucket)) {
+                QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName);
+                if (alarmListener != null && alarmListener.isWaiting()) {
+                    mAlarmManager.cancel(alarmListener);
+                    // Set the trigger time to 0 so that the alarm doesn't think it's still waiting.
+                    alarmListener.setTriggerTime(0);
+                }
+            } else {
+                mToScheduleStartAlarms.add(userId, packageName, realStandbyBucket);
+            }
+        }
+
+        void postProcess() {
+            for (int u = 0; u < mToScheduleStartAlarms.numUsers(); ++u) {
+                final int userId = mToScheduleStartAlarms.keyAt(u);
+                for (int p = 0; p < mToScheduleStartAlarms.numPackagesForUser(userId); ++p) {
+                    final String packageName = mToScheduleStartAlarms.keyAt(u, p);
+                    final int standbyBucket = mToScheduleStartAlarms.get(userId, packageName);
+                    maybeScheduleStartAlarmLocked(userId, packageName, standbyBucket);
+                }
+            }
+        }
+
+        void reset() {
+            wasJobChanged = false;
+            mToScheduleStartAlarms.clear();
+        }
+    }
+
+    private final UidConstraintUpdater mUpdateUidConstraints = new UidConstraintUpdater();
+
+    private boolean maybeUpdateConstraintForUidLocked(final int uid) {
+        mService.getJobStore().forEachJobForSourceUid(uid, mUpdateUidConstraints);
+
+        mUpdateUidConstraints.postProcess();
+        boolean changed = mUpdateUidConstraints.wasJobChanged;
+        mUpdateUidConstraints.reset();
+        return changed;
+    }
+
     /**
      * Maybe schedule a non-wakeup alarm for the next time this package will have quota to run
      * again. This should only be called if the package is already out of quota.
@@ -1052,6 +1199,7 @@
 
     private final class Timer {
         private final Package mPkg;
+        private final int mUid;
 
         // List of jobs currently running for this app that started when the app wasn't in the
         // foreground.
@@ -1059,16 +1207,18 @@
         private long mStartTimeElapsed;
         private int mBgJobCount;
 
-        Timer(int userId, String packageName) {
+        Timer(int uid, int userId, String packageName) {
             mPkg = new Package(userId, packageName);
+            mUid = uid;
         }
 
         void startTrackingJob(@NonNull JobStatus jobStatus) {
-            if (jobStatus.uidActive) {
-                // We intentionally don't pay attention to fg state changes after a job has started.
+            if (isTopStartedJob(jobStatus)) {
+                // We intentionally don't pay attention to fg state changes after a TOP job has
+                // started.
                 if (DEBUG) {
                     Slog.v(TAG,
-                            "Timer ignoring " + jobStatus.toShortString() + " because uidActive");
+                            "Timer ignoring " + jobStatus.toShortString() + " because isTop");
                 }
                 return;
             }
@@ -1076,7 +1226,7 @@
             synchronized (mLock) {
                 // Always track jobs, even when charging.
                 mRunningBgJobs.add(jobStatus);
-                if (!mChargeTracker.isCharging()) {
+                if (shouldTrackLocked()) {
                     mBgJobCount++;
                     if (mRunningBgJobs.size() == 1) {
                         // Started tracking the first job.
@@ -1142,6 +1292,10 @@
             }
         }
 
+        boolean isRunning(JobStatus jobStatus) {
+            return mRunningBgJobs.contains(jobStatus);
+        }
+
         long getCurrentDuration(long nowElapsed) {
             synchronized (mLock) {
                 return !isActive() ? 0 : nowElapsed - mStartTimeElapsed;
@@ -1154,17 +1308,21 @@
             }
         }
 
-        void onChargingChanged(long nowElapsed, boolean isCharging) {
+        private boolean shouldTrackLocked() {
+            return !mChargeTracker.isCharging() && !mForegroundUids.get(mUid);
+        }
+
+        void onStateChanged(long nowElapsed, boolean isQuotaFree) {
             synchronized (mLock) {
-                if (isCharging) {
+                if (isQuotaFree) {
                     emitSessionLocked(nowElapsed);
-                } else {
+                } else if (shouldTrackLocked()) {
                     // Start timing from unplug.
                     if (mRunningBgJobs.size() > 0) {
                         mStartTimeElapsed = nowElapsed;
                         // NOTE: this does have the unfortunate consequence that if the device is
-                        // repeatedly plugged in and unplugged, the job count for a package may be
-                        // artificially high.
+                        // repeatedly plugged in and unplugged, or an app changes foreground state
+                        // very frequently, the job count for a package may be artificially high.
                         mBgJobCount = mRunningBgJobs.size();
                         // Starting the timer means that all cached execution stats are now
                         // incorrect.
@@ -1371,6 +1529,38 @@
                         }
                         break;
                     }
+                    case MSG_UID_PROCESS_STATE_CHANGED: {
+                        final int uid = msg.arg1;
+                        final int procState = msg.arg2;
+                        final int userId = UserHandle.getUserId(uid);
+                        final long nowElapsed = sElapsedRealtimeClock.millis();
+
+                        synchronized (mLock) {
+                            boolean isQuotaFree;
+                            if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+                                mForegroundUids.put(uid, true);
+                                isQuotaFree = true;
+                            } else {
+                                mForegroundUids.delete(uid);
+                                isQuotaFree = false;
+                            }
+                            // Update Timers first.
+                            final int userIndex = mPkgTimers.indexOfKey(userId);
+                            if (userIndex != -1) {
+                                final int numPkgs = mPkgTimers.numPackagesForUser(userId);
+                                for (int p = 0; p < numPkgs; ++p) {
+                                    Timer t = mPkgTimers.valueAt(userIndex, p);
+                                    if (t != null) {
+                                        t.onStateChanged(nowElapsed, isQuotaFree);
+                                    }
+                                }
+                            }
+                            if (maybeUpdateConstraintForUidLocked(uid)) {
+                                mStateChangedListener.onControllerStateChanged();
+                            }
+                        }
+                        break;
+                    }
                 }
             }
         }
@@ -1420,6 +1610,12 @@
 
     @VisibleForTesting
     @NonNull
+    SparseBooleanArray getForegroundUids() {
+        return mForegroundUids;
+    }
+
+    @VisibleForTesting
+    @NonNull
     Handler getHandler() {
         return mHandler;
     }
@@ -1450,6 +1646,10 @@
         pw.println("In parole: " + mInParole);
         pw.println();
 
+        pw.print("Foreground UIDs: ");
+        pw.println(mForegroundUids.toString());
+        pw.println();
+
         mTrackedJobs.forEach((jobs) -> {
             for (int j = 0; j < jobs.size(); j++) {
                 final JobStatus js = jobs.valueAt(j);
@@ -1460,6 +1660,9 @@
                 js.printUniqueId(pw);
                 pw.print(" from ");
                 UserHandle.formatUid(pw, js.getSourceUid());
+                if (mTopStartedJobs.contains(js)) {
+                    pw.print(" (TOP)");
+                }
                 pw.println();
 
                 pw.increaseIndent();
@@ -1511,6 +1714,11 @@
         proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isCharging());
         proto.write(StateControllerProto.QuotaController.IS_IN_PAROLE, mInParole);
 
+        for (int i = 0; i < mForegroundUids.size(); ++i) {
+            proto.write(StateControllerProto.QuotaController.FOREGROUND_UIDS,
+                    mForegroundUids.keyAt(i));
+        }
+
         mTrackedJobs.forEach((jobs) -> {
             for (int j = 0; j < jobs.size(); j++) {
                 final JobStatus js = jobs.valueAt(j);
@@ -1526,6 +1734,8 @@
                 proto.write(
                         StateControllerProto.QuotaController.TrackedJob.EFFECTIVE_STANDBY_BUCKET,
                         getEffectiveStandbyBucket(js));
+                proto.write(StateControllerProto.QuotaController.TrackedJob.IS_TOP_STARTED_JOB,
+                        mTopStartedJobs.contains(js));
                 proto.write(StateControllerProto.QuotaController.TrackedJob.HAS_QUOTA,
                         js.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
                 proto.write(StateControllerProto.QuotaController.TrackedJob.REMAINING_QUOTA_MS,
diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java
index 29465ad..9e33943 100644
--- a/services/core/java/com/android/server/location/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/GnssConfiguration.java
@@ -29,7 +29,10 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
@@ -66,6 +69,7 @@
             "USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL";
     private static final String CONFIG_GPS_LOCK = "GPS_LOCK";
     private static final String CONFIG_ES_EXTENSION_SEC = "ES_EXTENSION_SEC";
+    public static final String CONFIG_NFW_PROXY_APPS = "NFW_PROXY_APPS";
 
     // Limit on NI emergency mode time extension after emergency sessions ends
     private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300;  // 5 minute maximum
@@ -171,6 +175,32 @@
     }
 
     /**
+     * Returns the list of proxy apps from the value of config parameter NFW_PROXY_APPS or
+     * {@Collections.EMPTY_LIST} if no value is provided.
+     */
+    List<String> getProxyApps() {
+        // Space separated list of Android proxy app package names.
+        String proxyAppsStr = mProperties.getProperty(CONFIG_NFW_PROXY_APPS);
+        if (TextUtils.isEmpty(proxyAppsStr)) {
+            return Collections.EMPTY_LIST;
+        }
+
+        String[] proxyAppsArray = proxyAppsStr.trim().split("\\s+");
+        if (proxyAppsArray.length == 0) {
+            return Collections.EMPTY_LIST;
+        }
+
+        // TODO(b/122856486): Validate proxy app names so that a system app or some popular app
+        //                    with location permission is not specified as a proxy app.
+        ArrayList proxyApps = new ArrayList(proxyAppsArray.length);
+        for (String proxyApp : proxyAppsArray) {
+            proxyApps.add(proxyApp);
+        }
+
+        return proxyApps;
+    }
+
+    /**
      * Updates the GNSS HAL satellite blacklist.
      */
     void setSatelliteBlacklist(int[] constellations, int[] svids) {
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 269767a..d346ddc 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -64,6 +64,7 @@
 import android.telephony.gsm.GsmCellLocation;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.StatsLog;
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.location.GpsNetInitiatedHandler;
@@ -371,6 +372,7 @@
     private boolean mSuplEsEnabled = false;
 
     private final Context mContext;
+    private final Looper mLooper;
     private final LocationExtras mLocationExtras = new LocationExtras();
     private final GnssStatusListenerHelper mGnssStatusListenerHelper;
     private final GnssSatelliteBlacklistHelper mGnssSatelliteBlacklistHelper;
@@ -381,6 +383,7 @@
     private final NtpTimeHelper mNtpTimeHelper;
     private final GnssBatchingProvider mGnssBatchingProvider;
     private final GnssGeofenceProvider mGnssGeofenceProvider;
+    private GnssVisibilityControl mGnssVisibilityControl;
 
     // Handler for processing events
     private Handler mHandler;
@@ -555,6 +558,9 @@
         mC2KServerPort = mGnssConfiguration.getC2KPort(TCP_MIN_PORT);
         mNIHandler.setEmergencyExtensionSeconds(mGnssConfiguration.getEsExtensionSec());
         mSuplEsEnabled = mGnssConfiguration.getSuplEs(0) == 1;
+        if (mGnssVisibilityControl != null) {
+            mGnssVisibilityControl.updateProxyApps(mGnssConfiguration.getProxyApps());
+        }
     }
 
     public GnssLocationProvider(Context context, LocationProviderManager locationProviderManager,
@@ -562,6 +568,7 @@
         super(locationProviderManager);
 
         mContext = context;
+        mLooper = looper;
 
         // Create a wake lock
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -1704,6 +1711,24 @@
                         ", response: " + userResponse);
             }
             native_send_ni_response(notificationId, userResponse);
+
+            StatsLog.write(StatsLog.GNSS_NI_EVENT_REPORTED,
+                    StatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_RESPONSE,
+                    notificationId,
+                    /* niType= */ 0,
+                    /* needNotify= */ false,
+                    /* needVerify= */ false,
+                    /* privacyOverride= */ false,
+                    /* timeout= */ 0,
+                    /* defaultResponse= */ 0,
+                    /* requestorId= */ null,
+                    /* text= */ null,
+                    /* requestorIdEncoding= */ 0,
+                    /* textEncoding= */ 0,
+                    mSuplEsEnabled,
+                    mEnabled,
+                    userResponse);
+
             return true;
         }
     };
@@ -1753,6 +1778,22 @@
         notification.textEncoding = textEncoding;
 
         mNIHandler.handleNiNotification(notification);
+        StatsLog.write(StatsLog.GNSS_NI_EVENT_REPORTED,
+                StatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_REQUEST,
+                notification.notificationId,
+                notification.niType,
+                notification.needNotify,
+                notification.needVerify,
+                notification.privacyOverride,
+                notification.timeout,
+                notification.defaultResponse,
+                notification.requestorId,
+                notification.text,
+                notification.requestorIdEncoding,
+                notification.textEncoding,
+                mSuplEsEnabled,
+                mEnabled,
+                /* userResponse= */ 0);
     }
 
     /**
@@ -1834,6 +1875,27 @@
         }
     }
 
+    // Implements method nfwNotifyCb() in IGnssVisibilityControlCallback.hal.
+    @NativeEntryPoint
+    private void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
+            String otherProtocolStackName, byte requestor, String requestorId, byte responseType,
+            boolean inEmergencyMode, boolean isCachedLocation) {
+        if (mGnssVisibilityControl == null) {
+            Log.e(TAG, "reportNfwNotification: mGnssVisibilityControl is not initialized.");
+            return;
+        }
+
+        mGnssVisibilityControl.reportNfwNotification(proxyAppPackageName, protocolStack,
+                otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode,
+                isCachedLocation);
+    }
+
+    // Implements method isInEmergencySession() in IGnssVisibilityControlCallback.hal.
+    @NativeEntryPoint
+    boolean isInEmergencySession() {
+        return mNIHandler.getInEmergency();
+    }
+
     private void sendMessage(int message, int arg, Object obj) {
         // hold a wake lock until this message is delivered
         // note that this assumes the message will not be removed from the queue before
@@ -1922,6 +1984,10 @@
                 native_cleanup();
             }
 
+            if (native_is_gnss_visibility_control_supported()) {
+                mGnssVisibilityControl = new GnssVisibilityControl(mContext, mLooper);
+            }
+
             // load default GPS configuration
             // (this configuration might change in the future based on SIM changes)
             reloadGpsProperties();
@@ -2079,6 +2145,8 @@
 
     private static native boolean native_is_supported();
 
+    private static native boolean native_is_gnss_visibility_control_supported();
+
     private static native void native_init_once();
 
     private native boolean native_init();
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
new file mode 100644
index 0000000..845aa9d
--- /dev/null
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.annotation.SuppressLint;
+import android.app.AppOpsManager;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Handles GNSS non-framework location access user visibility and control.
+ *
+ * The state of the GnssVisibilityControl object must be accessed/modified through the Handler
+ * thread only.
+ */
+class GnssVisibilityControl {
+    private static final String TAG = "GnssVisibilityControl";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    // Constants related to non-framework (NFW) location access permission proxy apps.
+    private static final String NFW_PROXY_APP_PKG_ACTIVITY_NAME_SUFFIX =
+            ".NonFrameworkLocationAccessActivity";
+    private static final String NFW_INTENT_ACTION_NFW_LOCATION_ACCESS_SUFFIX =
+            ".intent.action.NON_FRAMEWORK_LOCATION_ACCESS";
+    private static final String NFW_INTENT_TYPE = "text/plain";
+
+    private static final String LOCATION_PERMISSION_NAME =
+            "android.permission.ACCESS_FINE_LOCATION";
+
+    // Wakelocks
+    private static final String WAKELOCK_KEY = TAG;
+    private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
+    private final PowerManager.WakeLock mWakeLock;
+
+    private final AppOpsManager mAppOps;
+    private final PackageManager mPackageManager;
+
+    private final Handler mHandler;
+    private final Context mContext;
+
+    // Number of non-framework location access proxy apps is expected to be small (< 5).
+    private static final int HASH_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
+    private HashMap<String, Boolean> mProxyAppToLocationPermissions = new HashMap<>(
+            HASH_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS);
+
+    private PackageManager.OnPermissionsChangedListener mOnPermissionsChangedListener =
+            uid -> postEvent(() -> handlePermissionsChanged(uid));
+
+    GnssVisibilityControl(Context context, Looper looper) {
+        mContext = context;
+        PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
+        mHandler = new Handler(looper);
+        mAppOps = mContext.getSystemService(AppOpsManager.class);
+        mPackageManager = mContext.getPackageManager();
+        // TODO(b/122855984): Handle global location settings on/off.
+        // TODO(b/122856189): Handle roaming case.
+    }
+
+    void updateProxyApps(List<String> nfwLocationAccessProxyApps) {
+        // NOTE: This class doesn't explicitly register and listen for SIM_STATE_CHANGED event
+        //       but rather piggy backs on the GnssLocationProvider SIM_STATE_CHANGED handling
+        //       so that the order of processing is preserved. GnssLocationProvider should
+        //       first load the new config parameters for the new SIM and then call this method.
+        postEvent(() -> handleSubscriptionOrSimChanged(nfwLocationAccessProxyApps));
+    }
+
+    void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
+            String otherProtocolStackName, byte requestor, String requestorId, byte responseType,
+            boolean inEmergencyMode, boolean isCachedLocation) {
+        postEvent(() -> handleNfwNotification(
+                new NfwNotification(proxyAppPackageName, protocolStack, otherProtocolStackName,
+                        requestor, requestorId, responseType, inEmergencyMode, isCachedLocation)));
+    }
+
+    private void handleSubscriptionOrSimChanged(List<String> nfwLocationAccessProxyApps) {
+        if (nfwLocationAccessProxyApps.isEmpty()) {
+            // Stop listening for app permission changes. Clear the app list in GNSS HAL.
+            if (!mProxyAppToLocationPermissions.isEmpty()) {
+                mPackageManager.removeOnPermissionsChangeListener(mOnPermissionsChangedListener);
+                mProxyAppToLocationPermissions.clear();
+                updateNfwLocationAccessProxyAppsInGnssHal();
+            }
+            return;
+        }
+
+        if (mProxyAppToLocationPermissions.isEmpty()) {
+            mPackageManager.addOnPermissionsChangeListener(mOnPermissionsChangedListener);
+        } else {
+            mProxyAppToLocationPermissions.clear();
+        }
+
+        for (String proxApp : nfwLocationAccessProxyApps) {
+            mProxyAppToLocationPermissions.put(proxApp, hasLocationPermission(proxApp));
+        }
+
+        updateNfwLocationAccessProxyAppsInGnssHal();
+    }
+
+    // Represents NfwNotification structure in IGnssVisibilityControlCallback.hal
+    private static class NfwNotification {
+        private static final String KEY_PROTOCOL_STACK = "ProtocolStack";
+        private static final String KEY_OTHER_PROTOCOL_STACK_NAME = "OtherProtocolStackName";
+        private static final String KEY_REQUESTOR = "Requestor";
+        private static final String KEY_REQUESTOR_ID = "RequestorId";
+        private static final String KEY_RESPONSE_TYPE = "ResponseType";
+        private static final String KEY_IN_EMERGENCY_MODE = "InEmergencyMode";
+        private static final String KEY_IS_CACHED_LOCATION = "IsCachedLocation";
+
+        // This must match with NfwResponseType enum in IGnssVisibilityControlCallback.hal.
+        private static final byte NFW_RESPONSE_TYPE_REJECTED = 0;
+        private static final byte NFW_RESPONSE_TYPE_ACCEPTED_NO_LOCATION_PROVIDED = 1;
+        private static final byte NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED = 2;
+
+        private final String mProxyAppPackageName;
+        private final byte mProtocolStack;
+        private final String mOtherProtocolStackName;
+        private final byte mRequestor;
+        private final String mRequestorId;
+        private final byte mResponseType;
+        private final boolean mInEmergencyMode;
+        private final boolean mIsCachedLocation;
+
+        NfwNotification(String proxyAppPackageName, byte protocolStack,
+                String otherProtocolStackName, byte requestor, String requestorId,
+                byte responseType, boolean inEmergencyMode, boolean isCachedLocation) {
+            mProxyAppPackageName = proxyAppPackageName;
+            mProtocolStack = protocolStack;
+            mOtherProtocolStackName = otherProtocolStackName;
+            mRequestor = requestor;
+            mRequestorId = requestorId;
+            mResponseType = responseType;
+            mInEmergencyMode = inEmergencyMode;
+            mIsCachedLocation = isCachedLocation;
+        }
+
+        void copyFieldsToIntent(Intent intent) {
+            intent.putExtra(KEY_PROTOCOL_STACK, mProtocolStack);
+            if (!TextUtils.isEmpty(mOtherProtocolStackName)) {
+                intent.putExtra(KEY_OTHER_PROTOCOL_STACK_NAME, mOtherProtocolStackName);
+            }
+            intent.putExtra(KEY_REQUESTOR, mRequestor);
+            if (!TextUtils.isEmpty(mRequestorId)) {
+                intent.putExtra(KEY_REQUESTOR_ID, mRequestorId);
+            }
+            intent.putExtra(KEY_RESPONSE_TYPE, mResponseType);
+            intent.putExtra(KEY_IN_EMERGENCY_MODE, mInEmergencyMode);
+            if (mResponseType == NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED) {
+                intent.putExtra(KEY_IS_CACHED_LOCATION, mIsCachedLocation);
+            }
+        }
+
+        @SuppressLint("DefaultLocale")
+        public String toString() {
+            return String.format(
+                    "[Notification] proxyAppPackageName: %s, protocolStack: %d"
+                            + ", otherProtocolStackName: %s, requestor: %d, requestorId: %s"
+                            + ", responseType: %d, inEmergencyMode: %b, isCachedLocation: %b",
+                    mProxyAppPackageName, mProtocolStack, mOtherProtocolStackName,
+                    mRequestor, mRequestorId, mResponseType, mInEmergencyMode, mIsCachedLocation);
+        }
+
+        String getResponseTypeAsString() {
+            switch (mResponseType) {
+                case NFW_RESPONSE_TYPE_REJECTED:
+                    return "REJECTED";
+                case NFW_RESPONSE_TYPE_ACCEPTED_NO_LOCATION_PROVIDED:
+                    return "ACCEPTED_NO_LOCATION_PROVIDED";
+                case NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED:
+                    return "ACCEPTED_LOCATION_PROVIDED";
+                default:
+                    return "<Unknown>";
+            }
+        }
+    }
+
+    private void handlePermissionsChanged(int uid) {
+        if (mProxyAppToLocationPermissions.isEmpty()) {
+            return;
+        }
+
+        for (Map.Entry<String, Boolean> entry : mProxyAppToLocationPermissions.entrySet()) {
+            // Cannot cache uid since the application could be uninstalled and reinstalled.
+            final String proxyApp = entry.getKey();
+            final Integer nfwProxyAppUid = getApplicationUid(proxyApp);
+            if (nfwProxyAppUid == null || nfwProxyAppUid != uid) {
+                continue;
+            }
+
+            final boolean isLocationPermissionEnabled = hasLocationPermission(proxyApp);
+            if (isLocationPermissionEnabled != entry.getValue()) {
+                Log.i(TAG, "Location permission setting is changed to "
+                        + (isLocationPermissionEnabled ? "enabled" : "disabled")
+                        + " for non-framework location access proxy app "
+                        + proxyApp);
+                entry.setValue(isLocationPermissionEnabled);
+                updateNfwLocationAccessProxyAppsInGnssHal();
+                return;
+            }
+        }
+    }
+
+    private Integer getApplicationUid(String pkgName) {
+        try {
+            return mPackageManager.getApplicationInfo(pkgName, 0).uid;
+        } catch (PackageManager.NameNotFoundException e) {
+            if (DEBUG) {
+                Log.d(TAG, "Non-framework location access proxy app "
+                        + pkgName + " is not found.");
+            }
+            return null;
+        }
+    }
+
+    private boolean hasLocationPermission(String pkgName) {
+        return mPackageManager.checkPermission(LOCATION_PERMISSION_NAME, pkgName)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    private void updateNfwLocationAccessProxyAppsInGnssHal() {
+        // Get a count of proxy apps with location permission enabled to array creation size.
+        int countLocationPermissionEnabledProxyApps = 0;
+        for (Boolean hasLocationPermissionEnabled : mProxyAppToLocationPermissions.values()) {
+            if (hasLocationPermissionEnabled) {
+                ++countLocationPermissionEnabledProxyApps;
+            }
+        }
+
+        int i = 0;
+        String[] locationPermissionEnabledProxyApps =
+                new String[countLocationPermissionEnabledProxyApps];
+        for (Map.Entry<String, Boolean> entry : mProxyAppToLocationPermissions.entrySet()) {
+            final String proxyApp = entry.getKey();
+            final boolean hasLocationPermissionEnabled = entry.getValue();
+            if (hasLocationPermissionEnabled) {
+                locationPermissionEnabledProxyApps[i++] = proxyApp;
+            }
+        }
+
+        String proxyAppsStr = Arrays.toString(locationPermissionEnabledProxyApps);
+        Log.i(TAG, "Updating non-framework location access proxy apps in the GNSS HAL to: "
+                + proxyAppsStr);
+        boolean result = native_enable_nfw_location_access(locationPermissionEnabledProxyApps);
+        if (!result) {
+            Log.e(TAG, "Failed to update non-framework location access proxy apps in the"
+                    + " GNSS HAL to: " + proxyAppsStr);
+        }
+    }
+
+    private void handleNfwNotification(NfwNotification nfwNotification) {
+        if (DEBUG) Log.d(TAG, nfwNotification.toString());
+
+        final String proxyAppPackageName = nfwNotification.mProxyAppPackageName;
+        if (TextUtils.isEmpty(proxyAppPackageName)) {
+            Log.e(TAG, "ProxyAppPackageName field is not set. Not sending intent to proxy app for "
+                    + nfwNotification);
+            return;
+        }
+
+        Boolean isLocationPermissionEnabled = mProxyAppToLocationPermissions.get(
+                proxyAppPackageName);
+        if (isLocationPermissionEnabled == null) {
+            // App is not in the configured list.
+            Log.e(TAG, "Could not find proxy app with name: " + proxyAppPackageName + " in the "
+                    + "value specified for config parameter: "
+                    + GnssConfiguration.CONFIG_NFW_PROXY_APPS + ". Not sending intent to proxy app"
+                    + " for " + nfwNotification);
+            return;
+        }
+
+        // Send intent to non-framework location proxy app with notification information.
+        final Intent intent = new Intent(
+                proxyAppPackageName + NFW_INTENT_ACTION_NFW_LOCATION_ACCESS_SUFFIX);
+        final String proxAppActivityName =
+                proxyAppPackageName + NFW_PROXY_APP_PKG_ACTIVITY_NAME_SUFFIX;
+        intent.setClassName(proxyAppPackageName, proxAppActivityName);
+        intent.setType(NFW_INTENT_TYPE);
+        nfwNotification.copyFieldsToIntent(intent);
+
+        // Check if the proxy app is still installed.
+        final Integer clsAppUid = getApplicationUid(proxyAppPackageName);
+        if (clsAppUid == null || intent.resolveActivity(mPackageManager) == null) {
+            Log.i(TAG, "Proxy application " + proxyAppPackageName + " and/or activity "
+                    + proxAppActivityName + " is not found. Not sending"
+                    + " intent to proxy app for " + nfwNotification);
+            return;
+        }
+
+        // Display location icon attributed to this proxy app.
+        mAppOps.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, clsAppUid, proxyAppPackageName);
+
+        // Log proxy app permission mismatch between framework and GNSS HAL.
+        boolean isLocationRequestAccepted =
+                nfwNotification.mResponseType != NfwNotification.NFW_RESPONSE_TYPE_REJECTED;
+        if (isLocationPermissionEnabled != isLocationRequestAccepted) {
+            Log.w(TAG, "Permission mismatch. Framework proxy app " + proxyAppPackageName
+                    + " location permission is set to " + isLocationPermissionEnabled
+                    + " but GNSS non-framework location access response type is "
+                    + nfwNotification.getResponseTypeAsString() + " for " + nfwNotification);
+        }
+
+        // Notify proxy app.
+        try {
+            if (DEBUG) {
+                Log.d(TAG, "Sending non-framework location access notification intent: " + intent);
+            }
+            mContext.startActivityAsUser(intent, UserHandle.getUserHandleForUid(clsAppUid));
+        } catch (ActivityNotFoundException e) {
+            Log.w(TAG, "Activity not found. Failed to send non-framework location access"
+                    + " notification intent to proxy app activity: " + proxAppActivityName);
+        }
+    }
+
+    private void postEvent(Runnable event) {
+        // Hold a wake lock until this message is delivered.
+        // Note that this assumes the message will not be removed from the queue before
+        // it is handled (otherwise the wake lock would be leaked).
+        mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
+        if (!mHandler.post(runEventAndReleaseWakeLock(event))) {
+            mWakeLock.release();
+        }
+    }
+
+    private Runnable runEventAndReleaseWakeLock(Runnable event) {
+        return () -> {
+            try {
+                event.run();
+            } finally {
+                mWakeLock.release();
+            }
+        };
+    }
+
+    private native boolean native_enable_nfw_location_access(String[] proxyApps);
+}
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index 86bc9f3..fe91c63 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -52,7 +52,6 @@
         mExtras = null;
 
         setProperties(properties);
-        setEnabled(true);
     }
 
     /** Sets the enabled state of this mock provider. */
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index d611a17..7fffe8e 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -80,7 +80,7 @@
     private final ControllerStub mController;
     private final SessionStub mSession;
     private final SessionCb mSessionCb;
-    private final MediaSessionService mService;
+    private final MediaSessionService.ServiceImpl mService;
     private final Context mContext;
 
     private final Object mLock = new Object();
@@ -120,7 +120,8 @@
     private String mMetadataDescription;
 
     public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
-            SessionCallbackLink cb, String tag, MediaSessionService service, Looper handlerLooper) {
+            SessionCallbackLink cb, String tag, MediaSessionService.ServiceImpl service,
+            Looper handlerLooper) {
         mOwnerPid = ownerPid;
         mOwnerUid = ownerUid;
         mUserId = userId;
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index ba7b87e..d20ed8c 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -16,79 +16,15 @@
 
 package com.android.server.media;
 
-import static android.os.UserHandle.USER_ALL;
-
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.INotificationManager;
-import android.app.KeyguardManager;
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
-import android.database.ContentObserver;
-import android.media.AudioManager;
-import android.media.AudioManagerInternal;
-import android.media.AudioPlaybackConfiguration;
-import android.media.AudioSystem;
-import android.media.IAudioService;
-import android.media.IRemoteVolumeController;
-import android.media.MediaController2;
-import android.media.Session2CommandGroup;
 import android.media.Session2Token;
-import android.media.session.IActiveSessionsListener;
-import android.media.session.ICallback;
-import android.media.session.IOnMediaKeyListener;
-import android.media.session.IOnVolumeKeyLongPressListener;
-import android.media.session.ISession;
-import android.media.session.ISession2TokensListener;
-import android.media.session.ISessionManager;
-import android.media.session.MediaSession;
-import android.media.session.MediaSessionManager;
-import android.media.session.SessionCallbackLink;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerExecutor;
 import android.os.IBinder;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.speech.RecognizerIntent;
-import android.text.TextUtils;
 import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.view.KeyEvent;
-import android.view.ViewConfiguration;
 
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.DumpUtils;
-import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.Watchdog;
 import com.android.server.Watchdog.Monitor;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -97,2040 +33,124 @@
 public class MediaSessionService extends SystemService implements Monitor {
     private static final String TAG = "MediaSessionService";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    // Leave log for key event always.
-    private static final boolean DEBUG_KEY_EVENT = true;
 
-    private static final int WAKELOCK_TIMEOUT = 5000;
-    private static final int MEDIA_KEY_LISTENER_TIMEOUT = 1000;
-
-    private final SessionManagerImpl mSessionManagerImpl;
-    private final MessageHandler mHandler = new MessageHandler();
-    private final PowerManager.WakeLock mMediaEventWakeLock;
-    private final int mLongPressTimeout;
-    private final INotificationManager mNotificationManager;
-    private final Object mLock = new Object();
-    // Keeps the full user id for each user.
-    @GuardedBy("mLock")
-    private final SparseIntArray mFullUserIds = new SparseIntArray();
-    @GuardedBy("mLock")
-    private final SparseArray<FullUserRecord> mUserRecords = new SparseArray<FullUserRecord>();
-    @GuardedBy("mLock")
-    private final ArrayList<SessionsListenerRecord> mSessionsListeners
-            = new ArrayList<SessionsListenerRecord>();
-    // Map user id as index to list of Session2Tokens
-    // TODO: Keep session2 info in MediaSessionStack for prioritizing both session1 and session2 in
-    //       one place.
-    @GuardedBy("mLock")
-    private final SparseArray<List<Session2Token>> mSession2TokensPerUser = new SparseArray<>();
-    @GuardedBy("mLock")
-    private final List<Session2TokensListenerRecord> mSession2TokensListenerRecords =
-            new ArrayList<>();
-
-    private KeyguardManager mKeyguardManager;
-    private IAudioService mAudioService;
-    private AudioManagerInternal mAudioManagerInternal;
-    private ActivityManager mActivityManager;
-    private ContentResolver mContentResolver;
-    private SettingsObserver mSettingsObserver;
-    private boolean mHasFeatureLeanback;
-
-    // The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile)
-    // It's always not null after the MediaSessionService is started.
-    private FullUserRecord mCurrentFullUserRecord;
-    private MediaSessionRecord mGlobalPrioritySession;
-    private AudioPlayerStateMonitor mAudioPlayerStateMonitor;
-
-    // Used to notify system UI when remote volume was changed. TODO find a
-    // better way to handle this.
-    private IRemoteVolumeController mRvc;
+    private final ServiceImpl mImpl;
 
     public MediaSessionService(Context context) {
         super(context);
-        mSessionManagerImpl = new SessionManagerImpl();
-        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
-        mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
-        mNotificationManager = INotificationManager.Stub.asInterface(
-                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+        mImpl = new MediaSessionServiceImpl(context);
     }
 
     @Override
     public void onStart() {
-        publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl);
+        publishBinderService(Context.MEDIA_SESSION_SERVICE, mImpl.getServiceBinder());
         Watchdog.getInstance().addMonitor(this);
-        mKeyguardManager =
-                (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
-        mAudioService = getAudioService();
-        mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
-        mActivityManager =
-                (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
-        mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
-        mAudioPlayerStateMonitor.registerListener(
-                (config, isRemoved) -> {
-                    if (isRemoved || !config.isActive() || config.getPlayerType()
-                            == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
-                        return;
-                    }
-                    synchronized (mLock) {
-                        FullUserRecord user = getFullUserRecordLocked(
-                                UserHandle.getUserId(config.getClientUid()));
-                        if (user != null) {
-                            user.mPriorityStack.updateMediaButtonSessionIfNeeded();
-                        }
-                    }
-                }, null /* handler */);
-        mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
-        mContentResolver = getContext().getContentResolver();
-        mSettingsObserver = new SettingsObserver();
-        mSettingsObserver.observe();
-        mHasFeatureLeanback = getContext().getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_LEANBACK);
 
-        updateUser();
+        mImpl.onStart();
     }
 
-    private IAudioService getAudioService() {
-        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
-        return IAudioService.Stub.asInterface(b);
+    @Override
+    public void onStartUser(int userId) {
+        mImpl.onStartUser(userId);
     }
 
-    private boolean isGlobalPriorityActiveLocked() {
-        return mGlobalPrioritySession != null && mGlobalPrioritySession.isActive();
+    @Override
+    public void onSwitchUser(int userId) {
+        mImpl.onSwitchUser(userId);
     }
 
+    // Called when the user with the userId is removed.
+    @Override
+    public void onStopUser(int userId) {
+        mImpl.onStopUser(userId);
+    }
+
+    @Override
+    public void monitor() {
+        mImpl.monitor();
+    }
+
+    /**
+     * Updates session.
+     */
     public void updateSession(MediaSessionRecord record) {
-        synchronized (mLock) {
-            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
-            if (user == null) {
-                Log.w(TAG, "Unknown session updated. Ignoring.");
-                return;
-            }
-            if ((record.getFlags() & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
-                if (DEBUG_KEY_EVENT) {
-                    Log.d(TAG, "Global priority session is updated, active=" + record.isActive());
-                }
-                user.pushAddressedPlayerChangedLocked();
-            } else {
-                if (!user.mPriorityStack.contains(record)) {
-                    Log.w(TAG, "Unknown session updated. Ignoring.");
-                    return;
-                }
-                user.mPriorityStack.onSessionStateChange(record);
-            }
-            mHandler.postSessionsChanged(record.getUserId());
-        }
+        mImpl.updateSession(record);
     }
 
+    /**
+     * Sets global priority session.
+     */
     public void setGlobalPrioritySession(MediaSessionRecord record) {
-        synchronized (mLock) {
-            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
-            if (mGlobalPrioritySession != record) {
-                Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession
-                        + " to " + record);
-                mGlobalPrioritySession = record;
-                if (user != null && user.mPriorityStack.contains(record)) {
-                    // Handle the global priority session separately.
-                    // Otherwise, it can be the media button session regardless of the active state
-                    // because it or other system components might have been the lastly played media
-                    // app.
-                    user.mPriorityStack.removeSession(record);
-                }
-            }
-        }
-    }
-
-    private List<MediaSessionRecord> getActiveSessionsLocked(int userId) {
-        List<MediaSessionRecord> records = new ArrayList<>();
-        if (userId == USER_ALL) {
-            int size = mUserRecords.size();
-            for (int i = 0; i < size; i++) {
-                records.addAll(mUserRecords.valueAt(i).mPriorityStack.getActiveSessions(userId));
-            }
-        } else {
-            FullUserRecord user = getFullUserRecordLocked(userId);
-            if (user == null) {
-                Log.w(TAG, "getSessions failed. Unknown user " + userId);
-                return records;
-            }
-            records.addAll(user.mPriorityStack.getActiveSessions(userId));
-        }
-
-        // Return global priority session at the first whenever it's asked.
-        if (isGlobalPriorityActiveLocked()
-                && (userId == USER_ALL || userId == mGlobalPrioritySession.getUserId())) {
-            records.add(0, mGlobalPrioritySession);
-        }
-        return records;
+        mImpl.setGlobalPrioritySession(record);
     }
 
     List<Session2Token> getSession2TokensLocked(int userId) {
-        List<Session2Token> list = new ArrayList<>();
-        if (userId == USER_ALL) {
-            for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
-                list.addAll(mSession2TokensPerUser.valueAt(i));
-            }
-        } else {
-            list.addAll(mSession2TokensPerUser.get(userId));
-        }
-        return list;
+        return mImpl.getSession2TokensLocked(userId);
     }
 
     /**
      * Tells the system UI that volume has changed on an active remote session.
      */
     public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) {
-        if (mRvc == null || !session.isActive()) {
-            return;
-        }
-        try {
-            mRvc.remoteVolumeChanged(session.getControllerBinder(), flags);
-        } catch (Exception e) {
-            Log.wtf(TAG, "Error sending volume change to system UI.", e);
-        }
+        mImpl.notifyRemoteVolumeChanged(flags, session);
     }
 
+    /**
+     * Called when session playstate is changed.
+     */
     public void onSessionPlaystateChanged(MediaSessionRecord record, int oldState, int newState) {
-        synchronized (mLock) {
-            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
-            if (user == null || !user.mPriorityStack.contains(record)) {
-                Log.d(TAG, "Unknown session changed playback state. Ignoring.");
-                return;
-            }
-            user.mPriorityStack.onPlaystateChanged(record, oldState, newState);
-        }
+        mImpl.onSessionPlaystateChanged(record, oldState, newState);
     }
 
+    /**
+     * Called when session playback type is changed.
+     */
     public void onSessionPlaybackTypeChanged(MediaSessionRecord record) {
-        synchronized (mLock) {
-            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
-            if (user == null || !user.mPriorityStack.contains(record)) {
-                Log.d(TAG, "Unknown session changed playback type. Ignoring.");
-                return;
-            }
-            pushRemoteVolumeUpdateLocked(record.getUserId());
-        }
-    }
-
-    @Override
-    public void onStartUser(int userId) {
-        if (DEBUG) Log.d(TAG, "onStartUser: " + userId);
-        updateUser();
-    }
-
-    @Override
-    public void onSwitchUser(int userId) {
-        if (DEBUG) Log.d(TAG, "onSwitchUser: " + userId);
-        updateUser();
-    }
-
-    // Called when the user with the userId is removed.
-    @Override
-    public void onStopUser(int userId) {
-        if (DEBUG) Log.d(TAG, "onStopUser: " + userId);
-        synchronized (mLock) {
-            // TODO: Also handle removing user in updateUser() because adding/switching user is
-            //       handled in updateUser().
-            FullUserRecord user = getFullUserRecordLocked(userId);
-            if (user != null) {
-                if (user.mFullUserId == userId) {
-                    user.destroySessionsForUserLocked(USER_ALL);
-                    mUserRecords.remove(userId);
-                } else {
-                    user.destroySessionsForUserLocked(userId);
-                }
-            }
-            mSession2TokensPerUser.remove(userId);
-            updateUser();
-        }
-    }
-
-    @Override
-    public void monitor() {
-        synchronized (mLock) {
-            // Check for deadlock
-        }
+        mImpl.onSessionPlaybackTypeChanged(record);
     }
 
     protected void enforcePhoneStatePermission(int pid, int uid) {
-        if (getContext().checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Must hold the MODIFY_PHONE_STATE permission.");
-        }
+        mImpl.enforcePhoneStatePermission(pid, uid);
     }
 
     void sessionDied(MediaSessionRecord session) {
-        synchronized (mLock) {
-            destroySessionLocked(session);
-        }
+        mImpl.sessionDied(session);
     }
 
     void destroySession(MediaSessionRecord session) {
-        synchronized (mLock) {
-            destroySessionLocked(session);
-        }
-    }
-
-    private void updateUser() {
-        synchronized (mLock) {
-            UserManager manager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
-            mFullUserIds.clear();
-            List<UserInfo> allUsers = manager.getUsers();
-            if (allUsers != null) {
-                for (UserInfo userInfo : allUsers) {
-                    if (userInfo.isManagedProfile()) {
-                        mFullUserIds.put(userInfo.id, userInfo.profileGroupId);
-                    } else {
-                        mFullUserIds.put(userInfo.id, userInfo.id);
-                        if (mUserRecords.get(userInfo.id) == null) {
-                            mUserRecords.put(userInfo.id, new FullUserRecord(userInfo.id));
-                        }
-                    }
-                    if (mSession2TokensPerUser.get(userInfo.id) == null) {
-                        mSession2TokensPerUser.put(userInfo.id, new ArrayList<>());
-                    }
-                }
-            }
-            // Ensure that the current full user exists.
-            int currentFullUserId = ActivityManager.getCurrentUser();
-            mCurrentFullUserRecord = mUserRecords.get(currentFullUserId);
-            if (mCurrentFullUserRecord == null) {
-                Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId);
-                mCurrentFullUserRecord = new FullUserRecord(currentFullUserId);
-                mUserRecords.put(currentFullUserId, mCurrentFullUserRecord);
-                if (mSession2TokensPerUser.get(currentFullUserId) == null) {
-                    mSession2TokensPerUser.put(currentFullUserId, new ArrayList<>());
-                }
-            }
-            mFullUserIds.put(currentFullUserId, currentFullUserId);
-        }
-    }
-
-    private void updateActiveSessionListeners() {
-        synchronized (mLock) {
-            for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
-                SessionsListenerRecord listener = mSessionsListeners.get(i);
-                try {
-                    enforceMediaPermissions(listener.componentName, listener.pid, listener.uid,
-                            listener.userId);
-                } catch (SecurityException e) {
-                    Log.i(TAG, "ActiveSessionsListener " + listener.componentName
-                            + " is no longer authorized. Disconnecting.");
-                    mSessionsListeners.remove(i);
-                    try {
-                        listener.listener
-                                .onActiveSessionsChanged(new ArrayList<MediaSession.Token>());
-                    } catch (Exception e1) {
-                        // ignore
-                    }
-                }
-            }
-        }
-    }
-
-    /*
-     * When a session is removed several things need to happen.
-     * 1. We need to remove it from the relevant user.
-     * 2. We need to remove it from the priority stack.
-     * 3. We need to remove it from all sessions.
-     * 4. If this is the system priority session we need to clear it.
-     * 5. We need to unlink to death from the cb binder
-     * 6. We need to tell the session to do any final cleanup (onDestroy)
-     */
-    private void destroySessionLocked(MediaSessionRecord session) {
-        if (DEBUG) {
-            Log.d(TAG, "Destroying " + session);
-        }
-        FullUserRecord user = getFullUserRecordLocked(session.getUserId());
-        if (mGlobalPrioritySession == session) {
-            mGlobalPrioritySession = null;
-            if (session.isActive() && user != null) {
-                user.pushAddressedPlayerChangedLocked();
-            }
-        } else {
-            if (user != null) {
-                user.mPriorityStack.removeSession(session);
-            }
-        }
-
-        try {
-            session.getCallback().getBinder().unlinkToDeath(session, 0);
-        } catch (Exception e) {
-            // ignore exceptions while destroying a session.
-        }
-        session.onDestroy();
-        mHandler.postSessionsChanged(session.getUserId());
-    }
-
-    private void enforcePackageName(String packageName, int uid) {
-        if (TextUtils.isEmpty(packageName)) {
-            throw new IllegalArgumentException("packageName may not be empty");
-        }
-        String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
-        final int packageCount = packages.length;
-        for (int i = 0; i < packageCount; i++) {
-            if (packageName.equals(packages[i])) {
-                return;
-            }
-        }
-        throw new IllegalArgumentException("packageName is not owned by the calling process");
-    }
-
-    /**
-     * Checks a caller's authorization to register an IRemoteControlDisplay.
-     * Authorization is granted if one of the following is true:
-     * <ul>
-     * <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL
-     * permission</li>
-     * <li>the caller's listener is one of the enabled notification listeners
-     * for the caller's user</li>
-     * </ul>
-     */
-    private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
-            int resolvedUserId) {
-        if (isCurrentVolumeController(pid, uid)) return;
-        if (getContext()
-                .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
-                    != PackageManager.PERMISSION_GRANTED
-                && !isEnabledNotificationListener(compName, UserHandle.getUserId(uid),
-                        resolvedUserId)) {
-            throw new SecurityException("Missing permission to control media.");
-        }
-    }
-
-    private boolean isCurrentVolumeController(int pid, int uid) {
-        return getContext().checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
-                pid, uid) == PackageManager.PERMISSION_GRANTED;
-    }
-
-    private void enforceSystemUiPermission(String action, int pid, int uid) {
-        if (!isCurrentVolumeController(pid, uid)) {
-            throw new SecurityException("Only system ui may " + action);
-        }
-    }
-
-    /**
-     * This checks if the component is an enabled notification listener for the
-     * specified user. Enabled components may only operate on behalf of the user
-     * they're running as.
-     *
-     * @param compName The component that is enabled.
-     * @param userId The user id of the caller.
-     * @param forUserId The user id they're making the request on behalf of.
-     * @return True if the component is enabled, false otherwise
-     */
-    private boolean isEnabledNotificationListener(ComponentName compName, int userId,
-            int forUserId) {
-        if (userId != forUserId) {
-            // You may not access another user's content as an enabled listener.
-            return false;
-        }
-        if (DEBUG) {
-            Log.d(TAG, "Checking if enabled notification listener " + compName);
-        }
-        if (compName != null) {
-            try {
-                return mNotificationManager.isNotificationListenerAccessGrantedForUser(
-                        compName, userId);
-            } catch(RemoteException e) {
-                Log.w(TAG, "Dead NotificationManager in isEnabledNotificationListener", e);
-            }
-        }
-        return false;
-    }
-
-    private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
-            String callerPackageName, SessionCallbackLink cb, String tag) throws RemoteException {
-        synchronized (mLock) {
-            return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag);
-        }
-    }
-
-    /*
-     * When a session is created the following things need to happen.
-     * 1. Its callback binder needs a link to death
-     * 2. It needs to be added to all sessions.
-     * 3. It needs to be added to the priority stack.
-     * 4. It needs to be added to the relevant user record.
-     */
-    private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
-            String callerPackageName, SessionCallbackLink cb, String tag) {
-        FullUserRecord user = getFullUserRecordLocked(userId);
-        if (user == null) {
-            Log.wtf(TAG, "Request from invalid user: " +  userId);
-            throw new RuntimeException("Session request from invalid user.");
-        }
-
-        final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
-                callerPackageName, cb, tag, this, mHandler.getLooper());
-        try {
-            cb.getBinder().linkToDeath(session, 0);
-        } catch (RemoteException e) {
-            throw new RuntimeException("Media Session owner died prematurely.", e);
-        }
-
-        user.mPriorityStack.addSession(session);
-        mHandler.postSessionsChanged(userId);
-
-        if (DEBUG) {
-            Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
-        }
-        return session;
-    }
-
-    private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
-        for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
-            if (mSessionsListeners.get(i).listener.asBinder() == listener.asBinder()) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    private int findIndexOfSession2TokensListenerLocked(ISession2TokensListener listener) {
-        for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
-            if (mSession2TokensListenerRecords.get(i).listener.asBinder() == listener.asBinder()) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-
-    private void pushSessionsChanged(int userId) {
-        synchronized (mLock) {
-            FullUserRecord user = getFullUserRecordLocked(userId);
-            if (user == null) {
-                Log.w(TAG, "pushSessionsChanged failed. No user with id=" + userId);
-                return;
-            }
-            List<MediaSessionRecord> records = getActiveSessionsLocked(userId);
-            int size = records.size();
-            ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>();
-            for (int i = 0; i < size; i++) {
-                tokens.add(new MediaSession.Token(records.get(i).getControllerBinder()));
-            }
-            pushRemoteVolumeUpdateLocked(userId);
-            for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
-                SessionsListenerRecord record = mSessionsListeners.get(i);
-                if (record.userId == USER_ALL || record.userId == userId) {
-                    try {
-                        record.listener.onActiveSessionsChanged(tokens);
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Dead ActiveSessionsListener in pushSessionsChanged, removing",
-                                e);
-                        mSessionsListeners.remove(i);
-                    }
-                }
-            }
-        }
-    }
-
-    private void pushRemoteVolumeUpdateLocked(int userId) {
-        if (mRvc != null) {
-            try {
-                FullUserRecord user = getFullUserRecordLocked(userId);
-                if (user == null) {
-                    Log.w(TAG, "pushRemoteVolumeUpdateLocked failed. No user with id=" + userId);
-                    return;
-                }
-                MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
-                mRvc.updateRemoteController(record == null ? null : record.getControllerBinder());
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error sending default remote volume to sys ui.", e);
-            }
-        }
+        mImpl.destroySession(session);
     }
 
     void pushSession2TokensChangedLocked(int userId) {
-        List<Session2Token> allSession2Tokens = getSession2TokensLocked(USER_ALL);
-        List<Session2Token> session2Tokens = getSession2TokensLocked(userId);
-
-        for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
-            Session2TokensListenerRecord listenerRecord = mSession2TokensListenerRecords.get(i);
-            try {
-                if (listenerRecord.userId == USER_ALL) {
-                    listenerRecord.listener.onSession2TokensChanged(allSession2Tokens);
-                } else if (listenerRecord.userId == userId) {
-                    listenerRecord.listener.onSession2TokensChanged(session2Tokens);
-                }
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to notify Session2Token change. Removing listener.", e);
-                mSession2TokensListenerRecords.remove(i);
-            }
-        }
+        mImpl.pushSession2TokensChangedLocked(userId);
     }
 
     /**
-     * Called when the media button receiver for the {@param record} is changed.
-     *
-     * @param record the media session whose media button receiver is updated.
+     * Called when media button receiver changed.
      */
     public void onMediaButtonReceiverChanged(MediaSessionRecord record) {
-        synchronized (mLock) {
-            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
-            MediaSessionRecord mediaButtonSession =
-                    user.mPriorityStack.getMediaButtonSession();
-            if (record == mediaButtonSession) {
-                user.rememberMediaButtonReceiverLocked(mediaButtonSession);
-            }
-        }
+        mImpl.onMediaButtonReceiverChanged(record);
     }
 
-    private String getCallingPackageName(int uid) {
-        String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
-        if (packages != null && packages.length > 0) {
-            return packages[0];
-        }
-        return "";
-    }
-
-    private void dispatchVolumeKeyLongPressLocked(KeyEvent keyEvent) {
-        if (mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
-            return;
-        }
-        try {
-            mCurrentFullUserRecord.mOnVolumeKeyLongPressListener.onVolumeKeyLongPress(keyEvent);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to send " + keyEvent + " to volume key long-press listener");
-        }
-    }
-
-    private FullUserRecord getFullUserRecordLocked(int userId) {
-        int fullUserId = mFullUserIds.get(userId, -1);
-        if (fullUserId < 0) {
-            return null;
-        }
-        return mUserRecords.get(fullUserId);
-    }
-
-    /**
-     * Information about a full user and its corresponding managed profiles.
-     *
-     * <p>Since the full user runs together with its managed profiles, a user wouldn't differentiate
-     * them when he/she presses a media/volume button. So keeping media sessions for them in one
-     * place makes more sense and increases the readability.</p>
-     * <p>The contents of this object is guarded by {@link #mLock}.
-     */
-    final class FullUserRecord implements MediaSessionStack.OnMediaButtonSessionChangedListener {
-        public static final int COMPONENT_TYPE_INVALID = 0;
-        public static final int COMPONENT_TYPE_BROADCAST = 1;
-        public static final int COMPONENT_TYPE_ACTIVITY = 2;
-        public static final int COMPONENT_TYPE_SERVICE = 3;
-        private static final String COMPONENT_NAME_USER_ID_DELIM = ",";
-
-        private final int mFullUserId;
-        private final MediaSessionStack mPriorityStack;
-        private PendingIntent mLastMediaButtonReceiver;
-        private ComponentName mRestoredMediaButtonReceiver;
-        private int mRestoredMediaButtonReceiverComponentType;
-        private int mRestoredMediaButtonReceiverUserId;
-
-        private IOnVolumeKeyLongPressListener mOnVolumeKeyLongPressListener;
-        private int mOnVolumeKeyLongPressListenerUid;
-        private KeyEvent mInitialDownVolumeKeyEvent;
-        private int mInitialDownVolumeStream;
-        private boolean mInitialDownMusicOnly;
-
-        private IOnMediaKeyListener mOnMediaKeyListener;
-        private int mOnMediaKeyListenerUid;
-        private ICallback mCallback;
-
-        public FullUserRecord(int fullUserId) {
-            mFullUserId = fullUserId;
-            mPriorityStack = new MediaSessionStack(mAudioPlayerStateMonitor, this);
-            // Restore the remembered media button receiver before the boot.
-            String mediaButtonReceiverInfo = Settings.Secure.getStringForUser(mContentResolver,
-                    Settings.System.MEDIA_BUTTON_RECEIVER, mFullUserId);
-            if (mediaButtonReceiverInfo == null) {
-                return;
-            }
-            String[] tokens = mediaButtonReceiverInfo.split(COMPONENT_NAME_USER_ID_DELIM);
-            if (tokens == null || (tokens.length != 2 && tokens.length != 3)) {
-                return;
-            }
-            mRestoredMediaButtonReceiver = ComponentName.unflattenFromString(tokens[0]);
-            mRestoredMediaButtonReceiverUserId = Integer.parseInt(tokens[1]);
-            if (tokens.length == 3) {
-                mRestoredMediaButtonReceiverComponentType = Integer.parseInt(tokens[2]);
-            } else {
-                mRestoredMediaButtonReceiverComponentType =
-                        getComponentType(mRestoredMediaButtonReceiver);
-            }
-        }
-
-        public void destroySessionsForUserLocked(int userId) {
-            List<MediaSessionRecord> sessions = mPriorityStack.getPriorityList(false, userId);
-            for (MediaSessionRecord session : sessions) {
-                MediaSessionService.this.destroySessionLocked(session);
-            }
-        }
-
-        public void dumpLocked(PrintWriter pw, String prefix) {
-            pw.print(prefix + "Record for full_user=" + mFullUserId);
-            // Dump managed profile user ids associated with this user.
-            int size = mFullUserIds.size();
-            for (int i = 0; i < size; i++) {
-                if (mFullUserIds.keyAt(i) != mFullUserIds.valueAt(i)
-                        && mFullUserIds.valueAt(i) == mFullUserId) {
-                    pw.print(", profile_user=" + mFullUserIds.keyAt(i));
-                }
-            }
-            pw.println();
-            String indent = prefix + "  ";
-            pw.println(indent + "Volume key long-press listener: " + mOnVolumeKeyLongPressListener);
-            pw.println(indent + "Volume key long-press listener package: " +
-                    getCallingPackageName(mOnVolumeKeyLongPressListenerUid));
-            pw.println(indent + "Media key listener: " + mOnMediaKeyListener);
-            pw.println(indent + "Media key listener package: " +
-                    getCallingPackageName(mOnMediaKeyListenerUid));
-            pw.println(indent + "Callback: " + mCallback);
-            pw.println(indent + "Last MediaButtonReceiver: " + mLastMediaButtonReceiver);
-            pw.println(indent + "Restored MediaButtonReceiver: " + mRestoredMediaButtonReceiver);
-            pw.println(indent + "Restored MediaButtonReceiverComponentType: "
-                    + mRestoredMediaButtonReceiverComponentType);
-            mPriorityStack.dump(pw, indent);
-            pw.println(indent + "Session2Tokens:");
-            for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
-                List<Session2Token> list = mSession2TokensPerUser.valueAt(i);
-                if (list == null || list.size() == 0) {
-                    continue;
-                }
-                for (Session2Token token : list) {
-                    pw.println(indent + "  " + token);
-                }
-            }
-        }
-
-        @Override
-        public void onMediaButtonSessionChanged(MediaSessionRecord oldMediaButtonSession,
-                MediaSessionRecord newMediaButtonSession) {
-            if (DEBUG_KEY_EVENT) {
-                Log.d(TAG, "Media button session is changed to " + newMediaButtonSession);
-            }
-            synchronized (mLock) {
-                if (oldMediaButtonSession != null) {
-                    mHandler.postSessionsChanged(oldMediaButtonSession.getUserId());
-                }
-                if (newMediaButtonSession != null) {
-                    rememberMediaButtonReceiverLocked(newMediaButtonSession);
-                    mHandler.postSessionsChanged(newMediaButtonSession.getUserId());
-                }
-                pushAddressedPlayerChangedLocked();
-            }
-        }
-
-        // Remember media button receiver and keep it in the persistent storage.
-        public void rememberMediaButtonReceiverLocked(MediaSessionRecord record) {
-            PendingIntent receiver = record.getMediaButtonReceiver();
-            mLastMediaButtonReceiver = receiver;
-            mRestoredMediaButtonReceiver = null;
-            mRestoredMediaButtonReceiverComponentType = COMPONENT_TYPE_INVALID;
-
-            String mediaButtonReceiverInfo = "";
-            if (receiver != null) {
-                ComponentName component = receiver.getIntent().getComponent();
-                if (component != null
-                        && record.getPackageName().equals(component.getPackageName())) {
-                    String componentName = component.flattenToString();
-                    int componentType = getComponentType(component);
-                    mediaButtonReceiverInfo = String.join(COMPONENT_NAME_USER_ID_DELIM,
-                            componentName, String.valueOf(record.getUserId()),
-                            String.valueOf(componentType));
-                }
-            }
-            Settings.Secure.putStringForUser(mContentResolver,
-                    Settings.System.MEDIA_BUTTON_RECEIVER, mediaButtonReceiverInfo,
-                    mFullUserId);
-        }
-
-        private void pushAddressedPlayerChangedLocked() {
-            if (mCallback == null) {
-                return;
-            }
-            try {
-                MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked();
-                if (mediaButtonSession != null) {
-                    mCallback.onAddressedPlayerChangedToMediaSession(
-                            new MediaSession.Token(mediaButtonSession.getControllerBinder()));
-                } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
-                    mCallback.onAddressedPlayerChangedToMediaButtonReceiver(
-                            mCurrentFullUserRecord.mLastMediaButtonReceiver
-                                    .getIntent().getComponent());
-                } else if (mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
-                    mCallback.onAddressedPlayerChangedToMediaButtonReceiver(
-                            mCurrentFullUserRecord.mRestoredMediaButtonReceiver);
-                }
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to pushAddressedPlayerChangedLocked", e);
-            }
-        }
-
-        private MediaSessionRecord getMediaButtonSessionLocked() {
-            return isGlobalPriorityActiveLocked()
-                    ? mGlobalPrioritySession : mPriorityStack.getMediaButtonSession();
-        }
-
-        private int getComponentType(@Nullable ComponentName componentName) {
-            if (componentName == null) {
-                return COMPONENT_TYPE_INVALID;
-            }
-            PackageManager pm = getContext().getPackageManager();
-            try {
-                ActivityInfo activityInfo = pm.getActivityInfo(componentName,
-                        PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                                | PackageManager.GET_ACTIVITIES);
-                if (activityInfo != null) {
-                    return COMPONENT_TYPE_ACTIVITY;
-                }
-            } catch (NameNotFoundException e) {
-            }
-            try {
-                ServiceInfo serviceInfo = pm.getServiceInfo(componentName,
-                        PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                                | PackageManager.GET_SERVICES);
-                if (serviceInfo != null) {
-                    return COMPONENT_TYPE_SERVICE;
-                }
-            } catch (NameNotFoundException e) {
-            }
-            // Pick legacy behavior for BroadcastReceiver or unknown.
-            return COMPONENT_TYPE_BROADCAST;
-        }
-    }
-
-    final class SessionsListenerRecord implements IBinder.DeathRecipient {
-        public final IActiveSessionsListener listener;
-        public final ComponentName componentName;
-        public final int userId;
-        public final int pid;
-        public final int uid;
-
-        public SessionsListenerRecord(IActiveSessionsListener listener,
-                ComponentName componentName,
-                int userId, int pid, int uid) {
-            this.listener = listener;
-            this.componentName = componentName;
-            this.userId = userId;
-            this.pid = pid;
-            this.uid = uid;
-        }
-
-        @Override
-        public void binderDied() {
-            synchronized (mLock) {
-                mSessionsListeners.remove(this);
-            }
-        }
-    }
-
-    final class Session2TokensListenerRecord implements IBinder.DeathRecipient {
-        public final ISession2TokensListener listener;
-        public final int userId;
-
-        Session2TokensListenerRecord(ISession2TokensListener listener,
-                int userId) {
-            this.listener = listener;
-            this.userId = userId;
-        }
-
-        @Override
-        public void binderDied() {
-            synchronized (mLock) {
-                mSession2TokensListenerRecords.remove(this);
-            }
-        }
-    }
-
-    final class SettingsObserver extends ContentObserver {
-        private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(
-                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
-
-        private SettingsObserver() {
-            super(null);
-        }
-
-        private void observe() {
-            mContentResolver.registerContentObserver(mSecureSettingsUri,
-                    false, this, USER_ALL);
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            updateActiveSessionListeners();
-        }
-    }
-
-    class SessionManagerImpl extends ISessionManager.Stub {
-        private static final String EXTRA_WAKELOCK_ACQUIRED =
-                "android.media.AudioService.WAKELOCK_ACQUIRED";
-        private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number
-
-        private boolean mVoiceButtonDown = false;
-        private boolean mVoiceButtonHandled = false;
-
-        @Override
-        public ISession createSession(String packageName, SessionCallbackLink cb, String tag,
-                int userId) throws RemoteException {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                enforcePackageName(packageName, uid);
-                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
-                        false /* allowAll */, true /* requireFull */, "createSession", packageName);
-                if (cb == null) {
-                    throw new IllegalArgumentException("Controller callback cannot be null");
-                }
-                return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag)
-                        .getSessionBinder();
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void notifySession2Created(Session2Token sessionToken) throws RemoteException {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                if (DEBUG) {
-                    Log.d(TAG, "Session2 is created " + sessionToken);
-                }
-                if (uid != sessionToken.getUid()) {
-                    throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid
-                            + " but actually=" + sessionToken.getUid());
-                }
-                Controller2Callback callback = new Controller2Callback(sessionToken);
-                // Note: It's safe not to keep controller here because it wouldn't be GC'ed until
-                //       it's closed.
-                // TODO: Keep controller as well for better readability
-                //       because the GC behavior isn't straightforward.
-                MediaController2 controller = new MediaController2(getContext(), sessionToken,
-                        new HandlerExecutor(mHandler), callback);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public List<IBinder> 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<IBinder> binders = new ArrayList<IBinder>();
-                synchronized (mLock) {
-                    List<MediaSessionRecord> records = getActiveSessionsLocked(resolvedUserId);
-                    for (MediaSessionRecord record : records) {
-                        binders.add(record.getControllerBinder().asBinder());
-                    }
-                }
-                return binders;
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public List<Session2Token> getSession2Tokens(int userId) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-
-            try {
-                // Check that they can make calls on behalf of the user and
-                // get the final user id
-                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
-                        true /* allowAll */, true /* requireFull */, "getSession2Tokens",
-                        null /* optional packageName */);
-                List<Session2Token> result;
-                synchronized (mLock) {
-                    result = getSession2TokensLocked(resolvedUserId);
-                }
-                return result;
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void addSessionsListener(IActiveSessionsListener listener,
-                ComponentName componentName, int userId) throws RemoteException {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-
-            try {
-                int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
-                synchronized (mLock) {
-                    int index = findIndexOfSessionsListenerLocked(listener);
-                    if (index != -1) {
-                        Log.w(TAG, "ActiveSessionsListener is already added, ignoring");
-                        return;
-                    }
-                    SessionsListenerRecord record = new SessionsListenerRecord(listener,
-                            componentName, resolvedUserId, pid, uid);
-                    try {
-                        listener.asBinder().linkToDeath(record, 0);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "ActiveSessionsListener is dead, ignoring it", e);
-                        return;
-                    }
-                    mSessionsListeners.add(record);
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void removeSessionsListener(IActiveSessionsListener listener)
-                throws RemoteException {
-            synchronized (mLock) {
-                int index = findIndexOfSessionsListenerLocked(listener);
-                if (index != -1) {
-                    SessionsListenerRecord record = mSessionsListeners.remove(index);
-                    try {
-                        record.listener.asBinder().unlinkToDeath(record, 0);
-                    } catch (Exception e) {
-                        // ignore exceptions, the record is being removed
-                    }
-                }
-            }
-        }
-
-        @Override
-        public void addSession2TokensListener(ISession2TokensListener listener,
-                int userId) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-
-            try {
-                // Check that they can make calls on behalf of the user and get the final user id.
-                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
-                        true /* allowAll */, true /* requireFull */, "addSession2TokensListener",
-                        null /* optional packageName */);
-                synchronized (mLock) {
-                    int index = findIndexOfSession2TokensListenerLocked(listener);
-                    if (index >= 0) {
-                        Log.w(TAG, "addSession2TokensListener is already added, ignoring");
-                        return;
-                    }
-                    mSession2TokensListenerRecords.add(
-                            new Session2TokensListenerRecord(listener, resolvedUserId));
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void removeSession2TokensListener(ISession2TokensListener listener) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-
-            try {
-                synchronized (mLock) {
-                    int index = findIndexOfSession2TokensListenerLocked(listener);
-                    if (index >= 0) {
-                        Session2TokensListenerRecord listenerRecord =
-                                mSession2TokensListenerRecords.remove(index);
-                        try {
-                            listenerRecord.listener.asBinder().unlinkToDeath(listenerRecord, 0);
-                        } catch (Exception e) {
-                            // Ignore exception.
-                        }
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        /**
-         * Handles the dispatching of the media button events to one of the
-         * registered listeners, or if there was none, broadcast an
-         * ACTION_MEDIA_BUTTON intent to the rest of the system.
-         *
-         * @param packageName The caller package
-         * @param asSystemService {@code true} if the event sent to the session as if it was come
-         *          from the system service instead of the app process. This helps sessions to
-         *          distinguish between the key injection by the app and key events from the
-         *          hardware devices. Should be used only when the volume key events aren't handled
-         *          by foreground activity. {@code false} otherwise to tell session about the real
-         *          caller.
-         * @param keyEvent a non-null KeyEvent whose key code is one of the
-         *            supported media buttons
-         * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held
-         *            while this key event is dispatched.
-         */
-        @Override
-        public void dispatchMediaKeyEvent(String packageName, boolean asSystemService,
-                KeyEvent keyEvent, boolean needWakeLock) {
-            if (keyEvent == null || !KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
-                Log.w(TAG, "Attempted to dispatch null or non-media key event.");
-                return;
-            }
-
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                if (DEBUG) {
-                    Log.d(TAG, "dispatchMediaKeyEvent, pkg=" + packageName + " pid=" + pid
-                            + ", uid=" + uid + ", asSystem=" + asSystemService + ", event="
-                            + keyEvent);
-                }
-                if (!isUserSetupComplete()) {
-                    // Global media key handling can have the side-effect of starting new
-                    // activities which is undesirable while setup is in progress.
-                    Slog.i(TAG, "Not dispatching media key event because user "
-                            + "setup is in progress.");
-                    return;
-                }
-
-                synchronized (mLock) {
-                    boolean isGlobalPriorityActive = isGlobalPriorityActiveLocked();
-                    if (isGlobalPriorityActive && uid != Process.SYSTEM_UID) {
-                        // Prevent dispatching key event through reflection while the global
-                        // priority session is active.
-                        Slog.i(TAG, "Only the system can dispatch media key event "
-                                + "to the global priority session.");
-                        return;
-                    }
-                    if (!isGlobalPriorityActive) {
-                        if (mCurrentFullUserRecord.mOnMediaKeyListener != null) {
-                            if (DEBUG_KEY_EVENT) {
-                                Log.d(TAG, "Send " + keyEvent + " to the media key listener");
-                            }
-                            try {
-                                mCurrentFullUserRecord.mOnMediaKeyListener.onMediaKey(keyEvent,
-                                        new MediaKeyListenerResultReceiver(packageName, pid, uid,
-                                                asSystemService, keyEvent, needWakeLock));
-                                return;
-                            } catch (RemoteException e) {
-                                Log.w(TAG, "Failed to send " + keyEvent
-                                        + " to the media key listener");
-                            }
-                        }
-                    }
-                    if (!isGlobalPriorityActive && isVoiceKey(keyEvent.getKeyCode())) {
-                        handleVoiceKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
-                                needWakeLock);
-                    } else {
-                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
-                                keyEvent, needWakeLock);
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void setCallback(ICallback callback) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                if (!UserHandle.isSameApp(uid, Process.BLUETOOTH_UID)) {
-                    throw new SecurityException("Only Bluetooth service processes can set"
-                            + " Callback");
-                }
-                synchronized (mLock) {
-                    int userId = UserHandle.getUserId(uid);
-                    FullUserRecord user = getFullUserRecordLocked(userId);
-                    if (user == null || user.mFullUserId != userId) {
-                        Log.w(TAG, "Only the full user can set the callback"
-                                + ", userId=" + userId);
-                        return;
-                    }
-                    user.mCallback = callback;
-                    Log.d(TAG, "The callback " + user.mCallback
-                            + " is set by " + getCallingPackageName(uid));
-                    if (user.mCallback == null) {
-                        return;
-                    }
-                    try {
-                        user.mCallback.asBinder().linkToDeath(
-                                new IBinder.DeathRecipient() {
-                                    @Override
-                                    public void binderDied() {
-                                        synchronized (mLock) {
-                                            user.mCallback = null;
-                                        }
-                                    }
-                                }, 0);
-                        user.pushAddressedPlayerChangedLocked();
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Failed to set callback", e);
-                        user.mCallback = null;
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void setOnVolumeKeyLongPressListener(IOnVolumeKeyLongPressListener listener) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                // Enforce SET_VOLUME_KEY_LONG_PRESS_LISTENER permission.
-                if (getContext().checkPermission(
-                        android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER, pid, uid)
-                            != PackageManager.PERMISSION_GRANTED) {
-                    throw new SecurityException("Must hold the SET_VOLUME_KEY_LONG_PRESS_LISTENER" +
-                            " permission.");
-                }
-
-                synchronized (mLock) {
-                    int userId = UserHandle.getUserId(uid);
-                    FullUserRecord user = getFullUserRecordLocked(userId);
-                    if (user == null || user.mFullUserId != userId) {
-                        Log.w(TAG, "Only the full user can set the volume key long-press listener"
-                                + ", userId=" + userId);
-                        return;
-                    }
-                    if (user.mOnVolumeKeyLongPressListener != null &&
-                            user.mOnVolumeKeyLongPressListenerUid != uid) {
-                        Log.w(TAG, "The volume key long-press listener cannot be reset"
-                                + " by another app , mOnVolumeKeyLongPressListener="
-                                + user.mOnVolumeKeyLongPressListenerUid
-                                + ", uid=" + uid);
-                        return;
-                    }
-
-                    user.mOnVolumeKeyLongPressListener = listener;
-                    user.mOnVolumeKeyLongPressListenerUid = uid;
-
-                    Log.d(TAG, "The volume key long-press listener "
-                            + listener + " is set by " + getCallingPackageName(uid));
-
-                    if (user.mOnVolumeKeyLongPressListener != null) {
-                        try {
-                            user.mOnVolumeKeyLongPressListener.asBinder().linkToDeath(
-                                    new IBinder.DeathRecipient() {
-                                        @Override
-                                        public void binderDied() {
-                                            synchronized (mLock) {
-                                                user.mOnVolumeKeyLongPressListener = null;
-                                            }
-                                        }
-                                    }, 0);
-                        } catch (RemoteException e) {
-                            Log.w(TAG, "Failed to set death recipient "
-                                    + user.mOnVolumeKeyLongPressListener);
-                            user.mOnVolumeKeyLongPressListener = null;
-                        }
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void setOnMediaKeyListener(IOnMediaKeyListener listener) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                // Enforce SET_MEDIA_KEY_LISTENER permission.
-                if (getContext().checkPermission(
-                        android.Manifest.permission.SET_MEDIA_KEY_LISTENER, pid, uid)
-                            != PackageManager.PERMISSION_GRANTED) {
-                    throw new SecurityException("Must hold the SET_MEDIA_KEY_LISTENER" +
-                            " permission.");
-                }
-
-                synchronized (mLock) {
-                    int userId = UserHandle.getUserId(uid);
-                    FullUserRecord user = getFullUserRecordLocked(userId);
-                    if (user == null || user.mFullUserId != userId) {
-                        Log.w(TAG, "Only the full user can set the media key listener"
-                                + ", userId=" + userId);
-                        return;
-                    }
-                    if (user.mOnMediaKeyListener != null && user.mOnMediaKeyListenerUid != uid) {
-                        Log.w(TAG, "The media key listener cannot be reset by another app. "
-                                + ", mOnMediaKeyListenerUid=" + user.mOnMediaKeyListenerUid
-                                + ", uid=" + uid);
-                        return;
-                    }
-
-                    user.mOnMediaKeyListener = listener;
-                    user.mOnMediaKeyListenerUid = uid;
-
-                    Log.d(TAG, "The media key listener " + user.mOnMediaKeyListener
-                            + " is set by " + getCallingPackageName(uid));
-
-                    if (user.mOnMediaKeyListener != null) {
-                        try {
-                            user.mOnMediaKeyListener.asBinder().linkToDeath(
-                                    new IBinder.DeathRecipient() {
-                                        @Override
-                                        public void binderDied() {
-                                            synchronized (mLock) {
-                                                user.mOnMediaKeyListener = null;
-                                            }
-                                        }
-                                    }, 0);
-                        } catch (RemoteException e) {
-                            Log.w(TAG, "Failed to set death recipient " + user.mOnMediaKeyListener);
-                            user.mOnMediaKeyListener = null;
-                        }
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        /**
-         * Handles the dispatching of the volume button events to one of the
-         * registered listeners. If there's a volume key long-press listener and
-         * there's no active global priority session, long-pressess will be sent to the
-         * long-press listener instead of adjusting volume.
-         *
-         * @param packageName The caller's package name, obtained by Context#getPackageName()
-         * @param opPackageName The caller's op package name, obtained by Context#getOpPackageName()
-         * @param asSystemService {@code true} if the event sent to the session as if it was come
-         *          from the system service instead of the app process. This helps sessions to
-         *          distinguish between the key injection by the app and key events from the
-         *          hardware devices. Should be used only when the volume key events aren't handled
-         *          by foreground activity. {@code false} otherwise to tell session about the real
-         *          caller.
-         * @param keyEvent a non-null KeyEvent whose key code is one of the
-         *            {@link KeyEvent#KEYCODE_VOLUME_UP},
-         *            {@link KeyEvent#KEYCODE_VOLUME_DOWN},
-         *            or {@link KeyEvent#KEYCODE_VOLUME_MUTE}.
-         * @param stream stream type to adjust volume.
-         * @param musicOnly true if both UI nor haptic feedback aren't needed when adjust volume.
-         */
-        @Override
-        public void dispatchVolumeKeyEvent(String packageName, String opPackageName,
-                boolean asSystemService, KeyEvent keyEvent, int stream, boolean musicOnly) {
-            if (keyEvent == null ||
-                    (keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_UP
-                             && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_DOWN
-                             && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_MUTE)) {
-                Log.w(TAG, "Attempted to dispatch null or non-volume key event.");
-                return;
-            }
-
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-
-            if (DEBUG_KEY_EVENT) {
-                Log.d(TAG, "dispatchVolumeKeyEvent, pkg=" + packageName + ", pid=" + pid + ", uid="
-                        + uid + ", asSystem=" + asSystemService + ", event=" + keyEvent);
-            }
-
-            try {
-                synchronized (mLock) {
-                    if (isGlobalPriorityActiveLocked()
-                            || mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
-                        dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
-                                asSystemService, keyEvent, stream, musicOnly);
-                    } else {
-                        // TODO: Consider the case when both volume up and down keys are pressed
-                        //       at the same time.
-                        if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
-                            if (keyEvent.getRepeatCount() == 0) {
-                                // Keeps the copy of the KeyEvent because it can be reused.
-                                mCurrentFullUserRecord.mInitialDownVolumeKeyEvent =
-                                        KeyEvent.obtain(keyEvent);
-                                mCurrentFullUserRecord.mInitialDownVolumeStream = stream;
-                                mCurrentFullUserRecord.mInitialDownMusicOnly = musicOnly;
-                                mHandler.sendMessageDelayed(
-                                        mHandler.obtainMessage(
-                                                MessageHandler.MSG_VOLUME_INITIAL_DOWN,
-                                                mCurrentFullUserRecord.mFullUserId, 0),
-                                        mLongPressTimeout);
-                            }
-                            if (keyEvent.getRepeatCount() > 0 || keyEvent.isLongPress()) {
-                                mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
-                                if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null) {
-                                    dispatchVolumeKeyLongPressLocked(
-                                            mCurrentFullUserRecord.mInitialDownVolumeKeyEvent);
-                                    // Mark that the key is already handled.
-                                    mCurrentFullUserRecord.mInitialDownVolumeKeyEvent = null;
-                                }
-                                dispatchVolumeKeyLongPressLocked(keyEvent);
-                            }
-                        } else { // if up
-                            mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
-                            if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null
-                                    && mCurrentFullUserRecord.mInitialDownVolumeKeyEvent
-                                            .getDownTime() == keyEvent.getDownTime()) {
-                                // Short-press. Should change volume.
-                                dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
-                                        asSystemService,
-                                        mCurrentFullUserRecord.mInitialDownVolumeKeyEvent,
-                                        mCurrentFullUserRecord.mInitialDownVolumeStream,
-                                        mCurrentFullUserRecord.mInitialDownMusicOnly);
-                                dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
-                                        asSystemService, keyEvent, stream, musicOnly);
-                            } else {
-                                dispatchVolumeKeyLongPressLocked(keyEvent);
-                            }
-                        }
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        private void dispatchVolumeKeyEventLocked(String packageName, String opPackageName, int pid,
-                int uid, boolean asSystemService, KeyEvent keyEvent, int stream,
-                boolean musicOnly) {
-            boolean down = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
-            boolean up = keyEvent.getAction() == KeyEvent.ACTION_UP;
-            int direction = 0;
-            boolean isMute = false;
-            switch (keyEvent.getKeyCode()) {
-                case KeyEvent.KEYCODE_VOLUME_UP:
-                    direction = AudioManager.ADJUST_RAISE;
-                    break;
-                case KeyEvent.KEYCODE_VOLUME_DOWN:
-                    direction = AudioManager.ADJUST_LOWER;
-                    break;
-                case KeyEvent.KEYCODE_VOLUME_MUTE:
-                    isMute = true;
-                    break;
-            }
-            if (down || up) {
-                int flags = AudioManager.FLAG_FROM_KEY;
-                if (musicOnly) {
-                    // This flag is used when the screen is off to only affect active media.
-                    flags |= AudioManager.FLAG_ACTIVE_MEDIA_ONLY;
-                } else {
-                    // These flags are consistent with the home screen
-                    if (up) {
-                        flags |= AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE;
-                    } else {
-                        flags |= AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE;
-                    }
-                }
-                if (direction != 0) {
-                    // If this is action up we want to send a beep for non-music events
-                    if (up) {
-                        direction = 0;
-                    }
-                    dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid,
-                            asSystemService, stream, direction, flags);
-                } else if (isMute) {
-                    if (down && keyEvent.getRepeatCount() == 0) {
-                        dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid,
-                                asSystemService, stream, AudioManager.ADJUST_TOGGLE_MUTE, flags);
-                    }
-                }
-            }
-        }
-
-        @Override
-        public void dispatchAdjustVolume(String packageName, String opPackageName,
-                int suggestedStream, int delta, int flags) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                synchronized (mLock) {
-                    dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid, false,
-                            suggestedStream, delta, flags);
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void setRemoteVolumeController(IRemoteVolumeController rvc) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                enforceSystemUiPermission("listen for volume changes", pid, uid);
-                mRvc = rvc;
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public boolean isGlobalPriorityActive() {
-            synchronized (mLock) {
-                return isGlobalPriorityActiveLocked();
-            }
-        }
-
-        @Override
-        public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
-            if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
-
-            pw.println("MEDIA SESSION SERVICE (dumpsys media_session)");
-            pw.println();
-
-            synchronized (mLock) {
-                pw.println(mSessionsListeners.size() + " sessions listeners.");
-                pw.println("Global priority session is " + mGlobalPrioritySession);
-                if (mGlobalPrioritySession != null) {
-                    mGlobalPrioritySession.dump(pw, "  ");
-                }
-                pw.println("User Records:");
-                int count = mUserRecords.size();
-                for (int i = 0; i < count; i++) {
-                    mUserRecords.valueAt(i).dumpLocked(pw, "");
-                }
-                mAudioPlayerStateMonitor.dump(getContext(), pw, "");
-            }
-        }
-
-        /**
-         * Returns if the controller's package is trusted (i.e. has either MEDIA_CONTENT_CONTROL
-         * permission or an enabled notification listener)
-         *
-         * @param controllerPackageName package name of the controller app
-         * @param controllerPid pid of the controller app
-         * @param controllerUid uid of the controller app
-         */
-        @Override
-        public boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid)
-                throws RemoteException {
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                // Don't perform sanity check between controllerPackageName and controllerUid.
-                // When an (activity|service) runs on the another apps process by specifying
-                // android:process in the AndroidManifest.xml, then PID and UID would have the
-                // running process' information instead of the (activity|service) that has created
-                // MediaController.
-                // Note that we can use Context#getOpPackageName() instead of
-                // Context#getPackageName() for getting package name that matches with the PID/UID,
-                // but it doesn't tell which package has created the MediaController, so useless.
-                return hasMediaControlPermission(UserHandle.getUserId(uid), controllerPackageName,
-                        controllerPid, controllerUid);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        // For MediaSession
-        private int verifySessionsRequest(ComponentName componentName, int userId, final int pid,
-                final int uid) {
-            String packageName = null;
-            if (componentName != null) {
-                // If they gave us a component name verify they own the
-                // package
-                packageName = componentName.getPackageName();
-                enforcePackageName(packageName, uid);
-            }
-            // Check that they can make calls on behalf of the user and
-            // get the final user id
-            int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
-                    true /* allowAll */, true /* requireFull */, "getSessions", packageName);
-            // Check if they have the permissions or their component is
-            // enabled for the user they're calling from.
-            enforceMediaPermissions(componentName, pid, uid, resolvedUserId);
-            return resolvedUserId;
-        }
-
-        private boolean hasMediaControlPermission(int resolvedUserId, String packageName,
-                int pid, int uid) throws RemoteException {
-            // Allow API calls from the System UI
-            if (isCurrentVolumeController(pid, uid)) {
-                return true;
-            }
-
-            // Check if it's system server or has MEDIA_CONTENT_CONTROL.
-            // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
-            // check here.
-            if (uid == Process.SYSTEM_UID || getContext().checkPermission(
-                    android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
-                    == PackageManager.PERMISSION_GRANTED) {
-                return true;
-            } else if (DEBUG) {
-                Log.d(TAG, packageName + " (uid=" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
-            }
-
-            // You may not access another user's content as an enabled listener.
-            final int userId = UserHandle.getUserId(uid);
-            if (resolvedUserId != userId) {
-                return false;
-            }
-
-            // TODO(jaewan): (Post-P) Propose NotificationManager#hasEnabledNotificationListener(
-            //               String pkgName) to notification team for optimization
-            final List<ComponentName> enabledNotificationListeners =
-                    mNotificationManager.getEnabledNotificationListeners(userId);
-            if (enabledNotificationListeners != null) {
-                for (int i = 0; i < enabledNotificationListeners.size(); i++) {
-                    if (TextUtils.equals(packageName,
-                            enabledNotificationListeners.get(i).getPackageName())) {
-                        return true;
-                    }
-                }
-            }
-            if (DEBUG) {
-                Log.d(TAG, packageName + " (uid=" + uid + ") doesn't have an enabled "
-                        + "notification listener");
-            }
-            return false;
-        }
-
-        private void dispatchAdjustVolumeLocked(String packageName, String opPackageName, int pid,
-                int uid, boolean asSystemService, int suggestedStream, int direction, int flags) {
-            MediaSessionRecord session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
-                    : mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession();
-
-            boolean preferSuggestedStream = false;
-            if (isValidLocalStreamType(suggestedStream)
-                    && AudioSystem.isStreamActive(suggestedStream, 0)) {
-                preferSuggestedStream = true;
-            }
-            if (DEBUG_KEY_EVENT) {
-                Log.d(TAG, "Adjusting " + session + " by " + direction + ". flags="
-                        + flags + ", suggestedStream=" + suggestedStream
-                        + ", preferSuggestedStream=" + preferSuggestedStream);
-            }
-            if (session == null || preferSuggestedStream) {
-                if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0
-                        && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
-                    if (DEBUG) {
-                        Log.d(TAG, "No active session to adjust, skipping media only volume event");
-                    }
-                    return;
-                }
-
-                // Execute mAudioService.adjustSuggestedStreamVolume() on
-                // handler thread of MediaSessionService.
-                // This will release the MediaSessionService.mLock sooner and avoid
-                // a potential deadlock between MediaSessionService.mLock and
-                // ActivityManagerService lock.
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        final String callingOpPackageName;
-                        final int callingUid;
-                        if (asSystemService) {
-                            callingOpPackageName = getContext().getOpPackageName();
-                            callingUid = Process.myUid();
-                        } else {
-                            callingOpPackageName = opPackageName;
-                            callingUid = uid;
-                        }
-                        try {
-                            mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(suggestedStream,
-                                    direction, flags, callingOpPackageName, callingUid);
-                        } catch (SecurityException | IllegalArgumentException e) {
-                            Log.e(TAG, "Cannot adjust volume: direction=" + direction
-                                    + ", suggestedStream=" + suggestedStream + ", flags=" + flags
-                                    + ", packageName=" + packageName + ", uid=" + uid
-                                    + ", asSystemService=" + asSystemService, e);
-                        }
-                    }
-                });
-            } else {
-                session.adjustVolume(packageName, opPackageName, pid, uid, null, asSystemService,
-                        direction, flags, true);
-            }
-        }
-
-        private void handleVoiceKeyEventLocked(String packageName, int pid, int uid,
-                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
-            int action = keyEvent.getAction();
-            boolean isLongPress = (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;
-            if (action == KeyEvent.ACTION_DOWN) {
-                if (keyEvent.getRepeatCount() == 0) {
-                    mVoiceButtonDown = true;
-                    mVoiceButtonHandled = false;
-                } else if (mVoiceButtonDown && !mVoiceButtonHandled && isLongPress) {
-                    mVoiceButtonHandled = true;
-                    startVoiceInput(needWakeLock);
-                }
-            } else if (action == KeyEvent.ACTION_UP) {
-                if (mVoiceButtonDown) {
-                    mVoiceButtonDown = false;
-                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
-                        // Resend the down then send this event through
-                        KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
-                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
-                                downEvent, needWakeLock);
-                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
-                                keyEvent, needWakeLock);
-                    }
-                }
-            }
-        }
-
-        private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid,
-                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
-            MediaSessionRecord session = mCurrentFullUserRecord.getMediaButtonSessionLocked();
-            if (session != null) {
-                if (DEBUG_KEY_EVENT) {
-                    Log.d(TAG, "Sending " + keyEvent + " to " + session);
-                }
-                if (needWakeLock) {
-                    mKeyEventReceiver.aquireWakeLockLocked();
-                }
-                // If we don't need a wakelock use -1 as the id so we won't release it later.
-                session.sendMediaButton(packageName, pid, uid, asSystemService, keyEvent,
-                        needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
-                        mKeyEventReceiver);
-                if (mCurrentFullUserRecord.mCallback != null) {
-                    try {
-                        mCurrentFullUserRecord.mCallback.onMediaKeyEventDispatchedToMediaSession(
-                                keyEvent, new MediaSession.Token(session.getControllerBinder()));
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Failed to send callback", e);
-                    }
-                }
-            } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null
-                    || mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
-                if (needWakeLock) {
-                    mKeyEventReceiver.aquireWakeLockLocked();
-                }
-                Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
-                mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-                mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-                // TODO: Find a way to also send PID/UID in secure way.
-                String callerPackageName =
-                        (asSystemService) ? getContext().getPackageName() : packageName;
-                mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callerPackageName);
-                try {
-                    if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
-                        PendingIntent receiver = mCurrentFullUserRecord.mLastMediaButtonReceiver;
-                        if (DEBUG_KEY_EVENT) {
-                            Log.d(TAG, "Sending " + keyEvent
-                                    + " to the last known PendingIntent " + receiver);
-                        }
-                        receiver.send(getContext(),
-                                needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
-                                mediaButtonIntent, mKeyEventReceiver, mHandler);
-                        if (mCurrentFullUserRecord.mCallback != null) {
-                            ComponentName componentName = mCurrentFullUserRecord
-                                    .mLastMediaButtonReceiver.getIntent().getComponent();
-                            if (componentName != null) {
-                                mCurrentFullUserRecord.mCallback
-                                        .onMediaKeyEventDispatchedToMediaButtonReceiver(
-                                                keyEvent, componentName);
-                            }
-                        }
-                    } else {
-                        ComponentName receiver =
-                                mCurrentFullUserRecord.mRestoredMediaButtonReceiver;
-                        int componentType = mCurrentFullUserRecord
-                                .mRestoredMediaButtonReceiverComponentType;
-                        UserHandle userHandle = UserHandle.of(mCurrentFullUserRecord
-                                .mRestoredMediaButtonReceiverUserId);
-                        if (DEBUG_KEY_EVENT) {
-                            Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
-                                    + receiver + ", type=" + componentType);
-                        }
-                        mediaButtonIntent.setComponent(receiver);
-                        try {
-                            switch (componentType) {
-                                case FullUserRecord.COMPONENT_TYPE_ACTIVITY:
-                                    getContext().startActivityAsUser(mediaButtonIntent, userHandle);
-                                    break;
-                                case FullUserRecord.COMPONENT_TYPE_SERVICE:
-                                    getContext().startForegroundServiceAsUser(mediaButtonIntent,
-                                            userHandle);
-                                    break;
-                                default:
-                                    // Legacy behavior for other cases.
-                                    getContext().sendBroadcastAsUser(mediaButtonIntent, userHandle);
-                            }
-                        } catch (Exception e) {
-                            Log.w(TAG, "Error sending media button to the restored intent "
-                                    + receiver + ", type=" + componentType, e);
-                        }
-                        if (mCurrentFullUserRecord.mCallback != null) {
-                            mCurrentFullUserRecord.mCallback
-                                    .onMediaKeyEventDispatchedToMediaButtonReceiver(
-                                            keyEvent, receiver);
-                        }
-                    }
-                } catch (CanceledException e) {
-                    Log.i(TAG, "Error sending key event to media button receiver "
-                            + mCurrentFullUserRecord.mLastMediaButtonReceiver, e);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Failed to send callback", e);
-                }
-            }
-        }
-
-        private void startVoiceInput(boolean needWakeLock) {
-            Intent voiceIntent = null;
-            // select which type of search to launch:
-            // - screen on and device unlocked: action is ACTION_WEB_SEARCH
-            // - device locked or screen off: action is
-            // ACTION_VOICE_SEARCH_HANDS_FREE
-            // with EXTRA_SECURE set to true if the device is securely locked
-            PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
-            boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
-            if (!isLocked && pm.isScreenOn()) {
-                voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
-                Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
-            } else {
-                voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
-                voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
-                        isLocked && mKeyguardManager.isKeyguardSecure());
-                Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
-            }
-            // start the search activity
-            if (needWakeLock) {
-                mMediaEventWakeLock.acquire();
-            }
-            try {
-                if (voiceIntent != null) {
-                    voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                    if (DEBUG) Log.d(TAG, "voiceIntent: " + voiceIntent);
-                    getContext().startActivityAsUser(voiceIntent, UserHandle.CURRENT);
-                }
-            } catch (ActivityNotFoundException e) {
-                Log.w(TAG, "No activity for search: " + e);
-            } finally {
-                if (needWakeLock) {
-                    mMediaEventWakeLock.release();
-                }
-            }
-        }
-
-        private boolean isVoiceKey(int keyCode) {
-            return keyCode == KeyEvent.KEYCODE_HEADSETHOOK
-                    || (!mHasFeatureLeanback && keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
-        }
-
-        private boolean isUserSetupComplete() {
-            return Settings.Secure.getIntForUser(getContext().getContentResolver(),
-                    Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
-        }
-
-        // we only handle public stream types, which are 0-5
-        private boolean isValidLocalStreamType(int streamType) {
-            return streamType >= AudioManager.STREAM_VOICE_CALL
-                    && streamType <= AudioManager.STREAM_NOTIFICATION;
-        }
-
-        private class MediaKeyListenerResultReceiver extends ResultReceiver implements Runnable {
-            private final String mPackageName;
-            private final int mPid;
-            private final int mUid;
-            private final boolean mAsSystemService;
-            private final KeyEvent mKeyEvent;
-            private final boolean mNeedWakeLock;
-            private boolean mHandled;
-
-            private MediaKeyListenerResultReceiver(String packageName, int pid, int uid,
-                    boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
-                super(mHandler);
-                mHandler.postDelayed(this, MEDIA_KEY_LISTENER_TIMEOUT);
-                mPackageName = packageName;
-                mPid = pid;
-                mUid = uid;
-                mAsSystemService = asSystemService;
-                mKeyEvent = keyEvent;
-                mNeedWakeLock = needWakeLock;
-            }
-
-            @Override
-            public void run() {
-                Log.d(TAG, "The media key listener is timed-out for " + mKeyEvent);
-                dispatchMediaKeyEvent();
-            }
-
-            @Override
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                if (resultCode == MediaSessionManager.RESULT_MEDIA_KEY_HANDLED) {
-                    mHandled = true;
-                    mHandler.removeCallbacks(this);
-                    return;
-                }
-                dispatchMediaKeyEvent();
-            }
-
-            private void dispatchMediaKeyEvent() {
-                if (mHandled) {
-                    return;
-                }
-                mHandled = true;
-                mHandler.removeCallbacks(this);
-                synchronized (mLock) {
-                    if (!isGlobalPriorityActiveLocked()
-                            && isVoiceKey(mKeyEvent.getKeyCode())) {
-                        handleVoiceKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
-                                mKeyEvent, mNeedWakeLock);
-                    } else {
-                        dispatchMediaKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
-                                mKeyEvent, mNeedWakeLock);
-                    }
-                }
-            }
-        }
-
-        private KeyEventWakeLockReceiver mKeyEventReceiver = new KeyEventWakeLockReceiver(mHandler);
-
-        class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable,
-                PendingIntent.OnFinished {
-            private final Handler mHandler;
-            private int mRefCount = 0;
-            private int mLastTimeoutId = 0;
-
-            public KeyEventWakeLockReceiver(Handler handler) {
-                super(handler);
-                mHandler = handler;
-            }
-
-            public void onTimeout() {
-                synchronized (mLock) {
-                    if (mRefCount == 0) {
-                        // We've already released it, so just return
-                        return;
-                    }
-                    mLastTimeoutId++;
-                    mRefCount = 0;
-                    releaseWakeLockLocked();
-                }
-            }
-
-            public void aquireWakeLockLocked() {
-                if (mRefCount == 0) {
-                    mMediaEventWakeLock.acquire();
-                }
-                mRefCount++;
-                mHandler.removeCallbacks(this);
-                mHandler.postDelayed(this, WAKELOCK_TIMEOUT);
-
-            }
-
-            @Override
-            public void run() {
-                onTimeout();
-            }
-
-            @Override
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                if (resultCode < mLastTimeoutId) {
-                    // Ignore results from calls that were before the last
-                    // timeout, just in case.
-                    return;
-                } else {
-                    synchronized (mLock) {
-                        if (mRefCount > 0) {
-                            mRefCount--;
-                            if (mRefCount == 0) {
-                                releaseWakeLockLocked();
-                            }
-                        }
-                    }
-                }
-            }
-
-            private void releaseWakeLockLocked() {
-                mMediaEventWakeLock.release();
-                mHandler.removeCallbacks(this);
-            }
-
-            @Override
-            public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
-                    String resultData, Bundle resultExtras) {
-                onReceiveResult(resultCode, null);
-            }
-        };
-
-        BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (intent == null) {
-                    return;
-                }
-                Bundle extras = intent.getExtras();
-                if (extras == null) {
-                    return;
-                }
-                synchronized (mLock) {
-                    if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)
-                            && mMediaEventWakeLock.isHeld()) {
-                        mMediaEventWakeLock.release();
-                    }
-                }
-            }
-        };
-    }
-
-    final class MessageHandler extends Handler {
-        private static final int MSG_SESSIONS_CHANGED = 1;
-        private static final int MSG_VOLUME_INITIAL_DOWN = 2;
-        private final SparseArray<Integer> mIntegerCache = new SparseArray<>();
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_SESSIONS_CHANGED:
-                    pushSessionsChanged((int) msg.obj);
-                    break;
-                case MSG_VOLUME_INITIAL_DOWN:
-                    synchronized (mLock) {
-                        FullUserRecord user = mUserRecords.get((int) msg.arg1);
-                        if (user != null && user.mInitialDownVolumeKeyEvent != null) {
-                            dispatchVolumeKeyLongPressLocked(user.mInitialDownVolumeKeyEvent);
-                            // Mark that the key is already handled.
-                            user.mInitialDownVolumeKeyEvent = null;
-                        }
-                    }
-                    break;
-            }
-        }
-
-        public void postSessionsChanged(int userId) {
-            // Use object instead of the arguments when posting message to remove pending requests.
-            Integer userIdInteger = mIntegerCache.get(userId);
-            if (userIdInteger == null) {
-                userIdInteger = Integer.valueOf(userId);
-                mIntegerCache.put(userId, userIdInteger);
-            }
-            removeMessages(MSG_SESSIONS_CHANGED, userIdInteger);
-            obtainMessage(MSG_SESSIONS_CHANGED, userIdInteger).sendToTarget();
-        }
-    }
-
-    private class Controller2Callback extends MediaController2.ControllerCallback {
-        private final Session2Token mToken;
-
-        Controller2Callback(Session2Token token) {
-            mToken = token;
-        }
-
-        @Override
-        public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) {
-            synchronized (mLock) {
-                int userId = UserHandle.getUserId(mToken.getUid());
-                mSession2TokensPerUser.get(userId).add(mToken);
-                pushSession2TokensChangedLocked(userId);
-            }
-        }
-
-        @Override
-        public void onDisconnected(MediaController2 controller) {
-            synchronized (mLock) {
-                int userId = UserHandle.getUserId(mToken.getUid());
-                mSession2TokensPerUser.get(userId).remove(mToken);
-                pushSession2TokensChangedLocked(userId);
-            }
-        }
+    abstract static class ServiceImpl {
+        public abstract void onStart();
+        public abstract void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session);
+        public abstract void onSessionPlaystateChanged(
+                MediaSessionRecord record, int oldState, int newState);
+        public abstract void onSessionPlaybackTypeChanged(MediaSessionRecord record);
+        public abstract void onStartUser(int userId);
+        public abstract void onSwitchUser(int userId);
+        public abstract void monitor();
+        public abstract void onMediaButtonReceiverChanged(MediaSessionRecord record);
+        protected abstract void enforcePhoneStatePermission(int pid, int uid);
+        abstract void updateSession(MediaSessionRecord record);
+        abstract void setGlobalPrioritySession(MediaSessionRecord record);
+        abstract List<Session2Token> getSession2TokensLocked(int userId);
+        abstract void onStopUser(int userId);
+        abstract void sessionDied(MediaSessionRecord session);
+        abstract void destroySession(MediaSessionRecord session);
+        abstract void pushSession2TokensChangedLocked(int userId);
+        abstract Context getContext();
+        abstract IBinder getServiceBinder();
     }
 }
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
new file mode 100644
index 0000000..f374c6d
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -0,0 +1,2142 @@
+/*
+ * 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 com.android.server.media;
+
+import static android.os.UserHandle.USER_ALL;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.INotificationManager;
+import android.app.KeyguardManager;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.media.AudioManager;
+import android.media.AudioManagerInternal;
+import android.media.AudioPlaybackConfiguration;
+import android.media.AudioSystem;
+import android.media.IAudioService;
+import android.media.IRemoteVolumeController;
+import android.media.MediaController2;
+import android.media.Session2CommandGroup;
+import android.media.Session2Token;
+import android.media.session.IActiveSessionsListener;
+import android.media.session.ICallback;
+import android.media.session.IOnMediaKeyListener;
+import android.media.session.IOnVolumeKeyLongPressListener;
+import android.media.session.ISession;
+import android.media.session.ISession2TokensListener;
+import android.media.session.ISessionManager;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
+import android.media.session.SessionCallbackLink;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.speech.RecognizerIntent;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.DumpUtils;
+import com.android.server.LocalServices;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * System implementation of MediaSessionManager
+ */
+public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
+    private static final String TAG = "MediaSessionService";
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    // Leave log for key event always.
+    private static final boolean DEBUG_KEY_EVENT = true;
+
+    private static final int WAKELOCK_TIMEOUT = 5000;
+    private static final int MEDIA_KEY_LISTENER_TIMEOUT = 1000;
+
+    private final Context mContext;
+    private final SessionManagerImpl mSessionManagerImpl;
+    private final MessageHandler mHandler = new MessageHandler();
+    private final PowerManager.WakeLock mMediaEventWakeLock;
+    private final int mLongPressTimeout;
+    private final INotificationManager mNotificationManager;
+    private final Object mLock = new Object();
+    // Keeps the full user id for each user.
+    @GuardedBy("mLock")
+    private final SparseIntArray mFullUserIds = new SparseIntArray();
+    @GuardedBy("mLock")
+    private final SparseArray<FullUserRecord> mUserRecords = new SparseArray<FullUserRecord>();
+    @GuardedBy("mLock")
+    private final ArrayList<SessionsListenerRecord> mSessionsListeners =
+            new ArrayList<SessionsListenerRecord>();
+    // Map user id as index to list of Session2Tokens
+    // TODO: Keep session2 info in MediaSessionStack for prioritizing both session1 and session2 in
+    //       one place.
+    @GuardedBy("mLock")
+    private final SparseArray<List<Session2Token>> mSession2TokensPerUser = new SparseArray<>();
+    @GuardedBy("mLock")
+    private final List<Session2TokensListenerRecord> mSession2TokensListenerRecords =
+            new ArrayList<>();
+
+    private KeyguardManager mKeyguardManager;
+    private IAudioService mAudioService;
+    private AudioManagerInternal mAudioManagerInternal;
+    private ActivityManager mActivityManager;
+    private ContentResolver mContentResolver;
+    private SettingsObserver mSettingsObserver;
+    private boolean mHasFeatureLeanback;
+
+    // The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile)
+    // It's always not null after the MediaSessionService is started.
+    private FullUserRecord mCurrentFullUserRecord;
+    private MediaSessionRecord mGlobalPrioritySession;
+    private AudioPlayerStateMonitor mAudioPlayerStateMonitor;
+
+    // Used to notify system UI when remote volume was changed. TODO find a
+    // better way to handle this.
+    private IRemoteVolumeController mRvc;
+
+    public MediaSessionServiceImpl(Context context) {
+        mContext = context;
+        mSessionManagerImpl = new SessionManagerImpl();
+        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
+        mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
+        mNotificationManager = INotificationManager.Stub.asInterface(
+                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+    }
+
+    Context getContext() {
+        return mContext;
+    }
+
+    IBinder getServiceBinder() {
+        return mSessionManagerImpl;
+    }
+
+    @Override
+    public void onStart() {
+        mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        mAudioService = getAudioService();
+        mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
+        mActivityManager =
+                (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+        mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
+        mAudioPlayerStateMonitor.registerListener(
+                (config, isRemoved) -> {
+                    if (isRemoved || !config.isActive() || config.getPlayerType()
+                            == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
+                        return;
+                    }
+                    synchronized (mLock) {
+                        FullUserRecord user = getFullUserRecordLocked(
+                                UserHandle.getUserId(config.getClientUid()));
+                        if (user != null) {
+                            user.mPriorityStack.updateMediaButtonSessionIfNeeded();
+                        }
+                    }
+                }, null /* handler */);
+        mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
+        mContentResolver = mContext.getContentResolver();
+        mSettingsObserver = new SettingsObserver();
+        mSettingsObserver.observe();
+        mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_LEANBACK);
+
+        updateUser();
+    }
+
+    private IAudioService getAudioService() {
+        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+        return IAudioService.Stub.asInterface(b);
+    }
+
+    private boolean isGlobalPriorityActiveLocked() {
+        return mGlobalPrioritySession != null && mGlobalPrioritySession.isActive();
+    }
+
+    @Override
+    public void updateSession(MediaSessionRecord record) {
+        synchronized (mLock) {
+            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+            if (user == null) {
+                Log.w(TAG, "Unknown session updated. Ignoring.");
+                return;
+            }
+            if ((record.getFlags() & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
+                if (DEBUG_KEY_EVENT) {
+                    Log.d(TAG, "Global priority session is updated, active=" + record.isActive());
+                }
+                user.pushAddressedPlayerChangedLocked();
+            } else {
+                if (!user.mPriorityStack.contains(record)) {
+                    Log.w(TAG, "Unknown session updated. Ignoring.");
+                    return;
+                }
+                user.mPriorityStack.onSessionStateChange(record);
+            }
+            mHandler.postSessionsChanged(record.getUserId());
+        }
+    }
+
+    @Override
+    public void setGlobalPrioritySession(MediaSessionRecord record) {
+        synchronized (mLock) {
+            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+            if (mGlobalPrioritySession != record) {
+                Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession
+                        + " to " + record);
+                mGlobalPrioritySession = record;
+                if (user != null && user.mPriorityStack.contains(record)) {
+                    // Handle the global priority session separately.
+                    // Otherwise, it can be the media button session regardless of the active state
+                    // because it or other system components might have been the lastly played media
+                    // app.
+                    user.mPriorityStack.removeSession(record);
+                }
+            }
+        }
+    }
+
+    private List<MediaSessionRecord> getActiveSessionsLocked(int userId) {
+        List<MediaSessionRecord> records = new ArrayList<>();
+        if (userId == USER_ALL) {
+            int size = mUserRecords.size();
+            for (int i = 0; i < size; i++) {
+                records.addAll(mUserRecords.valueAt(i).mPriorityStack.getActiveSessions(userId));
+            }
+        } else {
+            FullUserRecord user = getFullUserRecordLocked(userId);
+            if (user == null) {
+                Log.w(TAG, "getSessions failed. Unknown user " + userId);
+                return records;
+            }
+            records.addAll(user.mPriorityStack.getActiveSessions(userId));
+        }
+
+        // Return global priority session at the first whenever it's asked.
+        if (isGlobalPriorityActiveLocked()
+                && (userId == USER_ALL || userId == mGlobalPrioritySession.getUserId())) {
+            records.add(0, mGlobalPrioritySession);
+        }
+        return records;
+    }
+
+    List<Session2Token> getSession2TokensLocked(int userId) {
+        List<Session2Token> list = new ArrayList<>();
+        if (userId == USER_ALL) {
+            for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
+                list.addAll(mSession2TokensPerUser.valueAt(i));
+            }
+        } else {
+            list.addAll(mSession2TokensPerUser.get(userId));
+        }
+        return list;
+    }
+
+    /**
+     * Tells the system UI that volume has changed on an active remote session.
+     */
+    public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) {
+        if (mRvc == null || !session.isActive()) {
+            return;
+        }
+        try {
+            mRvc.remoteVolumeChanged(session.getControllerBinder(), flags);
+        } catch (Exception e) {
+            Log.wtf(TAG, "Error sending volume change to system UI.", e);
+        }
+    }
+
+    @Override
+    public void onSessionPlaystateChanged(MediaSessionRecord record, int oldState, int newState) {
+        synchronized (mLock) {
+            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+            if (user == null || !user.mPriorityStack.contains(record)) {
+                Log.d(TAG, "Unknown session changed playback state. Ignoring.");
+                return;
+            }
+            user.mPriorityStack.onPlaystateChanged(record, oldState, newState);
+        }
+    }
+
+    @Override
+    public void onSessionPlaybackTypeChanged(MediaSessionRecord record) {
+        synchronized (mLock) {
+            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+            if (user == null || !user.mPriorityStack.contains(record)) {
+                Log.d(TAG, "Unknown session changed playback type. Ignoring.");
+                return;
+            }
+            pushRemoteVolumeUpdateLocked(record.getUserId());
+        }
+    }
+
+    @Override
+    public void onStartUser(int userId) {
+        if (DEBUG) Log.d(TAG, "onStartUser: " + userId);
+        updateUser();
+    }
+
+    @Override
+    public void onSwitchUser(int userId) {
+        if (DEBUG) Log.d(TAG, "onSwitchUser: " + userId);
+        updateUser();
+    }
+
+    // Called when the user with the userId is removed.
+    @Override
+    public void onStopUser(int userId) {
+        if (DEBUG) Log.d(TAG, "onStopUser: " + userId);
+        synchronized (mLock) {
+            // TODO: Also handle removing user in updateUser() because adding/switching user is
+            //       handled in updateUser().
+            FullUserRecord user = getFullUserRecordLocked(userId);
+            if (user != null) {
+                if (user.mFullUserId == userId) {
+                    user.destroySessionsForUserLocked(USER_ALL);
+                    mUserRecords.remove(userId);
+                } else {
+                    user.destroySessionsForUserLocked(userId);
+                }
+            }
+            mSession2TokensPerUser.remove(userId);
+            updateUser();
+        }
+    }
+
+    @Override
+    public void monitor() {
+        synchronized (mLock) {
+            // Check for deadlock
+        }
+    }
+
+    protected void enforcePhoneStatePermission(int pid, int uid) {
+        if (mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must hold the MODIFY_PHONE_STATE permission.");
+        }
+    }
+
+    void sessionDied(MediaSessionRecord session) {
+        synchronized (mLock) {
+            destroySessionLocked(session);
+        }
+    }
+
+    void destroySession(MediaSessionRecord session) {
+        synchronized (mLock) {
+            destroySessionLocked(session);
+        }
+    }
+
+    private void updateUser() {
+        synchronized (mLock) {
+            UserManager manager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            mFullUserIds.clear();
+            List<UserInfo> allUsers = manager.getUsers();
+            if (allUsers != null) {
+                for (UserInfo userInfo : allUsers) {
+                    if (userInfo.isManagedProfile()) {
+                        mFullUserIds.put(userInfo.id, userInfo.profileGroupId);
+                    } else {
+                        mFullUserIds.put(userInfo.id, userInfo.id);
+                        if (mUserRecords.get(userInfo.id) == null) {
+                            mUserRecords.put(userInfo.id, new FullUserRecord(userInfo.id));
+                        }
+                    }
+                    if (mSession2TokensPerUser.get(userInfo.id) == null) {
+                        mSession2TokensPerUser.put(userInfo.id, new ArrayList<>());
+                    }
+                }
+            }
+            // Ensure that the current full user exists.
+            int currentFullUserId = ActivityManager.getCurrentUser();
+            mCurrentFullUserRecord = mUserRecords.get(currentFullUserId);
+            if (mCurrentFullUserRecord == null) {
+                Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId);
+                mCurrentFullUserRecord = new FullUserRecord(currentFullUserId);
+                mUserRecords.put(currentFullUserId, mCurrentFullUserRecord);
+                if (mSession2TokensPerUser.get(currentFullUserId) == null) {
+                    mSession2TokensPerUser.put(currentFullUserId, new ArrayList<>());
+                }
+            }
+            mFullUserIds.put(currentFullUserId, currentFullUserId);
+        }
+    }
+
+    private void updateActiveSessionListeners() {
+        synchronized (mLock) {
+            for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
+                SessionsListenerRecord listener = mSessionsListeners.get(i);
+                try {
+                    enforceMediaPermissions(listener.componentName, listener.pid, listener.uid,
+                            listener.userId);
+                } catch (SecurityException e) {
+                    Log.i(TAG, "ActiveSessionsListener " + listener.componentName
+                            + " is no longer authorized. Disconnecting.");
+                    mSessionsListeners.remove(i);
+                    try {
+                        listener.listener
+                                .onActiveSessionsChanged(new ArrayList<MediaSession.Token>());
+                    } catch (Exception e1) {
+                        // ignore
+                    }
+                }
+            }
+        }
+    }
+
+    /*
+     * When a session is removed several things need to happen.
+     * 1. We need to remove it from the relevant user.
+     * 2. We need to remove it from the priority stack.
+     * 3. We need to remove it from all sessions.
+     * 4. If this is the system priority session we need to clear it.
+     * 5. We need to unlink to death from the cb binder
+     * 6. We need to tell the session to do any final cleanup (onDestroy)
+     */
+    private void destroySessionLocked(MediaSessionRecord session) {
+        if (DEBUG) {
+            Log.d(TAG, "Destroying " + session);
+        }
+        FullUserRecord user = getFullUserRecordLocked(session.getUserId());
+        if (mGlobalPrioritySession == session) {
+            mGlobalPrioritySession = null;
+            if (session.isActive() && user != null) {
+                user.pushAddressedPlayerChangedLocked();
+            }
+        } else {
+            if (user != null) {
+                user.mPriorityStack.removeSession(session);
+            }
+        }
+
+        try {
+            session.getCallback().getBinder().unlinkToDeath(session, 0);
+        } catch (Exception e) {
+            // ignore exceptions while destroying a session.
+        }
+        session.onDestroy();
+        mHandler.postSessionsChanged(session.getUserId());
+    }
+
+    private void enforcePackageName(String packageName, int uid) {
+        if (TextUtils.isEmpty(packageName)) {
+            throw new IllegalArgumentException("packageName may not be empty");
+        }
+        String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
+        final int packageCount = packages.length;
+        for (int i = 0; i < packageCount; i++) {
+            if (packageName.equals(packages[i])) {
+                return;
+            }
+        }
+        throw new IllegalArgumentException("packageName is not owned by the calling process");
+    }
+
+    /**
+     * Checks a caller's authorization to register an IRemoteControlDisplay.
+     * Authorization is granted if one of the following is true:
+     * <ul>
+     * <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL
+     * permission</li>
+     * <li>the caller's listener is one of the enabled notification listeners
+     * for the caller's user</li>
+     * </ul>
+     */
+    private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
+            int resolvedUserId) {
+        if (isCurrentVolumeController(pid, uid)) return;
+        if (mContext
+                .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
+                != PackageManager.PERMISSION_GRANTED
+                && !isEnabledNotificationListener(compName, UserHandle.getUserId(uid),
+                resolvedUserId)) {
+            throw new SecurityException("Missing permission to control media.");
+        }
+    }
+
+    private boolean isCurrentVolumeController(int pid, int uid) {
+        return mContext.checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
+                pid, uid) == PackageManager.PERMISSION_GRANTED;
+    }
+
+    private void enforceSystemUiPermission(String action, int pid, int uid) {
+        if (!isCurrentVolumeController(pid, uid)) {
+            throw new SecurityException("Only system ui may " + action);
+        }
+    }
+
+    /**
+     * This checks if the component is an enabled notification listener for the
+     * specified user. Enabled components may only operate on behalf of the user
+     * they're running as.
+     *
+     * @param compName The component that is enabled.
+     * @param userId The user id of the caller.
+     * @param forUserId The user id they're making the request on behalf of.
+     * @return True if the component is enabled, false otherwise
+     */
+    private boolean isEnabledNotificationListener(ComponentName compName, int userId,
+            int forUserId) {
+        if (userId != forUserId) {
+            // You may not access another user's content as an enabled listener.
+            return false;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Checking if enabled notification listener " + compName);
+        }
+        if (compName != null) {
+            try {
+                return mNotificationManager.isNotificationListenerAccessGrantedForUser(
+                        compName, userId);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Dead NotificationManager in isEnabledNotificationListener", e);
+            }
+        }
+        return false;
+    }
+
+    private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
+            String callerPackageName, SessionCallbackLink cb, String tag) throws RemoteException {
+        synchronized (mLock) {
+            return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag);
+        }
+    }
+
+    /*
+     * When a session is created the following things need to happen.
+     * 1. Its callback binder needs a link to death
+     * 2. It needs to be added to all sessions.
+     * 3. It needs to be added to the priority stack.
+     * 4. It needs to be added to the relevant user record.
+     */
+    private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
+            String callerPackageName, SessionCallbackLink cb, String tag) {
+        FullUserRecord user = getFullUserRecordLocked(userId);
+        if (user == null) {
+            Log.wtf(TAG, "Request from invalid user: " +  userId);
+            throw new RuntimeException("Session request from invalid user.");
+        }
+
+        final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
+                callerPackageName, cb, tag, this, mHandler.getLooper());
+        try {
+            cb.getBinder().linkToDeath(session, 0);
+        } catch (RemoteException e) {
+            throw new RuntimeException("Media Session owner died prematurely.", e);
+        }
+
+        user.mPriorityStack.addSession(session);
+        mHandler.postSessionsChanged(userId);
+
+        if (DEBUG) {
+            Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
+        }
+        return session;
+    }
+
+    private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
+        for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
+            if (mSessionsListeners.get(i).listener.asBinder() == listener.asBinder()) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private int findIndexOfSession2TokensListenerLocked(ISession2TokensListener listener) {
+        for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
+            if (mSession2TokensListenerRecords.get(i).listener.asBinder() == listener.asBinder()) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+
+    private void pushSessionsChanged(int userId) {
+        synchronized (mLock) {
+            FullUserRecord user = getFullUserRecordLocked(userId);
+            if (user == null) {
+                Log.w(TAG, "pushSessionsChanged failed. No user with id=" + userId);
+                return;
+            }
+            List<MediaSessionRecord> records = getActiveSessionsLocked(userId);
+            int size = records.size();
+            ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>();
+            for (int i = 0; i < size; i++) {
+                tokens.add(new MediaSession.Token(records.get(i).getControllerBinder()));
+            }
+            pushRemoteVolumeUpdateLocked(userId);
+            for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
+                SessionsListenerRecord record = mSessionsListeners.get(i);
+                if (record.userId == USER_ALL || record.userId == userId) {
+                    try {
+                        record.listener.onActiveSessionsChanged(tokens);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Dead ActiveSessionsListener in pushSessionsChanged, removing",
+                                e);
+                        mSessionsListeners.remove(i);
+                    }
+                }
+            }
+        }
+    }
+
+    private void pushRemoteVolumeUpdateLocked(int userId) {
+        if (mRvc != null) {
+            try {
+                FullUserRecord user = getFullUserRecordLocked(userId);
+                if (user == null) {
+                    Log.w(TAG, "pushRemoteVolumeUpdateLocked failed. No user with id=" + userId);
+                    return;
+                }
+                MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
+                mRvc.updateRemoteController(record == null ? null : record.getControllerBinder());
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error sending default remote volume to sys ui.", e);
+            }
+        }
+    }
+
+    void pushSession2TokensChangedLocked(int userId) {
+        List<Session2Token> allSession2Tokens = getSession2TokensLocked(USER_ALL);
+        List<Session2Token> session2Tokens = getSession2TokensLocked(userId);
+
+        for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
+            Session2TokensListenerRecord listenerRecord = mSession2TokensListenerRecords.get(i);
+            try {
+                if (listenerRecord.userId == USER_ALL) {
+                    listenerRecord.listener.onSession2TokensChanged(allSession2Tokens);
+                } else if (listenerRecord.userId == userId) {
+                    listenerRecord.listener.onSession2TokensChanged(session2Tokens);
+                }
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to notify Session2Token change. Removing listener.", e);
+                mSession2TokensListenerRecords.remove(i);
+            }
+        }
+    }
+
+    /**
+     * Called when the media button receiver for the {@code record} is changed.
+     *
+     * @param record the media session whose media button receiver is updated.
+     */
+    public void onMediaButtonReceiverChanged(MediaSessionRecord record) {
+        synchronized (mLock) {
+            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+            MediaSessionRecord mediaButtonSession =
+                    user.mPriorityStack.getMediaButtonSession();
+            if (record == mediaButtonSession) {
+                user.rememberMediaButtonReceiverLocked(mediaButtonSession);
+            }
+        }
+    }
+
+    private String getCallingPackageName(int uid) {
+        String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
+        if (packages != null && packages.length > 0) {
+            return packages[0];
+        }
+        return "";
+    }
+
+    private void dispatchVolumeKeyLongPressLocked(KeyEvent keyEvent) {
+        if (mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
+            return;
+        }
+        try {
+            mCurrentFullUserRecord.mOnVolumeKeyLongPressListener.onVolumeKeyLongPress(keyEvent);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to send " + keyEvent + " to volume key long-press listener");
+        }
+    }
+
+    private FullUserRecord getFullUserRecordLocked(int userId) {
+        int fullUserId = mFullUserIds.get(userId, -1);
+        if (fullUserId < 0) {
+            return null;
+        }
+        return mUserRecords.get(fullUserId);
+    }
+
+    /**
+     * Information about a full user and its corresponding managed profiles.
+     *
+     * <p>Since the full user runs together with its managed profiles, a user wouldn't differentiate
+     * them when he/she presses a media/volume button. So keeping media sessions for them in one
+     * place makes more sense and increases the readability.</p>
+     * <p>The contents of this object is guarded by {@link #mLock}.
+     */
+    final class FullUserRecord implements MediaSessionStack.OnMediaButtonSessionChangedListener {
+        public static final int COMPONENT_TYPE_INVALID = 0;
+        public static final int COMPONENT_TYPE_BROADCAST = 1;
+        public static final int COMPONENT_TYPE_ACTIVITY = 2;
+        public static final int COMPONENT_TYPE_SERVICE = 3;
+        private static final String COMPONENT_NAME_USER_ID_DELIM = ",";
+
+        private final int mFullUserId;
+        private final MediaSessionStack mPriorityStack;
+        private PendingIntent mLastMediaButtonReceiver;
+        private ComponentName mRestoredMediaButtonReceiver;
+        private int mRestoredMediaButtonReceiverComponentType;
+        private int mRestoredMediaButtonReceiverUserId;
+
+        private IOnVolumeKeyLongPressListener mOnVolumeKeyLongPressListener;
+        private int mOnVolumeKeyLongPressListenerUid;
+        private KeyEvent mInitialDownVolumeKeyEvent;
+        private int mInitialDownVolumeStream;
+        private boolean mInitialDownMusicOnly;
+
+        private IOnMediaKeyListener mOnMediaKeyListener;
+        private int mOnMediaKeyListenerUid;
+        private ICallback mCallback;
+
+        FullUserRecord(int fullUserId) {
+            mFullUserId = fullUserId;
+            mPriorityStack = new MediaSessionStack(mAudioPlayerStateMonitor, this);
+            // Restore the remembered media button receiver before the boot.
+            String mediaButtonReceiverInfo = Settings.Secure.getStringForUser(mContentResolver,
+                    Settings.System.MEDIA_BUTTON_RECEIVER, mFullUserId);
+            if (mediaButtonReceiverInfo == null) {
+                return;
+            }
+            String[] tokens = mediaButtonReceiverInfo.split(COMPONENT_NAME_USER_ID_DELIM);
+            if (tokens == null || (tokens.length != 2 && tokens.length != 3)) {
+                return;
+            }
+            mRestoredMediaButtonReceiver = ComponentName.unflattenFromString(tokens[0]);
+            mRestoredMediaButtonReceiverUserId = Integer.parseInt(tokens[1]);
+            if (tokens.length == 3) {
+                mRestoredMediaButtonReceiverComponentType = Integer.parseInt(tokens[2]);
+            } else {
+                mRestoredMediaButtonReceiverComponentType =
+                        getComponentType(mRestoredMediaButtonReceiver);
+            }
+        }
+
+        public void destroySessionsForUserLocked(int userId) {
+            List<MediaSessionRecord> sessions = mPriorityStack.getPriorityList(false, userId);
+            for (MediaSessionRecord session : sessions) {
+                MediaSessionServiceImpl.this.destroySessionLocked(session);
+            }
+        }
+
+        public void dumpLocked(PrintWriter pw, String prefix) {
+            pw.print(prefix + "Record for full_user=" + mFullUserId);
+            // Dump managed profile user ids associated with this user.
+            int size = mFullUserIds.size();
+            for (int i = 0; i < size; i++) {
+                if (mFullUserIds.keyAt(i) != mFullUserIds.valueAt(i)
+                        && mFullUserIds.valueAt(i) == mFullUserId) {
+                    pw.print(", profile_user=" + mFullUserIds.keyAt(i));
+                }
+            }
+            pw.println();
+            String indent = prefix + "  ";
+            pw.println(indent + "Volume key long-press listener: " + mOnVolumeKeyLongPressListener);
+            pw.println(indent + "Volume key long-press listener package: "
+                    + getCallingPackageName(mOnVolumeKeyLongPressListenerUid));
+            pw.println(indent + "Media key listener: " + mOnMediaKeyListener);
+            pw.println(indent + "Media key listener package: "
+                    + getCallingPackageName(mOnMediaKeyListenerUid));
+            pw.println(indent + "Callback: " + mCallback);
+            pw.println(indent + "Last MediaButtonReceiver: " + mLastMediaButtonReceiver);
+            pw.println(indent + "Restored MediaButtonReceiver: " + mRestoredMediaButtonReceiver);
+            pw.println(indent + "Restored MediaButtonReceiverComponentType: "
+                    + mRestoredMediaButtonReceiverComponentType);
+            mPriorityStack.dump(pw, indent);
+            pw.println(indent + "Session2Tokens:");
+            for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
+                List<Session2Token> list = mSession2TokensPerUser.valueAt(i);
+                if (list == null || list.size() == 0) {
+                    continue;
+                }
+                for (Session2Token token : list) {
+                    pw.println(indent + "  " + token);
+                }
+            }
+        }
+
+        @Override
+        public void onMediaButtonSessionChanged(MediaSessionRecord oldMediaButtonSession,
+                MediaSessionRecord newMediaButtonSession) {
+            if (DEBUG_KEY_EVENT) {
+                Log.d(TAG, "Media button session is changed to " + newMediaButtonSession);
+            }
+            synchronized (mLock) {
+                if (oldMediaButtonSession != null) {
+                    mHandler.postSessionsChanged(oldMediaButtonSession.getUserId());
+                }
+                if (newMediaButtonSession != null) {
+                    rememberMediaButtonReceiverLocked(newMediaButtonSession);
+                    mHandler.postSessionsChanged(newMediaButtonSession.getUserId());
+                }
+                pushAddressedPlayerChangedLocked();
+            }
+        }
+
+        // Remember media button receiver and keep it in the persistent storage.
+        public void rememberMediaButtonReceiverLocked(MediaSessionRecord record) {
+            PendingIntent receiver = record.getMediaButtonReceiver();
+            mLastMediaButtonReceiver = receiver;
+            mRestoredMediaButtonReceiver = null;
+            mRestoredMediaButtonReceiverComponentType = COMPONENT_TYPE_INVALID;
+
+            String mediaButtonReceiverInfo = "";
+            if (receiver != null) {
+                ComponentName component = receiver.getIntent().getComponent();
+                if (component != null
+                        && record.getPackageName().equals(component.getPackageName())) {
+                    String componentName = component.flattenToString();
+                    int componentType = getComponentType(component);
+                    mediaButtonReceiverInfo = String.join(COMPONENT_NAME_USER_ID_DELIM,
+                            componentName, String.valueOf(record.getUserId()),
+                            String.valueOf(componentType));
+                }
+            }
+            Settings.Secure.putStringForUser(mContentResolver,
+                    Settings.System.MEDIA_BUTTON_RECEIVER, mediaButtonReceiverInfo,
+                    mFullUserId);
+        }
+
+        private void pushAddressedPlayerChangedLocked() {
+            if (mCallback == null) {
+                return;
+            }
+            try {
+                MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked();
+                if (mediaButtonSession != null) {
+                    mCallback.onAddressedPlayerChangedToMediaSession(
+                            new MediaSession.Token(mediaButtonSession.getControllerBinder()));
+                } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
+                    mCallback.onAddressedPlayerChangedToMediaButtonReceiver(
+                            mCurrentFullUserRecord.mLastMediaButtonReceiver
+                                    .getIntent().getComponent());
+                } else if (mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
+                    mCallback.onAddressedPlayerChangedToMediaButtonReceiver(
+                            mCurrentFullUserRecord.mRestoredMediaButtonReceiver);
+                }
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to pushAddressedPlayerChangedLocked", e);
+            }
+        }
+
+        private MediaSessionRecord getMediaButtonSessionLocked() {
+            return isGlobalPriorityActiveLocked()
+                    ? mGlobalPrioritySession : mPriorityStack.getMediaButtonSession();
+        }
+
+        private int getComponentType(@Nullable ComponentName componentName) {
+            if (componentName == null) {
+                return COMPONENT_TYPE_INVALID;
+            }
+            PackageManager pm = mContext.getPackageManager();
+            try {
+                ActivityInfo activityInfo = pm.getActivityInfo(componentName,
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                                | PackageManager.GET_ACTIVITIES);
+                if (activityInfo != null) {
+                    return COMPONENT_TYPE_ACTIVITY;
+                }
+            } catch (NameNotFoundException e) {
+            }
+            try {
+                ServiceInfo serviceInfo = pm.getServiceInfo(componentName,
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                                | PackageManager.GET_SERVICES);
+                if (serviceInfo != null) {
+                    return COMPONENT_TYPE_SERVICE;
+                }
+            } catch (NameNotFoundException e) {
+            }
+            // Pick legacy behavior for BroadcastReceiver or unknown.
+            return COMPONENT_TYPE_BROADCAST;
+        }
+    }
+
+    final class SessionsListenerRecord implements IBinder.DeathRecipient {
+        public final IActiveSessionsListener listener;
+        public final ComponentName componentName;
+        public final int userId;
+        public final int pid;
+        public final int uid;
+
+        SessionsListenerRecord(IActiveSessionsListener listener,
+                ComponentName componentName,
+                int userId, int pid, int uid) {
+            this.listener = listener;
+            this.componentName = componentName;
+            this.userId = userId;
+            this.pid = pid;
+            this.uid = uid;
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (mLock) {
+                mSessionsListeners.remove(this);
+            }
+        }
+    }
+
+    final class Session2TokensListenerRecord implements IBinder.DeathRecipient {
+        public final ISession2TokensListener listener;
+        public final int userId;
+
+        Session2TokensListenerRecord(ISession2TokensListener listener,
+                int userId) {
+            this.listener = listener;
+            this.userId = userId;
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (mLock) {
+                mSession2TokensListenerRecords.remove(this);
+            }
+        }
+    }
+
+    final class SettingsObserver extends ContentObserver {
+        private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(
+                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+
+        private SettingsObserver() {
+            super(null);
+        }
+
+        private void observe() {
+            mContentResolver.registerContentObserver(mSecureSettingsUri,
+                    false, this, USER_ALL);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            updateActiveSessionListeners();
+        }
+    }
+
+    class SessionManagerImpl extends ISessionManager.Stub {
+        private static final String EXTRA_WAKELOCK_ACQUIRED =
+                "android.media.AudioService.WAKELOCK_ACQUIRED";
+        private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number
+
+        private boolean mVoiceButtonDown = false;
+        private boolean mVoiceButtonHandled = false;
+
+        @Override
+        public ISession createSession(String packageName, SessionCallbackLink cb, String tag,
+                int userId) throws RemoteException {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                enforcePackageName(packageName, uid);
+                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                        false /* allowAll */, true /* requireFull */, "createSession", packageName);
+                if (cb == null) {
+                    throw new IllegalArgumentException("Controller callback cannot be null");
+                }
+                return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag)
+                        .getSessionBinder();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifySession2Created(Session2Token sessionToken) throws RemoteException {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (DEBUG) {
+                    Log.d(TAG, "Session2 is created " + sessionToken);
+                }
+                if (uid != sessionToken.getUid()) {
+                    throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid
+                            + " but actually=" + sessionToken.getUid());
+                }
+                Controller2Callback callback = new Controller2Callback(sessionToken);
+                // Note: It's safe not to keep controller here because it wouldn't be GC'ed until
+                //       it's closed.
+                // TODO: Keep controller as well for better readability
+                //       because the GC behavior isn't straightforward.
+                MediaController2 controller = new MediaController2(mContext, sessionToken,
+                        new HandlerExecutor(mHandler), callback);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public List<IBinder> 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<IBinder> binders = new ArrayList<IBinder>();
+                synchronized (mLock) {
+                    List<MediaSessionRecord> records = getActiveSessionsLocked(resolvedUserId);
+                    for (MediaSessionRecord record : records) {
+                        binders.add(record.getControllerBinder().asBinder());
+                    }
+                }
+                return binders;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public List<Session2Token> getSession2Tokens(int userId) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                // Check that they can make calls on behalf of the user and
+                // get the final user id
+                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                        true /* allowAll */, true /* requireFull */, "getSession2Tokens",
+                        null /* optional packageName */);
+                List<Session2Token> result;
+                synchronized (mLock) {
+                    result = getSession2TokensLocked(resolvedUserId);
+                }
+                return result;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void addSessionsListener(IActiveSessionsListener listener,
+                ComponentName componentName, int userId) throws RemoteException {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
+                synchronized (mLock) {
+                    int index = findIndexOfSessionsListenerLocked(listener);
+                    if (index != -1) {
+                        Log.w(TAG, "ActiveSessionsListener is already added, ignoring");
+                        return;
+                    }
+                    SessionsListenerRecord record = new SessionsListenerRecord(listener,
+                            componentName, resolvedUserId, pid, uid);
+                    try {
+                        listener.asBinder().linkToDeath(record, 0);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "ActiveSessionsListener is dead, ignoring it", e);
+                        return;
+                    }
+                    mSessionsListeners.add(record);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void removeSessionsListener(IActiveSessionsListener listener)
+                throws RemoteException {
+            synchronized (mLock) {
+                int index = findIndexOfSessionsListenerLocked(listener);
+                if (index != -1) {
+                    SessionsListenerRecord record = mSessionsListeners.remove(index);
+                    try {
+                        record.listener.asBinder().unlinkToDeath(record, 0);
+                    } catch (Exception e) {
+                        // ignore exceptions, the record is being removed
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void addSession2TokensListener(ISession2TokensListener listener,
+                int userId) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                // Check that they can make calls on behalf of the user and get the final user id.
+                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                        true /* allowAll */, true /* requireFull */, "addSession2TokensListener",
+                        null /* optional packageName */);
+                synchronized (mLock) {
+                    int index = findIndexOfSession2TokensListenerLocked(listener);
+                    if (index >= 0) {
+                        Log.w(TAG, "addSession2TokensListener is already added, ignoring");
+                        return;
+                    }
+                    mSession2TokensListenerRecords.add(
+                            new Session2TokensListenerRecord(listener, resolvedUserId));
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void removeSession2TokensListener(ISession2TokensListener listener) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                synchronized (mLock) {
+                    int index = findIndexOfSession2TokensListenerLocked(listener);
+                    if (index >= 0) {
+                        Session2TokensListenerRecord listenerRecord =
+                                mSession2TokensListenerRecords.remove(index);
+                        try {
+                            listenerRecord.listener.asBinder().unlinkToDeath(listenerRecord, 0);
+                        } catch (Exception e) {
+                            // Ignore exception.
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        /**
+         * Handles the dispatching of the media button events to one of the
+         * registered listeners, or if there was none, broadcast an
+         * ACTION_MEDIA_BUTTON intent to the rest of the system.
+         *
+         * @param packageName The caller package
+         * @param asSystemService {@code true} if the event sent to the session as if it was come
+         *          from the system service instead of the app process. This helps sessions to
+         *          distinguish between the key injection by the app and key events from the
+         *          hardware devices. Should be used only when the volume key events aren't handled
+         *          by foreground activity. {@code false} otherwise to tell session about the real
+         *          caller.
+         * @param keyEvent a non-null KeyEvent whose key code is one of the
+         *            supported media buttons
+         * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held
+         *            while this key event is dispatched.
+         */
+        @Override
+        public void dispatchMediaKeyEvent(String packageName, boolean asSystemService,
+                KeyEvent keyEvent, boolean needWakeLock) {
+            if (keyEvent == null || !KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
+                Log.w(TAG, "Attempted to dispatch null or non-media key event.");
+                return;
+            }
+
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (DEBUG) {
+                    Log.d(TAG, "dispatchMediaKeyEvent, pkg=" + packageName + " pid=" + pid
+                            + ", uid=" + uid + ", asSystem=" + asSystemService + ", event="
+                            + keyEvent);
+                }
+                if (!isUserSetupComplete()) {
+                    // Global media key handling can have the side-effect of starting new
+                    // activities which is undesirable while setup is in progress.
+                    Slog.i(TAG, "Not dispatching media key event because user "
+                            + "setup is in progress.");
+                    return;
+                }
+
+                synchronized (mLock) {
+                    boolean isGlobalPriorityActive = isGlobalPriorityActiveLocked();
+                    if (isGlobalPriorityActive && uid != Process.SYSTEM_UID) {
+                        // Prevent dispatching key event through reflection while the global
+                        // priority session is active.
+                        Slog.i(TAG, "Only the system can dispatch media key event "
+                                + "to the global priority session.");
+                        return;
+                    }
+                    if (!isGlobalPriorityActive) {
+                        if (mCurrentFullUserRecord.mOnMediaKeyListener != null) {
+                            if (DEBUG_KEY_EVENT) {
+                                Log.d(TAG, "Send " + keyEvent + " to the media key listener");
+                            }
+                            try {
+                                mCurrentFullUserRecord.mOnMediaKeyListener.onMediaKey(keyEvent,
+                                        new MediaKeyListenerResultReceiver(packageName, pid, uid,
+                                                asSystemService, keyEvent, needWakeLock));
+                                return;
+                            } catch (RemoteException e) {
+                                Log.w(TAG, "Failed to send " + keyEvent
+                                        + " to the media key listener");
+                            }
+                        }
+                    }
+                    if (!isGlobalPriorityActive && isVoiceKey(keyEvent.getKeyCode())) {
+                        handleVoiceKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
+                                needWakeLock);
+                    } else {
+                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+                                keyEvent, needWakeLock);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void setCallback(ICallback callback) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (!UserHandle.isSameApp(uid, Process.BLUETOOTH_UID)) {
+                    throw new SecurityException("Only Bluetooth service processes can set"
+                            + " Callback");
+                }
+                synchronized (mLock) {
+                    int userId = UserHandle.getUserId(uid);
+                    FullUserRecord user = getFullUserRecordLocked(userId);
+                    if (user == null || user.mFullUserId != userId) {
+                        Log.w(TAG, "Only the full user can set the callback"
+                                + ", userId=" + userId);
+                        return;
+                    }
+                    user.mCallback = callback;
+                    Log.d(TAG, "The callback " + user.mCallback
+                            + " is set by " + getCallingPackageName(uid));
+                    if (user.mCallback == null) {
+                        return;
+                    }
+                    try {
+                        user.mCallback.asBinder().linkToDeath(
+                                new IBinder.DeathRecipient() {
+                                    @Override
+                                    public void binderDied() {
+                                        synchronized (mLock) {
+                                            user.mCallback = null;
+                                        }
+                                    }
+                                }, 0);
+                        user.pushAddressedPlayerChangedLocked();
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to set callback", e);
+                        user.mCallback = null;
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void setOnVolumeKeyLongPressListener(IOnVolumeKeyLongPressListener listener) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                // Enforce SET_VOLUME_KEY_LONG_PRESS_LISTENER permission.
+                if (mContext.checkPermission(
+                        android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER, pid, uid)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException("Must hold the SET_VOLUME_KEY_LONG_PRESS_LISTENER"
+                            + " permission.");
+                }
+
+                synchronized (mLock) {
+                    int userId = UserHandle.getUserId(uid);
+                    FullUserRecord user = getFullUserRecordLocked(userId);
+                    if (user == null || user.mFullUserId != userId) {
+                        Log.w(TAG, "Only the full user can set the volume key long-press listener"
+                                + ", userId=" + userId);
+                        return;
+                    }
+                    if (user.mOnVolumeKeyLongPressListener != null
+                            && user.mOnVolumeKeyLongPressListenerUid != uid) {
+                        Log.w(TAG, "The volume key long-press listener cannot be reset"
+                                + " by another app , mOnVolumeKeyLongPressListener="
+                                + user.mOnVolumeKeyLongPressListenerUid
+                                + ", uid=" + uid);
+                        return;
+                    }
+
+                    user.mOnVolumeKeyLongPressListener = listener;
+                    user.mOnVolumeKeyLongPressListenerUid = uid;
+
+                    Log.d(TAG, "The volume key long-press listener "
+                            + listener + " is set by " + getCallingPackageName(uid));
+
+                    if (user.mOnVolumeKeyLongPressListener != null) {
+                        try {
+                            user.mOnVolumeKeyLongPressListener.asBinder().linkToDeath(
+                                    new IBinder.DeathRecipient() {
+                                        @Override
+                                        public void binderDied() {
+                                            synchronized (mLock) {
+                                                user.mOnVolumeKeyLongPressListener = null;
+                                            }
+                                        }
+                                    }, 0);
+                        } catch (RemoteException e) {
+                            Log.w(TAG, "Failed to set death recipient "
+                                    + user.mOnVolumeKeyLongPressListener);
+                            user.mOnVolumeKeyLongPressListener = null;
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void setOnMediaKeyListener(IOnMediaKeyListener listener) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                // Enforce SET_MEDIA_KEY_LISTENER permission.
+                if (mContext.checkPermission(
+                        android.Manifest.permission.SET_MEDIA_KEY_LISTENER, pid, uid)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException("Must hold the SET_MEDIA_KEY_LISTENER permission.");
+                }
+
+                synchronized (mLock) {
+                    int userId = UserHandle.getUserId(uid);
+                    FullUserRecord user = getFullUserRecordLocked(userId);
+                    if (user == null || user.mFullUserId != userId) {
+                        Log.w(TAG, "Only the full user can set the media key listener"
+                                + ", userId=" + userId);
+                        return;
+                    }
+                    if (user.mOnMediaKeyListener != null && user.mOnMediaKeyListenerUid != uid) {
+                        Log.w(TAG, "The media key listener cannot be reset by another app. "
+                                + ", mOnMediaKeyListenerUid=" + user.mOnMediaKeyListenerUid
+                                + ", uid=" + uid);
+                        return;
+                    }
+
+                    user.mOnMediaKeyListener = listener;
+                    user.mOnMediaKeyListenerUid = uid;
+
+                    Log.d(TAG, "The media key listener " + user.mOnMediaKeyListener
+                            + " is set by " + getCallingPackageName(uid));
+
+                    if (user.mOnMediaKeyListener != null) {
+                        try {
+                            user.mOnMediaKeyListener.asBinder().linkToDeath(
+                                    new IBinder.DeathRecipient() {
+                                        @Override
+                                        public void binderDied() {
+                                            synchronized (mLock) {
+                                                user.mOnMediaKeyListener = null;
+                                            }
+                                        }
+                                    }, 0);
+                        } catch (RemoteException e) {
+                            Log.w(TAG, "Failed to set death recipient " + user.mOnMediaKeyListener);
+                            user.mOnMediaKeyListener = null;
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        /**
+         * Handles the dispatching of the volume button events to one of the
+         * registered listeners. If there's a volume key long-press listener and
+         * there's no active global priority session, long-pressess will be sent to the
+         * long-press listener instead of adjusting volume.
+         *
+         * @param packageName The caller's package name, obtained by Context#getPackageName()
+         * @param opPackageName The caller's op package name, obtained by Context#getOpPackageName()
+         * @param asSystemService {@code true} if the event sent to the session as if it was come
+         *          from the system service instead of the app process. This helps sessions to
+         *          distinguish between the key injection by the app and key events from the
+         *          hardware devices. Should be used only when the volume key events aren't handled
+         *          by foreground activity. {@code false} otherwise to tell session about the real
+         *          caller.
+         * @param keyEvent a non-null KeyEvent whose key code is one of the
+         *            {@link KeyEvent#KEYCODE_VOLUME_UP},
+         *            {@link KeyEvent#KEYCODE_VOLUME_DOWN},
+         *            or {@link KeyEvent#KEYCODE_VOLUME_MUTE}.
+         * @param stream stream type to adjust volume.
+         * @param musicOnly true if both UI nor haptic feedback aren't needed when adjust volume.
+         */
+        @Override
+        public void dispatchVolumeKeyEvent(String packageName, String opPackageName,
+                boolean asSystemService, KeyEvent keyEvent, int stream, boolean musicOnly) {
+            if (keyEvent == null
+                    || (keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_UP
+                            && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_DOWN
+                            && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_MUTE)) {
+                Log.w(TAG, "Attempted to dispatch null or non-volume key event.");
+                return;
+            }
+
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            if (DEBUG_KEY_EVENT) {
+                Log.d(TAG, "dispatchVolumeKeyEvent, pkg=" + packageName + ", pid=" + pid + ", uid="
+                        + uid + ", asSystem=" + asSystemService + ", event=" + keyEvent);
+            }
+
+            try {
+                synchronized (mLock) {
+                    if (isGlobalPriorityActiveLocked()
+                            || mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
+                        dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+                                asSystemService, keyEvent, stream, musicOnly);
+                    } else {
+                        // TODO: Consider the case when both volume up and down keys are pressed
+                        //       at the same time.
+                        if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
+                            if (keyEvent.getRepeatCount() == 0) {
+                                // Keeps the copy of the KeyEvent because it can be reused.
+                                mCurrentFullUserRecord.mInitialDownVolumeKeyEvent =
+                                        KeyEvent.obtain(keyEvent);
+                                mCurrentFullUserRecord.mInitialDownVolumeStream = stream;
+                                mCurrentFullUserRecord.mInitialDownMusicOnly = musicOnly;
+                                mHandler.sendMessageDelayed(
+                                        mHandler.obtainMessage(
+                                                MessageHandler.MSG_VOLUME_INITIAL_DOWN,
+                                                mCurrentFullUserRecord.mFullUserId, 0),
+                                        mLongPressTimeout);
+                            }
+                            if (keyEvent.getRepeatCount() > 0 || keyEvent.isLongPress()) {
+                                mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
+                                if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null) {
+                                    dispatchVolumeKeyLongPressLocked(
+                                            mCurrentFullUserRecord.mInitialDownVolumeKeyEvent);
+                                    // Mark that the key is already handled.
+                                    mCurrentFullUserRecord.mInitialDownVolumeKeyEvent = null;
+                                }
+                                dispatchVolumeKeyLongPressLocked(keyEvent);
+                            }
+                        } else { // if up
+                            mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
+                            if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null
+                                    && mCurrentFullUserRecord.mInitialDownVolumeKeyEvent
+                                    .getDownTime() == keyEvent.getDownTime()) {
+                                // Short-press. Should change volume.
+                                dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+                                        asSystemService,
+                                        mCurrentFullUserRecord.mInitialDownVolumeKeyEvent,
+                                        mCurrentFullUserRecord.mInitialDownVolumeStream,
+                                        mCurrentFullUserRecord.mInitialDownMusicOnly);
+                                dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+                                        asSystemService, keyEvent, stream, musicOnly);
+                            } else {
+                                dispatchVolumeKeyLongPressLocked(keyEvent);
+                            }
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        private void dispatchVolumeKeyEventLocked(String packageName, String opPackageName, int pid,
+                int uid, boolean asSystemService, KeyEvent keyEvent, int stream,
+                boolean musicOnly) {
+            boolean down = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
+            boolean up = keyEvent.getAction() == KeyEvent.ACTION_UP;
+            int direction = 0;
+            boolean isMute = false;
+            switch (keyEvent.getKeyCode()) {
+                case KeyEvent.KEYCODE_VOLUME_UP:
+                    direction = AudioManager.ADJUST_RAISE;
+                    break;
+                case KeyEvent.KEYCODE_VOLUME_DOWN:
+                    direction = AudioManager.ADJUST_LOWER;
+                    break;
+                case KeyEvent.KEYCODE_VOLUME_MUTE:
+                    isMute = true;
+                    break;
+            }
+            if (down || up) {
+                int flags = AudioManager.FLAG_FROM_KEY;
+                if (musicOnly) {
+                    // This flag is used when the screen is off to only affect active media.
+                    flags |= AudioManager.FLAG_ACTIVE_MEDIA_ONLY;
+                } else {
+                    // These flags are consistent with the home screen
+                    if (up) {
+                        flags |= AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE;
+                    } else {
+                        flags |= AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE;
+                    }
+                }
+                if (direction != 0) {
+                    // If this is action up we want to send a beep for non-music events
+                    if (up) {
+                        direction = 0;
+                    }
+                    dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid,
+                            asSystemService, stream, direction, flags);
+                } else if (isMute) {
+                    if (down && keyEvent.getRepeatCount() == 0) {
+                        dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid,
+                                asSystemService, stream, AudioManager.ADJUST_TOGGLE_MUTE, flags);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void dispatchAdjustVolume(String packageName, String opPackageName,
+                int suggestedStream, int delta, int flags) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid, false,
+                            suggestedStream, delta, flags);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void setRemoteVolumeController(IRemoteVolumeController rvc) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                enforceSystemUiPermission("listen for volume changes", pid, uid);
+                mRvc = rvc;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public boolean isGlobalPriorityActive() {
+            synchronized (mLock) {
+                return isGlobalPriorityActiveLocked();
+            }
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
+            if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+
+            pw.println("MEDIA SESSION SERVICE (dumpsys media_session)");
+            pw.println();
+
+            synchronized (mLock) {
+                pw.println(mSessionsListeners.size() + " sessions listeners.");
+                pw.println("Global priority session is " + mGlobalPrioritySession);
+                if (mGlobalPrioritySession != null) {
+                    mGlobalPrioritySession.dump(pw, "  ");
+                }
+                pw.println("User Records:");
+                int count = mUserRecords.size();
+                for (int i = 0; i < count; i++) {
+                    mUserRecords.valueAt(i).dumpLocked(pw, "");
+                }
+                mAudioPlayerStateMonitor.dump(mContext, pw, "");
+            }
+        }
+
+        /**
+         * Returns if the controller's package is trusted (i.e. has either MEDIA_CONTENT_CONTROL
+         * permission or an enabled notification listener)
+         *
+         * @param controllerPackageName package name of the controller app
+         * @param controllerPid pid of the controller app
+         * @param controllerUid uid of the controller app
+         */
+        @Override
+        public boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid)
+                throws RemoteException {
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                // Don't perform sanity check between controllerPackageName and controllerUid.
+                // When an (activity|service) runs on the another apps process by specifying
+                // android:process in the AndroidManifest.xml, then PID and UID would have the
+                // running process' information instead of the (activity|service) that has created
+                // MediaController.
+                // Note that we can use Context#getOpPackageName() instead of
+                // Context#getPackageName() for getting package name that matches with the PID/UID,
+                // but it doesn't tell which package has created the MediaController, so useless.
+                return hasMediaControlPermission(UserHandle.getUserId(uid), controllerPackageName,
+                        controllerPid, controllerUid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        // For MediaSession
+        private int verifySessionsRequest(ComponentName componentName, int userId, final int pid,
+                final int uid) {
+            String packageName = null;
+            if (componentName != null) {
+                // If they gave us a component name verify they own the
+                // package
+                packageName = componentName.getPackageName();
+                enforcePackageName(packageName, uid);
+            }
+            // Check that they can make calls on behalf of the user and
+            // get the final user id
+            int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                    true /* allowAll */, true /* requireFull */, "getSessions", packageName);
+            // Check if they have the permissions or their component is
+            // enabled for the user they're calling from.
+            enforceMediaPermissions(componentName, pid, uid, resolvedUserId);
+            return resolvedUserId;
+        }
+
+        private boolean hasMediaControlPermission(int resolvedUserId, String packageName,
+                int pid, int uid) throws RemoteException {
+            // Allow API calls from the System UI
+            if (isCurrentVolumeController(pid, uid)) {
+                return true;
+            }
+
+            // Check if it's system server or has MEDIA_CONTENT_CONTROL.
+            // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
+            // check here.
+            if (uid == Process.SYSTEM_UID || mContext.checkPermission(
+                    android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
+                    == PackageManager.PERMISSION_GRANTED) {
+                return true;
+            } else if (DEBUG) {
+                Log.d(TAG, packageName + " (uid=" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
+            }
+
+            // You may not access another user's content as an enabled listener.
+            final int userId = UserHandle.getUserId(uid);
+            if (resolvedUserId != userId) {
+                return false;
+            }
+
+            // TODO(jaewan): (Post-P) Propose NotificationManager#hasEnabledNotificationListener(
+            //               String pkgName) to notification team for optimization
+            final List<ComponentName> enabledNotificationListeners =
+                    mNotificationManager.getEnabledNotificationListeners(userId);
+            if (enabledNotificationListeners != null) {
+                for (int i = 0; i < enabledNotificationListeners.size(); i++) {
+                    if (TextUtils.equals(packageName,
+                            enabledNotificationListeners.get(i).getPackageName())) {
+                        return true;
+                    }
+                }
+            }
+            if (DEBUG) {
+                Log.d(TAG, packageName + " (uid=" + uid + ") doesn't have an enabled "
+                        + "notification listener");
+            }
+            return false;
+        }
+
+        private void dispatchAdjustVolumeLocked(String packageName, String opPackageName, int pid,
+                int uid, boolean asSystemService, int suggestedStream, int direction, int flags) {
+            MediaSessionRecord session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
+                    : mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession();
+
+            boolean preferSuggestedStream = false;
+            if (isValidLocalStreamType(suggestedStream)
+                    && AudioSystem.isStreamActive(suggestedStream, 0)) {
+                preferSuggestedStream = true;
+            }
+            if (DEBUG_KEY_EVENT) {
+                Log.d(TAG, "Adjusting " + session + " by " + direction + ". flags="
+                        + flags + ", suggestedStream=" + suggestedStream
+                        + ", preferSuggestedStream=" + preferSuggestedStream);
+            }
+            if (session == null || preferSuggestedStream) {
+                if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0
+                        && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
+                    if (DEBUG) {
+                        Log.d(TAG, "No active session to adjust, skipping media only volume event");
+                    }
+                    return;
+                }
+
+                // Execute mAudioService.adjustSuggestedStreamVolume() on
+                // handler thread of MediaSessionService.
+                // This will release the MediaSessionService.mLock sooner and avoid
+                // a potential deadlock between MediaSessionService.mLock and
+                // ActivityManagerService lock.
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        final String callingOpPackageName;
+                        final int callingUid;
+                        if (asSystemService) {
+                            callingOpPackageName = mContext.getOpPackageName();
+                            callingUid = Process.myUid();
+                        } else {
+                            callingOpPackageName = opPackageName;
+                            callingUid = uid;
+                        }
+                        try {
+                            mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(suggestedStream,
+                                    direction, flags, callingOpPackageName, callingUid);
+                        } catch (SecurityException | IllegalArgumentException e) {
+                            Log.e(TAG, "Cannot adjust volume: direction=" + direction
+                                    + ", suggestedStream=" + suggestedStream + ", flags=" + flags
+                                    + ", packageName=" + packageName + ", uid=" + uid
+                                    + ", asSystemService=" + asSystemService, e);
+                        }
+                    }
+                });
+            } else {
+                session.adjustVolume(packageName, opPackageName, pid, uid, null, asSystemService,
+                        direction, flags, true);
+            }
+        }
+
+        private void handleVoiceKeyEventLocked(String packageName, int pid, int uid,
+                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
+            int action = keyEvent.getAction();
+            boolean isLongPress = (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;
+            if (action == KeyEvent.ACTION_DOWN) {
+                if (keyEvent.getRepeatCount() == 0) {
+                    mVoiceButtonDown = true;
+                    mVoiceButtonHandled = false;
+                } else if (mVoiceButtonDown && !mVoiceButtonHandled && isLongPress) {
+                    mVoiceButtonHandled = true;
+                    startVoiceInput(needWakeLock);
+                }
+            } else if (action == KeyEvent.ACTION_UP) {
+                if (mVoiceButtonDown) {
+                    mVoiceButtonDown = false;
+                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
+                        // Resend the down then send this event through
+                        KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
+                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+                                downEvent, needWakeLock);
+                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+                                keyEvent, needWakeLock);
+                    }
+                }
+            }
+        }
+
+        private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid,
+                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
+            MediaSessionRecord session = mCurrentFullUserRecord.getMediaButtonSessionLocked();
+            if (session != null) {
+                if (DEBUG_KEY_EVENT) {
+                    Log.d(TAG, "Sending " + keyEvent + " to " + session);
+                }
+                if (needWakeLock) {
+                    mKeyEventReceiver.aquireWakeLockLocked();
+                }
+                // If we don't need a wakelock use -1 as the id so we won't release it later.
+                session.sendMediaButton(packageName, pid, uid, asSystemService, keyEvent,
+                        needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
+                        mKeyEventReceiver);
+                if (mCurrentFullUserRecord.mCallback != null) {
+                    try {
+                        mCurrentFullUserRecord.mCallback.onMediaKeyEventDispatchedToMediaSession(
+                                keyEvent, new MediaSession.Token(session.getControllerBinder()));
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to send callback", e);
+                    }
+                }
+            } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null
+                    || mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
+                if (needWakeLock) {
+                    mKeyEventReceiver.aquireWakeLockLocked();
+                }
+                Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+                mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+                mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+                // TODO: Find a way to also send PID/UID in secure way.
+                String callerPackageName =
+                        (asSystemService) ? mContext.getPackageName() : packageName;
+                mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callerPackageName);
+                try {
+                    if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
+                        PendingIntent receiver = mCurrentFullUserRecord.mLastMediaButtonReceiver;
+                        if (DEBUG_KEY_EVENT) {
+                            Log.d(TAG, "Sending " + keyEvent
+                                    + " to the last known PendingIntent " + receiver);
+                        }
+                        receiver.send(mContext,
+                                needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
+                                mediaButtonIntent, mKeyEventReceiver, mHandler);
+                        if (mCurrentFullUserRecord.mCallback != null) {
+                            ComponentName componentName = mCurrentFullUserRecord
+                                    .mLastMediaButtonReceiver.getIntent().getComponent();
+                            if (componentName != null) {
+                                mCurrentFullUserRecord.mCallback
+                                        .onMediaKeyEventDispatchedToMediaButtonReceiver(
+                                                keyEvent, componentName);
+                            }
+                        }
+                    } else {
+                        ComponentName receiver =
+                                mCurrentFullUserRecord.mRestoredMediaButtonReceiver;
+                        int componentType = mCurrentFullUserRecord
+                                .mRestoredMediaButtonReceiverComponentType;
+                        UserHandle userHandle = UserHandle.of(mCurrentFullUserRecord
+                                .mRestoredMediaButtonReceiverUserId);
+                        if (DEBUG_KEY_EVENT) {
+                            Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
+                                    + receiver + ", type=" + componentType);
+                        }
+                        mediaButtonIntent.setComponent(receiver);
+                        try {
+                            switch (componentType) {
+                                case FullUserRecord.COMPONENT_TYPE_ACTIVITY:
+                                    mContext.startActivityAsUser(mediaButtonIntent, userHandle);
+                                    break;
+                                case FullUserRecord.COMPONENT_TYPE_SERVICE:
+                                    mContext.startForegroundServiceAsUser(mediaButtonIntent,
+                                            userHandle);
+                                    break;
+                                default:
+                                    // Legacy behavior for other cases.
+                                    mContext.sendBroadcastAsUser(mediaButtonIntent, userHandle);
+                            }
+                        } catch (Exception e) {
+                            Log.w(TAG, "Error sending media button to the restored intent "
+                                    + receiver + ", type=" + componentType, e);
+                        }
+                        if (mCurrentFullUserRecord.mCallback != null) {
+                            mCurrentFullUserRecord.mCallback
+                                    .onMediaKeyEventDispatchedToMediaButtonReceiver(
+                                            keyEvent, receiver);
+                        }
+                    }
+                } catch (CanceledException e) {
+                    Log.i(TAG, "Error sending key event to media button receiver "
+                            + mCurrentFullUserRecord.mLastMediaButtonReceiver, e);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to send callback", e);
+                }
+            }
+        }
+
+        private void startVoiceInput(boolean needWakeLock) {
+            Intent voiceIntent = null;
+            // select which type of search to launch:
+            // - screen on and device unlocked: action is ACTION_WEB_SEARCH
+            // - device locked or screen off: action is
+            // ACTION_VOICE_SEARCH_HANDS_FREE
+            // with EXTRA_SECURE set to true if the device is securely locked
+            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+            boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+            if (!isLocked && pm.isScreenOn()) {
+                voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
+                Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
+            } else {
+                voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+                voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
+                        isLocked && mKeyguardManager.isKeyguardSecure());
+                Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
+            }
+            // start the search activity
+            if (needWakeLock) {
+                mMediaEventWakeLock.acquire();
+            }
+            try {
+                if (voiceIntent != null) {
+                    voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                    if (DEBUG) Log.d(TAG, "voiceIntent: " + voiceIntent);
+                    mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT);
+                }
+            } catch (ActivityNotFoundException e) {
+                Log.w(TAG, "No activity for search: " + e);
+            } finally {
+                if (needWakeLock) {
+                    mMediaEventWakeLock.release();
+                }
+            }
+        }
+
+        private boolean isVoiceKey(int keyCode) {
+            return keyCode == KeyEvent.KEYCODE_HEADSETHOOK
+                    || (!mHasFeatureLeanback && keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+        }
+
+        private boolean isUserSetupComplete() {
+            return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
+        }
+
+        // we only handle public stream types, which are 0-5
+        private boolean isValidLocalStreamType(int streamType) {
+            return streamType >= AudioManager.STREAM_VOICE_CALL
+                    && streamType <= AudioManager.STREAM_NOTIFICATION;
+        }
+
+        private class MediaKeyListenerResultReceiver extends ResultReceiver implements Runnable {
+            private final String mPackageName;
+            private final int mPid;
+            private final int mUid;
+            private final boolean mAsSystemService;
+            private final KeyEvent mKeyEvent;
+            private final boolean mNeedWakeLock;
+            private boolean mHandled;
+
+            private MediaKeyListenerResultReceiver(String packageName, int pid, int uid,
+                    boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
+                super(mHandler);
+                mHandler.postDelayed(this, MEDIA_KEY_LISTENER_TIMEOUT);
+                mPackageName = packageName;
+                mPid = pid;
+                mUid = uid;
+                mAsSystemService = asSystemService;
+                mKeyEvent = keyEvent;
+                mNeedWakeLock = needWakeLock;
+            }
+
+            @Override
+            public void run() {
+                Log.d(TAG, "The media key listener is timed-out for " + mKeyEvent);
+                dispatchMediaKeyEvent();
+            }
+
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                if (resultCode == MediaSessionManager.RESULT_MEDIA_KEY_HANDLED) {
+                    mHandled = true;
+                    mHandler.removeCallbacks(this);
+                    return;
+                }
+                dispatchMediaKeyEvent();
+            }
+
+            private void dispatchMediaKeyEvent() {
+                if (mHandled) {
+                    return;
+                }
+                mHandled = true;
+                mHandler.removeCallbacks(this);
+                synchronized (mLock) {
+                    if (!isGlobalPriorityActiveLocked()
+                            && isVoiceKey(mKeyEvent.getKeyCode())) {
+                        handleVoiceKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
+                                mKeyEvent, mNeedWakeLock);
+                    } else {
+                        dispatchMediaKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
+                                mKeyEvent, mNeedWakeLock);
+                    }
+                }
+            }
+        }
+
+        private KeyEventWakeLockReceiver mKeyEventReceiver = new KeyEventWakeLockReceiver(mHandler);
+
+        class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable,
+                PendingIntent.OnFinished {
+            private final Handler mHandler;
+            private int mRefCount = 0;
+            private int mLastTimeoutId = 0;
+
+            KeyEventWakeLockReceiver(Handler handler) {
+                super(handler);
+                mHandler = handler;
+            }
+
+            public void onTimeout() {
+                synchronized (mLock) {
+                    if (mRefCount == 0) {
+                        // We've already released it, so just return
+                        return;
+                    }
+                    mLastTimeoutId++;
+                    mRefCount = 0;
+                    releaseWakeLockLocked();
+                }
+            }
+
+            public void aquireWakeLockLocked() {
+                if (mRefCount == 0) {
+                    mMediaEventWakeLock.acquire();
+                }
+                mRefCount++;
+                mHandler.removeCallbacks(this);
+                mHandler.postDelayed(this, WAKELOCK_TIMEOUT);
+
+            }
+
+            @Override
+            public void run() {
+                onTimeout();
+            }
+
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                if (resultCode < mLastTimeoutId) {
+                    // Ignore results from calls that were before the last
+                    // timeout, just in case.
+                    return;
+                } else {
+                    synchronized (mLock) {
+                        if (mRefCount > 0) {
+                            mRefCount--;
+                            if (mRefCount == 0) {
+                                releaseWakeLockLocked();
+                            }
+                        }
+                    }
+                }
+            }
+
+            private void releaseWakeLockLocked() {
+                mMediaEventWakeLock.release();
+                mHandler.removeCallbacks(this);
+            }
+
+            @Override
+            public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
+                    String resultData, Bundle resultExtras) {
+                onReceiveResult(resultCode, null);
+            }
+        };
+
+        BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent == null) {
+                    return;
+                }
+                Bundle extras = intent.getExtras();
+                if (extras == null) {
+                    return;
+                }
+                synchronized (mLock) {
+                    if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)
+                            && mMediaEventWakeLock.isHeld()) {
+                        mMediaEventWakeLock.release();
+                    }
+                }
+            }
+        };
+    }
+
+    final class MessageHandler extends Handler {
+        private static final int MSG_SESSIONS_CHANGED = 1;
+        private static final int MSG_VOLUME_INITIAL_DOWN = 2;
+        private final SparseArray<Integer> mIntegerCache = new SparseArray<>();
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SESSIONS_CHANGED:
+                    pushSessionsChanged((int) msg.obj);
+                    break;
+                case MSG_VOLUME_INITIAL_DOWN:
+                    synchronized (mLock) {
+                        FullUserRecord user = mUserRecords.get((int) msg.arg1);
+                        if (user != null && user.mInitialDownVolumeKeyEvent != null) {
+                            dispatchVolumeKeyLongPressLocked(user.mInitialDownVolumeKeyEvent);
+                            // Mark that the key is already handled.
+                            user.mInitialDownVolumeKeyEvent = null;
+                        }
+                    }
+                    break;
+            }
+        }
+
+        public void postSessionsChanged(int userId) {
+            // Use object instead of the arguments when posting message to remove pending requests.
+            Integer userIdInteger = mIntegerCache.get(userId);
+            if (userIdInteger == null) {
+                userIdInteger = Integer.valueOf(userId);
+                mIntegerCache.put(userId, userIdInteger);
+            }
+            removeMessages(MSG_SESSIONS_CHANGED, userIdInteger);
+            obtainMessage(MSG_SESSIONS_CHANGED, userIdInteger).sendToTarget();
+        }
+    }
+
+    private class Controller2Callback extends MediaController2.ControllerCallback {
+        private final Session2Token mToken;
+
+        Controller2Callback(Session2Token token) {
+            mToken = token;
+        }
+
+        @Override
+        public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) {
+            synchronized (mLock) {
+                int userId = UserHandle.getUserId(mToken.getUid());
+                mSession2TokensPerUser.get(userId).add(mToken);
+                pushSession2TokensChangedLocked(userId);
+            }
+        }
+
+        @Override
+        public void onDisconnected(MediaController2 controller) {
+            synchronized (mLock) {
+                int userId = UserHandle.getUserId(mToken.getUid());
+                mSession2TokensPerUser.get(userId).remove(mToken);
+                pushSession2TokensChangedLocked(userId);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java b/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
index 6a5f563..64c451d 100644
--- a/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
+++ b/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
@@ -159,12 +159,13 @@
                     + serviceInfo.packageName + "/" + serviceInfo.name);
             return false;
         }
-        if (!hasCaptureVideoPermission(serviceInfo.packageName)) {
-            // If the service does not have permission to capture video then it
-            // isn't going to be terribly useful as a remote display, is it?
-            // Kind of makes you wonder what it's doing there in the first place.
+        if (mPackageManager.checkPermission(Manifest.permission.REMOTE_DISPLAY_PROVIDER,
+                        serviceInfo.packageName) != PackageManager.PERMISSION_GRANTED) {
+            // If the service does not have this permission then the system will not bind to it.
+            // This is to prevent non privileged apps declaring themselves as remote display
+            // providers just to be bound to by the system and keep their process alive.
             Slog.w(TAG, "Ignoring remote display provider service because it does not "
-                    + "have the CAPTURE_VIDEO_OUTPUT or CAPTURE_SECURE_VIDEO_OUTPUT "
+                    + "have the REMOTE_DISPLAY_PROVIDER "
                     + "permission: " + serviceInfo.packageName + "/" + serviceInfo.name);
             return false;
         }
@@ -172,18 +173,6 @@
         return true;
     }
 
-    private boolean hasCaptureVideoPermission(String packageName) {
-        if (mPackageManager.checkPermission(Manifest.permission.CAPTURE_VIDEO_OUTPUT,
-                packageName) == PackageManager.PERMISSION_GRANTED) {
-            return true;
-        }
-        if (mPackageManager.checkPermission(Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT,
-                packageName) == PackageManager.PERMISSION_GRANTED) {
-            return true;
-        }
-        return false;
-    }
-
     private int findProvider(String packageName, String className) {
         int count = mProviders.size();
         for (int i = 0; i < count; i++) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 20eebe7..7323e93 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2311,22 +2311,22 @@
         }
 
         @Override
-        public boolean areAppOverlaysAllowed(String pkg) {
-            return areAppOverlaysAllowedForPackage(pkg, Binder.getCallingUid());
+        public boolean areBubblesAllowed(String pkg) {
+            return areBubblesAllowedForPackage(pkg, Binder.getCallingUid());
         }
 
         @Override
-        public boolean areAppOverlaysAllowedForPackage(String pkg, int uid) {
-            enforceSystemOrSystemUIOrSamePackage("Caller not system or systemui or same package",
-                    pkg);
-            return mPreferencesHelper.areAppOverlaysAllowed(pkg, uid);
+        public boolean areBubblesAllowedForPackage(String pkg, int uid) {
+            enforceSystemOrSystemUIOrSamePackage(pkg,
+                    "Caller not system or systemui or same package");
+            return mPreferencesHelper.areBubblessAllowed(pkg, uid);
         }
 
         @Override
-        public void setAppOverlaysAllowed(String pkg, int uid, boolean allowed) {
+        public void setBubblesAllowed(String pkg, int uid, boolean allowed) {
             checkCallerIsSystem();
 
-            mPreferencesHelper.setAppOverlaysAllowed(pkg, uid, allowed);
+            mPreferencesHelper.setBubblesAllowed(pkg, uid, allowed);
             handleSavePolicyFile();
         }
 
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 28f6972..7a21aa2 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -81,7 +81,7 @@
     private static final String ATT_NAME = "name";
     private static final String ATT_UID = "uid";
     private static final String ATT_ID = "id";
-    private static final String ATT_APP_OVERLAY = "overlay";
+    private static final String ATT_ALLOW_BUBBLE = "allow_bubble";
     private static final String ATT_PRIORITY = "priority";
     private static final String ATT_VISIBILITY = "visibility";
     private static final String ATT_IMPORTANCE = "importance";
@@ -94,8 +94,9 @@
     private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE;
     private static final int DEFAULT_IMPORTANCE = NotificationManager.IMPORTANCE_UNSPECIFIED;
     private static final boolean DEFAULT_SHOW_BADGE = true;
-    private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true;
+    private static final boolean DEFAULT_ALLOW_BUBBLE = true;
     private static final boolean DEFAULT_OEM_LOCKED_IMPORTANCE  = false;
+
     /**
      * Default value for what fields are user locked. See {@link LockableAppFields} for all lockable
      * fields.
@@ -108,7 +109,7 @@
     @IntDef({LockableAppFields.USER_LOCKED_IMPORTANCE})
     public @interface LockableAppFields {
         int USER_LOCKED_IMPORTANCE = 0x00000001;
-        int USER_LOCKED_APP_OVERLAY = 0x00000002;
+        int USER_LOCKED_BUBBLE = 0x00000002;
     }
 
     // pkg|uid => PackagePreferences
@@ -176,7 +177,7 @@
                                     XmlUtils.readBooleanAttribute(
                                             parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE),
                                     XmlUtils.readBooleanAttribute(
-                                            parser, ATT_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY));
+                                            parser, ATT_ALLOW_BUBBLE, DEFAULT_ALLOW_BUBBLE));
                             r.importance = XmlUtils.readIntAttribute(
                                     parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
                             r.priority = XmlUtils.readIntAttribute(
@@ -272,11 +273,11 @@
     private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid) {
         return getOrCreatePackagePreferences(pkg, uid,
                 DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE,
-                DEFAULT_ALLOW_APP_OVERLAY);
+                DEFAULT_ALLOW_BUBBLE);
     }
 
     private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid, int importance,
-            int priority, int visibility, boolean showBadge, boolean allowAppOverlay) {
+            int priority, int visibility, boolean showBadge, boolean allowBubble) {
         final String key = packagePreferencesKey(pkg, uid);
         synchronized (mPackagePreferences) {
             PackagePreferences
@@ -290,7 +291,7 @@
                 r.priority = priority;
                 r.visibility = visibility;
                 r.showBadge = showBadge;
-                r.appOverlay = allowAppOverlay;
+                r.allowBubble = allowBubble;
 
                 try {
                     createDefaultChannelIfNeeded(r);
@@ -392,7 +393,7 @@
                                 || r.channels.size() > 0
                                 || r.groups.size() > 0
                                 || r.delegate != null
-                                || r.appOverlay != DEFAULT_ALLOW_APP_OVERLAY;
+                                || r.allowBubble != DEFAULT_ALLOW_BUBBLE;
                 if (hasNonDefaultSettings) {
                     out.startTag(null, TAG_PACKAGE);
                     out.attribute(null, ATT_NAME, r.pkg);
@@ -405,8 +406,8 @@
                     if (r.visibility != DEFAULT_VISIBILITY) {
                         out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
                     }
-                    if (r.appOverlay != DEFAULT_ALLOW_APP_OVERLAY) {
-                        out.attribute(null, ATT_APP_OVERLAY, Boolean.toString(r.appOverlay));
+                    if (r.allowBubble != DEFAULT_ALLOW_BUBBLE) {
+                        out.attribute(null, ATT_ALLOW_BUBBLE, Boolean.toString(r.allowBubble));
                     }
                     out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(r.showBadge));
                     out.attribute(null, ATT_APP_USER_LOCKED_FIELDS,
@@ -452,14 +453,28 @@
         out.endTag(null, TAG_RANKING);
     }
 
-    public void setAppOverlaysAllowed(String pkg, int uid, boolean allowed) {
+    /**
+     * Sets whether bubbles are allowed.
+     *
+     * @param pkg the package to allow or not allow bubbles for.
+     * @param uid the uid to allow or not allow bubbles for.
+     * @param allowed whether bubbles are allowed.
+     */
+    public void setBubblesAllowed(String pkg, int uid, boolean allowed) {
         PackagePreferences p = getOrCreatePackagePreferences(pkg, uid);
-        p.appOverlay = allowed;
-        p.lockedAppFields = p.lockedAppFields | LockableAppFields.USER_LOCKED_APP_OVERLAY;
+        p.allowBubble = allowed;
+        p.lockedAppFields = p.lockedAppFields | LockableAppFields.USER_LOCKED_BUBBLE;
     }
 
-    public boolean areAppOverlaysAllowed(String pkg, int uid) {
-        return getOrCreatePackagePreferences(pkg, uid).appOverlay;
+    /**
+     * Whether bubbles are allowed.
+     *
+     * @param pkg the package to check if bubbles are allowed for
+     * @param uid the uid to check if bubbles are allowed for.
+     * @return whether bubbles are allowed.
+     */
+    public boolean areBubblessAllowed(String pkg, int uid) {
+        return getOrCreatePackagePreferences(pkg, uid).allowBubble;
     }
 
     public int getAppLockedFields(String pkg, int uid) {
@@ -1232,8 +1247,8 @@
         if (original.canShowBadge() != update.canShowBadge()) {
             update.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE);
         }
-        if (original.isAppOverlayAllowed() != update.isAppOverlayAllowed()) {
-            update.lockFields(NotificationChannel.USER_LOCKED_ALLOW_APP_OVERLAY);
+        if (original.isBubbleAllowed() != update.isBubbleAllowed()) {
+            update.lockFields(NotificationChannel.USER_LOCKED_ALLOW_BUBBLE);
         }
     }
 
@@ -1654,7 +1669,7 @@
         int priority = DEFAULT_PRIORITY;
         int visibility = DEFAULT_VISIBILITY;
         boolean showBadge = DEFAULT_SHOW_BADGE;
-        boolean appOverlay = DEFAULT_ALLOW_APP_OVERLAY;
+        boolean allowBubble = DEFAULT_ALLOW_BUBBLE;
         int lockedAppFields = DEFAULT_LOCKED_APP_FIELDS;
         boolean oemLockedImportance = DEFAULT_OEM_LOCKED_IMPORTANCE;
         List<String> futureOemLockedChannels = new ArrayList<>();
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 16143d3..74fbea1 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -24,11 +24,14 @@
 
 import android.annotation.NonNull;
 import android.content.om.OverlayInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.os.Build.VERSION_CODES;
 import android.os.IBinder;
 import android.os.IIdmap2;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.Slog;
 
@@ -51,6 +54,13 @@
     private final Installer mInstaller;
     private IIdmap2 mIdmap2Service;
 
+    private static final boolean VENDOR_IS_Q_OR_LATER;
+    static {
+        // STOPSHIP(b/119390857): Check api version once Q sdk version is finalized
+        final String value = SystemProperties.get("ro.vndk.version", "Q");
+        VENDOR_IS_Q_OR_LATER = value.equals("Q") || value.equals("q");
+    }
+
     IdmapManager(final Installer installer) {
         mInstaller = installer;
         if (FEATURE_FLAG_IDMAP2) {
@@ -69,10 +79,13 @@
         final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath();
         try {
             if (FEATURE_FLAG_IDMAP2) {
-                if (mIdmap2Service.verifyIdmap(overlayPath, userId)) {
+                int policies = determineFulfilledPolicies(overlayPackage);
+                boolean enforce = enforceOverlayable(overlayPackage);
+                if (mIdmap2Service.verifyIdmap(overlayPath, policies, enforce, userId)) {
                     return true;
                 }
-                return mIdmap2Service.createIdmap(targetPath, overlayPath, userId) != null;
+                return mIdmap2Service.createIdmap(targetPath, overlayPath, policies, enforce,
+                    userId) != null;
             } else {
                 mInstaller.idmap(targetPath, overlayPath, sharedGid);
                 return true;
@@ -156,4 +169,71 @@
             }, SECOND_IN_MILLIS);
         }
     }
+
+    /**
+     * Checks if overlayable and policies should be enforced on the specified overlay for backwards
+     * compatibility with pre-Q overlays.
+     */
+    private boolean enforceOverlayable(@NonNull final PackageInfo overlayPackage) {
+        final ApplicationInfo ai = overlayPackage.applicationInfo;
+        if (ai.targetSdkVersion >= VERSION_CODES.Q) {
+            // Always enforce policies for overlays targeting Q+.
+            return true;
+        }
+
+        if (ai.isVendor() && !VENDOR_IS_Q_OR_LATER) {
+            // If the overlay is on a pre-Q vendor partition, do not enforce overlayable
+            // restrictions on this overlay because the pre-Q platform has no understanding of
+            // overlayable.
+            return false;
+        }
+
+        // Do not enforce overlayable restrictions on pre-Q overlays signed with the
+        // platform signature.
+        return !ai.isSignedWithPlatformKey();
+    }
+
+    /**
+     * Retrieves a bitmask for idmap2 that represents the policies the specified overlay fulfills.
+     * @throws SecurityException if the overlay is not allowed to overlay any resource
+     */
+    private int determineFulfilledPolicies(@NonNull final PackageInfo overlayPackage)
+            throws SecurityException {
+        final ApplicationInfo ai = overlayPackage.applicationInfo;
+        final boolean overlayIsQOrLater = ai.targetSdkVersion >= VERSION_CODES.Q;
+
+        int fulfilledPolicies = 0;
+
+        // TODO(b/119402606) : Add signature policy
+
+        // Vendor partition (/vendor)
+        if (ai.isVendor()) {
+            if (overlayIsQOrLater) {
+                fulfilledPolicies |= IIdmap2.POLICY_VENDOR_PARTITION;
+            } else if (VENDOR_IS_Q_OR_LATER) {
+                throw new SecurityException("Overlay must target Q sdk or higher");
+            }
+        }
+
+        // Product partition (/product)
+        if (ai.isProduct()) {
+            if (overlayIsQOrLater) {
+                fulfilledPolicies |= IIdmap2.POLICY_PRODUCT_PARTITION;
+            } else {
+                throw new SecurityException("Overlay must target Q sdk or higher");
+            }
+        }
+
+        // System partition (/system)
+        if (ai.isSystemApp()) {
+            if (overlayIsQOrLater) {
+                fulfilledPolicies |= IIdmap2.POLICY_SYSTEM_PARTITION;
+            } else {
+                throw new SecurityException("Overlay must target Q sdk or higher");
+            }
+        }
+
+        // All overlays can overlay resources with the public policy
+        return fulfilledPolicies | IIdmap2.POLICY_PUBLIC;
+    }
 }
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index b0d2704..1cbf0bf 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -270,7 +270,9 @@
             Slog.d(TAG, "onTargetPackageUpgraded packageName=" + packageName + " userId=" + userId);
         }
 
-        updateAllOverlaysForTarget(packageName, userId, 0);
+        if (updateAllOverlaysForTarget(packageName, userId, 0)) {
+            mListener.onOverlaysChanged(packageName, userId);
+        }
     }
 
     void onTargetPackageRemoved(@NonNull final String packageName, final int userId) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d1a67bb..6fe32c5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -239,6 +239,7 @@
 import android.os.storage.StorageManagerInternal;
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
+import android.permission.PermissionControllerManager;
 import android.provider.MediaStore;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
@@ -317,7 +318,6 @@
 import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionsState;
-import com.android.server.pm.permission.PermissionsState.PermissionState;
 import com.android.server.security.VerityUtils;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
@@ -370,6 +370,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -443,6 +444,8 @@
     private static final boolean ENABLE_FREE_CACHE_V2 =
             SystemProperties.getBoolean("fw.free_cache_v2", true);
 
+    private static final long BACKUP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(60);
+
     private static final int RADIO_UID = Process.PHONE_UID;
     private static final int LOG_UID = Process.LOG_UID;
     private static final int NFC_UID = Process.NFC_UID;
@@ -1339,6 +1342,8 @@
     final @Nullable String mSystemTextClassifierPackage;
     final @Nullable String mWellbeingPackage;
     final @Nullable String mDocumenterPackage;
+    final @Nullable String mConfiguratorPackage;
+    final @Nullable String mAppPredictionServicePackage;
     final @NonNull String mServicesSystemSharedLibraryPackageName;
     final @NonNull String mSharedSystemSharedLibraryPackageName;
 
@@ -2862,6 +2867,9 @@
 
             mWellbeingPackage = getWellbeingPackageName();
             mDocumenterPackage = getDocumenterPackageName();
+            mConfiguratorPackage =
+                    mContext.getString(R.string.config_deviceConfiguratorPackageName);
+            mAppPredictionServicePackage = getAppPredictionServicePackageName();
 
             // Now that we know all of the shared libraries, update all clients to have
             // the correct library paths.
@@ -3744,7 +3752,7 @@
     /**
      * Returns whether or not a full application can see an instant application.
      * <p>
-     * Currently, there are three cases in which this can occur:
+     * Currently, there are four cases in which this can occur:
      * <ol>
      * <li>The calling application is a "special" process. Special processes
      *     are those with a UID < {@link Process#FIRST_APPLICATION_UID}.</li>
@@ -3752,6 +3760,7 @@
      *     {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.</li>
      * <li>The calling application is the default launcher on the
      *     system partition.</li>
+     * <li>The calling application is the default app prediction service.</li>
      * </ol>
      */
     private boolean canViewInstantApps(int callingUid, int userId) {
@@ -3769,6 +3778,11 @@
                     && isCallerSameApp(homeComponent.getPackageName(), callingUid)) {
                 return true;
             }
+            // TODO(b/122900055) Change/Remove this and replace with new permission role.
+            if (mAppPredictionServicePackage != null
+                    && isCallerSameApp(mAppPredictionServicePackage, callingUid)) {
+                return true;
+            }
         }
         return false;
     }
@@ -5484,13 +5498,13 @@
         final int callingUserId = UserHandle.getUserId(callingUid);
         final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
         // Map to base uids.
-        uid1 = UserHandle.getAppId(uid1);
-        uid2 = UserHandle.getAppId(uid2);
+        final int appId1 = UserHandle.getAppId(uid1);
+        final int appId2 = UserHandle.getAppId(uid2);
         // reader
         synchronized (mPackages) {
             Signature[] s1;
             Signature[] s2;
-            Object obj = mSettings.getSettingLPr(uid1);
+            Object obj = mSettings.getSettingLPr(appId1);
             if (obj != null) {
                 if (obj instanceof SharedUserSetting) {
                     if (isCallerInstantApp) {
@@ -5509,7 +5523,7 @@
             } else {
                 return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
             }
-            obj = mSettings.getSettingLPr(uid2);
+            obj = mSettings.getSettingLPr(appId2);
             if (obj != null) {
                 if (obj instanceof SharedUserSetting) {
                     if (isCallerInstantApp) {
@@ -5564,11 +5578,11 @@
         final int callingUid = Binder.getCallingUid();
         final int callingUserId = UserHandle.getUserId(callingUid);
         // Map to base uids.
-        uid = UserHandle.getAppId(uid);
+        final int appId = UserHandle.getAppId(uid);
         // reader
         synchronized (mPackages) {
             final PackageParser.SigningDetails signingDetails;
-            final Object obj = mSettings.getSettingLPr(uid);
+            final Object obj = mSettings.getSettingLPr(appId);
             if (obj != null) {
                 if (obj instanceof SharedUserSetting) {
                     final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
@@ -5684,10 +5698,10 @@
         final int callingUid = Binder.getCallingUid();
         final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
         final int userId = UserHandle.getUserId(uid);
-        uid = UserHandle.getAppId(uid);
+        final int appId = UserHandle.getAppId(uid);
         // reader
         synchronized (mPackages) {
-            Object obj = mSettings.getSettingLPr(uid);
+            final Object obj = mSettings.getSettingLPr(appId);
             if (obj instanceof SharedUserSetting) {
                 if (isCallerInstantApp) {
                     return null;
@@ -5722,8 +5736,9 @@
         if (getInstantAppPackageName(callingUid) != null) {
             return null;
         }
+        final int appId = UserHandle.getAppId(uid);
         synchronized (mPackages) {
-            Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+            final Object obj = mSettings.getSettingLPr(appId);
             if (obj instanceof SharedUserSetting) {
                 final SharedUserSetting sus = (SharedUserSetting) obj;
                 return sus.name + ":" + sus.userId;
@@ -5750,8 +5765,8 @@
         final String[] names = new String[uids.length];
         synchronized (mPackages) {
             for (int i = uids.length - 1; i >= 0; i--) {
-                final int uid = uids[i];
-                Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+                final int appId = UserHandle.getAppId(uids[i]);
+                final Object obj = mSettings.getSettingLPr(appId);
                 if (obj instanceof SharedUserSetting) {
                     final SharedUserSetting sus = (SharedUserSetting) obj;
                     names[i] = "shared:" + sus.name;
@@ -5799,8 +5814,9 @@
         if (getInstantAppPackageName(callingUid) != null) {
             return 0;
         }
+        final int appId = UserHandle.getAppId(uid);
         synchronized (mPackages) {
-            Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+            final Object obj = mSettings.getSettingLPr(appId);
             if (obj instanceof SharedUserSetting) {
                 final SharedUserSetting sus = (SharedUserSetting) obj;
                 return sus.pkgFlags;
@@ -5821,8 +5837,9 @@
         if (getInstantAppPackageName(callingUid) != null) {
             return 0;
         }
+        final int appId = UserHandle.getAppId(uid);
         synchronized (mPackages) {
-            Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+            final Object obj = mSettings.getSettingLPr(appId);
             if (obj instanceof SharedUserSetting) {
                 final SharedUserSetting sus = (SharedUserSetting) obj;
                 return sus.pkgPrivateFlags;
@@ -5842,10 +5859,10 @@
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return false;
         }
-        uid = UserHandle.getAppId(uid);
+        final int appId = UserHandle.getAppId(uid);
         // reader
         synchronized (mPackages) {
-            Object obj = mSettings.getSettingLPr(uid);
+            final Object obj = mSettings.getSettingLPr(appId);
             if (obj instanceof SharedUserSetting) {
                 final SharedUserSetting sus = (SharedUserSetting) obj;
                 final Iterator<PackageSetting> it = sus.packages.iterator();
@@ -13774,14 +13791,20 @@
             IBackupManager bm = IBackupManager.Stub.asInterface(
                     ServiceManager.getService(Context.BACKUP_SERVICE));
             if (bm != null) {
+                int userId = args.user.getIdentifier();
+                // For backwards compatibility as USER_ALL previously routed directly to USER_SYSTEM
+                // in the BackupManager. USER_ALL is used in compatibility tests.
+                if (userId == UserHandle.USER_ALL) {
+                    userId = UserHandle.USER_SYSTEM;
+                }
                 if (DEBUG_INSTALL) {
-                    Log.v(TAG, "token " + token + " to BM for possible restore");
+                    Log.v(TAG, "token " + token + " to BM for possible restore for user " + userId);
                 }
                 Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
                 try {
-                    // TODO: http://b/22388012
-                    if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
-                        bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
+                    if (bm.isBackupServiceActive(userId)) {
+                        bm.restoreAtInstallForUser(
+                                userId, res.pkg.applicationInfo.packageName, token);
                     } else {
                         doRestore = false;
                     }
@@ -18940,7 +18963,8 @@
 
     @GuardedBy("mPackages")
     private int getUidTargetSdkVersionLockedLPr(int uid) {
-        Object obj = mSettings.getSettingLPr(uid);
+        final int appId = UserHandle.getAppId(uid);
+        final Object obj = mSettings.getSettingLPr(appId);
         if (obj instanceof SharedUserSetting) {
             final SharedUserSetting sus = (SharedUserSetting) obj;
             int vers = Build.VERSION_CODES.CUR_DEVELOPMENT;
@@ -19131,7 +19155,7 @@
         // writer
         synchronized (mPackages) {
             PackageParser.Package pkg = mPackages.get(packageName);
-            if (pkg == null || pkg.applicationInfo.uid != callingUid) {
+            if (pkg == null || !isCallerSameApp(packageName, callingUid)) {
                 if (mContext.checkCallingOrSelfPermission(
                         android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
                         != PackageManager.PERMISSION_GRANTED) {
@@ -19572,28 +19596,32 @@
             throw new SecurityException("Only the system may call getPermissionGrantBackup()");
         }
 
-        ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
-        try {
-            final XmlSerializer serializer = new FastXmlSerializer();
-            serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
-            serializer.startDocument(null, true);
-            serializer.startTag(null, TAG_PERMISSION_BACKUP);
+        AtomicReference<byte[]> backup = new AtomicReference<>();
+        mContext.getSystemService(PermissionControllerManager.class).getRuntimePermissionBackup(
+                UserHandle.of(userId), mContext.getMainExecutor(), (b) -> {
+                    synchronized (backup) {
+                        backup.set(b);
+                        backup.notifyAll();
+                    }
+                });
 
-            synchronized (mPackages) {
-                serializeRuntimePermissionGrantsLPr(serializer, userId);
-            }
+        long start = System.currentTimeMillis();
+        synchronized (backup) {
+            while (backup.get() == null) {
+                long timeLeft = start + BACKUP_TIMEOUT_MILLIS - System.currentTimeMillis();
+                if (timeLeft <= 0) {
+                    return null;
+                }
 
-            serializer.endTag(null, TAG_PERMISSION_BACKUP);
-            serializer.endDocument();
-            serializer.flush();
-        } catch (Exception e) {
-            if (DEBUG_BACKUP) {
-                Slog.e(TAG, "Unable to write default apps for backup", e);
+                try {
+                    backup.wait(timeLeft);
+                } catch (InterruptedException ignored) {
+                    return null;
+                }
             }
-            return null;
         }
 
-        return dataStream.toByteArray();
+        return backup.get();
     }
 
     @Override
@@ -19619,66 +19647,6 @@
     }
 
     @GuardedBy("mPackages")
-    private void serializeRuntimePermissionGrantsLPr(XmlSerializer serializer, final int userId)
-            throws IOException {
-        serializer.startTag(null, TAG_ALL_GRANTS);
-
-        final int N = mSettings.mPackages.size();
-        for (int i = 0; i < N; i++) {
-            final PackageSetting ps = mSettings.mPackages.valueAt(i);
-            boolean pkgGrantsKnown = false;
-
-            PermissionsState packagePerms = ps.getPermissionsState();
-
-            for (PermissionState state : packagePerms.getRuntimePermissionStates(userId)) {
-                final int grantFlags = state.getFlags();
-                // only look at grants that are not system/policy fixed
-                if ((grantFlags & SYSTEM_RUNTIME_GRANT_MASK) == 0) {
-                    final boolean isGranted = state.isGranted();
-                    // And only back up the user-twiddled state bits
-                    if (isGranted || (grantFlags & USER_RUNTIME_GRANT_MASK) != 0) {
-                        final String packageName = mSettings.mPackages.keyAt(i);
-                        if (!pkgGrantsKnown) {
-                            serializer.startTag(null, TAG_GRANT);
-                            serializer.attribute(null, ATTR_PACKAGE_NAME, packageName);
-                            pkgGrantsKnown = true;
-                        }
-
-                        final boolean userSet =
-                                (grantFlags & FLAG_PERMISSION_USER_SET) != 0;
-                        final boolean userFixed =
-                                (grantFlags & FLAG_PERMISSION_USER_FIXED) != 0;
-                        final boolean revoke =
-                                (grantFlags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0;
-
-                        serializer.startTag(null, TAG_PERMISSION);
-                        serializer.attribute(null, ATTR_PERMISSION_NAME, state.getName());
-                        if (isGranted) {
-                            serializer.attribute(null, ATTR_IS_GRANTED, "true");
-                        }
-                        if (userSet) {
-                            serializer.attribute(null, ATTR_USER_SET, "true");
-                        }
-                        if (userFixed) {
-                            serializer.attribute(null, ATTR_USER_FIXED, "true");
-                        }
-                        if (revoke) {
-                            serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
-                        }
-                        serializer.endTag(null, TAG_PERMISSION);
-                    }
-                }
-            }
-
-            if (pkgGrantsKnown) {
-                serializer.endTag(null, TAG_GRANT);
-            }
-        }
-
-        serializer.endTag(null, TAG_ALL_GRANTS);
-    }
-
-    @GuardedBy("mPackages")
     private void processRestoredPermissionGrantsLPr(XmlPullParser parser, int userId)
             throws XmlPullParserException, IOException {
         String pkgName = null;
@@ -19860,6 +19828,14 @@
                         .setPackage(launcherComponent.getPackageName());
                 mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUid));
             }
+            // TODO(b/122900055) Change/Remove this and replace with new permission role.
+            if (mAppPredictionServicePackage != null) {
+                Intent predictorIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED)
+                        .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo)
+                        .putExtra(Intent.EXTRA_USER, UserHandle.of(userId))
+                        .setPackage(mAppPredictionServicePackage);
+                mContext.sendBroadcastAsUser(predictorIntent, UserHandle.of(launcherUid));
+            }
         }
     }
 
@@ -20012,6 +19988,20 @@
         return mContext.getString(R.string.config_defaultWellbeingPackage);
     }
 
+    private String getAppPredictionServicePackageName() {
+        String flattenedAppPredictionServiceComponentName =
+                mContext.getString(R.string.config_defaultAppPredictionService);
+        if (flattenedAppPredictionServiceComponentName == null) {
+            return null;
+        }
+        ComponentName appPredictionServiceComponentName =
+                ComponentName.unflattenFromString(flattenedAppPredictionServiceComponentName);
+        if (appPredictionServiceComponentName == null) {
+            return null;
+        }
+        return appPredictionServiceComponentName.getPackageName();
+    }
+
     @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId, String callingPackage) {
@@ -23174,6 +23164,8 @@
                     return mWellbeingPackage;
                 case PackageManagerInternal.PACKAGE_DOCUMENTER:
                     return mDocumenterPackage;
+                case PackageManagerInternal.PACKAGE_CONFIGURATOR:
+                    return mConfiguratorPackage;
             }
             return null;
         }
@@ -23190,6 +23182,11 @@
         }
 
         @Override
+        public void setLocationExtraPackagesProvider(PackagesProvider provider) {
+            mDefaultPermissionPolicy.setLocationExtraPackagesProvider(provider);
+        }
+
+        @Override
         public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
             mDefaultPermissionPolicy.setVoiceInteractionPackagesProvider(provider);
         }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 95da209..b0f2326 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2790,13 +2790,13 @@
                 // dataPath   - path to package's data path
                 // seinfo     - seinfo label for the app (assigned at install time)
                 // gids       - supplementary gids this app launches with
+                // profileableFromShellFlag  - 0 or 1 if the package is profileable from shell.
                 //
                 // NOTE: We prefer not to expose all ApplicationInfo flags for now.
                 //
                 // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
                 // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
-                //   frameworks/base/libs/packagelistparser
-                //   system/core/run-as/run-as.c
+                //   system/core/libpackagelistparser
                 //
                 sb.setLength(0);
                 sb.append(ai.packageName);
@@ -2816,6 +2816,8 @@
                 } else {
                     sb.append("none");
                 }
+                sb.append(" ");
+                sb.append(ai.isProfileableByShell() ? "1" : "0");
                 sb.append("\n");
                 writer.append(sb);
             }
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 83f0fde..563fd7f 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -20,8 +20,10 @@
 import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageInfo;
 import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
 import android.content.res.Resources;
 import android.os.PersistableBundle;
 import android.text.format.Formatter;
@@ -640,6 +642,55 @@
     }
 
     /**
+     * Returns a list of ShortcutInfos that match the given intent filter and the category of
+     * available ShareTarget definitions in this package.
+     */
+    public List<ShortcutManager.ShareShortcutInfo> getMatchingShareTargets(
+            @NonNull IntentFilter filter) {
+        final List<ShareTargetInfo> matchedTargets = new ArrayList<>();
+        for (int i = 0; i < mShareTargets.size(); i++) {
+            final ShareTargetInfo target = mShareTargets.get(i);
+            for (ShareTargetInfo.TargetData data : target.mTargetData) {
+                if (filter.hasDataType(data.mMimeType)) {
+                    // Matched at least with one data type
+                    matchedTargets.add(target);
+                    break;
+                }
+            }
+        }
+
+        if (matchedTargets.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        // Get the list of all dynamic shortcuts in this package
+        final ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
+        findAll(shortcuts, ShortcutInfo::isDynamicVisible, ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+
+        final List<ShortcutManager.ShareShortcutInfo> result = new ArrayList<>();
+        for (int i = 0; i < shortcuts.size(); i++) {
+            final ShortcutInfo si = shortcuts.get(i);
+            for (int j = 0; j < matchedTargets.size(); j++) {
+                // Shortcut must have all of share target categories
+                boolean hasAllCategories = true;
+                final ShareTargetInfo target = matchedTargets.get(j);
+                for (int q = 0; q < target.mCategories.length; q++) {
+                    if (!si.getCategories().contains(target.mCategories[q])) {
+                        hasAllCategories = false;
+                        break;
+                    }
+                }
+                if (hasAllCategories) {
+                    result.add(new ShortcutManager.ShareShortcutInfo(si, new ComponentName(
+                            getPackageName(), target.mTargetClass)));
+                    break;
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
      * Return the filenames (excluding path names) of icon bitmap files from this package.
      */
     public ArraySet<String> getUsedBitmapFiles() {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 2b773f4..fdbaba2 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -46,6 +46,7 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
 import android.content.pm.ShortcutServiceInternal;
 import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
 import android.content.res.Resources;
@@ -2149,6 +2150,23 @@
         }
     }
 
+    @Override
+    public ParceledListSlice<ShortcutManager.ShareShortcutInfo> getShareTargets(String packageName,
+            IntentFilter filter, @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+
+        synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
+            final List<ShortcutManager.ShareShortcutInfo> shortcutInfoList = new ArrayList<>();
+
+            final ShortcutUser user = getUserShortcutsLocked(userId);
+            user.forAllPackages(p -> shortcutInfoList.addAll(p.getMatchingShareTargets(filter)));
+
+            return new ParceledListSlice<>(shortcutInfoList);
+        }
+    }
+
     @GuardedBy("mLock")
     private ParceledListSlice<ShortcutInfo> getShortcutsWithQueryLocked(@NonNull String packageName,
             @UserIdInt int userId, int cloneFlags, @NonNull Predicate<ShortcutInfo> query) {
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index ac05ee8..bd14223 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -130,7 +130,7 @@
                 ServiceManager.getService("apexservice"));
         boolean success;
         try {
-            success = apex.submitStagedSession(sessionId, apexInfoList);
+            success = apex.submitStagedSession(sessionId, new int[0], apexInfoList);
         } catch (RemoteException re) {
             Slog.e(TAG, "Unable to contact apexservice", re);
             return false;
diff --git a/services/core/java/com/android/server/pm/dex/DexLogger.java b/services/core/java/com/android/server/pm/dex/DexLogger.java
index 68a755b..78fa82c 100644
--- a/services/core/java/com/android/server/pm/dex/DexLogger.java
+++ b/services/core/java/com/android/server/pm/dex/DexLogger.java
@@ -28,7 +28,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.pm.Installer;
 import com.android.server.pm.Installer.InstallerException;
@@ -53,21 +52,18 @@
 
     private final IPackageManager mPackageManager;
     private final PackageDynamicCodeLoading mPackageDynamicCodeLoading;
-    private final Object mInstallLock;
-    @GuardedBy("mInstallLock")
     private final Installer mInstaller;
 
-    public DexLogger(IPackageManager pms, Installer installer, Object installLock) {
-        this(pms, installer, installLock, new PackageDynamicCodeLoading());
+    public DexLogger(IPackageManager pms, Installer installer) {
+        this(pms, installer, new PackageDynamicCodeLoading());
     }
 
     @VisibleForTesting
-    DexLogger(IPackageManager pms, Installer installer, Object installLock,
+    DexLogger(IPackageManager pms, Installer installer,
             PackageDynamicCodeLoading packageDynamicCodeLoading) {
         mPackageManager = pms;
         mPackageDynamicCodeLoading = packageDynamicCodeLoading;
         mInstaller = installer;
-        mInstallLock = installLock;
     }
 
     public Set<String> getAllPackagesWithDynamicCodeLoading() {
@@ -131,14 +127,16 @@
             }
 
             byte[] hash = null;
-            synchronized (mInstallLock) {
-                try {
-                    hash = mInstaller.hashSecondaryDexFile(filePath, packageName, appInfo.uid,
-                            appInfo.volumeUuid, storageFlags);
-                } catch (InstallerException e) {
-                    Slog.e(TAG, "Got InstallerException when hashing file " + filePath
-                            + ": " + e.getMessage());
-                }
+            try {
+                // Note that we do not take the install lock here. Hashing should never interfere
+                // with app update/compilation/removal. We may get anomalous results if a file
+                // changes while we hash it, but that can happen anyway and is harmless for our
+                // purposes.
+                hash = mInstaller.hashSecondaryDexFile(filePath, packageName, appInfo.uid,
+                        appInfo.volumeUuid, storageFlags);
+            } catch (InstallerException e) {
+                Slog.e(TAG, "Got InstallerException when hashing file " + filePath
+                        + ": " + e.getMessage());
             }
 
             String fileName = new File(filePath).getName();
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index e57d9d7..b546836 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -129,7 +129,7 @@
         mPackageDexOptimizer = pdo;
         mInstaller = installer;
         mInstallLock = installLock;
-        mDexLogger = new DexLogger(pms, installer, installLock);
+        mDexLogger = new DexLogger(pms, installer);
     }
 
     public DexLogger getDexLogger() {
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 3a49412..17f8347 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -247,6 +247,10 @@
     public boolean isDocumenter() {
         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0;
     }
+    public boolean isConfigurator() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_CONFIGURATOR)
+            != 0;
+    }
 
     public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
         if (!origPackageName.equals(sourcePackageName)) {
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 789664d..ceaf69d 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -225,6 +225,7 @@
     private final Handler mHandler;
 
     private PackagesProvider mLocationPackagesProvider;
+    private PackagesProvider mLocationExtraPackagesProvider;
     private PackagesProvider mVoiceInteractionPackagesProvider;
     private PackagesProvider mSmsAppPackagesProvider;
     private PackagesProvider mDialerAppPackagesProvider;
@@ -270,6 +271,13 @@
         }
     }
 
+    /** Sets the provider for loction extra packages. */
+    public void setLocationExtraPackagesProvider(PackagesProvider provider) {
+        synchronized (mLock) {
+            mLocationExtraPackagesProvider = provider;
+        }
+    }
+
     public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
         synchronized (mLock) {
             mVoiceInteractionPackagesProvider = provider;
@@ -403,6 +411,7 @@
         Log.i(TAG, "Granting permissions to default platform handlers for user " + userId);
 
         final PackagesProvider locationPackagesProvider;
+        final PackagesProvider locationExtraPackagesProvider;
         final PackagesProvider voiceInteractionPackagesProvider;
         final PackagesProvider smsAppPackagesProvider;
         final PackagesProvider dialerAppPackagesProvider;
@@ -412,6 +421,7 @@
 
         synchronized (mLock) {
             locationPackagesProvider = mLocationPackagesProvider;
+            locationExtraPackagesProvider = mLocationExtraPackagesProvider;
             voiceInteractionPackagesProvider = mVoiceInteractionPackagesProvider;
             smsAppPackagesProvider = mSmsAppPackagesProvider;
             dialerAppPackagesProvider = mDialerAppPackagesProvider;
@@ -424,6 +434,8 @@
                 ? voiceInteractionPackagesProvider.getPackages(userId) : null;
         String[] locationPackageNames = (locationPackagesProvider != null)
                 ? locationPackagesProvider.getPackages(userId) : null;
+        String[] locationExtraPackageNames = (locationExtraPackagesProvider != null)
+                ? locationExtraPackagesProvider.getPackages(userId) : null;
         String[] smsAppPackageNames = (smsAppPackagesProvider != null)
                 ? smsAppPackagesProvider.getPackages(userId) : null;
         String[] dialerAppPackageNames = (dialerAppPackagesProvider != null)
@@ -638,6 +650,12 @@
                         LOCATION_PERMISSIONS, ACTIVITY_RECOGNITION_PERMISSIONS);
             }
         }
+        if (locationExtraPackageNames != null) {
+            // Also grant location permission to location extra packages.
+            for (String packageName : locationExtraPackageNames) {
+                grantPermissionsToSystemPackage(packageName, userId, LOCATION_PERMISSIONS);
+            }
+        }
 
         // Music
         Intent musicIntent = new Intent(Intent.ACTION_VIEW)
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 93964cb..30b5e49 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1640,6 +1640,13 @@
                 // Special permissions for the system default text classifier.
                 allowed = true;
             }
+            if (!allowed && bp.isConfigurator()
+                    && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+                    PackageManagerInternal.PACKAGE_CONFIGURATOR,
+                    UserHandle.USER_SYSTEM))) {
+                // Special permissions for the device configurator.
+                allowed = true;
+            }
             if (!allowed && bp.isWellbeing()
                     && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
                     PackageManagerInternal.PACKAGE_WELLBEING, UserHandle.USER_SYSTEM))) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 383549a..41cab2d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -84,8 +84,10 @@
 import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
 
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
-import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
-import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs
+        .CAMERA_LENS_COVER_ABSENT;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs
+        .CAMERA_LENS_UNCOVERED;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
 import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_DELEGATE;
@@ -478,6 +480,7 @@
     int mShortPressOnSleepBehavior;
     int mShortPressOnWindowBehavior;
     boolean mHasSoftInput = false;
+    boolean mHapticTextHandleEnabled;
     boolean mUseTvRouting;
     int mVeryLongPressTimeout;
     boolean mAllowStartActivityForLongPressOnPowerDuringSetup;
@@ -565,6 +568,10 @@
     private boolean mScreenshotChordPowerKeyTriggered;
     private long mScreenshotChordPowerKeyTime;
 
+    private static final long MOVING_DISPLAY_TO_TOP_DURATION_MILLIS = 10;
+    private volatile boolean mMovingDisplayToTopKeyTriggered;
+    private volatile long mMovingDisplayToTopKeyTime;
+
     // Ringer toggle should reuse timing and triggering from screenshot power and a11y vol up
     private int mRingerToggleChord = VOLUME_HUSH_OFF;
 
@@ -604,7 +611,7 @@
     private boolean mAodShowing;
 
     private boolean mPerDisplayFocusEnabled = false;
-    private int mTopFocusedDisplayId = INVALID_DISPLAY;
+    private volatile int mTopFocusedDisplayId = INVALID_DISPLAY;
 
     private static final int MSG_ENABLE_POINTER_LOCATION = 1;
     private static final int MSG_DISABLE_POINTER_LOCATION = 2;
@@ -632,6 +639,7 @@
     private static final int MSG_POWER_VERY_LONG_PRESS = 25;
     private static final int MSG_NOTIFY_USER_ACTIVITY = 26;
     private static final int MSG_RINGER_TOGGLE_CHORD = 27;
+    private static final int MSG_MOVE_DISPLAY_TO_TOP = 28;
 
     private class PolicyHandler extends Handler {
         @Override
@@ -727,6 +735,10 @@
                 case MSG_RINGER_TOGGLE_CHORD:
                     handleRingerChordGesture();
                     break;
+                case MSG_MOVE_DISPLAY_TO_TOP:
+                    mWindowManagerFuncs.moveDisplayToTop(msg.arg1);
+                    mMovingDisplayToTopKeyTriggered = false;
+                    break;
             }
         }
     }
@@ -808,6 +820,13 @@
         }
     };
 
+    private Runnable mPossibleVeryLongPressReboot = new Runnable() {
+        @Override
+        public void run() {
+            mActivityManagerInternal.prepareForPossibleShutdown();
+        }
+    };
+
     private void handleRingerChordGesture() {
         if (mRingerToggleChord == VOLUME_HUSH_OFF) {
             return;
@@ -953,6 +972,8 @@
         // Inform the StatusBar; but do not allow it to consume the event.
         sendSystemKeyToStatusBarAsync(event.getKeyCode());
 
+        schedulePossibleVeryLongPressReboot();
+
         // If the power key has still not yet been handled, then detect short
         // press, long press, or multi press and decide what to do.
         mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
@@ -1056,6 +1077,7 @@
         if (hasVeryLongPressOnPowerBehavior()) {
             mHandler.removeMessages(MSG_POWER_VERY_LONG_PRESS);
         }
+        cancelPossibleVeryLongPressReboot();
     }
 
     private void cancelPendingBackKeyAction() {
@@ -1815,6 +1837,9 @@
         mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_allowStartActivityForLongPressOnPowerInSetup);
 
+        mHapticTextHandleEnabled = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableHapticTextHandle);
+
         mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION;
 
         mHandleVolumeKeysInWM = mContext.getResources().getBoolean(
@@ -2557,12 +2582,25 @@
         final int eventDisplayId = event.getDisplayId();
         if (result == 0 && !mPerDisplayFocusEnabled
                 && eventDisplayId != INVALID_DISPLAY && eventDisplayId != mTopFocusedDisplayId) {
-            // Someone tries to send a key event to a display which doesn't have a focused window.
-            // We drop the event here, or it will cause ANR.
-            // TODO (b/121057974): The user may be confused about why the key doesn't work, so we
-            // may need to deal with this problem.
-            Slog.i(TAG, "Dropping this event targeting display #" + eventDisplayId
-                    + " because the focus is on display #" + mTopFocusedDisplayId);
+            // An event is targeting a non-focused display. Try to move the display to top so that
+            // it can become the focused display to interact with the user.
+            final long eventDownTime = event.getDownTime();
+            if (mMovingDisplayToTopKeyTime < eventDownTime) {
+                // We have not handled this event yet. Move the display to top, and then tell
+                // dispatcher to try again later.
+                mMovingDisplayToTopKeyTime = eventDownTime;
+                mMovingDisplayToTopKeyTriggered = true;
+                mHandler.sendMessage(
+                        mHandler.obtainMessage(MSG_MOVE_DISPLAY_TO_TOP, eventDisplayId, 0));
+                return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
+            } else if (mMovingDisplayToTopKeyTriggered) {
+                // The message has not been handled yet. Tell dispatcher to try again later.
+                return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
+            }
+            // The target display is still not the top focused display. Drop the event because the
+            // display may not contain any window which can receive keys.
+            Slog.w(TAG, "Dropping key targeting non-focused display #" + eventDisplayId
+                    + " keyCode=" + KeyEvent.keyCodeToString(event.getKeyCode()));
             return -1;
         }
         return result;
@@ -4900,6 +4938,15 @@
         }
     }
 
+    private void schedulePossibleVeryLongPressReboot() {
+        mHandler.removeCallbacks(mPossibleVeryLongPressReboot);
+        mHandler.postDelayed(mPossibleVeryLongPressReboot, mVeryLongPressTimeout);
+    }
+
+    private void cancelPossibleVeryLongPressReboot() {
+        mHandler.removeCallbacks(mPossibleVeryLongPressReboot);
+    }
+
     // TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
     private void updateScreenOffSleepToken(boolean acquire) {
         if (acquire) {
@@ -5157,8 +5204,11 @@
             case HapticFeedbackConstants.CLOCK_TICK:
             case HapticFeedbackConstants.CONTEXT_CLICK:
                 return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
-            case HapticFeedbackConstants.KEYBOARD_RELEASE:
             case HapticFeedbackConstants.TEXT_HANDLE_MOVE:
+                if (!mHapticTextHandleEnabled) {
+                    return null;
+                }
+            case HapticFeedbackConstants.KEYBOARD_RELEASE:
             case HapticFeedbackConstants.VIRTUAL_KEY_RELEASE:
             case HapticFeedbackConstants.ENTRY_BUMP:
             case HapticFeedbackConstants.DRAG_CROSSING:
@@ -5323,11 +5373,13 @@
                 pw.println(mAllowStartActivityForLongPressOnPowerDuringSetup);
         pw.print(prefix);
                 pw.print("mHasSoftInput="); pw.print(mHasSoftInput);
-                pw.print(" mDismissImeOnBackKeyPressed="); pw.println(mDismissImeOnBackKeyPressed);
+                pw.print(" mHapticTextHandleEnabled="); pw.println(mHapticTextHandleEnabled);
         pw.print(prefix);
-                pw.print("mIncallPowerBehavior=");
-                pw.print(incallPowerBehaviorToString(mIncallPowerBehavior));
-                pw.print(" mIncallBackBehavior=");
+                pw.print("mDismissImeOnBackKeyPressed="); pw.print(mDismissImeOnBackKeyPressed);
+                pw.print(" mIncallPowerBehavior=");
+                pw.println(incallPowerBehaviorToString(mIncallPowerBehavior));
+        pw.print(prefix);
+                pw.print("mIncallBackBehavior=");
                 pw.print(incallBackBehaviorToString(mIncallBackBehavior));
                 pw.print(" mEndcallBehavior=");
                 pw.println(endcallBehaviorToString(mEndcallBehavior));
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 98f6f0e..e1a911e 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -637,6 +637,12 @@
          * Notifies window manager that user is switched.
          */
         void onUserSwitched();
+
+        /**
+         * Hint to window manager that the user is interacting with a display that should be treated
+         * as the top display.
+         */
+        void moveDisplayToTop(int displayId);
     }
 
     /**
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
index 45c975b..055c941 100644
--- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
@@ -62,6 +62,8 @@
                         mContext.getContentResolver(),
                         Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
 
+                // TODO: STOPSHIP: Remove the following code once we remove default_sms_application
+                // and use the new config_defaultRoleHolders.
                 if (result == null) {
                     Collection<SmsApplication.SmsApplicationData> applications =
                             SmsApplication.getApplicationCollectionAsUser(mContext, userId);
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index b488337..5516b23 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -229,9 +229,12 @@
         // Any role for which we have a record are already migrated
         RoleUserState userState = getOrCreateUserState(userId);
         if (!userState.isRoleAvailable(role)) {
-            userState.addRoleName(role);
             List<String> roleHolders = mLegacyRoleResolver.getRoleHolders(role, userId);
+            if (roleHolders.isEmpty()) {
+                return;
+            }
             Slog.i(LOG_TAG, "Migrating " + role + ", legacy holders: " + roleHolders);
+            userState.addRoleName(role);
             int size = roleHolders.size();
             for (int i = 0; i < size; i++) {
                 userState.addRoleHolder(role, roleHolders.get(i));
@@ -406,7 +409,6 @@
         @Nullable
         private ArraySet<String> getRoleHoldersInternal(@NonNull String roleName,
                 @UserIdInt int userId) {
-            migrateRoleIfNecessary(roleName, userId);
             RoleUserState userState = getOrCreateUserState(userId);
             return userState.getRoleHolders(roleName);
         }
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 69e1449..02dcc49 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -193,14 +193,18 @@
      *
      * @param roleName the name of the role to query for
      *
-     * @return the set of role holders. {@code null} should not be returned and indicates an issue.
+     * @return the set of role holders, or {@code null} if and only if the role is not found
      */
     @Nullable
     public ArraySet<String> getRoleHolders(@NonNull String roleName) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
 
-            return new ArraySet<>(mRoles.get(roleName));
+            ArraySet<String> packageNames = mRoles.get(roleName);
+            if (packageNames == null) {
+                return null;
+            }
+            return new ArraySet<>(packageNames);
         }
     }
 
@@ -268,8 +272,7 @@
      * @param roleName the name of the role to add the holder to
      * @param packageName the package name of the new holder
      *
-     * @return {@code false} only if the set of role holders is null, which should not happen and
-     *         indicates an issue.
+     * @return {@code false} if and only if the role is not found
      */
     @CheckResult
     public boolean addRoleHolder(@NonNull String roleName, @NonNull String packageName) {
@@ -302,8 +305,7 @@
      * @param roleName the name of the role to remove the holder from
      * @param packageName the package name of the holder to remove
      *
-     * @return {@code false} only if the set of role holders is null, which should not happen and
-     *         indicates an issue.
+     * @return {@code false} if and only if the role is not found
      */
     @CheckResult
     public boolean removeRoleHolder(@NonNull String roleName, @NonNull String packageName) {
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 8021265..d12f7ed 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -977,6 +977,8 @@
                             ensureRollbackDataLoadedLocked();
                             mAvailableRollbacks.add(data);
                         }
+
+                        scheduleExpiration(ROLLBACK_LIFETIME_DURATION_MILLIS);
                     } catch (IOException e) {
                         Log.e(TAG, "Unable to enable rollback", e);
                         removeFile(data.backupDir);
diff --git a/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java b/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java
index 438c303..d77cf90 100644
--- a/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java
+++ b/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java
@@ -23,6 +23,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
+import android.util.StatsLog;
 
 import java.security.GeneralSecurityException;
 import java.util.Arrays;
@@ -66,12 +67,14 @@
 
     private final Context mContext;
     private final String mSourcePackage;
+    private final SignedConfigEvent mEvent;
     private final SignatureVerifier mVerifier;
 
-    GlobalSettingsConfigApplicator(Context context, String sourcePackage) {
+    GlobalSettingsConfigApplicator(Context context, String sourcePackage, SignedConfigEvent event) {
         mContext = context;
         mSourcePackage = sourcePackage;
-        mVerifier = new SignatureVerifier();
+        mEvent = event;
+        mVerifier = new SignatureVerifier(mEvent);
     }
 
     private boolean checkSignature(String data, String signature) {
@@ -79,6 +82,7 @@
             return mVerifier.verifySignature(data, signature);
         } catch (GeneralSecurityException e) {
             Slog.e(TAG, "Failed to verify signature", e);
+            mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__SECURITY_EXCEPTION;
             return false;
         }
     }
@@ -109,14 +113,17 @@
         SignedConfig config;
         try {
             config = SignedConfig.parse(configStr, ALLOWED_KEYS, KEY_VALUE_MAPPERS);
+            mEvent.version = config.version;
         } catch (InvalidConfigException e) {
             Slog.e(TAG, "Failed to parse global settings from package " + mSourcePackage, e);
+            mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__INVALID_CONFIG;
             return;
         }
         int currentVersion = getCurrentConfigVersion();
         if (currentVersion >= config.version) {
             Slog.i(TAG, "Global settings from package " + mSourcePackage
                     + " is older than existing: " + config.version + "<=" + currentVersion);
+            mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__OLD_CONFIG;
             return;
         }
         // We have new config!
@@ -126,10 +133,12 @@
                 config.getMatchingConfig(Build.VERSION.SDK_INT);
         if (matchedConfig == null) {
             Slog.i(TAG, "Settings is not applicable to current SDK version; ignoring");
+            mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__NOT_APPLICABLE;
             return;
         }
 
         Slog.i(TAG, "Updating global settings to version " + config.version);
         updateCurrentConfig(config.version, matchedConfig.values);
+        mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__APPLIED;
     }
 }
diff --git a/services/core/java/com/android/server/signedconfig/SignatureVerifier.java b/services/core/java/com/android/server/signedconfig/SignatureVerifier.java
index 944db84..56db32a 100644
--- a/services/core/java/com/android/server/signedconfig/SignatureVerifier.java
+++ b/services/core/java/com/android/server/signedconfig/SignatureVerifier.java
@@ -18,6 +18,7 @@
 
 import android.os.Build;
 import android.util.Slog;
+import android.util.StatsLog;
 
 import java.nio.charset.StandardCharsets;
 import java.security.InvalidKeyException;
@@ -42,11 +43,18 @@
     private static final String DEBUG_KEY =
             "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaAn2XVifsLTHg616nTsOMVmlhBoECGbTEBTKKvdd2hO60"
             + "pj1pnU8SMkhYfaNxZuKgw9LNvOwlFwStboIYeZ3lQ==";
+    private static final String PROD_KEY =
+            "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+lky6wKyGL6lE1VrD0YTMHwb0Xwc+tzC8MvnrzVxodvTp"
+            + "VY/jV7V+Zktcx+pry43XPABFRXtbhTo+qykhyBA1g==";
 
+    private final SignedConfigEvent mEvent;
     private final PublicKey mDebugKey;
+    private final PublicKey mProdKey;
 
-    public SignatureVerifier() {
-        mDebugKey = createKey(DEBUG_KEY);
+    public SignatureVerifier(SignedConfigEvent event) {
+        mEvent = event;
+        mDebugKey = Build.IS_DEBUGGABLE ? createKey(DEBUG_KEY) : null;
+        mProdKey = createKey(PROD_KEY);
     }
 
     private static PublicKey createKey(String base64) {
@@ -67,6 +75,14 @@
         }
     }
 
+    private boolean verifyWithPublicKey(PublicKey key, byte[] data, byte[] signature)
+            throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+        Signature verifier = Signature.getInstance("SHA256withECDSA");
+        verifier.initVerify(key);
+        verifier.update(data);
+        return verifier.verify(signature);
+    }
+
     /**
      * Verify a signature for signed config.
      *
@@ -80,6 +96,7 @@
         try {
             signature = Base64.getDecoder().decode(base64Signature);
         } catch (IllegalArgumentException e) {
+            mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__BASE64_FAILURE_SIGNATURE;
             Slog.e(TAG, "Failed to base64 decode signature");
             return false;
         }
@@ -89,11 +106,9 @@
         if (Build.IS_DEBUGGABLE) {
             if (mDebugKey != null) {
                 if (DBG) Slog.w(TAG, "Trying to verify signature using debug key");
-                Signature verifier = Signature.getInstance("SHA256withECDSA");
-                verifier.initVerify(mDebugKey);
-                verifier.update(data);
-                if (verifier.verify(signature)) {
+                if (verifyWithPublicKey(mDebugKey, data, signature)) {
                     Slog.i(TAG, "Verified config using debug key");
+                    mEvent.verifiedWith = StatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__DEBUG;
                     return true;
                 } else {
                     if (DBG) Slog.i(TAG, "Config verification failed using debug key");
@@ -102,8 +117,20 @@
                 Slog.w(TAG, "Debuggable build, but have no debug key");
             }
         }
-        // TODO verify production key.
-        Slog.w(TAG, "NO PRODUCTION KEY YET, FAILING VERIFICATION");
-        return false;
+        if (mProdKey ==  null) {
+            Slog.e(TAG, "No prod key; construction failed?");
+            mEvent.status =
+                    StatsLog.SIGNED_CONFIG_REPORTED__STATUS__SIGNATURE_CHECK_FAILED_PROD_KEY_ABSENT;
+            return false;
+        }
+        if (verifyWithPublicKey(mProdKey, data, signature)) {
+            Slog.i(TAG, "Verified config using production key");
+            mEvent.verifiedWith = StatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__PRODUCTION;
+            return true;
+        } else {
+            if (DBG) Slog.i(TAG, "Verification failed using production key");
+            mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__SIGNATURE_CHECK_FAILED;
+            return false;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigEvent.java b/services/core/java/com/android/server/signedconfig/SignedConfigEvent.java
new file mode 100644
index 0000000..2f2062c
--- /dev/null
+++ b/services/core/java/com/android/server/signedconfig/SignedConfigEvent.java
@@ -0,0 +1,39 @@
+/*
+ * 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.signedconfig;
+
+import android.util.StatsLog;
+
+/**
+ * Helper class to allow a SignedConfigReported event to be built up in stages.
+ */
+public class SignedConfigEvent {
+
+    public int type = StatsLog.SIGNED_CONFIG_REPORTED__TYPE__UNKNOWN_TYPE;
+    public int status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__UNKNOWN_STATUS;
+    public int version = 0;
+    public String fromPackage = null;
+    public int verifiedWith = StatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__NO_KEY;
+
+    /**
+     * Write this event to statslog.
+     */
+    public void send() {
+        StatsLog.write(StatsLog.SIGNED_CONFIG_REPORTED,
+                type, status, version, fromPackage, verifiedWith);
+    }
+
+}
diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigService.java b/services/core/java/com/android/server/signedconfig/SignedConfigService.java
index 6bcee14..dc39542 100644
--- a/services/core/java/com/android/server/signedconfig/SignedConfigService.java
+++ b/services/core/java/com/android/server/signedconfig/SignedConfigService.java
@@ -26,6 +26,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.util.Slog;
+import android.util.StatsLog;
 
 import com.android.server.LocalServices;
 
@@ -82,21 +83,30 @@
         }
         if (metaData.containsKey(KEY_GLOBAL_SETTINGS)
                 && metaData.containsKey(KEY_GLOBAL_SETTINGS_SIGNATURE)) {
-            String config = metaData.getString(KEY_GLOBAL_SETTINGS);
-            String signature = metaData.getString(KEY_GLOBAL_SETTINGS_SIGNATURE);
+            SignedConfigEvent event = new SignedConfigEvent();
             try {
-                // Base64 encoding is standard (not URL safe) encoding: RFC4648
-                config = new String(Base64.getDecoder().decode(config), StandardCharsets.UTF_8);
-            } catch (IllegalArgumentException iae) {
-                Slog.e(TAG, "Failed to base64 decode global settings config from " + packageName);
-                return;
+                event.type = StatsLog.SIGNED_CONFIG_REPORTED__TYPE__GLOBAL_SETTINGS;
+                event.fromPackage = packageName;
+                String config = metaData.getString(KEY_GLOBAL_SETTINGS);
+                String signature = metaData.getString(KEY_GLOBAL_SETTINGS_SIGNATURE);
+                try {
+                    // Base64 encoding is standard (not URL safe) encoding: RFC4648
+                    config = new String(Base64.getDecoder().decode(config), StandardCharsets.UTF_8);
+                } catch (IllegalArgumentException iae) {
+                    Slog.e(TAG, "Failed to base64 decode global settings config from "
+                            + packageName);
+                    event.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__BASE64_FAILURE_CONFIG;
+                    return;
+                }
+                if (DBG) {
+                    Slog.d(TAG, "Got global settings config: " + config);
+                    Slog.d(TAG, "Got global settings signature: " + signature);
+                }
+                new GlobalSettingsConfigApplicator(mContext, packageName, event).applyConfig(
+                        config, signature);
+            } finally {
+                event.send();
             }
-            if (DBG) {
-                Slog.d(TAG, "Got global settings config: " + config);
-                Slog.d(TAG, "Got global settings signature: " + signature);
-            }
-            new GlobalSettingsConfigApplicator(mContext, packageName).applyConfig(
-                    config, signature);
         } else {
             if (DBG) Slog.d(TAG, "Package has no global settings config/signature.");
         }
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 30aa528..4e71a05 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -43,6 +43,7 @@
 import android.content.pm.UserInfo;
 import android.hardware.fingerprint.FingerprintManager;
 import android.net.ConnectivityManager;
+import android.net.INetworkStatsService;
 import android.net.Network;
 import android.net.NetworkRequest;
 import android.net.NetworkStats;
@@ -90,7 +91,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.procstats.IProcessStats;
 import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.net.NetworkStatsFactory;
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
 import com.android.internal.os.BinderCallsStats.ExportedCallStat;
@@ -210,6 +210,7 @@
 
     private final Context mContext;
     private final AlarmManager mAlarmManager;
+    private final INetworkStatsService mNetworkStatsService;
     @GuardedBy("sStatsdLock")
     private static IStatsManager sStatsd;
     private static final Object sStatsdLock = new Object();
@@ -257,6 +258,8 @@
         super();
         mContext = context;
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+        mNetworkStatsService = INetworkStatsService.Stub.asInterface(
+              ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
         mBaseDir.mkdirs();
         mAppUpdateReceiver = new AppUpdateReceiver();
         mUserUpdateReceiver = new BroadcastReceiver() {
@@ -788,14 +791,14 @@
             if (ifaces.length == 0) {
                 return;
             }
-            NetworkStatsFactory nsf = new NetworkStatsFactory();
+            if (mNetworkStatsService == null) {
+                Slog.e(TAG, "NetworkStats Service is not available!");
+                return;
+            }
             // Combine all the metrics per Uid into one record.
-            NetworkStats stats =
-                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
-                            null)
-                            .groupedByUid();
+            NetworkStats stats = mNetworkStatsService.getDetailedUidStats(ifaces).groupedByUid();
             addNetworkStats(tagId, pulledData, stats, false);
-        } catch (java.io.IOException e) {
+        } catch (RemoteException e) {
             Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -812,12 +815,14 @@
             if (ifaces.length == 0) {
                 return;
             }
-            NetworkStatsFactory nsf = new NetworkStatsFactory();
+            if (mNetworkStatsService == null) {
+                Slog.e(TAG, "NetworkStats Service is not available!");
+                return;
+            }
             NetworkStats stats = rollupNetworkStatsByFGBG(
-                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
-                            null));
+                    mNetworkStatsService.getDetailedUidStats(ifaces));
             addNetworkStats(tagId, pulledData, stats, true);
-        } catch (java.io.IOException e) {
+        } catch (RemoteException e) {
             Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -834,14 +839,14 @@
             if (ifaces.length == 0) {
                 return;
             }
-            NetworkStatsFactory nsf = new NetworkStatsFactory();
+            if (mNetworkStatsService == null) {
+                Slog.e(TAG, "NetworkStats Service is not available!");
+                return;
+            }
             // Combine all the metrics per Uid into one record.
-            NetworkStats stats =
-                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
-                            null)
-                            .groupedByUid();
+            NetworkStats stats = mNetworkStatsService.getDetailedUidStats(ifaces).groupedByUid();
             addNetworkStats(tagId, pulledData, stats, false);
-        } catch (java.io.IOException e) {
+        } catch (RemoteException e) {
             Slog.e(TAG, "Pulling netstats for mobile bytes has error", e);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -874,12 +879,14 @@
             if (ifaces.length == 0) {
                 return;
             }
-            NetworkStatsFactory nsf = new NetworkStatsFactory();
+            if (mNetworkStatsService == null) {
+                Slog.e(TAG, "NetworkStats Service is not available!");
+                return;
+            }
             NetworkStats stats = rollupNetworkStatsByFGBG(
-                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
-                            null));
+                    mNetworkStatsService.getDetailedUidStats(ifaces));
             addNetworkStats(tagId, pulledData, stats, true);
-        } catch (java.io.IOException e) {
+        } catch (RemoteException e) {
             Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -2058,6 +2065,17 @@
         mContext.unregisterReceiver(mShutdownEventReceiver);
         cancelAnomalyAlarm();
         cancelPullingAlarm();
+
+        BinderCallsStatsService.Internal binderStats =
+                LocalServices.getService(BinderCallsStatsService.Internal.class);
+        if (binderStats != null) {
+            binderStats.reset();
+        }
+
+        LooperStats looperStats = LocalServices.getService(LooperStats.class);
+        if (looperStats != null) {
+            looperStats.reset();
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 1f638c7..65d66f4 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -278,12 +278,12 @@
         }
 
         // Since positionChildAt() is called during the creation process of pinned stacks,
-        // ActivityStack#getWindowContainerController() can be null. In this special case,
+        // ActivityStack#getStack() can be null. In this special case,
         // since DisplayContest#positionStackAt() is called in TaskStack#onConfigurationChanged(),
         // we don't have to call WindowContainerController#positionChildAt() here.
-        if (stack.getWindowContainerController() != null && mDisplayContent != null) {
+        if (stack.getTaskStack() != null && mDisplayContent != null) {
             mDisplayContent.positionStackAt(insertPosition,
-                    stack.getWindowContainerController().mContainer, includingParents);
+                    stack.getTaskStack(), includingParents);
         }
         if (!wasContained) {
             stack.setParent(this);
@@ -450,13 +450,12 @@
     @VisibleForTesting
     <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
             int stackId, boolean onTop) {
-        if (windowingMode == WINDOWING_MODE_PINNED) {
-            return (T) new PinnedActivityStack(this, stackId,
-                    mRootActivityContainer.mStackSupervisor, onTop);
+        if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
+            throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
+                    + "activity type.");
         }
         return (T) new ActivityStack(this, stackId,
-                mRootActivityContainer.mStackSupervisor, windowingMode, activityType,
-                onTop);
+                mRootActivityContainer.mStackSupervisor, windowingMode, activityType, onTop);
     }
 
     /**
@@ -626,6 +625,10 @@
             return;
         }
 
+        // Collect the stacks that are necessary to be removed instead of performing the removal
+        // by looping mStacks, so that we don't miss any stacks after the stack size changed or
+        // stacks reordered.
+        final ArrayList<ActivityStack> stacks = new ArrayList<>();
         for (int j = windowingModes.length - 1 ; j >= 0; --j) {
             final int windowingMode = windowingModes[j];
             for (int i = mStacks.size() - 1; i >= 0; --i) {
@@ -636,9 +639,13 @@
                 if (stack.getWindowingMode() != windowingMode) {
                     continue;
                 }
-                mRootActivityContainer.mStackSupervisor.removeStack(stack);
+                stacks.add(stack);
             }
         }
+
+        for (int i = stacks.size() - 1; i >= 0; --i) {
+            mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
+        }
     }
 
     void removeStacksWithActivityTypes(int... activityTypes) {
@@ -646,15 +653,23 @@
             return;
         }
 
+        // Collect the stacks that are necessary to be removed instead of performing the removal
+        // by looping mStacks, so that we don't miss any stacks after the stack size changed or
+        // stacks reordered.
+        final ArrayList<ActivityStack> stacks = new ArrayList<>();
         for (int j = activityTypes.length - 1 ; j >= 0; --j) {
             final int activityType = activityTypes[j];
             for (int i = mStacks.size() - 1; i >= 0; --i) {
                 final ActivityStack stack = mStacks.get(i);
                 if (stack.getActivityType() == activityType) {
-                    mRootActivityContainer.mStackSupervisor.removeStack(stack);
+                    stacks.add(stack);
                 }
             }
         }
+
+        for (int i = stacks.size() - 1; i >= 0; --i) {
+            mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
+        }
     }
 
     void onStackWindowingModeChanged(ActivityStack stack) {
@@ -1019,8 +1034,8 @@
         return mSplitScreenPrimaryStack != null;
     }
 
-    PinnedActivityStack getPinnedStack() {
-        return (PinnedActivityStack) mPinnedStack;
+    ActivityStack getPinnedStack() {
+        return mPinnedStack;
     }
 
     boolean hasPinnedStack() {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9f8af50..b8634d8 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2508,6 +2508,13 @@
         final IBinder binder =
                 (freezeScreenIfNeeded && appToken != null) ? appToken.asBinder() : null;
         mAppWindowToken.setOrientation(requestedOrientation, binder, this);
+
+        // Push the new configuration to the requested app in case where it's not pushed, e.g. when
+        // the request is handled at task level with letterbox.
+        if (!getMergedOverrideConfiguration().equals(
+                mLastReportedConfiguration.getMergedConfiguration())) {
+            ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+        }
     }
 
     int getOrientation() {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 4d7de90..891c3da 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -114,6 +114,7 @@
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.IActivityController;
+import android.app.RemoteAction;
 import android.app.ResultInfo;
 import android.app.WindowConfiguration.ActivityType;
 import android.app.WindowConfiguration.WindowingMode;
@@ -173,8 +174,7 @@
 /**
  * State and management of a single stack of activities.
  */
-class ActivityStack<T extends StackWindowController> extends ConfigurationContainer
-        implements StackWindowListener {
+class ActivityStack extends ConfigurationContainer {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_ATM;
     private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
     private static final String TAG_APP = TAG + POSTFIX_APP;
@@ -297,8 +297,7 @@
     static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2;
 
     final ActivityTaskManagerService mService;
-    private final WindowManagerService mWindowManager;
-    T mWindowContainerController;
+    final WindowManagerService mWindowManager;
 
     /**
      * The back history of all previous (and possibly still
@@ -397,6 +396,9 @@
     static final int DESTROY_ACTIVITIES_MSG = FIRST_ACTIVITY_STACK_MSG + 5;
     static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 6;
 
+    // TODO: remove after unification.
+    TaskStack mTaskStack;
+
     private static class ScheduleDestroyArgs {
         final WindowProcessController mOwner;
         final String mReason;
@@ -495,21 +497,30 @@
         // stacks on a wrong display.
         mDisplayId = display.mDisplayId;
         setActivityType(activityType);
-        mWindowContainerController = createStackWindowController(display.mDisplayId, onTop,
-                mTmpRect2);
+        createTaskStack(display.mDisplayId, onTop, mTmpRect2);
         setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
                 false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
                 true /* creating */);
         display.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
     }
 
-    T createStackWindowController(int displayId, boolean onTop, Rect outBounds) {
-        return (T) new StackWindowController(mStackId, this, displayId, onTop, outBounds,
-                mRootActivityContainer.mWindowManager);
+    void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
+        final DisplayContent dc = mWindowManager.mRoot.getDisplayContent(displayId);
+        if (dc == null) {
+            throw new IllegalArgumentException("Trying to add stackId=" + mStackId
+                    + " to unknown displayId=" + displayId);
+        }
+        mTaskStack = new TaskStack(mWindowManager, mStackId, this);
+        dc.setStackOnDisplay(mStackId, onTop, mTaskStack);
+        if (mTaskStack.matchParentBounds()) {
+            outBounds.setEmpty();
+        } else {
+            mTaskStack.getRawBounds(outBounds);
+        }
     }
 
-    T getWindowContainerController() {
-        return mWindowContainerController;
+    TaskStack getTaskStack() {
+        return mTaskStack;
     }
 
     /**
@@ -553,6 +564,9 @@
         if (display == null) {
             return;
         }
+        if (getTaskStack() == null) {
+            return;
+        }
 
         // Update bounds if applicable
         boolean hasNewOverrideBounds = false;
@@ -560,8 +574,7 @@
         if (getRequestedOverrideWindowingMode() == WINDOWING_MODE_PINNED) {
             // Pinned calculation already includes rotation
             mTmpRect2.set(mTmpRect);
-            hasNewOverrideBounds = getWindowContainerController().mContainer
-                            .calculatePinnedBoundsForConfigChange(mTmpRect2);
+            hasNewOverrideBounds = getTaskStack().calculatePinnedBoundsForConfigChange(mTmpRect2);
         } else {
             final int newRotation = getWindowConfiguration().getRotation();
             if (!matchParentBounds()) {
@@ -588,7 +601,7 @@
                             || getRequestedOverrideWindowingMode()
                             == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
                         mTmpRect2.set(mTmpRect);
-                        getWindowContainerController().mContainer
+                        getTaskStack()
                                 .calculateDockedBoundsForConfigChange(newParentConfig, mTmpRect2);
                         hasNewOverrideBounds = true;
                     }
@@ -786,7 +799,11 @@
 
             mTmpRect2.setEmpty();
             if (windowingMode != WINDOWING_MODE_FULLSCREEN) {
-                mWindowContainerController.getRawBounds(mTmpRect2);
+                if (mTaskStack.matchParentBounds()) {
+                    mTmpRect2.setEmpty();
+                } else {
+                    mTaskStack.getRawBounds(mTmpRect2);
+                }
             }
 
             if (!Objects.equals(getRequestedOverrideBounds(), mTmpRect2)) {
@@ -843,7 +860,12 @@
         // Reparent the window container before we try to update the position when adding it to
         // the new display below
         mTmpRect2.setEmpty();
-        mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
+        if (mTaskStack == null) {
+            // TODO: Remove after unification.
+            Log.w(TAG, "Task stack is not valid when reparenting.");
+        } else {
+            mTaskStack.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
+        }
         setBounds(mTmpRect2.isEmpty() ? null : mTmpRect2);
         activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
         if (!displayRemoved) {
@@ -876,8 +898,10 @@
     /** Removes the stack completely. Also calls WindowManager to do the same on its side. */
     void remove() {
         removeFromDisplay();
-        mWindowContainerController.removeContainer();
-        mWindowContainerController = null;
+        if (mTaskStack != null) {
+            mTaskStack.removeIfPossible();
+            mTaskStack = null;
+        }
         onParentChanged();
     }
 
@@ -890,26 +914,35 @@
      */
     void getStackDockedModeBounds(Rect dockedBounds, Rect currentTempTaskBounds,
             Rect outStackBounds, Rect outTempTaskBounds) {
-        mWindowContainerController.getStackDockedModeBounds(getParent().getConfiguration(),
-                dockedBounds, currentTempTaskBounds,
-                outStackBounds, outTempTaskBounds);
+        if (mTaskStack != null) {
+            mTaskStack.getStackDockedModeBoundsLocked(getParent().getConfiguration(), dockedBounds,
+                    currentTempTaskBounds, outStackBounds, outTempTaskBounds);
+        } else {
+            outStackBounds.setEmpty();
+            outTempTaskBounds.setEmpty();
+        }
     }
 
     void prepareFreezingTaskBounds() {
-        mWindowContainerController.prepareFreezingTaskBounds();
+        if (mTaskStack != null) {
+            // TODO: This cannot be false after unification.
+            mTaskStack.prepareFreezingTaskBounds();
+        }
     }
 
     void getWindowContainerBounds(Rect outBounds) {
-        if (mWindowContainerController != null) {
-            mWindowContainerController.getBounds(outBounds);
+        if (mTaskStack != null) {
+            mTaskStack.getBounds(outBounds);
             return;
         }
         outBounds.setEmpty();
     }
 
     void positionChildWindowContainerAtTop(TaskRecord child) {
-        mWindowContainerController.positionChildAtTop(child.getTask(),
-                true /* includingParents */);
+        if (mTaskStack != null) {
+            // TODO: Remove after unification. This cannot be false after that.
+            mTaskStack.positionChildAtTop(child.getTask(), true /* includingParents */);
+        }
     }
 
     void positionChildWindowContainerAtBottom(TaskRecord child) {
@@ -918,14 +951,27 @@
         // task to bottom, the next focusable stack on the same display should be focused.
         final ActivityStack nextFocusableStack = getDisplay().getNextFocusableStack(
                 child.getStack(), true /* ignoreCurrent */);
-        mWindowContainerController.positionChildAtBottom(child.getTask(),
-                nextFocusableStack == null /* includingParents */);
+        if (mTaskStack != null) {
+            // TODO: Remove after unification. This cannot be false after that.
+            mTaskStack.positionChildAtBottom(child.getTask(),
+                    nextFocusableStack == null /* includingParents */);
+        }
     }
 
     /**
      * Returns whether to defer the scheduling of the multi-window mode.
      */
     boolean deferScheduleMultiWindowModeChanged() {
+        if (inPinnedWindowingMode()) {
+            // For the pinned stack, the deferring of the multi-window mode changed is tied to the
+            // transition animation into picture-in-picture, and is called once the animation
+            // completes, or is interrupted in a way that would leave the stack in a non-fullscreen
+            // state.
+            // @see BoundsAnimationController
+            // @see BoundsAnimationControllerTests
+            if (getTaskStack() == null) return false;
+            return getTaskStack().deferScheduleMultiWindowModeChanged();
+        }
         return false;
     }
 
@@ -2994,7 +3040,10 @@
         position = getAdjustedPositionForTask(task, position, null /* starting */);
         mTaskHistory.remove(task);
         mTaskHistory.add(position, task);
-        mWindowContainerController.positionChildAt(task.getTask(), position);
+        if (mTaskStack != null) {
+            // TODO: this could not be false after unification.
+            mTaskStack.positionChildAt(task.getTask(), position);
+        }
         updateTaskMovement(task, true);
     }
 
@@ -4909,8 +4958,7 @@
     }
 
     // TODO: Figure-out a way to consolidate with resize() method below.
-    @Override
-    public void requestResize(Rect bounds) {
+    void requestResize(Rect bounds) {
         mService.resizeStack(mStackId, bounds,
                 true /* allowResizeInDockedMode */, false /* preserveWindows */,
                 false /* animate */, -1 /* animationDuration */);
@@ -4948,7 +4996,8 @@
     }
 
     void onPipAnimationEndResize() {
-        mWindowContainerController.onPipAnimationEndResize();
+        if (mTaskStack == null) return;
+        mTaskStack.onPipAnimationEndResize();
     }
 
 
@@ -5494,6 +5543,65 @@
         }
     }
 
+
+    Rect getDefaultPictureInPictureBounds(float aspectRatio) {
+        if (getTaskStack() == null) return null;
+        return getTaskStack().getPictureInPictureBounds(aspectRatio, null /* currentStackBounds */);
+    }
+
+    void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration,
+            boolean fromFullscreen) {
+        if (!inPinnedWindowingMode()) return;
+        if (skipResizeAnimation(toBounds == null /* toFullscreen */)) {
+            mService.moveTasksToFullscreenStack(mStackId, true /* onTop */);
+        } else {
+            if (getTaskStack() == null) return;
+            getTaskStack().animateResizePinnedStack(toBounds, sourceHintBounds,
+                    animationDuration, fromFullscreen);
+        }
+    }
+
+    private boolean skipResizeAnimation(boolean toFullscreen) {
+        if (!toFullscreen) {
+            return false;
+        }
+        final Configuration parentConfig = getParent().getConfiguration();
+        final ActivityRecord top = topRunningNonOverlayTaskActivity();
+        return top != null && !top.isConfigurationCompatible(parentConfig);
+    }
+
+    void setPictureInPictureAspectRatio(float aspectRatio) {
+        if (getTaskStack() == null) return;
+        getTaskStack().setPictureInPictureAspectRatio(aspectRatio);
+    }
+
+    void setPictureInPictureActions(List<RemoteAction> actions) {
+        if (getTaskStack() == null) return;
+        getTaskStack().setPictureInPictureActions(actions);
+    }
+
+    boolean isAnimatingBoundsToFullscreen() {
+        if (getTaskStack() == null) return false;
+        return getTaskStack().isAnimatingBoundsToFullscreen();
+    }
+
+    public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
+            boolean forceUpdate) {
+        // It is guaranteed that the activities requiring the update will be in the pinned stack at
+        // this point (either reparented before the animation into PiP, or before reparenting after
+        // the animation out of PiP)
+        synchronized (mService.mGlobalLock) {
+            if (!isAttached()) {
+                return;
+            }
+            ArrayList<TaskRecord> tasks = getAllTasks();
+            for (int i = 0; i < tasks.size(); i++) {
+                mStackSupervisor.updatePictureInPictureMode(tasks.get(i), targetStackBounds,
+                        forceUpdate);
+            }
+        }
+    }
+
     public int getStackId() {
         return mStackId;
     }
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index a50ae84..3a288ca 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1674,8 +1674,8 @@
     }
 
     void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
-        // TODO(multi-display): Pinned stack display should be passed in.
-        final PinnedActivityStack stack =
+        // TODO(multi-display): The display containing the stack should be passed in.
+        final ActivityStack stack =
                 mRootActivityContainer.getDefaultDisplay().getPinnedStack();
         if (stack == null) {
             Slog.w(TAG, "resizePinnedStackLocked: pinned stack not found");
@@ -1686,7 +1686,7 @@
         // another AM call that is holding the AMS lock. In such a case, the pinnedBounds may be
         // incorrect if AMS.resizeStackWithBoundsFromWindowManager() is already called while waiting
         // for the AMS lock to be freed. So check and make sure these bounds are still good.
-        final PinnedStackWindowController stackController = stack.getWindowContainerController();
+        final TaskStack stackController = stack.getTaskStack();
         if (stackController.pinnedStackResizeDisallowed()) {
             return;
         }
@@ -1730,15 +1730,14 @@
              * invisible as well and added to the stopping list.  After which we process the
              * stopping list by handling the idle.
              */
-            final PinnedActivityStack pinnedStack = (PinnedActivityStack) stack;
-            pinnedStack.mForceHidden = true;
-            pinnedStack.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
-            pinnedStack.mForceHidden = false;
+            stack.mForceHidden = true;
+            stack.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
+            stack.mForceHidden = false;
             activityIdleInternalLocked(null, false /* fromTimeout */,
                     true /* processPausingActivites */, null /* configuration */);
 
             // Move all the tasks to the bottom of the fullscreen stack
-            moveTasksToFullscreenStackLocked(pinnedStack, !ON_TOP);
+            moveTasksToFullscreenStackLocked(stack, !ON_TOP);
         } else {
             for (int i = tasks.size() - 1; i >= 0; i--) {
                 removeTaskByIdLocked(tasks.get(i).taskId, true /* killProcess */,
@@ -2642,6 +2641,9 @@
                 try {
                     mService.moveTaskToFrontLocked(task.taskId, 0, options,
                             true /* fromRecents */);
+                    // Apply options to prevent pendingOptions be taken by client to make sure
+                    // the override pending app transition will be applied immediately.
+                    targetActivity.applyOptionsLocked();
                 } finally {
                     mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
                             targetActivity);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index a207354..916baa0 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
 import static android.app.Activity.RESULT_CANCELED;
 import static android.app.ActivityManager.START_ABORTED;
 import static android.app.ActivityManager.START_CANCELED;
@@ -50,6 +51,7 @@
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 
@@ -745,8 +747,9 @@
         // not sure if we need to create START_ABORTED_BACKGROUND so for now piggybacking
         // on START_ABORTED
         if (!abort) {
-            abort |= shouldAbortBackgroundActivityStart(callingUid, callingPackage, realCallingUid,
-                    callerApp, originatingPendingIntent, allowBackgroundActivityStart);
+            abort |= shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage,
+                    realCallingUid, callerApp, originatingPendingIntent,
+                    allowBackgroundActivityStart, intent);
         }
 
         // Merge the two options bundles, while realCallerOptions takes precedence.
@@ -893,9 +896,10 @@
                 true /* doResume */, checkedOptions, inTask, outActivity);
     }
 
-    private boolean shouldAbortBackgroundActivityStart(int callingUid, final String callingPackage,
-            int realCallingUid, WindowProcessController callerApp,
-            PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
+    private boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
+            final String callingPackage, int realCallingUid, WindowProcessController callerApp,
+            PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart,
+            Intent intent) {
         if (mService.isBackgroundActivityStartsEnabled()) {
             return false;
         }
@@ -908,19 +912,24 @@
             return false;
         }
         // don't abort if the callingUid is in the foreground or is a persistent system process
-        if (isUidForeground(callingUid) || isUidPersistentSystemProcess(callingUid)) {
+        final boolean isCallingUidForeground = isUidForeground(callingUid);
+        final boolean isCallingUidPersistentSystemProcess = isUidPersistentSystemProcess(
+                callingUid);
+        if (isCallingUidForeground || isCallingUidPersistentSystemProcess) {
             return false;
         }
         // take realCallingUid into consideration
+        final boolean isRealCallingUidForeground = isUidForeground(realCallingUid);
+        final boolean isRealCallingUidPersistentSystemProcess = isUidPersistentSystemProcess(
+                realCallingUid);
         if (realCallingUid != callingUid) {
             // don't abort if the realCallingUid is in the foreground and callingUid isn't
-            if (isUidForeground(realCallingUid)) {
+            if (isRealCallingUidForeground) {
                 return false;
             }
             // if the realCallingUid is a persistent system process, abort if the IntentSender
             // wasn't whitelisted to start an activity
-            if (isUidPersistentSystemProcess(realCallingUid) && (originatingPendingIntent != null)
-                    && allowBackgroundActivityStart) {
+            if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) {
                 return false;
             }
         }
@@ -928,11 +937,28 @@
         if (callerApp != null && callerApp.areBackgroundActivityStartsAllowed()) {
             return false;
         }
+        // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
+        if (mService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
+                == PERMISSION_GRANTED) {
+            return false;
+        }
         // don't abort if the caller has the same uid as the recents component
         if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
             return false;
         }
         // anything that has fallen through will currently be aborted
+        Slog.w(TAG, "Blocking background activity start [callingPackage: " + callingPackage
+                + "; callingUid: " + callingUid
+                + "; isCallingUidForeground: " + isCallingUidForeground
+                + "; isCallingUidPersistentSystemProcess: " + isCallingUidPersistentSystemProcess
+                + "; realCallingUid: " + realCallingUid
+                + "; isRealCallingUidForeground: " + isRealCallingUidForeground
+                + "; isRealCallingUidPersistentSystemProcess: "
+                        + isRealCallingUidPersistentSystemProcess
+                + "; originatingPendingIntent: " + originatingPendingIntent
+                + "; isBgStartWhitelisted: " + allowBackgroundActivityStart
+                + "; intent: " + intent
+                + "]");
         // TODO: remove this toast after feature development is done
         mService.mUiHandler.post(() -> {
             Toast.makeText(mService.mContext,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index e82e748..6a495d4 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -82,13 +82,10 @@
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.HOME_PROC;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.LAUNCHING_ACTIVITY;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto
-        .PREVIOUS_PROC_VISIBLE_TIME_MS;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage
-        .MODE;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage
-        .PACKAGE;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -210,6 +207,7 @@
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.VoiceInteractionManagerInternal;
+import android.sysprop.DisplayProperties;
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
 import android.text.format.Time;
@@ -245,7 +243,6 @@
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.server.appop.AppOpsService;
 import com.android.server.AttributeCache;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -261,6 +258,7 @@
 import com.android.server.am.PendingIntentController;
 import com.android.server.am.PendingIntentRecord;
 import com.android.server.am.UserState;
+import com.android.server.appop.AppOpsService;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.pm.UserManagerService;
 import com.android.server.uri.UriGrantsManagerInternal;
@@ -694,7 +692,7 @@
         final boolean isPc = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
 
         // Transfer any global setting for forcing RTL layout, into a System Property
-        SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
+        DisplayProperties.debug_force_rtl(forceRtl);
 
         final Configuration configuration = new Configuration();
         Settings.System.getConfiguration(resolver, configuration);
@@ -2407,7 +2405,7 @@
         try {
             synchronized (mGlobalLock) {
                 if (animate) {
-                    final PinnedActivityStack stack = mRootActivityContainer.getStack(stackId);
+                    final ActivityStack stack = mRootActivityContainer.getStack(stackId);
                     if (stack == null) {
                         Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
                         return;
@@ -3712,7 +3710,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                final PinnedActivityStack stack =
+                final ActivityStack stack =
                         mRootActivityContainer.getDefaultDisplay().getPinnedStack();
                 if (stack == null) {
                     Slog.w(TAG, "dismissPip: pinned stack not found.");
@@ -3834,9 +3832,8 @@
 
         // If we are animating to fullscreen then we have already dispatched the PIP mode
         // changed, so we should reflect that check here as well.
-        final PinnedActivityStack stack = r.getActivityStack();
-        final PinnedStackWindowController windowController = stack.getWindowContainerController();
-        return !windowController.mContainer.isAnimatingBoundsToFullscreen();
+        final TaskStack taskStack = r.getActivityStack().getTaskStack();
+        return !taskStack.isAnimatingBoundsToFullscreen();
     }
 
     @Override
@@ -3870,7 +3867,7 @@
                                 r.pictureInPictureArgs.getSourceRectHint());
                         mRootActivityContainer.moveActivityToPinnedStack(
                                 r, sourceBounds, aspectRatio, "enterPictureInPictureMode");
-                        final PinnedActivityStack stack = r.getActivityStack();
+                        final ActivityStack stack = r.getActivityStack();
                         stack.setPictureInPictureAspectRatio(aspectRatio);
                         stack.setPictureInPictureActions(actions);
                         MetricsLoggerWrapper.logPictureInPictureEnter(mContext, r.appInfo.uid,
@@ -3914,7 +3911,7 @@
                     // If the activity is already in picture-in-picture, update the pinned stack now
                     // if it is not already expanding to fullscreen. Otherwise, the arguments will
                     // be used the next time the activity enters PiP
-                    final PinnedActivityStack stack = r.getActivityStack();
+                    final ActivityStack stack = r.getActivityStack();
                     if (!stack.isAnimatingBoundsToFullscreen()) {
                         stack.setPictureInPictureAspectRatio(
                                 r.pictureInPictureArgs.getAspectRatio());
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 740d472..6527ca0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -328,14 +328,6 @@
     private int mLastOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
 
     /**
-     * Flag indicating that the application is receiving an orientation that has different metrics
-     * than it expected. E.g. Portrait instead of Landscape.
-     *
-     * @see #updateRotationUnchecked()
-     */
-    private boolean mAltOrientation = false;
-
-    /**
      * Orientation forced by some window. If there is no visible window that specifies orientation
      * it is set to {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}.
      *
@@ -1085,10 +1077,6 @@
         return mLastOrientation;
     }
 
-    boolean getAltOrientation() {
-        return mAltOrientation;
-    }
-
     int getLastWindowForcedOrientation() {
         return mLastWindowForcedOrientation;
     }
@@ -1130,15 +1118,9 @@
     boolean rotationNeedsUpdate() {
         final int lastOrientation = getLastOrientation();
         final int oldRotation = getRotation();
-        final boolean oldAltOrientation = getAltOrientation();
 
         final int rotation = mDisplayRotation.rotationForOrientation(lastOrientation, oldRotation);
-        final boolean altOrientation = !mDisplayRotation.rotationHasCompatibleMetrics(
-                lastOrientation, rotation);
-        if (oldRotation == rotation && oldAltOrientation == altOrientation) {
-            return false;
-        }
-        return true;
+        return oldRotation != rotation;
     }
 
     /**
@@ -1160,12 +1142,14 @@
     @Override
     boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
             ConfigurationContainer requestingContainer) {
+        final int previousRotation = mRotation;
         final Configuration config = updateOrientationFromAppTokens(
                 getRequestedOverrideConfiguration(), freezeDisplayToken, false);
-        // If display rotation class tells us that it doesn't consider app requested orientation,
-        // this display won't rotate just because of an app changes its requested orientation. Thus
-        // it indicates that this display chooses not to handle this request.
-        final boolean handled = getDisplayRotation().respectAppRequestedOrientation();
+        // This event is considered handled iff a configuration propagation is triggered, because
+        // that's the only place lower level containers check if they need to do something to this
+        // request. The only guaranteed signal is that the display is rotated to a different
+        // orientation (i.e. rotating 180 degrees doesn't count).
+        final boolean handled = (mRotation - previousRotation) % 2 != 0;
         if (config == null) {
             return handled;
         }
@@ -1334,7 +1318,6 @@
 
         final int oldRotation = mRotation;
         final int lastOrientation = mLastOrientation;
-        final boolean oldAltOrientation = mAltOrientation;
         final int rotation = mDisplayRotation.rotationForOrientation(lastOrientation, oldRotation);
         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Computed rotation=" + rotation + " for display id="
                 + mDisplayId + " based on lastOrientation=" + lastOrientation
@@ -1366,35 +1349,26 @@
         }
         final boolean rotateSeamlessly = mayRotateSeamlessly;
 
-        // TODO: Implement forced rotation changes.
-        //       Set mAltOrientation to indicate that the application is receiving
-        //       an orientation that has different metrics than it expected.
-        //       eg. Portrait instead of Landscape.
-
-        final boolean altOrientation = !mDisplayRotation.rotationHasCompatibleMetrics(
-                lastOrientation, rotation);
-
         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
                 + " selected orientation " + lastOrientation
                 + ", got rotation " + rotation + " which has "
-                + (altOrientation ? "incompatible" : "compatible") + " metrics");
+                + " metrics");
 
-        if (oldRotation == rotation && oldAltOrientation == altOrientation) {
+        if (oldRotation == rotation) {
             // No change.
             return false;
         }
 
         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
                 + " rotation changed to " + rotation
-                + (altOrientation ? " (alt)" : "") + " from " + oldRotation
-                + (oldAltOrientation ? " (alt)" : "") + ", lastOrientation=" + lastOrientation);
+                + " from " + oldRotation
+                + ", lastOrientation=" + lastOrientation);
 
         if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
             mWaitingForConfig = true;
         }
 
         mRotation = rotation;
-        mAltOrientation = altOrientation;
 
         mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
         mWmService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
@@ -1536,26 +1510,8 @@
     private DisplayInfo updateDisplayAndOrientation(int uiMode) {
         // Use the effective "visual" dimensions based on current rotation
         final boolean rotated = (mRotation == ROTATION_90 || mRotation == ROTATION_270);
-        final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
-        final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
-        int dw = realdw;
-        int dh = realdh;
-
-        if (mAltOrientation) {
-            if (realdw > realdh) {
-                // Turn landscape into portrait.
-                int maxw = (int)(realdh/1.3f);
-                if (maxw < realdw) {
-                    dw = maxw;
-                }
-            } else {
-                // Turn portrait into landscape.
-                int maxh = (int)(realdw/1.3f);
-                if (maxh < realdh) {
-                    dh = maxh;
-                }
-            }
-        }
+        final int dw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
+        final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
 
         // Update application display metrics.
         final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(mRotation);
@@ -2307,13 +2263,12 @@
         out.set(mDisplayFrames.mStable);
     }
 
-    TaskStack createStack(int stackId, boolean onTop, StackWindowController controller) {
-        if (DEBUG_STACK) Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId="
-                + mDisplayId);
+    void setStackOnDisplay(int stackId, boolean onTop, TaskStack stack) {
+        if (DEBUG_STACK) {
+            Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId=" + mDisplayId);
+        }
 
-        final TaskStack stack = new TaskStack(mWmService, stackId, controller);
         mTaskStackContainers.addStackToDisplay(stack, onTop);
-        return stack;
     }
 
     void moveStackToDisplay(TaskStack stack, boolean onTop) {
@@ -4015,7 +3970,6 @@
 
         /**
          * Adds the stack to this container.
-         * @see DisplayContent#createStack(int, boolean, StackWindowController)
          */
         void addStackToDisplay(TaskStack stack, boolean onTop) {
             addStackReferenceIfNeeded(stack);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index bcc7be4..bc165dc 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -329,15 +329,6 @@
         return mFixedToUserRotation;
     }
 
-    /**
-     * Returns {@code true} if this display rotation takes app requested orientation into
-     * consideration; {@code false} otherwise. For the time being the only case where this is {@code
-     * false} is when {@link #isFixedToUserRotation()} is {@code true}.
-     */
-    boolean respectAppRequestedOrientation() {
-        return !mFixedToUserRotation;
-    }
-
     public int getLandscapeRotation() {
         return mLandscapeRotation;
     }
@@ -685,36 +676,6 @@
         return rotation == mPortraitRotation || rotation == mUpsideDownRotation;
     }
 
-    /**
-     * Given an orientation constant and a rotation, returns true if the rotation
-     * has compatible metrics to the requested orientation.  For example, if
-     * the application requested landscape and got seascape, then the rotation
-     * has compatible metrics; if the application requested portrait and got landscape,
-     * then the rotation has incompatible metrics; if the application did not specify
-     * a preference, then anything goes.
-     *
-     * @param orientation An orientation constant, such as
-     * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
-     * @param rotation The rotation to check.
-     * @return True if the rotation is compatible with the requested orientation.
-     */
-    boolean rotationHasCompatibleMetrics(int orientation, int rotation) {
-        switch (orientation) {
-            case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
-            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
-            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
-                return isAnyPortrait(rotation);
-
-            case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
-            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
-            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
-                return isLandscapeOrSeascape(rotation);
-
-            default:
-                return true;
-        }
-    }
-
     private boolean isValidRotationChoice(final int preferredRotation) {
         // Determine if the given app orientation is compatible with the provided rotation choice.
         switch (mCurrentAppOrientation) {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 5f56fe5..177f244 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -462,22 +462,19 @@
             mOccluded = false;
             mDismissingKeyguardActivity = null;
 
-            // Only the top activity of the focused stack on each display may control it's
-            // occluded state.
-            final ActivityStack focusedStack = display.getFocusedStack();
-            if (focusedStack != null) {
-                final ActivityRecord topDismissing =
-                        focusedStack.getTopDismissingKeyguardActivity();
-                mOccluded = focusedStack.topActivityOccludesKeyguard() || (topDismissing != null
-                                && focusedStack.topRunningActivityLocked() == topDismissing
-                                && controller.canShowWhileOccluded(
+            final ActivityStack stack = getStackForControllingOccluding(display);
+            if (stack != null) {
+                final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
+                mOccluded = stack.topActivityOccludesKeyguard() || (topDismissing != null
+                        && stack.topRunningActivityLocked() == topDismissing
+                        && controller.canShowWhileOccluded(
                                 true /* dismissKeyguard */,
                                 false /* showWhenLocked */));
-                if (focusedStack.getTopDismissingKeyguardActivity() != null) {
-                    mDismissingKeyguardActivity = focusedStack.getTopDismissingKeyguardActivity();
+                if (stack.getTopDismissingKeyguardActivity() != null) {
+                    mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
                 }
-                mOccluded |= controller.mWindowManager.isShowingDream();
             }
+            mOccluded |= controller.mWindowManager.isShowingDream();
 
             // TODO(b/113840485): Handle app transition for individual display, and apply occluded
             // state change to secondary displays.
@@ -492,6 +489,23 @@
             }
         }
 
+        /**
+         * Gets the stack used to check the occluded state.
+         * <p>
+         * Only the top non-pinned activity of the focusable stack on each display can control its
+         * occlusion state.
+         */
+        private ActivityStack getStackForControllingOccluding(ActivityDisplay display) {
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                if (stack != null && stack.isFocusableAndVisible()
+                        && !stack.inPinnedWindowingMode()) {
+                    return stack;
+                }
+            }
+            return null;
+        }
+
         void dumpStatus(PrintWriter pw, String prefix) {
             final StringBuilder sb = new StringBuilder();
             sb.append(prefix);
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 3062d34..86dc66d 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -221,7 +221,7 @@
     }
 
     private boolean saveTaskToLaunchParam(TaskRecord task, PersistableLaunchParams params) {
-        final ActivityStack<?> stack = task.getStack();
+        final ActivityStack stack = task.getStack();
         final int displayId = stack.mDisplayId;
         final ActivityDisplay display =
                 mSupervisor.mRootActivityContainer.getActivityDisplay(displayId);
diff --git a/services/core/java/com/android/server/wm/PinnedActivityStack.java b/services/core/java/com/android/server/wm/PinnedActivityStack.java
deleted file mode 100644
index 2a05af4..0000000
--- a/services/core/java/com/android/server/wm/PinnedActivityStack.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-
-import android.app.RemoteAction;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * State and management of the pinned stack of activities.
- */
-class PinnedActivityStack extends ActivityStack<PinnedStackWindowController>
-        implements PinnedStackWindowListener {
-
-    PinnedActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
-            boolean onTop) {
-        super(display, stackId, supervisor, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, onTop);
-    }
-
-    @Override
-    PinnedStackWindowController createStackWindowController(int displayId, boolean onTop,
-            Rect outBounds) {
-        return new PinnedStackWindowController(mStackId, this, displayId, onTop, outBounds,
-                mRootActivityContainer.mWindowManager);
-    }
-
-    Rect getDefaultPictureInPictureBounds(float aspectRatio) {
-        return getWindowContainerController().getPictureInPictureBounds(aspectRatio,
-                null /* currentStackBounds */);
-    }
-
-    void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration,
-            boolean fromFullscreen) {
-        if (skipResizeAnimation(toBounds == null /* toFullscreen */)) {
-            mService.moveTasksToFullscreenStack(mStackId, true /* onTop */);
-        } else {
-            getWindowContainerController().animateResizePinnedStack(toBounds, sourceHintBounds,
-                    animationDuration, fromFullscreen);
-        }
-    }
-
-    private boolean skipResizeAnimation(boolean toFullscreen) {
-        if (!toFullscreen) {
-            return false;
-        }
-        final Configuration parentConfig = getParent().getConfiguration();
-        final ActivityRecord top = topRunningNonOverlayTaskActivity();
-        return top != null && !top.isConfigurationCompatible(parentConfig);
-    }
-
-    void setPictureInPictureAspectRatio(float aspectRatio) {
-        getWindowContainerController().setPictureInPictureAspectRatio(aspectRatio);
-    }
-
-    void setPictureInPictureActions(List<RemoteAction> actions) {
-        getWindowContainerController().setPictureInPictureActions(actions);
-    }
-
-    boolean isAnimatingBoundsToFullscreen() {
-        return getWindowContainerController().mContainer.isAnimatingBoundsToFullscreen();
-    }
-
-    /**
-     * Returns whether to defer the scheduling of the multi-window mode.
-     */
-    boolean deferScheduleMultiWindowModeChanged() {
-        // For the pinned stack, the deferring of the multi-window mode changed is tied to the
-        // transition animation into picture-in-picture, and is called once the animation completes,
-        // or is interrupted in a way that would leave the stack in a non-fullscreen state.
-        // @see BoundsAnimationController
-        // @see BoundsAnimationControllerTests
-        return mWindowContainerController.deferScheduleMultiWindowModeChanged();
-    }
-
-    public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
-            boolean forceUpdate) {
-        // It is guaranteed that the activities requiring the update will be in the pinned stack at
-        // this point (either reparented before the animation into PiP, or before reparenting after
-        // the animation out of PiP)
-        synchronized (mService.mGlobalLock) {
-            if (!isAttached()) {
-                return;
-            }
-            ArrayList<TaskRecord> tasks = getAllTasks();
-            for (int i = 0; i < tasks.size(); i++ ) {
-                mStackSupervisor.updatePictureInPictureMode(tasks.get(i), targetStackBounds,
-                        forceUpdate);
-            }
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
deleted file mode 100644
index 518e39b..0000000
--- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-
-import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
-import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
-import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
-import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState;
-
-import android.app.RemoteAction;
-import android.graphics.Rect;
-
-import java.util.List;
-
-/**
- * Controller for the pinned stack container. See {@link StackWindowController}.
- */
-public class PinnedStackWindowController extends StackWindowController {
-
-    private Rect mTmpFromBounds = new Rect();
-    private Rect mTmpToBounds = new Rect();
-
-    public PinnedStackWindowController(int stackId, PinnedStackWindowListener listener,
-            int displayId, boolean onTop, Rect outBounds, WindowManagerService service) {
-        super(stackId, listener, displayId, onTop, outBounds, service);
-    }
-
-    /**
-     * @return the {@param currentStackBounds} transformed to the give {@param aspectRatio}.  If
-     *         {@param currentStackBounds} is null, then the {@param aspectRatio} is applied to the
-     *         default bounds.
-     */
-    public Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) {
-        synchronized (mGlobalLock) {
-            if (!mService.mSupportsPictureInPicture || mContainer == null) {
-                return null;
-            }
-
-            final DisplayContent displayContent = mContainer.getDisplayContent();
-            if (displayContent == null) {
-                return null;
-            }
-
-            final PinnedStackController pinnedStackController =
-                    displayContent.getPinnedStackController();
-            if (stackBounds == null) {
-                // Calculate the aspect ratio bounds from the default bounds
-                stackBounds = pinnedStackController.getDefaultOrLastSavedBounds();
-            }
-
-            if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) {
-                return pinnedStackController.transformBoundsToAspectRatio(stackBounds, aspectRatio,
-                        true /* useCurrentMinEdgeSize */);
-            } else {
-                return stackBounds;
-            }
-        }
-    }
-
-    /**
-     * Animates the pinned stack.
-     */
-    public void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds,
-            int animationDuration, boolean fromFullscreen) {
-        synchronized (mGlobalLock) {
-            if (mContainer == null) {
-                throw new IllegalArgumentException("Pinned stack container not found :(");
-            }
-
-            // Get the from-bounds
-            final Rect fromBounds = new Rect();
-            mContainer.getBounds(fromBounds);
-
-            // Get non-null fullscreen to-bounds for animating if the bounds are null
-            @SchedulePipModeChangedState int schedulePipModeChangedState =
-                NO_PIP_MODE_CHANGED_CALLBACKS;
-            final boolean toFullscreen = toBounds == null;
-            if (toFullscreen) {
-                if (fromFullscreen) {
-                    throw new IllegalArgumentException("Should not defer scheduling PiP mode"
-                            + " change on animation to fullscreen.");
-                }
-                schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_START;
-
-                mService.getStackBounds(
-                        WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mTmpToBounds);
-                if (!mTmpToBounds.isEmpty()) {
-                    // If there is a fullscreen bounds, use that
-                    toBounds = new Rect(mTmpToBounds);
-                } else {
-                    // Otherwise, use the display bounds
-                    toBounds = new Rect();
-                    mContainer.getDisplayContent().getBounds(toBounds);
-                }
-            } else if (fromFullscreen) {
-                schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END;
-            }
-
-            mContainer.setAnimationFinalBounds(sourceHintBounds, toBounds, toFullscreen);
-
-            final Rect finalToBounds = toBounds;
-            final @SchedulePipModeChangedState int finalSchedulePipModeChangedState =
-                schedulePipModeChangedState;
-            final DisplayContent displayContent = mContainer.getDisplayContent();
-            displayContent.mBoundsAnimationController.getHandler().post(() -> {
-                if (mContainer == null) {
-                    return;
-                }
-                displayContent.mBoundsAnimationController.animateBounds(mContainer, fromBounds,
-                        finalToBounds, animationDuration, finalSchedulePipModeChangedState,
-                        fromFullscreen, toFullscreen);
-            });
-        }
-    }
-
-    /**
-     * Sets the current picture-in-picture aspect ratio.
-     */
-    public void setPictureInPictureAspectRatio(float aspectRatio) {
-        synchronized (mGlobalLock) {
-            if (!mService.mSupportsPictureInPicture || mContainer == null) {
-                return;
-            }
-
-            final PinnedStackController pinnedStackController =
-                    mContainer.getDisplayContent().getPinnedStackController();
-
-            if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) != 0) {
-                mContainer.getAnimationOrCurrentBounds(mTmpFromBounds);
-                mTmpToBounds.set(mTmpFromBounds);
-                getPictureInPictureBounds(aspectRatio, mTmpToBounds);
-                if (!mTmpToBounds.equals(mTmpFromBounds)) {
-                    animateResizePinnedStack(mTmpToBounds, null /* sourceHintBounds */,
-                            -1 /* duration */, false /* fromFullscreen */);
-                }
-                pinnedStackController.setAspectRatio(
-                        pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
-                                ? aspectRatio : -1f);
-            }
-        }
-    }
-
-    /**
-     * Sets the current picture-in-picture actions.
-     */
-    public void setPictureInPictureActions(List<RemoteAction> actions) {
-        synchronized (mGlobalLock) {
-            if (!mService.mSupportsPictureInPicture || mContainer == null) {
-                return;
-            }
-
-            mContainer.getDisplayContent().getPinnedStackController().setActions(actions);
-        }
-    }
-
-    /**
-     * @return whether the multi-window mode change should be deferred as a part of a transition
-     * from fullscreen to non-fullscreen bounds.
-     */
-    public boolean deferScheduleMultiWindowModeChanged() {
-        synchronized (mGlobalLock) {
-            return mContainer.deferScheduleMultiWindowModeChanged();
-        }
-    }
-
-    /**
-     * @return whether the stack can be resized from the bounds animation.
-     */
-    public boolean pinnedStackResizeDisallowed() {
-        synchronized (mGlobalLock) {
-            return mContainer.pinnedStackResizeDisallowed();
-        }
-    }
-
-    /**
-     * The following calls are made from WM to AM.
-     */
-
-    /** Calls directly into activity manager so window manager lock shouldn't held. */
-    public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
-            boolean forceUpdate) {
-        if (mListener != null) {
-            PinnedStackWindowListener listener = (PinnedStackWindowListener) mListener;
-            listener.updatePictureInPictureModeForPinnedStackAnimation(targetStackBounds,
-                    forceUpdate);
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowListener.java b/services/core/java/com/android/server/wm/PinnedStackWindowListener.java
deleted file mode 100644
index 33e8a60..0000000
--- a/services/core/java/com/android/server/wm/PinnedStackWindowListener.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import android.graphics.Rect;
-
-/**
- * Interface used by the creator of {@link PinnedStackWindowController} to listen to changes with
- * the stack container.
- */
-public interface PinnedStackWindowListener extends StackWindowListener {
-
-    /**
-     * Called when the stack container pinned stack animation will change the picture-in-picture
-     * mode. This is a direct call into ActivityManager.
-     */
-    default void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
-            boolean forceUpdate) {}
-}
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index f55c7c9..9b72141 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -234,7 +234,7 @@
         mWindowManager = wm;
         setWindowContainer(mWindowManager.mRoot);
         mDisplayManager = mService.mContext.getSystemService(DisplayManager.class);
-        mDisplayManager.registerDisplayListener(this, mService.mH);
+        mDisplayManager.registerDisplayListener(this, mService.mUiHandler);
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
 
         final Display[] displays = mDisplayManager.getDisplays();
@@ -955,7 +955,7 @@
         mWindowManager.deferSurfaceLayout();
 
         final ActivityDisplay display = r.getActivityStack().getDisplay();
-        PinnedActivityStack stack = display.getPinnedStack();
+        ActivityStack stack = display.getPinnedStack();
 
         // This will clear the pinned stack by moving an existing task to the full screen stack,
         // ensuring only one task is present.
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 937c9d9..58cf73a 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -47,10 +47,9 @@
 import android.view.IWindowSession;
 import android.view.IWindowSessionCallback;
 import android.view.InputChannel;
-import android.view.Surface;
+import android.view.InsetsState;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
-import android.view.InsetsState;
 import android.view.WindowManager;
 
 import com.android.internal.os.logging.MetricsLoggerWrapper;
@@ -432,7 +431,7 @@
 
     @Override
     public void insetsModified(IWindow window, InsetsState state) {
-        synchronized (mService.mWindowMap) {
+        synchronized (mService.mGlobalLock) {
             final WindowState windowState = mService.windowForClientLocked(this, window,
                     false /* throwOnError */);
             if (windowState != null) {
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
deleted file mode 100644
index ada807b..0000000
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ /dev/null
@@ -1,245 +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
- */
-
-package com.android.server.wm;
-
-import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
-import static com.android.server.wm.WindowContainer.POSITION_TOP;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.ref.WeakReference;
-
-/**
- * Controller for the stack container. This is created by activity manager to link activity stacks
- * to the stack container they use in window manager.
- *
- * Test class: {@link StackWindowControllerTests}
- */
-public class StackWindowController
-        extends WindowContainerController<TaskStack, StackWindowListener> {
-
-    private final int mStackId;
-
-    private final H mHandler;
-
-    final Rect mTmpBounds = new Rect();
-
-    public StackWindowController(int stackId, StackWindowListener listener, int displayId,
-            boolean onTop, Rect outBounds) {
-        this(stackId, listener, displayId, onTop, outBounds, WindowManagerService.getInstance());
-    }
-
-    @VisibleForTesting
-    public StackWindowController(int stackId, StackWindowListener listener,
-            int displayId, boolean onTop, Rect outBounds, WindowManagerService service) {
-        super(listener, service);
-        mStackId = stackId;
-        mHandler = new H(new WeakReference<>(this), service.mH.getLooper());
-
-        final DisplayContent dc = mRoot.getDisplayContent(displayId);
-        if (dc == null) {
-            throw new IllegalArgumentException("Trying to add stackId=" + stackId
-                    + " to unknown displayId=" + displayId);
-        }
-
-        dc.createStack(stackId, onTop, this);
-        getRawBounds(outBounds);
-    }
-
-    @Override
-    public void removeContainer() {
-        if (mContainer != null) {
-            mContainer.removeIfPossible();
-            super.removeContainer();
-        }
-    }
-
-    void reparent(int displayId, Rect outStackBounds, boolean onTop) {
-        if (mContainer == null) {
-            throw new IllegalArgumentException("Trying to move unknown stackId=" + mStackId
-                    + " to displayId=" + displayId);
-        }
-
-        final DisplayContent targetDc = mRoot.getDisplayContent(displayId);
-        if (targetDc == null) {
-            throw new IllegalArgumentException("Trying to move stackId=" + mStackId
-                    + " to unknown displayId=" + displayId);
-        }
-
-        targetDc.moveStackToDisplay(mContainer, onTop);
-        getRawBounds(outStackBounds);
-    }
-
-    void positionChildAt(Task child, int position) {
-        if (DEBUG_STACK) {
-            Slog.i(TAG_WM, "positionChildAt: positioning task=" + child + " at " + position);
-        }
-        if (child == null) {
-            if (DEBUG_STACK) {
-                Slog.i(TAG_WM, "positionChildAt: could not find task=" + this);
-            }
-            return;
-        }
-        if (mContainer == null) {
-            if (DEBUG_STACK) {
-                Slog.i(TAG_WM, "positionChildAt: could not find stack for task=" + mContainer);
-            }
-            return;
-        }
-        child.positionAt(position);
-        mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
-    }
-
-    void positionChildAtTop(Task child, boolean includingParents) {
-        if (child == null) {
-            // TODO: Fix the call-points that cause this to happen.
-            return;
-        }
-
-        mContainer.positionChildAt(POSITION_TOP, child, includingParents);
-
-        final DisplayContent displayContent = mContainer.getDisplayContent();
-        if (displayContent.mAppTransition.isTransitionSet()) {
-            child.setSendingToBottom(false);
-        }
-        displayContent.layoutAndAssignWindowLayersIfNeeded();
-    }
-
-    void positionChildAtBottom(Task child, boolean includingParents) {
-        if (child == null) {
-            // TODO: Fix the call-points that cause this to happen.
-            return;
-        }
-
-        mContainer.positionChildAt(POSITION_BOTTOM, child, includingParents);
-
-        if (mContainer.getDisplayContent().mAppTransition.isTransitionSet()) {
-            child.setSendingToBottom(true);
-        }
-        mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
-    }
-
-    /**
-     * Re-sizes a stack and its containing tasks.
-     *
-     * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
-     * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
-     * @param taskTempInsetBounds Inset bounds for individual tasks, keyed by task id.
-     */
-    public void resize(Rect bounds, SparseArray<Rect> taskBounds,
-            SparseArray<Rect> taskTempInsetBounds) {
-        if (mContainer == null) {
-            throw new IllegalArgumentException("resizeStack: stack " + this + " not found.");
-        }
-        // We might trigger a configuration change. Save the current task bounds for freezing.
-        mContainer.prepareFreezingTaskBounds();
-        if (mContainer.setBounds(bounds, taskBounds, taskTempInsetBounds)
-                && mContainer.isVisible()) {
-            mContainer.getDisplayContent().setLayoutNeeded();
-            mService.mWindowPlacerLocked.performSurfacePlacement();
-        }
-    }
-
-    public void onPipAnimationEndResize() {
-        mContainer.onPipAnimationEndResize();
-    }
-
-    /**
-     * @see TaskStack.getStackDockedModeBoundsLocked(ConfigurationContainer, Rect, Rect, Rect)
-     */
-    public void getStackDockedModeBounds(Configuration parentConfig, Rect dockedBounds,
-            Rect currentTempTaskBounds,
-            Rect outStackBounds, Rect outTempTaskBounds) {
-        if (mContainer != null) {
-            mContainer.getStackDockedModeBoundsLocked(parentConfig, dockedBounds,
-                    currentTempTaskBounds, outStackBounds, outTempTaskBounds);
-            return;
-        }
-        outStackBounds.setEmpty();
-        outTempTaskBounds.setEmpty();
-    }
-
-    public void prepareFreezingTaskBounds() {
-        if (mContainer == null) {
-            throw new IllegalArgumentException("prepareFreezingTaskBounds: stack " + this
-                    + " not found.");
-        }
-        mContainer.prepareFreezingTaskBounds();
-    }
-
-    public void getRawBounds(Rect outBounds) {
-        if (mContainer.matchParentBounds()) {
-            outBounds.setEmpty();
-        } else {
-            mContainer.getRawBounds(outBounds);
-        }
-    }
-
-    public void getBounds(Rect outBounds) {
-        if (mContainer != null) {
-            mContainer.getBounds(outBounds);
-            return;
-        }
-        outBounds.setEmpty();
-    }
-
-    void requestResize(Rect bounds) {
-        mHandler.obtainMessage(H.REQUEST_RESIZE, bounds).sendToTarget();
-    }
-
-    @Override
-    public String toString() {
-        return "{StackWindowController stackId=" + mStackId + "}";
-    }
-
-    private static final class H extends Handler {
-
-        static final int REQUEST_RESIZE = 0;
-
-        private final WeakReference<StackWindowController> mController;
-
-        H(WeakReference<StackWindowController> controller, Looper looper) {
-            super(looper);
-            mController = controller;
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            final StackWindowController controller = mController.get();
-            final StackWindowListener listener = (controller != null)
-                    ? controller.mListener : null;
-            if (listener == null) {
-                return;
-            }
-            switch (msg.what) {
-                case REQUEST_RESIZE:
-                    listener.requestResize((Rect) msg.obj);
-                    break;
-            }
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/wm/StackWindowListener.java b/services/core/java/com/android/server/wm/StackWindowListener.java
deleted file mode 100644
index c763c17..0000000
--- a/services/core/java/com/android/server/wm/StackWindowListener.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import android.graphics.Rect;
-
-/**
- * Interface used by the creator of {@link StackWindowController} to listen to changes with
- * the stack container.
- */
-public interface StackWindowListener extends WindowContainerListener {
-
-    /** Called when the stack container would like its controller to resize. */
-    void requestResize(Rect bounds);
-}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d334bd2..a7dd55b 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -209,26 +209,14 @@
         super.removeImmediately();
     }
 
-    void reparent(StackWindowController stackController, int position, boolean moveParents) {
-        if (DEBUG_STACK) {
-            Slog.i(TAG_WM, "reparent: moving taskId=" + mTaskId
-                    + " to stack=" + stackController + " at " + position);
-        }
-        final TaskStack stack = stackController.mContainer;
-        if (stack == null) {
-            throw new IllegalArgumentException("reparent: could not find stack="
-                    + stackController);
-        }
-        reparent(stack, position, moveParents);
-        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
-    }
-
-
     void reparent(TaskStack stack, int position, boolean moveParents) {
         if (stack == mStack) {
             throw new IllegalArgumentException(
                     "task=" + this + " already child of stack=" + mStack);
         }
+        if (stack == null) {
+            throw new IllegalArgumentException("reparent: could not find stack.");
+        }
         if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
                 + " from stack=" + mStack);
         EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
@@ -254,6 +242,7 @@
             onDisplayChanged(displayContent);
             prevDisplayContent.setLayoutNeeded();
         }
+        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
     }
 
     /** @see ActivityTaskManagerService#positionTaskInStack(int, int, int). */
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 6acd864..f3050a9 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -709,7 +709,7 @@
 
         final List<TaskRecord> tasksToCheck = new ArrayList<>();
         for (int i = 0; i < display.getChildCount(); ++i) {
-            ActivityStack<?> stack = display.getChildAt(i);
+            final ActivityStack stack = display.getChildAt(i);
             if (!stack.inFreeformWindowingMode()) {
                 continue;
             }
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 4a553cf..69dcaf4 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -455,17 +455,10 @@
         }
 
         final Rect bounds = updateOverrideConfigurationFromLaunchBounds();
-        final StackWindowController stackController = getStack().getWindowContainerController();
+        final TaskStack stack = getStack().getTaskStack();
 
-        if (DEBUG_STACK) {
-            Slog.i(TAG_WM, "TaskRecord: taskId=" + taskId
-                    + " stack=" + stackController + " bounds=" + bounds);
-        }
-
-        final TaskStack stack = stackController.mContainer;
         if (stack == null) {
-            throw new IllegalArgumentException("TaskRecord: invalid stack="
-                    + stackController);
+            throw new IllegalArgumentException("TaskRecord: invalid stack=" + mStack);
         }
         EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId);
         mTask = new Task(taskId, stack, userId, mService.mWindowManager, mResizeMode,
@@ -742,7 +735,7 @@
 
             // Must reparent first in window manager to avoid a situation where AM can delete the
             // we are coming from in WM before we reparent because it became empty.
-            mTask.reparent(toStack.getWindowContainerController(), position,
+            mTask.reparent(toStack.getTaskStack(), position,
                     moveStackMode == REPARENT_MOVE_STACK_TO_FRONT);
 
             final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
@@ -1278,28 +1271,28 @@
     }
 
     /**
-     * Checks if the root activity requires a particular orientation (either by override or
+     * Checks if the top activity requires a particular orientation (either by override or
      * activityInfo) and returns that. Otherwise, this returns ORIENTATION_UNDEFINED.
      */
-    private int getRootActivityRequestedOrientation() {
-        ActivityRecord root = getRootActivity();
+    private int getTopActivityRequestedOrientation() {
+        ActivityRecord top = getTopActivity();
         if (getRequestedOverrideConfiguration().orientation != ORIENTATION_UNDEFINED
-                || root == null) {
+                || top == null) {
             return getRequestedOverrideConfiguration().orientation;
         }
-        int rootScreenOrientation = root.getOrientation();
-        if (rootScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
+        int screenOrientation = top.getOrientation();
+        if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
             // NOSENSOR means the display's "natural" orientation, so return that.
             ActivityDisplay display = mStack != null ? mStack.getDisplay() : null;
             if (display != null && display.mDisplayContent != null) {
                 return mStack.getDisplay().mDisplayContent.getNaturalOrientation();
             }
-        } else if (rootScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
+        } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
             // LOCKED means the activity's orientation remains unchanged, so return existing value.
-            return root.getConfiguration().orientation;
-        } else if (ActivityInfo.isFixedOrientationLandscape(rootScreenOrientation)) {
+            return top.getConfiguration().orientation;
+        } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) {
             return ORIENTATION_LANDSCAPE;
-        } else if (ActivityInfo.isFixedOrientationPortrait(rootScreenOrientation)) {
+        } else if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) {
             return ORIENTATION_PORTRAIT;
         }
         return ORIENTATION_UNDEFINED;
@@ -2196,9 +2189,9 @@
             // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent"
             outOverrideBounds.setEmpty();
 
-            // If the task or its root activity require a different orientation, make it fit the
+            // If the task or its top activity requires a different orientation, make it fit the
             // available bounds by scaling down its bounds.
-            int forcedOrientation = getRootActivityRequestedOrientation();
+            int forcedOrientation = getTopActivityRequestedOrientation();
             if (forcedOrientation != ORIENTATION_UNDEFINED
                     && forcedOrientation != newParentConfig.orientation) {
                 final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index ee74bdf..8ed7d04 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -21,6 +21,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
@@ -33,6 +34,10 @@
 import static android.view.WindowManager.DOCKED_RIGHT;
 import static android.view.WindowManager.DOCKED_TOP;
 
+import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
+import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
+import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
+import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.StackProto.ADJUSTED_BOUNDS;
 import static com.android.server.wm.StackProto.ADJUSTED_FOR_IME;
@@ -47,10 +52,12 @@
 import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT;
 import static com.android.server.wm.StackProto.TASKS;
 import static com.android.server.wm.StackProto.WINDOW_CONTAINER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.CallSuper;
+import android.app.RemoteAction;
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -71,9 +78,10 @@
 import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
+import java.util.List;
 
 public class TaskStack extends WindowContainer<Task> implements
-        BoundsAnimationTarget {
+        BoundsAnimationTarget, ConfigurationContainerListener {
     /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
      * restrict IME adjustment so that a min portion of top stack remains visible.*/
     private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
@@ -93,6 +101,10 @@
     private Rect mTmpRect2 = new Rect();
     private Rect mTmpRect3 = new Rect();
 
+    /** For Pinned stack controlling. */
+    private Rect mTmpFromBounds = new Rect();
+    private Rect mTmpToBounds = new Rect();
+
     /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
     private final Rect mAdjustedBounds = new Rect();
 
@@ -141,6 +153,9 @@
 
     private Dimmer mDimmer = new Dimmer(this);
 
+    // TODO: remove after unification.
+    ActivityStack mActivityStack;
+
     /**
      * For {@link #prepareSurfaces}.
      */
@@ -150,10 +165,11 @@
     private final AnimatingAppWindowTokenRegistry mAnimatingAppWindowTokenRegistry =
             new AnimatingAppWindowTokenRegistry();
 
-    TaskStack(WindowManagerService service, int stackId, StackWindowController controller) {
+    TaskStack(WindowManagerService service, int stackId, ActivityStack activityStack) {
         super(service);
         mStackId = stackId;
-        setController(controller);
+        mActivityStack = activityStack;
+        activityStack.registerConfigurationChangeListener(this);
         mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.docked_stack_minimize_thickness);
         EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
@@ -572,6 +588,49 @@
         positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers);
     }
 
+    void positionChildAt(Task child, int position) {
+        if (DEBUG_STACK) {
+            Slog.i(TAG_WM, "positionChildAt: positioning task=" + child + " at " + position);
+        }
+        if (child == null) {
+            if (DEBUG_STACK) {
+                Slog.i(TAG_WM, "positionChildAt: could not find task=" + this);
+            }
+            return;
+        }
+        child.positionAt(position);
+        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+    }
+
+    void positionChildAtTop(Task child, boolean includingParents) {
+        if (child == null) {
+            // TODO: Fix the call-points that cause this to happen.
+            return;
+        }
+
+        positionChildAt(POSITION_TOP, child, includingParents);
+
+        final DisplayContent displayContent = getDisplayContent();
+        if (displayContent.mAppTransition.isTransitionSet()) {
+            child.setSendingToBottom(false);
+        }
+        displayContent.layoutAndAssignWindowLayersIfNeeded();
+    }
+
+    void positionChildAtBottom(Task child, boolean includingParents) {
+        if (child == null) {
+            // TODO: Fix the call-points that cause this to happen.
+            return;
+        }
+
+        positionChildAt(POSITION_BOTTOM, child, includingParents);
+
+        if (getDisplayContent().mAppTransition.isTransitionSet()) {
+            child.setSendingToBottom(true);
+        }
+        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+    }
+
     @Override
     void positionChildAt(int position, Task child, boolean includingParents) {
         positionChildAt(position, child, includingParents, child.showForAllUsers());
@@ -596,6 +655,21 @@
         EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop, targetPosition);
     }
 
+    void reparent(int displayId, Rect outStackBounds, boolean onTop) {
+        final DisplayContent targetDc = mWmService.mRoot.getDisplayContent(displayId);
+        if (targetDc == null) {
+            throw new IllegalArgumentException("Trying to move stackId=" + mStackId
+                    + " to unknown displayId=" + displayId);
+        }
+
+        targetDc.moveStackToDisplay(this, onTop);
+        if (matchParentBounds()) {
+            outStackBounds.setEmpty();
+        } else {
+            getRawBounds(outStackBounds);
+        }
+    }
+
     // TODO: We should really have users as a window container in the hierarchy so that we don't
     // have to do complicated things like we are doing in this method.
     private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers,
@@ -725,6 +799,23 @@
     }
 
     /**
+     * Re-sizes a stack and its containing tasks.
+     *
+     * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
+     * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
+     * @param taskTempInsetBounds Inset bounds for individual tasks, keyed by task id.
+     */
+    void resize(Rect bounds, SparseArray<Rect> taskBounds,
+            SparseArray<Rect> taskTempInsetBounds) {
+        // We might trigger a configuration change. Save the current task bounds for freezing.
+        prepareFreezingTaskBounds();
+        if (setBounds(bounds, taskBounds, taskTempInsetBounds) && isVisible()) {
+            getDisplayContent().setLayoutNeeded();
+            mWmService.mWindowPlacerLocked.performSurfacePlacement();
+        }
+    }
+
+    /**
      * Calculate an amount by which to expand the stack bounds in each direction.
      * Used to make room for shadows in the pinned windowing mode.
      */
@@ -929,12 +1020,7 @@
                 (dockedStack == null || dockedStack == this) ? null : dockedStack.getRawBounds();
         getStackDockedModeBoundsLocked(mDisplayContent.getConfiguration(), dockedBounds,
                 null /* currentTempTaskBounds */, bounds, tempBounds);
-        getController().requestResize(bounds);
-    }
-
-    @Override
-    StackWindowController getController() {
-        return (StackWindowController) super.getController();
+        mActivityStack.requestResize(bounds);
     }
 
     @Override
@@ -947,6 +1033,14 @@
     }
 
     @Override
+    void removeImmediately() {
+        if (mActivityStack != null) {
+            mActivityStack.unregisterConfigurationChangeListener(this);
+        }
+        super.removeImmediately();
+    }
+
+    @Override
     void onParentSet() {
         super.onParentSet();
 
@@ -1572,14 +1666,13 @@
                 // I don't believe you...
             }
 
-            final PinnedStackWindowController controller =
-                    (PinnedStackWindowController) getController();
-            if (schedulePipModeChangedCallback && controller != null) {
+            if (schedulePipModeChangedCallback && mActivityStack != null) {
                 // We need to schedule the PiP mode change before the animation up. It is possible
                 // in this case for the animation down to not have been completed, so always
                 // force-schedule and update to the client to ensure that it is notified that it
                 // is no longer in picture-in-picture mode
-                controller.updatePictureInPictureModeForPinnedStackAnimation(null, forceUpdate);
+                mActivityStack.updatePictureInPictureModeForPinnedStackAnimation(null,
+                        forceUpdate);
             }
         }
         return true;
@@ -1592,12 +1685,10 @@
             // Update to the final bounds if requested. This is done here instead of in the bounds
             // animator to allow us to coordinate this after we notify the PiP mode changed
 
-            final PinnedStackWindowController controller =
-                    (PinnedStackWindowController) getController();
-            if (schedulePipModeChangedCallback && controller != null) {
+            if (schedulePipModeChangedCallback) {
                 // We need to schedule the PiP mode change after the animation down, so use the
                 // final bounds
-                controller.updatePictureInPictureModeForPinnedStackAnimation(
+                mActivityStack.updatePictureInPictureModeForPinnedStackAnimation(
                         mBoundsAnimationTarget, false /* forceUpdate */);
             }
 
@@ -1624,6 +1715,135 @@
         }
     }
 
+    /**
+     * @return the current stack bounds transformed to the given {@param aspectRatio}. If
+     *         the default bounds is {@code null}, then the {@param aspectRatio} is applied to the
+     *         default bounds.
+     */
+    Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) {
+        if (!mWmService.mSupportsPictureInPicture) {
+            return null;
+        }
+
+        final DisplayContent displayContent = getDisplayContent();
+        if (displayContent == null) {
+            return null;
+        }
+
+        if (!inPinnedWindowingMode()) {
+            return null;
+        }
+
+        final PinnedStackController pinnedStackController =
+                displayContent.getPinnedStackController();
+        if (stackBounds == null) {
+            // Calculate the aspect ratio bounds from the default bounds
+            stackBounds = pinnedStackController.getDefaultOrLastSavedBounds();
+        }
+
+        if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) {
+            return pinnedStackController.transformBoundsToAspectRatio(stackBounds, aspectRatio,
+                    true /* useCurrentMinEdgeSize */);
+        } else {
+            return stackBounds;
+        }
+    }
+
+    /**
+     * Animates the pinned stack.
+     */
+    void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds,
+            int animationDuration, boolean fromFullscreen) {
+        if (!inPinnedWindowingMode()) {
+            return;
+        }
+        // Get the from-bounds
+        final Rect fromBounds = new Rect();
+        getBounds(fromBounds);
+
+        // Get non-null fullscreen to-bounds for animating if the bounds are null
+        @SchedulePipModeChangedState int schedulePipModeChangedState =
+                NO_PIP_MODE_CHANGED_CALLBACKS;
+        final boolean toFullscreen = toBounds == null;
+        if (toFullscreen) {
+            if (fromFullscreen) {
+                throw new IllegalArgumentException("Should not defer scheduling PiP mode"
+                        + " change on animation to fullscreen.");
+            }
+            schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_START;
+
+            mWmService.getStackBounds(
+                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mTmpToBounds);
+            if (!mTmpToBounds.isEmpty()) {
+                // If there is a fullscreen bounds, use that
+                toBounds = new Rect(mTmpToBounds);
+            } else {
+                // Otherwise, use the display bounds
+                toBounds = new Rect();
+                getDisplayContent().getBounds(toBounds);
+            }
+        } else if (fromFullscreen) {
+            schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END;
+        }
+
+        setAnimationFinalBounds(sourceHintBounds, toBounds, toFullscreen);
+
+        final Rect finalToBounds = toBounds;
+        final @SchedulePipModeChangedState int finalSchedulePipModeChangedState =
+                schedulePipModeChangedState;
+        final DisplayContent displayContent = getDisplayContent();
+        displayContent.mBoundsAnimationController.getHandler().post(() -> {
+            displayContent.mBoundsAnimationController.animateBounds(this, fromBounds,
+                    finalToBounds, animationDuration, finalSchedulePipModeChangedState,
+                    fromFullscreen, toFullscreen);
+        });
+    }
+
+    /**
+     * Sets the current picture-in-picture aspect ratio.
+     */
+    void setPictureInPictureAspectRatio(float aspectRatio) {
+        if (!mWmService.mSupportsPictureInPicture) {
+            return;
+        }
+
+        if (!inPinnedWindowingMode()) {
+            return;
+        }
+
+        final PinnedStackController pinnedStackController =
+                getDisplayContent().getPinnedStackController();
+
+        if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) == 0) {
+            return;
+        }
+        getAnimationOrCurrentBounds(mTmpFromBounds);
+        mTmpToBounds.set(mTmpFromBounds);
+        getPictureInPictureBounds(aspectRatio, mTmpToBounds);
+        if (!mTmpToBounds.equals(mTmpFromBounds)) {
+            animateResizePinnedStack(mTmpToBounds, null /* sourceHintBounds */,
+                    -1 /* duration */, false /* fromFullscreen */);
+        }
+        pinnedStackController.setAspectRatio(
+                pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
+                        ? aspectRatio : -1f);
+    }
+
+    /**
+     * Sets the current picture-in-picture actions.
+     */
+    void setPictureInPictureActions(List<RemoteAction> actions) {
+        if (!mWmService.mSupportsPictureInPicture) {
+            return;
+        }
+
+        if (!inPinnedWindowingMode()) {
+            return;
+        }
+
+        getDisplayContent().getPinnedStackController().setActions(actions);
+    }
+
     @Override
     public boolean isAttached() {
         synchronized (mWmService.mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index b219419..2e5df45 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -31,6 +31,10 @@
 
 import com.android.server.wm.WindowManagerService.H;
 
+/**
+ * 1. Adjust the top most focus display if touch down on some display.
+ * 2. Adjust the pointer icon when cursor moves to the task bounds.
+ */
 public class TaskTapPointerEventListener implements PointerEventListener {
 
     private final Region mTouchExcludeRegion = new Region();
@@ -67,7 +71,7 @@
                     return;
                 }
                 WindowContainer parent = mDisplayContent.getParent();
-                if (parent != null) {
+                if (parent != null && parent.getTopChild() != mDisplayContent) {
                     parent.positionChildAt(WindowContainer.POSITION_TOP, mDisplayContent,
                             true /* includingParents */);
                 }
@@ -80,8 +84,7 @@
         if (motionEvent.getDisplayId() != getDisplayId()) {
             return;
         }
-        final int action = motionEvent.getAction();
-        switch (action & MotionEvent.ACTION_MASK) {
+        switch (motionEvent.getActionMasked()) {
             case MotionEvent.ACTION_DOWN: {
                 final int x = (int) motionEvent.getX();
                 final int y = (int) motionEvent.getY();
@@ -97,7 +100,7 @@
                 }
             }
             break;
-
+            case MotionEvent.ACTION_HOVER_ENTER:
             case MotionEvent.ACTION_HOVER_MOVE: {
                 final int x = (int) motionEvent.getX();
                 final int y = (int) motionEvent.getY();
@@ -125,6 +128,7 @@
                     mPointerIconType = iconType;
                     if (mPointerIconType == TYPE_NOT_SPECIFIED) {
                         // Find the underlying window and ask it restore the pointer icon.
+                        mService.mH.removeMessages(H.RESTORE_POINTER_ICON);
                         mService.mH.obtainMessage(H.RESTORE_POINTER_ICON,
                                 x, y, mDisplayContent).sendToTarget();
                     } else {
@@ -133,6 +137,18 @@
                 }
             }
             break;
+            case MotionEvent.ACTION_HOVER_EXIT: {
+                final int x = (int) motionEvent.getX();
+                final int y = (int) motionEvent.getY();
+                if (mPointerIconType != TYPE_NOT_SPECIFIED) {
+                    mPointerIconType = TYPE_NOT_SPECIFIED;
+                    // Find the underlying window and ask it to restore the pointer icon.
+                    mService.mH.removeMessages(H.RESTORE_POINTER_ICON);
+                    mService.mH.obtainMessage(H.RESTORE_POINTER_ICON,
+                            x, y, mDisplayContent).sendToTarget();
+                }
+            }
+            break;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 25e61f8..1905877 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -437,6 +437,7 @@
                 if (mChildren.peekLast() != child) {
                     mChildren.remove(child);
                     mChildren.add(child);
+                    onChildPositionChanged();
                 }
                 if (includingParents && getParent() != null) {
                     getParent().positionChildAt(POSITION_TOP, this /* child */,
@@ -447,6 +448,7 @@
                 if (mChildren.peekFirst() != child) {
                     mChildren.remove(child);
                     mChildren.addFirst(child);
+                    onChildPositionChanged();
                 }
                 if (includingParents && getParent() != null) {
                     getParent().positionChildAt(POSITION_BOTTOM, this /* child */,
@@ -460,8 +462,8 @@
                 //       doing this adjustment here and remove any adjustments in the callers.
                 mChildren.remove(child);
                 mChildren.add(position, child);
+                onChildPositionChanged();
         }
-        onChildPositionChanged();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 90506e7..fda7a85 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -723,7 +723,7 @@
 
         void updateSystemUiSettings() {
             boolean changed;
-            synchronized (mWindowMap) {
+            synchronized (mGlobalLock) {
                 changed = ImmersiveModeConfirmation.loadSetting(mCurrentUserId, mContext)
                         || PolicyControl.reloadFromSetting(mContext);
             }
@@ -2629,12 +2629,23 @@
     @Override
     public void onUserSwitched() {
         mSettingsObserver.updateSystemUiSettings();
-        synchronized (mWindowMap) {
+        synchronized (mGlobalLock) {
             // force a re-application of focused window sysui visibility on each display.
             mRoot.forAllDisplayPolicies(DisplayPolicy::resetSystemUiVisibilityLw);
         }
     }
 
+    @Override
+    public void moveDisplayToTop(int displayId) {
+        synchronized (mGlobalLock) {
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+            if (displayContent != null && mRoot.getTopChild() != displayContent) {
+                mRoot.positionChildAt(WindowContainer.POSITION_TOP, displayContent,
+                        true /* includingParents */);
+            }
+        }
+    }
+
     /**
      * Starts deferring layout passes. Useful when doing multiple changes but to optimize
      * performance, only one layout pass should be done. This can be called multiple times, and
@@ -5932,8 +5943,6 @@
                     pw.print(" apps="); pw.print(mAppsFreezingScreen);
             final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked();
             pw.print("  mRotation="); pw.print(defaultDisplayContent.getRotation());
-                    pw.print(" mAltOrientation=");
-                            pw.println(defaultDisplayContent.getAltOrientation());
             pw.print("  mLastWindowForcedOrientation=");
                     pw.print(defaultDisplayContent.getLastWindowForcedOrientation());
                     pw.print(" mLastOrientation=");
@@ -6379,7 +6388,7 @@
     }
 
     void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) {
-        synchronized (mWindowMap) {
+        synchronized (mGlobalLock) {
             mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays;
         }
     }
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index c8c5e8f..fb00aeb 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -107,6 +107,7 @@
         "android.hardware.gnss@1.0",
         "android.hardware.gnss@1.1",
         "android.hardware.gnss@2.0",
+        "android.hardware.gnss.visibility_control@1.0",
         "android.hardware.input.classifier@1.0",
         "android.hardware.ir@1.0",
         "android.hardware.light@2.0",
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 64120076..90c9cc2 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -111,6 +111,7 @@
     jmethodID getKeyboardLayoutOverlay;
     jmethodID getDeviceAlias;
     jmethodID getTouchCalibrationForInputDevice;
+    jmethodID getContextForDisplay;
 } gServiceClassInfo;
 
 static struct {
@@ -260,17 +261,16 @@
 
     /* --- PointerControllerPolicyInterface implementation --- */
 
-    virtual void loadPointerIcon(SpriteIcon* icon);
-    virtual void loadPointerResources(PointerResources* outResources);
+    virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId);
+    virtual void loadPointerResources(PointerResources* outResources, int32_t displayId);
     virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
-            std::map<int32_t, PointerAnimation>* outAnimationResources);
+            std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId);
     virtual int32_t getDefaultPointerIconId();
     virtual int32_t getCustomPointerIconId();
 
 private:
     sp<InputManager> mInputManager;
 
-    jobject mContextObj;
     jobject mServiceObj;
     sp<Looper> mLooper;
 
@@ -329,7 +329,6 @@
         mLooper(looper), mInteractive(true) {
     JNIEnv* env = jniEnv();
 
-    mContextObj = env->NewGlobalRef(contextObj);
     mServiceObj = env->NewGlobalRef(serviceObj);
 
     {
@@ -351,7 +350,6 @@
 NativeInputManager::~NativeInputManager() {
     JNIEnv* env = jniEnv();
 
-    env->DeleteGlobalRef(mContextObj);
     env->DeleteGlobalRef(mServiceObj);
 }
 
@@ -1202,19 +1200,22 @@
     return result;
 }
 
-void NativeInputManager::loadPointerIcon(SpriteIcon* icon) {
+void NativeInputManager::loadPointerIcon(SpriteIcon* icon, int32_t displayId) {
     ATRACE_CALL();
     JNIEnv* env = jniEnv();
 
     ScopedLocalRef<jobject> pointerIconObj(env, env->CallObjectMethod(
-            mServiceObj, gServiceClassInfo.getPointerIcon));
+            mServiceObj, gServiceClassInfo.getPointerIcon, displayId));
     if (checkAndClearExceptionFromCallback(env, "getPointerIcon")) {
         return;
     }
 
+    ScopedLocalRef<jobject> displayContext(env, env->CallObjectMethod(
+            mServiceObj, gServiceClassInfo.getContextForDisplay, displayId));
+
     PointerIcon pointerIcon;
     status_t status = android_view_PointerIcon_load(env, pointerIconObj.get(),
-                                                    mContextObj, &pointerIcon);
+            displayContext.get(), &pointerIcon);
     if (!status && !pointerIcon.isNullIcon()) {
         *icon = SpriteIcon(pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY);
     } else {
@@ -1222,28 +1223,34 @@
     }
 }
 
-void NativeInputManager::loadPointerResources(PointerResources* outResources) {
+void NativeInputManager::loadPointerResources(PointerResources* outResources, int32_t displayId) {
     ATRACE_CALL();
     JNIEnv* env = jniEnv();
 
-    loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_HOVER,
+    ScopedLocalRef<jobject> displayContext(env, env->CallObjectMethod(
+            mServiceObj, gServiceClassInfo.getContextForDisplay, displayId));
+
+    loadSystemIconAsSprite(env, displayContext.get(), POINTER_ICON_STYLE_SPOT_HOVER,
             &outResources->spotHover);
-    loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_TOUCH,
+    loadSystemIconAsSprite(env, displayContext.get(), POINTER_ICON_STYLE_SPOT_TOUCH,
             &outResources->spotTouch);
-    loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_ANCHOR,
+    loadSystemIconAsSprite(env, displayContext.get(), POINTER_ICON_STYLE_SPOT_ANCHOR,
             &outResources->spotAnchor);
 }
 
 void NativeInputManager::loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
-        std::map<int32_t, PointerAnimation>* outAnimationResources) {
+        std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) {
     ATRACE_CALL();
     JNIEnv* env = jniEnv();
 
+    ScopedLocalRef<jobject> displayContext(env, env->CallObjectMethod(
+            mServiceObj, gServiceClassInfo.getContextForDisplay, displayId));
+
     for (int iconId = POINTER_ICON_STYLE_CONTEXT_MENU; iconId <= POINTER_ICON_STYLE_GRABBING;
              ++iconId) {
         PointerIcon pointerIcon;
         loadSystemIconAsSpriteWithPointerIcon(
-                env, mContextObj, iconId, &pointerIcon, &((*outResources)[iconId]));
+                env, displayContext.get(), iconId, &pointerIcon, &((*outResources)[iconId]));
         if (!pointerIcon.bitmapFrames.empty()) {
             PointerAnimation& animationData = (*outAnimationResources)[iconId];
             size_t numFrames = pointerIcon.bitmapFrames.size() + 1;
@@ -1258,7 +1265,7 @@
             }
         }
     }
-    loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_NULL,
+    loadSystemIconAsSprite(env, displayContext.get(), POINTER_ICON_STYLE_NULL,
             &((*outResources)[POINTER_ICON_STYLE_NULL]));
 }
 
@@ -1819,7 +1826,7 @@
             "getPointerLayer", "()I");
 
     GET_METHOD_ID(gServiceClassInfo.getPointerIcon, clazz,
-            "getPointerIcon", "()Landroid/view/PointerIcon;");
+            "getPointerIcon", "(I)Landroid/view/PointerIcon;");
 
     GET_METHOD_ID(gServiceClassInfo.getPointerDisplayId, clazz,
             "getPointerDisplayId", "()I");
@@ -1835,6 +1842,10 @@
             "getTouchCalibrationForInputDevice",
             "(Ljava/lang/String;I)Landroid/hardware/input/TouchCalibration;");
 
+    GET_METHOD_ID(gServiceClassInfo.getContextForDisplay, clazz,
+            "getContextForDisplay",
+            "(I)Landroid/content/Context;")
+
     // InputDevice
 
     FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice");
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index b290bc5..dcb2ff5 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -26,6 +26,7 @@
 #include <android/hardware/gnss/1.1/IGnssMeasurement.h>
 #include <android/hardware/gnss/2.0/IGnssMeasurement.h>
 #include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h>
 #include <nativehelper/JNIHelp.h>
 #include "jni.h"
 #include "hardware_legacy/power.h"
@@ -88,6 +89,8 @@
 static jmethodID method_correctionPlaneLngDeg;
 static jmethodID method_correctionPlaneAltDeg;
 static jmethodID method_correctionPlaneAzimDeg;
+static jmethodID method_reportNfwNotification;
+static jmethodID method_isInEmergencySession;
 
 /*
  * Save a pointer to JavaVm to attach/detach threads executing
@@ -152,6 +155,9 @@
 using IMeasurementCorrections =
     android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
 
+using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl;
+using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback;
+
 struct GnssDeathRecipient : virtual public hidl_death_recipient
 {
     // hidl_death_recipient interface
@@ -190,7 +196,7 @@
 // This boolean is needed to ensure that Gnsss Measurement Corrections related method are only
 // initalized when needed which will be few devices initially
 bool firstGnssMeasurementCorrectionInjected = false;
-
+sp<IGnssVisibilityControl> gnssVisibilityControlIface = nullptr;
 
 #define WAKE_LOCK_NAME  "GPS"
 
@@ -856,7 +862,7 @@
 
 Return<void> GnssMeasurementCallback::gnssMeasurementCb_2_0(
         const IGnssMeasurementCallback_V2_0::GnssData& data) {
-    // TODO(b/119571122): implement gnssMeasurementCb_2_0
+    translateAndSetGnssData(data);
     return Void();
 }
 
@@ -894,9 +900,8 @@
     return data.measurementCount;
 }
 
-template<>
-size_t GnssMeasurementCallback::getMeasurementCount<IGnssMeasurementCallback_V1_1::GnssData>
-        (const IGnssMeasurementCallback_V1_1::GnssData& data) {
+template<class T>
+size_t GnssMeasurementCallback::getMeasurementCount(const T& data) {
     return data.measurements.size();
 }
 
@@ -958,6 +963,17 @@
             ADR_STATE_HALF_CYCLE_REPORTED));
 }
 
+// Preallocate object as: JavaObject object(env, "android/location/GnssMeasurement");
+template<>
+void GnssMeasurementCallback::translateSingleGnssMeasurement
+        <IGnssMeasurementCallback_V2_0::GnssMeasurement>(
+        const IGnssMeasurementCallback_V2_0::GnssMeasurement* measurement_V2_0,
+        JavaObject& object) {
+    translateSingleGnssMeasurement(&(measurement_V2_0->v1_1), object);
+
+    SET(CodeType, (static_cast<int32_t>(measurement_V2_0->codeType)));
+}
+
 jobject GnssMeasurementCallback::translateGnssClock(
        JNIEnv* env, const IGnssMeasurementCallback_V1_0::GnssClock* clock) {
     JavaObject object(env, "android/location/GnssClock");
@@ -1080,6 +1096,54 @@
 }
 
 /*
+ * GnssVisibilityControlCallback implements callback methods of IGnssVisibilityControlCallback.hal.
+ */
+struct GnssVisibilityControlCallback : public IGnssVisibilityControlCallback {
+    Return<void> nfwNotifyCb(const IGnssVisibilityControlCallback::NfwNotification& notification)
+            override;
+    Return<bool> isInEmergencySession() override;
+};
+
+Return<void> GnssVisibilityControlCallback::nfwNotifyCb(
+        const IGnssVisibilityControlCallback::NfwNotification& notification) {
+    JNIEnv* env = getJniEnv();
+    jstring proxyAppPackageName = env->NewStringUTF(notification.proxyAppPackageName.c_str());
+    jstring otherProtocolStackName = env->NewStringUTF(notification.otherProtocolStackName.c_str());
+    jstring requestorId = env->NewStringUTF(notification.requestorId.c_str());
+
+    if (proxyAppPackageName && otherProtocolStackName && requestorId) {
+        env->CallVoidMethod(mCallbacksObj, method_reportNfwNotification, proxyAppPackageName,
+                            notification.protocolStack, otherProtocolStackName,
+                            notification.requestor, requestorId,
+                            notification.inEmergencyMode, notification.isCachedLocation);
+    } else {
+        ALOGE("%s: OOM Error\n", __func__);
+    }
+
+    if (requestorId) {
+        env->DeleteLocalRef(requestorId);
+    }
+
+    if (otherProtocolStackName) {
+        env->DeleteLocalRef(otherProtocolStackName);
+    }
+
+    if (proxyAppPackageName) {
+        env->DeleteLocalRef(proxyAppPackageName);
+    }
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+Return<bool> GnssVisibilityControlCallback::isInEmergencySession() {
+    JNIEnv* env = getJniEnv();
+    auto result = env->CallBooleanMethod(mCallbacksObj, method_isInEmergencySession);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return result;
+}
+
+/*
  * AGnssCallback_V1_0 implements callback methods required by the IAGnssCallback 1.0 interface.
  */
 struct AGnssCallback_V1_0 : public IAGnssCallback_V1_0 {
@@ -1313,6 +1377,9 @@
             "reportLocationBatch",
             "([Landroid/location/Location;)V");
     method_reportGnssServiceDied = env->GetMethodID(clazz, "reportGnssServiceDied", "()V");
+    method_reportNfwNotification = env->GetMethodID(clazz, "reportNfwNotification",
+            "(Ljava/lang/String;BLjava/lang/String;BLjava/lang/String;BZZ)V");
+    method_isInEmergencySession = env->GetMethodID(clazz, "isInEmergencySession", "()Z");
 
     /*
      * Save a pointer to JVM.
@@ -1388,12 +1455,6 @@
     if (gnssHal_V2_0 != nullptr) {
         // TODO(b/119638366): getExtensionGnssMeasurement_1_1 from gnssHal_V2_0
         auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0();
-        auto gnssCorrections = gnssHal_V2_0->getExtensionMeasurementCorrections();
-        if (!gnssCorrections.isOk()) {
-            ALOGD("Unable to get a handle to GnssMeasurementCorrections interface");
-        } else {
-            gnssCorrectionsIface = gnssCorrections;
-        }
         if (!gnssMeasurement.isOk()) {
             ALOGD("Unable to get a handle to GnssMeasurement_V2_0");
         } else {
@@ -1401,6 +1462,12 @@
             gnssMeasurementIface_V1_1 = gnssMeasurementIface_V2_0;
             gnssMeasurementIface = gnssMeasurementIface_V2_0;
         }
+        auto gnssCorrections = gnssHal_V2_0->getExtensionMeasurementCorrections();
+        if (!gnssCorrections.isOk()) {
+            ALOGD("Unable to get a handle to GnssMeasurementCorrections interface");
+        } else {
+            gnssCorrectionsIface = gnssCorrections;
+        }
     } else if (gnssHal_V1_1 != nullptr) {
          auto gnssMeasurement = gnssHal_V1_1->getExtensionGnssMeasurement_1_1();
          if (!gnssMeasurement.isOk()) {
@@ -1471,6 +1538,15 @@
     } else {
         gnssBatchingIface = gnssBatching;
     }
+
+    if (gnssHal_V2_0 != nullptr) {
+        auto gnssVisibilityControl = gnssHal_V2_0->getExtensionVisibilityControl();
+        if (!gnssVisibilityControl.isOk()) {
+            ALOGD("Unable to get a handle to GnssVisibilityControl interface");
+        } else {
+            gnssVisibilityControlIface = gnssVisibilityControl;
+        }
+    }
 }
 
 static jboolean android_location_GnssLocationProvider_is_supported(
@@ -1572,7 +1648,13 @@
     if (agnssRilIface != nullptr) {
         agnssRilIface->setCallback(aGnssRilCbIface);
     } else {
-        ALOGI("Unable to Initialize AGnss Ril interface\n");
+        ALOGI("Unable to initialize AGnss Ril interface\n");
+    }
+
+    if (gnssVisibilityControlIface != nullptr) {
+        sp<IGnssVisibilityControlCallback> gnssVisibilityControlCbIface =
+                new GnssVisibilityControlCallback();
+        gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
     }
 
     return JNI_TRUE;
@@ -1974,6 +2056,11 @@
     return result;
 }
 
+static jboolean android_location_GnssLocationProvider_is_gnss_visibility_control_supported(
+        JNIEnv* /* env */, jclass /* clazz */) {
+    return (gnssVisibilityControlIface != nullptr) ?  JNI_TRUE : JNI_FALSE;
+}
+
 static void android_location_GnssNetworkConnectivityHandler_update_network_state(JNIEnv* env,
                                                                        jobject /* obj */,
                                                                        jboolean connected,
@@ -2557,6 +2644,29 @@
     return gnssBatchingIface->stop();
 }
 
+static jboolean android_location_GnssVisibilityControl_enable_nfw_location_access(
+        JNIEnv* env, jobject, jobjectArray proxyApps) {
+    if (gnssVisibilityControlIface == nullptr) {
+        ALOGI("No GNSS Visibility Control interface available");
+        return JNI_FALSE;
+    }
+
+    const jsize length = env->GetArrayLength(proxyApps);
+    hidl_vec<hidl_string> hidlProxyApps(length);
+    for (int i = 0; i < length; ++i) {
+        jstring proxyApp = (jstring) (env->GetObjectArrayElement(proxyApps, i));
+        ScopedJniString jniProxyApp(env, proxyApp);
+        hidlProxyApps[i] = jniProxyApp;
+    }
+
+    auto result = gnssVisibilityControlIface->enableNfwLocationAccess(hidlProxyApps);
+    if (result.isOk()) {
+        return result;
+    } else {
+        return JNI_FALSE;
+    }
+}
+
 static const JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     {"class_init_native", "()V", reinterpret_cast<void *>(
@@ -2607,6 +2717,8 @@
     {"native_get_internal_state",
             "()Ljava/lang/String;",
             reinterpret_cast<void *>(android_location_GnssLocationProvider_get_internal_state)},
+    {"native_is_gnss_visibility_control_supported", "()Z", reinterpret_cast<void *>(
+            android_location_GnssLocationProvider_is_gnss_visibility_control_supported)},
 };
 
 static const JNINativeMethod sMethodsBatching[] = {
@@ -2736,6 +2848,14 @@
             reinterpret_cast<void *>(android_location_GnssConfiguration_set_es_extension_sec)},
 };
 
+static const JNINativeMethod sVisibilityControlMethods[] = {
+     /* name, signature, funcPtr */
+    {"native_enable_nfw_location_access",
+            "([Ljava/lang/String;)Z",
+            reinterpret_cast<void *>(
+                    android_location_GnssVisibilityControl_enable_nfw_location_access)},
+};
+
 int register_android_server_location_GnssLocationProvider(JNIEnv* env) {
     jniRegisterNativeMethods(
             env,
@@ -2767,6 +2887,11 @@
             "com/android/server/location/GnssConfiguration",
             sConfigurationMethods,
             NELEM(sConfigurationMethods));
+    jniRegisterNativeMethods(
+            env,
+            "com/android/server/location/GnssVisibilityControl",
+            sVisibilityControlMethods,
+            NELEM(sVisibilityControlMethods));
     return jniRegisterNativeMethods(
             env,
             "com/android/server/location/GnssLocationProvider",
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
new file mode 100644
index 0000000..eaab650
--- /dev/null
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
@@ -0,0 +1,143 @@
+/*
+ * 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.net.ipmemorystore;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+/**
+ * Encapsulating class for using the SQLite database backing the memory store.
+ *
+ * This class groups together the contracts and the SQLite helper used to
+ * use the database.
+ *
+ * @hide
+ */
+public class IpMemoryStoreDatabase {
+    /**
+     * Contract class for the Network Attributes table.
+     */
+    public static class NetworkAttributesContract {
+        public static final String TABLENAME = "NetworkAttributes";
+
+        public static final String COLNAME_L2KEY = "l2Key";
+        public static final String COLTYPE_L2KEY = "TEXT NOT NULL";
+
+        public static final String COLNAME_EXPIRYDATE = "expiryDate";
+        // Milliseconds since the Epoch, in true Java style
+        public static final String COLTYPE_EXPIRYDATE = "BIGINT";
+
+        public static final String COLNAME_ASSIGNEDV4ADDRESS = "assignedV4Address";
+        public static final String COLTYPE_ASSIGNEDV4ADDRESS = "INTEGER";
+
+        // Please note that the group hint is only a *hint*, hence its name. The client can offer
+        // this information to nudge the grouping in the decision it thinks is right, but it can't
+        // decide for the memory store what is the same L3 network.
+        public static final String COLNAME_GROUPHINT = "groupHint";
+        public static final String COLTYPE_GROUPHINT = "TEXT";
+
+        public static final String COLNAME_DNSADDRESSES = "dnsAddresses";
+        // Stored in marshalled form as is
+        public static final String COLTYPE_DNSADDRESSES = "BLOB";
+
+        public static final String COLNAME_MTU = "mtu";
+        public static final String COLTYPE_MTU = "INTEGER";
+
+        public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS "
+                + TABLENAME                 + " ("
+                + COLNAME_L2KEY             + " " + COLTYPE_L2KEY + " PRIMARY KEY NOT NULL, "
+                + COLNAME_EXPIRYDATE        + " " + COLTYPE_EXPIRYDATE        + ", "
+                + COLNAME_ASSIGNEDV4ADDRESS + " " + COLTYPE_ASSIGNEDV4ADDRESS + ", "
+                + COLNAME_GROUPHINT         + " " + COLTYPE_GROUPHINT         + ", "
+                + COLNAME_DNSADDRESSES      + " " + COLTYPE_DNSADDRESSES      + ", "
+                + COLNAME_MTU               + " " + COLTYPE_MTU               + ")";
+        public static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLENAME;
+    }
+
+    /**
+     * Contract class for the Private Data table.
+     */
+    public static class PrivateDataContract {
+        public static final String TABLENAME = "PrivateData";
+
+        public static final String COLNAME_L2KEY = "l2Key";
+        public static final String COLTYPE_L2KEY = "TEXT NOT NULL";
+
+        public static final String COLNAME_CLIENT = "client";
+        public static final String COLTYPE_CLIENT = "TEXT NOT NULL";
+
+        public static final String COLNAME_DATANAME = "dataName";
+        public static final String COLTYPE_DATANAME = "TEXT NOT NULL";
+
+        public static final String COLNAME_DATA = "data";
+        public static final String COLTYPE_DATA = "BLOB NOT NULL";
+
+        public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS "
+                + TABLENAME        + " ("
+                + COLNAME_L2KEY    + " " + COLTYPE_L2KEY    + ", "
+                + COLNAME_CLIENT   + " " + COLTYPE_CLIENT   + ", "
+                + COLNAME_DATANAME + " " + COLTYPE_DATANAME + ", "
+                + COLNAME_DATA     + " " + COLTYPE_DATA     + ", "
+                + "PRIMARY KEY ("
+                + COLNAME_L2KEY    + ", "
+                + COLNAME_CLIENT   + ", "
+                + COLNAME_DATANAME + "))";
+        public static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLENAME;
+    }
+
+    // To save memory when the DB is not used, close it after 30s of inactivity. This is
+    // determined manually based on what feels right.
+    private static final long IDLE_CONNECTION_TIMEOUT_MS = 30_000;
+
+    /** The SQLite DB helper */
+    public static class DbHelper extends SQLiteOpenHelper {
+        // Update this whenever changing the schema.
+        private static final int SCHEMA_VERSION = 1;
+        private static final String DATABASE_FILENAME = "IpMemoryStore.db";
+
+        public DbHelper(@NonNull final Context context) {
+            super(context, DATABASE_FILENAME, null, SCHEMA_VERSION);
+            setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS);
+        }
+
+        /** Called when the database is created */
+        public void onCreate(@NonNull final SQLiteDatabase db) {
+            db.execSQL(NetworkAttributesContract.CREATE_TABLE);
+            db.execSQL(PrivateDataContract.CREATE_TABLE);
+        }
+
+        /** Called when the database is upgraded */
+        public void onUpgrade(@NonNull final SQLiteDatabase db, final int oldVersion,
+                final int newVersion) {
+            // No upgrade supported yet.
+            db.execSQL(NetworkAttributesContract.DROP_TABLE);
+            db.execSQL(PrivateDataContract.DROP_TABLE);
+            onCreate(db);
+        }
+
+        /** Called when the database is downgraded */
+        public void onDowngrade(@NonNull final SQLiteDatabase db, final int oldVersion,
+                final int newVersion) {
+            // Downgrades always nuke all data and recreate an empty table.
+            db.execSQL(NetworkAttributesContract.DROP_TABLE);
+            db.execSQL(PrivateDataContract.DROP_TABLE);
+            onCreate(db);
+        }
+    }
+}
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
index c9759bf..55a72190 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
 import android.net.IIpMemoryStore;
 import android.net.ipmemorystore.Blob;
 import android.net.ipmemorystore.IOnBlobRetrievedListener;
@@ -27,6 +29,10 @@
 import android.net.ipmemorystore.IOnSameNetworkResponseListener;
 import android.net.ipmemorystore.IOnStatusListener;
 import android.net.ipmemorystore.NetworkAttributesParcelable;
+import android.util.Log;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 /**
  * Implementation for the IP memory store.
@@ -37,10 +43,75 @@
  * @hide
  */
 public class IpMemoryStoreService extends IIpMemoryStore.Stub {
-    final Context mContext;
+    private static final String TAG = IpMemoryStoreService.class.getSimpleName();
+    private static final int MAX_CONCURRENT_THREADS = 4;
 
+    @NonNull
+    final Context mContext;
+    @Nullable
+    final SQLiteDatabase mDb;
+    @NonNull
+    final ExecutorService mExecutor;
+
+    /**
+     * Construct an IpMemoryStoreService object.
+     * This constructor will block on disk access to open the database.
+     * @param context the context to access storage with.
+     */
     public IpMemoryStoreService(@NonNull final Context context) {
+        // Note that constructing the service will access the disk and block
+        // for some time, but it should make no difference to the clients. Because
+        // the interface is one-way, clients fire and forget requests, and the callback
+        // will get called eventually in any case, and the framework will wait for the
+        // service to be created to deliver subsequent requests.
+        // Avoiding this would mean the mDb member can't be final, which means the service would
+        // have to test for nullity, care for failure, and allow for a wait at every single access,
+        // which would make the code a lot more complex and require all methods to possibly block.
         mContext = context;
+        SQLiteDatabase db;
+        final IpMemoryStoreDatabase.DbHelper helper = new IpMemoryStoreDatabase.DbHelper(context);
+        try {
+            db = helper.getWritableDatabase();
+            if (null == db) Log.e(TAG, "Unexpected null return of getWriteableDatabase");
+        } catch (final SQLException e) {
+            Log.e(TAG, "Can't open the Ip Memory Store database", e);
+            db = null;
+        } catch (final Exception e) {
+            Log.wtf(TAG, "Impossible exception Ip Memory Store database", e);
+            db = null;
+        }
+        mDb = db;
+        // The work-stealing thread pool executor will spawn threads as needed up to
+        // the max only when there is no free thread available. This generally behaves
+        // exactly like one would expect it intuitively :
+        // - When work arrives, it will spawn a new thread iff there are no available threads
+        // - When there is no work to do it will shutdown threads after a while (the while
+        //   being equal to 2 seconds (not configurable) when max threads are spun up and
+        //   twice as much for every one less thread)
+        // - When all threads are busy the work is enqueued and waits for any worker
+        //   to become available.
+        // Because the stealing pool is made for very heavily parallel execution of
+        // small tasks that spawn others, it creates a queue per thread that in this
+        // case is overhead. However, the three behaviors above make it a superior
+        // choice to cached or fixedThreadPoolExecutor, neither of which can actually
+        // enqueue a task waiting for a thread to be free. This can probably be solved
+        // with judicious subclassing of ThreadPoolExecutor, but that's a lot of dangerous
+        // complexity for little benefit in this case.
+        mExecutor = Executors.newWorkStealingPool(MAX_CONCURRENT_THREADS);
+    }
+
+    /**
+     * Shutdown the memory store service, cancelling running tasks and dropping queued tasks.
+     *
+     * This is provided to give a way to clean up, and is meant to be available in case of an
+     * emergency shutdown.
+     */
+    public void shutdown() {
+        // By contrast with ExecutorService#shutdown, ExecutorService#shutdownNow tries
+        // to cancel the existing tasks, and does not wait for completion. It does not
+        // guarantee the threads can be terminated in any given amount of time.
+        mExecutor.shutdownNow();
+        if (mDb != null) mDb.close();
     }
 
     /**
@@ -61,7 +132,7 @@
     public void storeNetworkAttributes(@NonNull final String l2Key,
             @NonNull final NetworkAttributesParcelable attributes,
             @Nullable final IOnStatusListener listener) {
-        // TODO : implement this
+        // TODO : implement this.
     }
 
     /**
@@ -79,7 +150,7 @@
     public void storeBlob(@NonNull final String l2Key, @NonNull final String clientId,
             @NonNull final String name, @NonNull final Blob data,
             @Nullable final IOnStatusListener listener) {
-        // TODO : implement this
+        // TODO : implement this.
     }
 
     /**
@@ -99,7 +170,7 @@
     @Override
     public void findL2Key(@NonNull final NetworkAttributesParcelable attributes,
             @NonNull final IOnL2KeyResponseListener listener) {
-        // TODO : implement this
+        // TODO : implement this.
     }
 
     /**
@@ -114,7 +185,7 @@
     @Override
     public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2,
             @NonNull final IOnSameNetworkResponseListener listener) {
-        // TODO : implement this
+        // TODO : implement this.
     }
 
     /**
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
new file mode 100644
index 0000000..aa45400
--- /dev/null
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
@@ -0,0 +1,307 @@
+/*
+ * 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.net.ipmemorystore;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A class containing the logic around the relevance value for
+ * IP Memory Store.
+ *
+ * @hide
+ */
+public class RelevanceUtils {
+    /**
+     * The relevance is a decaying value that gets lower and lower until it
+     * reaches 0 after some time passes. It follows an exponential decay law,
+     * dropping slowly at first then faster and faster, because a network is
+     * likely to be visited again if it was visited not long ago, and the longer
+     * it hasn't been visited the more likely it is that it won't be visited
+     * again. For example, a network visited on holiday should stay fresh for
+     * the duration of the holiday and persist for a while, but after the venue
+     * hasn't been visited for a while it should quickly be discarded. What
+     * should accelerate forgetting the network is extended periods without
+     * visits, so that occasional venues get discarded but regular visits keep
+     * the network relevant, even if the visits are infrequent.
+     *
+     * This function must be stable by iteration, meaning that adjusting the same value
+     * for different dates iteratively multiple times should give the same result.
+     * Formally, if f is the decay function that associates a relevance x at a date d1
+     * to the value at ulterior date d3, then for any date d2 between d1 and d3 :
+     * f(x, d3 - d1) = f(f(x, d3 - d2), d2 - d1). Intuitively, this property simply
+     * means it should be the same to compute and store back the value after two months,
+     * or to do it once after one month, store it back, and do it again after another
+     * months has passed.
+     * The pair of the relevance and date define the entire curve, so any pair
+     * of values on the curve will define the same curve. Setting one of them to a
+     * constant, so as not to have to store it, means the other one will always suffice
+     * to describe the curve. For example, only storing the date for a known, constant
+     * value of the relevance is an efficient way of remembering this information (and
+     * to compare relevances together, as f is monotonically decreasing).
+     *
+     *** Choosing the function :
+     * Functions of the kind described above are standard exponential decay functions
+     * like the ones that govern atomic decay where the value at any given date can be
+     * computed uniformly from the value at a previous date and the time elapsed since
+     * that date. It is simple to picture this kind of function as one where after a
+     * given period of time called the half-life, the relevance value will have been
+     * halved. Decay of this kind is expressed in function of the previous value by
+     * functions like
+     * f(x, t) = x * F ^ (t / L)
+     * ...where x is the value, t is the elapsed time, L is the half-life (or more
+     * generally the F-th-life) and F the decay factor (typically 0.5, hence why L is
+     * usually called the half-life). The ^ symbol here is used for exponentiation.
+     * Or, starting at a given M for t = 0 :
+     * f(t) = M * F ^ (t / L)
+     *
+     * Because a line in the store needs to become irrelevant at some point but
+     * this class of functions never go to 0, a minimum cutoff has to be chosen to
+     * represent irrelevance. The simpler way of doing this is to simply add this
+     * minimum cutoff to the computation before and removing it after.
+     * Thus the function becomes :
+     * f(x, t) = ((x + K) * F ^ (t / L)) - K
+     * ...where K is the minimum cutoff, L the half-life, and F the factor between
+     * the original x and x after its half-life. Strictly speaking using the word
+     * "half-life" implies that F = 0.5, but the relation works for any value of F.
+     *
+     * It is easy enough to check that this function satisfies the stability
+     * relation that was given above for any value of F, L and K, which become
+     * parameters that can be defined at will.
+     *
+     * relevance
+     *  1.0 |
+     *      |\
+     *      | \
+     *      |  \            (this graph rendered with L = 75 days and K = 1/40)
+     *  0.75|   ',
+     *      |     \
+     *      |      '.
+     *      |        \.
+     *      |          \
+     *  0.5 |           '\
+     *      |             ''.
+     *      |                ''.
+     *      |                   ''.
+     *  0.25|                      '''..
+     *      |                           '''..
+     *      |                                ''''....
+     *      |                                        '''''..........
+     *    0 +-------------------------------------------------------''''''''''----
+     *      0       50       100      150     200      250     300      350     400 days
+     *
+     *** Choosing the parameters
+     * The maximum M is an arbitrary parameter that simply scales the curve.
+     * The tradeoff for M is pretty simple : if the relevance is going to be an
+     * integer, the bigger M is the more precision there is in the relevance.
+     * However, values of M that are easy for humans to read are preferable to
+     * help debugging, and a suitably low value may be enough to ensure there
+     * won't be integer overflows in intermediate computations.
+     * A value of 1_000_000 probably is plenty for precision, while still in the
+     * low range of what ints can represent.
+     *
+     * F and L are parameters to be chosen arbitrarily and have an impact on how
+     * fast the relevance will be decaying at first, keeping in mind that
+     * the 400 days value and the cap stay the same. In simpler words, F and L
+     * define the steepness of the curve.
+     * To keep things simple (and familiar) F is arbitrarily chosen to be 0.5, and
+     * L is set to 200 days visually to achieve the desired effect. Refer to the
+     * illustration above to get a feel of how that feels.
+     *
+     * Moreover, the memory store works on an assumption that the relevance should
+     * be capped, and that an entry with capped relevance should decay in 400 days.
+     * This is on premises that the networks a device will need to remember the
+     * longest should be networks visited about once a year.
+     * For this reason, the relevance is at the maximum M 400 days before expiry :
+     * f(M, 400 days) = 0
+     * From replacing this with the value of the function, K can then be derived
+     * from the values of M, F and L :
+     * (M + K) * F ^ (t / L) - K = 0
+     * K = M * F ^ (400 days / L) / (1 - F ^ (400 days / L))
+     * Replacing with actual values this gives :
+     * K = 1_000_000 * 0.5 ^ (400 / 200) / (1 - 0.5 ^ (400 / 200))
+     *   = 1_000_000 / 3 ≈ 333_333.3
+     * This ensures the function has the desired profile, the desired value at
+     * cap, and the desired value at expiry.
+     *
+     *** Useful relations
+     * Let's define the expiry time for any given relevance x as the interval of
+     * time such as :
+     * f(x, expiry) = 0
+     * which can be rewritten
+     * ((x + K) * F ^ (expiry / L)) = K
+     * ...giving an expression of the expiry in function of the relevance x as
+     * expiry = L * logF(K / (x + K))
+     * Conversely the relevance x can be expressed in function of the expiry as
+     * x = K / F ^ (expiry / L) - K
+     * These relations are useful in utility functions.
+     *
+     *** Bumping things up
+     * The last issue therefore is to decide how to bump up the relevance. The
+     * simple approach is to simply lift up the curve a little bit by a constant
+     * normalized amount, delaying the time of expiry. For example increasing
+     * the relevance by an amount I gives :
+     * x2 = x1 + I
+     * x2 and x1 correspond to two different expiry times expiry2 and expiry1,
+     * and replacing x1 and x2 in the relation above with their expression in
+     * function of the expiry comes :
+     * K / F ^ (expiry2 / L) - K = K / F ^ (expiry1 / L) - K + I
+     * which resolves to :
+     * expiry2 = L * logF(K / (I + K / F ^ (expiry1 / L)))
+     *
+     * In this implementation, the bump is defined as 1/25th of the cap for
+     * the relevance. This means a network will be remembered for the maximum
+     * period of 400 days if connected 25 times in succession not accounting
+     * for decay. Of course decay actually happens so it will take more than 25
+     * connections for any given network to actually reach the cap, but because
+     * decay is slow at first, it is a good estimate of how fast cap happens.
+     *
+     * Specifically, it gives the following four results :
+     * - A network that a device connects to once hits irrelevance about 32.7 days after
+     *   it was first registered if never connected again.
+     * - A network that a device connects to once a day at a fixed hour will hit the cap
+     *   on the 27th connection.
+     * - A network that a device connects to once a week at a fixed hour will hit the cap
+     *   on the 57th connection.
+     * - A network that a device connects to every day for 7 straight days then never again
+     *   expires 144 days after the last connection.
+     * These metrics tend to match pretty well the requirements.
+     */
+
+    // TODO : make these constants configurable at runtime. Don't forget to build it so that
+    // changes will wipe the database, migrate the values, or otherwise make sure the relevance
+    // values are still meaningful.
+
+    // How long, in milliseconds, is a capped relevance valid for, or in other
+    // words how many milliseconds after its relevance was set to RELEVANCE_CAP does
+    // any given line expire. 400 days.
+    @VisibleForTesting
+    public static final long CAPPED_RELEVANCE_LIFETIME_MS = 400L * 24 * 60 * 60 * 1000;
+
+    // The constant that represents a normalized 1.0 value for the relevance. In other words,
+    // the cap for the relevance. This is referred to as M in the explanation above.
+    @VisibleForTesting
+    public static final int CAPPED_RELEVANCE = 1_000_000;
+
+    // The decay factor. After a half-life, the relevance will have decayed by this value.
+    // This is referred to as F in the explanation above.
+    private static final double DECAY_FACTOR = 0.5;
+
+    // The half-life. After this time, the relevance will have decayed by a factor DECAY_FACTOR.
+    // This is referred to as L in the explanation above.
+    private static final long HALF_LIFE_MS = 200L * 24 * 60 * 60 * 1000;
+
+    // The value of the frame change. This is referred to as K in the explanation above.
+    private static final double IRRELEVANCE_FLOOR =
+            CAPPED_RELEVANCE * powF((double) CAPPED_RELEVANCE_LIFETIME_MS / HALF_LIFE_MS)
+            / (1 - powF((double) CAPPED_RELEVANCE_LIFETIME_MS / HALF_LIFE_MS));
+
+    // How much to bump the relevance by every time a line is written to.
+    @VisibleForTesting
+    public static final int RELEVANCE_BUMP = CAPPED_RELEVANCE / 25;
+
+    // Java doesn't include a function for the logarithm in an arbitrary base, so implement it
+    private static final double LOG_DECAY_FACTOR = Math.log(DECAY_FACTOR);
+    private static double logF(final double value) {
+        return Math.log(value) / LOG_DECAY_FACTOR;
+    }
+
+    // Utility function to get a power of the decay factor, to simplify the code.
+    private static double powF(final double value) {
+        return Math.pow(DECAY_FACTOR, value);
+    }
+
+    /**
+     * Compute the value of the relevance now given an expiry date.
+     *
+     * @param expiry the date at which the column in the database expires.
+     * @return the adjusted value of the relevance for this moment in time.
+     */
+    public static int computeRelevanceForNow(final long expiry) {
+        return computeRelevanceForTargetDate(expiry, System.currentTimeMillis());
+    }
+
+    /**
+     * Compute the value of the relevance at a given date from an expiry date.
+     *
+     * Because relevance decays with time, a relevance in the past corresponds to
+     * a different relevance later.
+     *
+     * Relevance is always a positive value. 0 means not relevant at all.
+     *
+     * See the explanation at the top of this file to get the justification for this
+     * computation.
+     *
+     * @param expiry the date at which the column in the database expires.
+     * @param target the target date to adjust the relevance to.
+     * @return the adjusted value of the relevance for the target moment.
+     */
+    public static int computeRelevanceForTargetDate(final long expiry, final long target) {
+        final long delay = expiry - target;
+        if (delay >= CAPPED_RELEVANCE_LIFETIME_MS) return CAPPED_RELEVANCE;
+        if (delay <= 0) return 0;
+        return (int) (IRRELEVANCE_FLOOR / powF((float) delay / HALF_LIFE_MS) - IRRELEVANCE_FLOOR);
+    }
+
+    /**
+     * Compute the expiry duration adjusted up for a new fresh write.
+     *
+     * Every time data is written to the memory store for a given line, the
+     * relevance is bumped up by a certain amount, which will boost the priority
+     * of this line for computation of group attributes, and delay (possibly
+     * indefinitely, if the line is accessed regularly) forgetting the data stored
+     * in that line.
+     * As opposed to bumpExpiryDate, this function uses a duration from now to expiry.
+     *
+     * See the explanation at the top of this file for a justification of this computation.
+     *
+     * @param oldExpiryDuration the old expiry duration in milliseconds from now.
+     * @return the expiry duration representing a bumped up relevance value.
+     */
+    public static long bumpExpiryDuration(final long oldExpiryDuration) {
+        // L * logF(K / (I + K / F ^ (expiry1 / L))), as documented above
+        final double divisionFactor = powF(((double) oldExpiryDuration) / HALF_LIFE_MS);
+        final double oldRelevance = IRRELEVANCE_FLOOR / divisionFactor;
+        final long newDuration =
+                (long) (HALF_LIFE_MS * logF(IRRELEVANCE_FLOOR / (RELEVANCE_BUMP + oldRelevance)));
+        return Math.min(newDuration, CAPPED_RELEVANCE_LIFETIME_MS);
+    }
+
+    /**
+     * Compute the new expiry date adjusted up for a new fresh write.
+     *
+     * Every time data is written to the memory store for a given line, the
+     * relevance is bumped up by a certain amount, which will boost the priority
+     * of this line for computation of group attributes, and delay (possibly
+     * indefinitely, if the line is accessed regularly) forgetting the data stored
+     * in that line.
+     * As opposed to bumpExpiryDuration, this function takes the old timestamp and returns the
+     * new timestamp.
+     *
+     * {@see bumpExpiryDuration}, and keep in mind that the bump depends on when this is called,
+     * because the relevance decays exponentially, therefore bumping up a high relevance (for a
+     * date far in the future) is less potent than bumping up a low relevance (for a date in
+     * a close future).
+     *
+     * @param oldExpiryDate the old date of expiration.
+     * @return the new expiration date after the relevance bump.
+     */
+    public static long bumpExpiryDate(final long oldExpiryDate) {
+        final long now = System.currentTimeMillis();
+        final long newDuration = bumpExpiryDuration(oldExpiryDate - now);
+        return now + newDuration;
+    }
+}
diff --git a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
new file mode 100644
index 0000000..5b77f54
--- /dev/null
+++ b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
@@ -0,0 +1,222 @@
+/*
+ * 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.ParcelableUtil.fromParcelableArray;
+import static android.net.shared.ParcelableUtil.toParcelableArray;
+
+import android.annotation.Nullable;
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddress;
+import android.net.LinkAddressParcelable;
+import android.net.LinkProperties;
+import android.net.LinkPropertiesParcelable;
+import android.net.ProxyInfo;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfo;
+import android.net.RouteInfoParcelable;
+import android.net.Uri;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+
+/**
+ * Collection of utility methods to convert to and from stable AIDL parcelables for LinkProperties
+ * and its attributes.
+ * @hide
+ */
+public final class LinkPropertiesParcelableUtil {
+
+    /**
+     * Convert a ProxyInfo to a ProxyInfoParcelable
+     */
+    public static ProxyInfoParcelable toStableParcelable(@Nullable ProxyInfo proxyInfo) {
+        if (proxyInfo == null) {
+            return null;
+        }
+        final ProxyInfoParcelable parcel = new ProxyInfoParcelable();
+        parcel.host = proxyInfo.getHost();
+        parcel.port = proxyInfo.getPort();
+        parcel.exclusionList = proxyInfo.getExclusionList();
+        parcel.pacFileUrl = proxyInfo.getPacFileUrl().toString();
+        return parcel;
+    }
+
+    /**
+     * Convert a ProxyInfoParcelable to a ProxyInfo
+     */
+    public static ProxyInfo fromStableParcelable(@Nullable ProxyInfoParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        if (Uri.EMPTY.toString().equals(parcel.pacFileUrl)) {
+            return ProxyInfo.buildDirectProxy(
+                    parcel.host, parcel.port, Arrays.asList(parcel.exclusionList));
+        } else {
+            return ProxyInfo.buildPacProxy(Uri.parse(parcel.pacFileUrl));
+        }
+    }
+
+    /**
+     * Convert an IpPrefixParcelable to an IpPrefix
+     */
+    public static IpPrefixParcelable toStableParcelable(@Nullable IpPrefix ipPrefix) {
+        if (ipPrefix == null) {
+            return null;
+        }
+        final IpPrefixParcelable parcel = new IpPrefixParcelable();
+        parcel.address = ipPrefix.getAddress().getHostAddress();
+        parcel.prefixLength = ipPrefix.getPrefixLength();
+        return parcel;
+    }
+
+    /**
+     * Convert an IpPrefix to an IpPrefixParcelable
+     */
+    public static IpPrefix fromStableParcelable(@Nullable IpPrefixParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        return new IpPrefix(InetAddresses.parseNumericAddress(parcel.address), parcel.prefixLength);
+    }
+
+    /**
+     * Convert a RouteInfoParcelable to a RouteInfo
+     */
+    public static RouteInfoParcelable toStableParcelable(@Nullable RouteInfo routeInfo) {
+        if (routeInfo == null) {
+            return null;
+        }
+        final RouteInfoParcelable parcel = new RouteInfoParcelable();
+        parcel.destination = toStableParcelable(routeInfo.getDestination());
+        parcel.gatewayAddr = routeInfo.getGateway().getHostAddress();
+        parcel.ifaceName = routeInfo.getInterface();
+        parcel.type = routeInfo.getType();
+        return parcel;
+    }
+
+    /**
+     * Convert a RouteInfo to a RouteInfoParcelable
+     */
+    public static RouteInfo fromStableParcelable(@Nullable RouteInfoParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        final IpPrefix destination = fromStableParcelable(parcel.destination);
+        return new RouteInfo(
+                destination, InetAddresses.parseNumericAddress(parcel.gatewayAddr),
+                parcel.ifaceName, parcel.type);
+    }
+
+    /**
+     * Convert a LinkAddressParcelable to a LinkAddress
+     */
+    public static LinkAddressParcelable toStableParcelable(@Nullable LinkAddress la) {
+        if (la == null) {
+            return null;
+        }
+        final LinkAddressParcelable parcel = new LinkAddressParcelable();
+        parcel.address = la.getAddress().getHostAddress();
+        parcel.prefixLength = la.getPrefixLength();
+        parcel.flags = la.getFlags();
+        parcel.scope = la.getScope();
+        return parcel;
+    }
+
+    /**
+     * Convert a LinkAddress to a LinkAddressParcelable
+     */
+    public static LinkAddress fromStableParcelable(@Nullable LinkAddressParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        return new LinkAddress(
+                InetAddresses.parseNumericAddress(parcel.address),
+                parcel.prefixLength,
+                parcel.flags,
+                parcel.scope);
+    }
+
+    /**
+     * Convert a LinkProperties to a LinkPropertiesParcelable
+     */
+    public static LinkPropertiesParcelable toStableParcelable(@Nullable LinkProperties lp) {
+        if (lp == null) {
+            return null;
+        }
+        final LinkPropertiesParcelable parcel = new LinkPropertiesParcelable();
+        parcel.ifaceName = lp.getInterfaceName();
+        parcel.linkAddresses = toParcelableArray(
+                lp.getLinkAddresses(),
+                LinkPropertiesParcelableUtil::toStableParcelable,
+                LinkAddressParcelable.class);
+        parcel.dnses = toParcelableArray(
+                lp.getDnsServers(), InetAddress::getHostAddress, String.class);
+        parcel.pcscfs = toParcelableArray(
+                lp.getPcscfServers(), InetAddress::getHostAddress, String.class);
+        parcel.validatedPrivateDnses = toParcelableArray(
+                lp.getValidatedPrivateDnsServers(), InetAddress::getHostAddress, String.class);
+        parcel.usePrivateDns = lp.isPrivateDnsActive();
+        parcel.privateDnsServerName = lp.getPrivateDnsServerName();
+        parcel.domains = lp.getDomains();
+        parcel.routes = toParcelableArray(
+                lp.getRoutes(), LinkPropertiesParcelableUtil::toStableParcelable,
+                RouteInfoParcelable.class);
+        parcel.httpProxy = toStableParcelable(lp.getHttpProxy());
+        parcel.mtu = lp.getMtu();
+        parcel.tcpBufferSizes = lp.getTcpBufferSizes();
+        parcel.nat64Prefix = toStableParcelable(lp.getNat64Prefix());
+        parcel.stackedLinks = toParcelableArray(
+                lp.getStackedLinks(), LinkPropertiesParcelableUtil::toStableParcelable,
+                LinkPropertiesParcelable.class);
+        return parcel;
+    }
+
+    /**
+     * Convert a LinkPropertiesParcelable to a LinkProperties
+     */
+    public static LinkProperties fromStableParcelable(@Nullable LinkPropertiesParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        final LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(parcel.ifaceName);
+        lp.setLinkAddresses(fromParcelableArray(parcel.linkAddresses,
+                LinkPropertiesParcelableUtil::fromStableParcelable));
+        lp.setDnsServers(fromParcelableArray(parcel.dnses, InetAddresses::parseNumericAddress));
+        lp.setPcscfServers(fromParcelableArray(parcel.pcscfs, InetAddresses::parseNumericAddress));
+        lp.setValidatedPrivateDnsServers(
+                fromParcelableArray(parcel.validatedPrivateDnses,
+                InetAddresses::parseNumericAddress));
+        lp.setUsePrivateDns(parcel.usePrivateDns);
+        lp.setPrivateDnsServerName(parcel.privateDnsServerName);
+        lp.setDomains(parcel.domains);
+        for (RouteInfoParcelable route : parcel.routes) {
+            lp.addRoute(fromStableParcelable(route));
+        }
+        lp.setHttpProxy(fromStableParcelable(parcel.httpProxy));
+        lp.setMtu(parcel.mtu);
+        lp.setTcpBufferSizes(parcel.tcpBufferSizes);
+        lp.setNat64Prefix(fromStableParcelable(parcel.nat64Prefix));
+        for (LinkPropertiesParcelable stackedLink : parcel.stackedLinks) {
+            lp.addStackedLink(fromStableParcelable(stackedLink));
+        }
+        return lp;
+    }
+}
diff --git a/services/net/java/android/net/shared/ParcelableUtil.java b/services/net/java/android/net/shared/ParcelableUtil.java
new file mode 100644
index 0000000..a18976c
--- /dev/null
+++ b/services/net/java/android/net/shared/ParcelableUtil.java
@@ -0,0 +1,63 @@
+/*
+ * 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 android.annotation.NonNull;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+/**
+ * Utility methods to help convert to/from stable parcelables.
+ * @hide
+ */
+public final class ParcelableUtil {
+    // Below methods could be implemented easily with streams, but streams are frowned upon in
+    // frameworks code.
+
+    /**
+     * Convert a list of BaseType items to an array of ParcelableType items using the specified
+     * converter function.
+     */
+    public static <ParcelableType, BaseType> ParcelableType[] toParcelableArray(
+            @NonNull List<BaseType> base,
+            @NonNull Function<BaseType, ParcelableType> conv,
+            @NonNull Class<ParcelableType> parcelClass) {
+        final ParcelableType[] out = (ParcelableType[]) Array.newInstance(parcelClass, base.size());
+        int i = 0;
+        for (BaseType b : base) {
+            out[i] = conv.apply(b);
+            i++;
+        }
+        return out;
+    }
+
+    /**
+     * Convert an array of ParcelableType items to a list of BaseType items using the specified
+     * converter function.
+     */
+    public static <ParcelableType, BaseType> ArrayList<BaseType> fromParcelableArray(
+            @NonNull ParcelableType[] parceled, @NonNull Function<ParcelableType, BaseType> conv) {
+        final ArrayList<BaseType> out = new ArrayList<>(parceled.length);
+        for (ParcelableType t : parceled) {
+            out.add(conv.apply(t));
+        }
+        return out;
+    }
+}
diff --git a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
index 7559560..9a6e003 100644
--- a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
@@ -58,7 +58,9 @@
 import com.android.server.backup.transport.TransportClient;
 import com.android.server.backup.transport.TransportClientManager;
 import com.android.server.backup.transport.TransportNotRegisteredException;
+import com.android.server.testing.shadows.ShadowApplicationPackageManager;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -66,6 +68,7 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowPackageManager;
 
 import java.util.ArrayList;
@@ -75,6 +78,7 @@
 import java.util.stream.Stream;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowApplicationPackageManager.class})
 @Presubmit
 public class TransportManagerTest {
     private static final String PACKAGE_A = "some.package.a";
@@ -102,6 +106,12 @@
         mTransportB1 = genericTransport(PACKAGE_B, "TransportBaz");
     }
 
+    /** Reset shadow state. */
+    @After
+    public void tearDown() throws Exception {
+        ShadowApplicationPackageManager.reset();
+    }
+
     @Test
     public void testRegisterTransports() throws Exception {
         setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
@@ -666,7 +676,8 @@
         packageInfo.packageName = packageName;
         packageInfo.applicationInfo = new ApplicationInfo();
         packageInfo.applicationInfo.privateFlags = flags;
-        mShadowPackageManager.addPackage(packageInfo);
+        mShadowPackageManager.installPackage(packageInfo);
+        ShadowApplicationPackageManager.addInstalledPackage(packageName, packageInfo);
     }
 
     private TransportManager createTransportManagerWithRegisteredTransports(
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 3b7fa3d..427aed7 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -514,10 +514,14 @@
     private void setUpForUpdateTransportAttributes() throws Exception {
         mTransportComponent = mTransport.getTransportComponent();
         String transportPackage = mTransportComponent.getPackageName();
+        PackageInfo packageInfo = getPackageInfo(transportPackage);
 
         ShadowPackageManager shadowPackageManager = shadowOf(mContext.getPackageManager());
-        shadowPackageManager.addPackage(transportPackage);
+        shadowPackageManager.installPackage(packageInfo);
         shadowPackageManager.setPackagesForUid(PACKAGE_UID, transportPackage);
+        // Set up for user invocations on ApplicationPackageManager.
+        ShadowApplicationPackageManager.addInstalledPackage(transportPackage, packageInfo);
+        ShadowApplicationPackageManager.setPackageUid(transportPackage, PACKAGE_UID);
 
         mTransportUid = mContext.getPackageManager().getPackageUid(transportPackage, 0);
     }
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
index dc32209..ab121ed 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
@@ -38,6 +38,7 @@
         extends org.robolectric.shadows.ShadowApplicationPackageManager {
     private static final Map<String, PackageInfo> sPackageInfos = new ArrayMap<>();
     private static final List<PackageInfo> sInstalledPackages = new ArrayList<>();
+    private static final Map<String, Integer> sPackageUids = new ArrayMap<>();
 
     /**
      * Registers the package {@code packageName} to be returned when invoking {@link
@@ -49,6 +50,14 @@
         sInstalledPackages.add(packageInfo);
     }
 
+    /**
+     * Sets the package uid {@code packageUid} for the package {@code packageName} to be returned
+     * when invoking {@link ApplicationPackageManager#getPackageUidAsUser(String, int, int)}.
+     */
+    public static void setPackageUid(String packageName, int packageUid) {
+        sPackageUids.put(packageName, packageUid);
+    }
+
     @Override
     protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
             throws NameNotFoundException {
@@ -63,6 +72,15 @@
         return sInstalledPackages;
     }
 
+    @Override
+    protected int getPackageUidAsUser(String packageName, int flags, int userId)
+            throws NameNotFoundException {
+        if (!sPackageUids.containsKey(packageName)) {
+            throw new NameNotFoundException(packageName);
+        }
+        return sPackageUids.get(packageName);
+    }
+
     /** Clear package state. */
     @Resetter
     public static void reset() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
index c8e6782..4a48468 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
@@ -85,6 +85,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -793,6 +794,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 114098433)
     public void testAllListeners() throws Exception {
         final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index f1cd0cd..57ee6dc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -33,6 +33,7 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -43,7 +44,12 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
+import android.app.AppGlobals;
+import android.app.IActivityManager;
+import android.app.IUidObserver;
 import android.app.job.JobInfo;
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
@@ -56,13 +62,16 @@
 import android.os.BatteryManagerInternal;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.os.SystemClock;
+import android.util.SparseBooleanArray;
 
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.JobSchedulerService.Constants;
+import com.android.server.job.JobStore;
 import com.android.server.job.controllers.QuotaController.ExecutionStats;
 import com.android.server.job.controllers.QuotaController.TimingSession;
 
@@ -96,9 +105,13 @@
     private BroadcastReceiver mChargingReceiver;
     private Constants mConstants;
     private QuotaController mQuotaController;
+    private int mSourceUid;
+    private IUidObserver mUidObserver;
 
     private MockitoSession mMockingSession;
     @Mock
+    private ActivityManagerInternal mActivityMangerInternal;
+    @Mock
     private AlarmManager mAlarmManager;
     @Mock
     private Context mContext;
@@ -107,6 +120,8 @@
     @Mock
     private UsageStatsManagerInternal mUsageStatsManager;
 
+    private JobStore mJobStore;
+
     @Before
     public void setUp() {
         mMockingSession = mockitoSession()
@@ -123,8 +138,17 @@
         when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService);
         when(mJobSchedulerService.getConstants()).thenReturn(mConstants);
         // Called in QuotaController constructor.
+        IActivityManager activityManager = ActivityManager.getService();
+        spyOn(activityManager);
+        try {
+            doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any());
+        } catch (RemoteException e) {
+            fail("registerUidObserver threw exception: " + e.getMessage());
+        }
         when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
         when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
+        doReturn(mActivityMangerInternal)
+                .when(() -> LocalServices.getService(ActivityManagerInternal.class));
         doReturn(mock(BatteryManagerInternal.class))
                 .when(() -> LocalServices.getService(BatteryManagerInternal.class));
         doReturn(mUsageStatsManager)
@@ -132,6 +156,9 @@
         // Used in JobStatus.
         doReturn(mock(PackageManagerInternal.class))
                 .when(() -> LocalServices.getService(PackageManagerInternal.class));
+        // Used in QuotaController.Handler.
+        mJobStore = JobStore.initAndGetForTesting(mContext, mContext.getFilesDir());
+        when(mJobSchedulerService.getJobStore()).thenReturn(mJobStore);
 
         // Freeze the clocks at 24 hours after this moment in time. Several tests create sessions
         // in the past, and QuotaController sometimes floors values at 0, so if the test time
@@ -150,10 +177,23 @@
         // Capture the listeners.
         ArgumentCaptor<BroadcastReceiver> receiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
+        ArgumentCaptor<IUidObserver> uidObserverCaptor =
+                ArgumentCaptor.forClass(IUidObserver.class);
         mQuotaController = new QuotaController(mJobSchedulerService);
 
         verify(mContext).registerReceiver(receiverCaptor.capture(), any());
         mChargingReceiver = receiverCaptor.getValue();
+        try {
+            verify(activityManager).registerUidObserver(
+                    uidObserverCaptor.capture(),
+                    eq(ActivityManager.UID_OBSERVER_PROCSTATE),
+                    eq(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE),
+                    any());
+            mUidObserver = uidObserverCaptor.getValue();
+            mSourceUid = AppGlobals.getPackageManager().getPackageUid(SOURCE_PACKAGE, 0, 0);
+        } catch (RemoteException e) {
+            fail(e.getMessage());
+        }
     }
 
     @After
@@ -182,6 +222,25 @@
         mChargingReceiver.onReceive(mContext, intent);
     }
 
+    private void setProcessState(int procState) {
+        try {
+            doReturn(procState).when(mActivityMangerInternal).getUidProcessState(mSourceUid);
+            SparseBooleanArray foregroundUids = mQuotaController.getForegroundUids();
+            spyOn(foregroundUids);
+            mUidObserver.onUidStateChanged(mSourceUid, procState, 0);
+            if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+                verify(foregroundUids, timeout(SECOND_IN_MILLIS).times(1))
+                        .put(eq(mSourceUid), eq(true));
+                assertTrue(foregroundUids.get(mSourceUid));
+            } else {
+                verify(foregroundUids, timeout(SECOND_IN_MILLIS).times(1)).delete(eq(mSourceUid));
+                assertFalse(foregroundUids.get(mSourceUid));
+            }
+        } catch (RemoteException e) {
+            fail("registerUidObserver threw exception: " + e.getMessage());
+        }
+    }
+
     private void setStandbyBucket(int bucketIndex) {
         int bucket;
         switch (bucketIndex) {
@@ -204,9 +263,18 @@
                 anyLong())).thenReturn(bucket);
     }
 
-    private void setStandbyBucket(int bucketIndex, JobStatus job) {
+    private void setStandbyBucket(int bucketIndex, JobStatus... jobs) {
         setStandbyBucket(bucketIndex);
-        job.setStandbyBucket(bucketIndex);
+        for (JobStatus job : jobs) {
+            job.setStandbyBucket(bucketIndex);
+        }
+    }
+
+    private void trackJobs(JobStatus... jobs) {
+        for (JobStatus job : jobs) {
+            mJobStore.add(job);
+            mQuotaController.maybeStartTrackingJobLocked(job, null);
+        }
     }
 
     private JobStatus createJobStatus(String testTag, int jobId) {
@@ -214,8 +282,11 @@
                 new ComponentName(mContext, "TestQuotaJobService"))
                 .setMinimumLatency(Math.abs(jobId) + 1)
                 .build();
-        return JobStatus.createFromJobInfo(
+        JobStatus js = JobStatus.createFromJobInfo(
                 jobInfo, CALLING_UID, SOURCE_PACKAGE, SOURCE_USER_ID, testTag);
+        // Make sure tests aren't passing just because the default bucket is likely ACTIVE.
+        js.setStandbyBucket(FREQUENT_INDEX);
+        return js;
     }
 
     private TimingSession createTimingSession(long start, long duration, int count) {
@@ -709,6 +780,7 @@
         verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
 
         JobStatus jobStatus = createJobStatus("testMaybeScheduleStartAlarmLocked_Active", 1);
+        setStandbyBucket(standbyBucket, jobStatus);
         mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
         mQuotaController.prepareForExecutionLocked(jobStatus);
         advanceElapsedClock(5 * MINUTE_IN_MILLIS);
@@ -1339,19 +1411,23 @@
         setDischarging();
 
         JobStatus jobStatus = createJobStatus("testTimerTracking_AllForeground", 1);
-        jobStatus.uidActive = true;
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
         mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
 
         assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
 
         mQuotaController.prepareForExecutionLocked(jobStatus);
         advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        // Change to a state that should still be considered foreground.
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
         mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
         assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
     }
 
     /**
-     * Tests that Timers properly track overlapping foreground and background jobs.
+     * Tests that Timers properly track sessions when switching between foreground and background
+     * states.
      */
     @Test
     public void testTimerTracking_ForegroundAndBackground() {
@@ -1360,7 +1436,6 @@
         JobStatus jobBg1 = createJobStatus("testTimerTracking_ForegroundAndBackground", 1);
         JobStatus jobBg2 = createJobStatus("testTimerTracking_ForegroundAndBackground", 2);
         JobStatus jobFg3 = createJobStatus("testTimerTracking_ForegroundAndBackground", 3);
-        jobFg3.uidActive = true;
         mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
         mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
         mQuotaController.maybeStartTrackingJobLocked(jobFg3, null);
@@ -1368,6 +1443,7 @@
         List<TimingSession> expected = new ArrayList<>();
 
         // UID starts out inactive.
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
         long start = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.prepareForExecutionLocked(jobBg1);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
@@ -1379,48 +1455,223 @@
 
         // Bg job starts while inactive, spans an entire active session, and ends after the
         // active session.
-        // Fg job starts after the bg job and ends before the bg job.
-        // Entire bg job duration should be counted since it started before active session. However,
-        // count should only be 1 since Timer shouldn't count fg jobs.
+        // App switching to foreground state then fg job starts.
+        // App remains in foreground state after coming to foreground, so there should only be one
+        // session.
         start = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
         mQuotaController.prepareForExecutionLocked(jobBg2);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
         mQuotaController.prepareForExecutionLocked(jobFg3);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
         mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
         mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
-        expected.add(createTimingSession(start, 30 * SECOND_IN_MILLIS, 1));
         assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
 
         advanceElapsedClock(SECOND_IN_MILLIS);
 
         // Bg job 1 starts, then fg job starts. Bg job 1 job ends. Shortly after, uid goes
         // "inactive" and then bg job 2 starts. Then fg job ends.
-        // This should result in two TimingSessions with a count of one each.
+        // This should result in two TimingSessions:
+        //  * The first should have a count of 1
+        //  * The second should have a count of 2 since it will include both jobs
         start = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
         mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
         mQuotaController.maybeStartTrackingJobLocked(jobFg3, null);
+        setProcessState(ActivityManager.PROCESS_STATE_LAST_ACTIVITY);
         mQuotaController.prepareForExecutionLocked(jobBg1);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
         mQuotaController.prepareForExecutionLocked(jobFg3);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
         mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
-        expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 1));
         advanceElapsedClock(10 * SECOND_IN_MILLIS); // UID "inactive" now
         start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
         mQuotaController.prepareForExecutionLocked(jobBg2);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
         mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
         mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
-        expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 1));
+        expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2));
         assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
     }
 
     /**
+     * Tests that Timers properly track overlapping top and background jobs.
+     */
+    @Test
+    public void testTimerTracking_TopAndNonTop() {
+        setDischarging();
+
+        JobStatus jobBg1 = createJobStatus("testTimerTracking_TopAndNonTop", 1);
+        JobStatus jobBg2 = createJobStatus("testTimerTracking_TopAndNonTop", 2);
+        JobStatus jobFg1 = createJobStatus("testTimerTracking_TopAndNonTop", 3);
+        JobStatus jobTop = createJobStatus("testTimerTracking_TopAndNonTop", 4);
+        mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
+        mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+        mQuotaController.maybeStartTrackingJobLocked(jobFg1, null);
+        mQuotaController.maybeStartTrackingJobLocked(jobTop, null);
+        assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        List<TimingSession> expected = new ArrayList<>();
+
+        // UID starts out inactive.
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mQuotaController.prepareForExecutionLocked(jobBg1);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        // Bg job starts while inactive, spans an entire active session, and ends after the
+        // active session.
+        // App switching to top state then fg job starts.
+        // App remains in top state after coming to top, so there should only be one
+        // session.
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+        mQuotaController.prepareForExecutionLocked(jobBg2);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        mQuotaController.prepareForExecutionLocked(jobTop);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+        assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        // Bg job 1 starts, then top job starts. Bg job 1 job ends. Then app goes to
+        // foreground_service and a new job starts. Shortly after, uid goes
+        // "inactive" and then bg job 2 starts. Then top job ends, followed by bg and fg jobs.
+        // This should result in two TimingSessions:
+        //  * The first should have a count of 1
+        //  * The second should have a count of 2, which accounts for the bg2 and fg, but not top
+        //    jobs.
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
+        mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+        mQuotaController.maybeStartTrackingJobLocked(jobTop, null);
+        setProcessState(ActivityManager.PROCESS_STATE_LAST_ACTIVITY);
+        mQuotaController.prepareForExecutionLocked(jobBg1);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        mQuotaController.prepareForExecutionLocked(jobTop);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        mQuotaController.prepareForExecutionLocked(jobFg1);
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS); // UID "inactive" now
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+        mQuotaController.prepareForExecutionLocked(jobBg2);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+        mQuotaController.maybeStopTrackingJobLocked(jobFg1, null, false);
+        expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2));
+        assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
+     * Tests that TOP jobs aren't stopped when an app runs out of quota.
+     */
+    @Test
+    public void testTracking_OutOfQuota_ForegroundAndBackground() {
+        setDischarging();
+
+        JobStatus jobBg = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 1);
+        JobStatus jobTop = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 2);
+        trackJobs(jobBg, jobTop);
+        setStandbyBucket(WORKING_INDEX, jobTop, jobBg); // 2 hour window
+        // Now the package only has 20 seconds to run.
+        final long remainingTimeMs = 20 * SECOND_IN_MILLIS;
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS,
+                        10 * MINUTE_IN_MILLIS - remainingTimeMs, 1));
+
+        InOrder inOrder = inOrder(mJobSchedulerService);
+
+        // UID starts out inactive.
+        setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+        // Start the job.
+        mQuotaController.prepareForExecutionLocked(jobBg);
+        advanceElapsedClock(remainingTimeMs / 2);
+        // New job starts after UID is in the foreground. Since the app is now in the foreground, it
+        // should continue to have remainingTimeMs / 2 time remaining.
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        mQuotaController.prepareForExecutionLocked(jobTop);
+        advanceElapsedClock(remainingTimeMs);
+
+        // Wait for some extra time to allow for job processing.
+        inOrder.verify(mJobSchedulerService,
+                timeout(remainingTimeMs + 2 * SECOND_IN_MILLIS).times(0))
+                .onControllerStateChanged();
+        assertEquals(remainingTimeMs / 2, mQuotaController.getRemainingExecutionTimeLocked(jobBg));
+        assertEquals(remainingTimeMs / 2, mQuotaController.getRemainingExecutionTimeLocked(jobTop));
+        // Go to a background state.
+        setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+        advanceElapsedClock(remainingTimeMs / 2 + 1);
+        inOrder.verify(mJobSchedulerService,
+                timeout(remainingTimeMs / 2 + 2 * SECOND_IN_MILLIS).times(1))
+                .onControllerStateChanged();
+        // Top job should still be allowed to run.
+        assertFalse(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+        // New jobs to run.
+        JobStatus jobBg2 = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 3);
+        JobStatus jobTop2 = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 4);
+        JobStatus jobFg = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 5);
+        setStandbyBucket(WORKING_INDEX, jobBg2, jobTop2, jobFg);
+
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1))
+                .onControllerStateChanged();
+        trackJobs(jobFg, jobTop);
+        mQuotaController.prepareForExecutionLocked(jobTop);
+        assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+        // App still in foreground so everything should be in quota.
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+        inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1))
+                .onControllerStateChanged();
+        // App is now in background and out of quota. Fg should now change to out of quota since it
+        // wasn't started. Top should remain in quota since it started when the app was in TOP.
+        assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertFalse(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertFalse(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        trackJobs(jobBg2);
+        assertFalse(jobBg2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+    }
+
+    /**
      * Tests that a job is properly updated and JobSchedulerService is notified when a job reaches
      * its quota.
      */
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
index 8b0e8ab..eb9b98e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -30,6 +30,7 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -147,6 +148,7 @@
         mTestLooper.dispatchAll();
     }
 
+    @Ignore("b/120845532")
     @Test
     public void arcInitiation_requestActiveSource() {
         mSendCecCommandSuccess = true;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
index 93a09dc..5d8131f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
@@ -40,7 +40,6 @@
 import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -142,7 +141,6 @@
         assertEquals(ADDR_UNREGISTERED, mLogicalAddress);
     }
 
-    @Ignore("b/110413065 Support multiple device types 4 and 5.")
     @Test
     public void testAllocatLogicalAddress_PlaybackPreferredNotOccupied() {
         mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_PLAYBACK_1, mCallback);
@@ -158,7 +156,6 @@
         assertEquals(ADDR_PLAYBACK_2, mLogicalAddress);
     }
 
-    @Ignore("b/110413065 Support multiple device types 4 and 5.")
     @Test
     public void testAllocatLogicalAddress_PlaybackNoPreferredNotOcuppied() {
         mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index 3b51a2a..3a6cdc2 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -21,6 +21,7 @@
 import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
 import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
 import static com.android.server.hdmi.Constants.ADDR_TUNER_1;
 import static com.android.server.hdmi.Constants.ADDR_TV;
 import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
@@ -29,9 +30,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.HdmiPortInfo;
 import android.media.AudioManager;
 import android.os.Looper;
-import android.os.SystemProperties;
 import android.os.test.TestLooper;
 
 import androidx.test.InstrumentationRegistry;
@@ -46,7 +47,6 @@
 import org.junit.runners.JUnit4;
 
 import java.util.ArrayList;
-
 @SmallTest
 @RunWith(JUnit4.class)
 /** Tests for {@link HdmiCecLocalDeviceAudioSystem} class. */
@@ -67,9 +67,15 @@
     private int mMusicVolume;
     private int mMusicMaxVolume;
     private boolean mMusicMute;
-    private int mAvrPhysicalAddress;
+    private static final int SELF_PHYSICAL_ADDRESS = 0x2000;
+    private static final int HDMI_1_PHYSICAL_ADDRESS = 0x2100;
+    private static final int HDMI_2_PHYSICAL_ADDRESS = 0x2200;
+    private static final int HDMI_3_PHYSICAL_ADDRESS = 0x2300;
     private int mInvokeDeviceEventState;
     private HdmiDeviceInfo mDeviceInfo;
+    private boolean mMutingEnabled;
+    private boolean mArcSupport;
+    private HdmiPortInfo[] mHdmiPortInfo;
 
     @Before
     public void setUp() {
@@ -141,9 +147,20 @@
                 }
 
                 @Override
-                int pathToPortId(int path) {
-                    // port id is not useful for the test right now
-                    return 1;
+                void writeStringSetting(String key, String value) {
+                    // do nothing
+                }
+
+                @Override
+                boolean readBooleanSetting(String key, boolean defVal) {
+                    switch (key) {
+                        case Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE:
+                            return mMutingEnabled;
+                        case Constants.PROPERTY_ARC_SUPPORT:
+                            return mArcSupport;
+                        default:
+                            return defVal;
+                    }
                 }
             };
 
@@ -154,11 +171,17 @@
             void setIsActiveSource(boolean on) {
                 mIsActiveSource = on;
             }
+
+            @Override
+            protected int getPreferredAddress() {
+                return ADDR_PLAYBACK_1;
+            }
         };
         mHdmiCecLocalDeviceAudioSystem.init();
         mHdmiCecLocalDevicePlayback.init();
         mHdmiControlService.setIoLooper(mMyLooper);
         mNativeWrapper = new FakeNativeWrapper();
+        mNativeWrapper.setPhysicalAddress(SELF_PHYSICAL_ADDRESS);
         mHdmiCecController =
             HdmiCecController.createWithNativeWrapper(mHdmiControlService, mNativeWrapper);
         mHdmiControlService.setCecController(mHdmiCecController);
@@ -166,15 +189,28 @@
         mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
         mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
         mLocalDevices.add(mHdmiCecLocalDevicePlayback);
+        mHdmiCecLocalDeviceAudioSystem.setRoutingControlFeatureEnables(true);
+        mHdmiPortInfo = new HdmiPortInfo[4];
+        mHdmiPortInfo[0] =
+            new HdmiPortInfo(
+                0, HdmiPortInfo.PORT_INPUT, SELF_PHYSICAL_ADDRESS, true, false, false);
+        mHdmiPortInfo[1] =
+            new HdmiPortInfo(
+                2, HdmiPortInfo.PORT_INPUT, HDMI_1_PHYSICAL_ADDRESS, true, false, false);
+        mHdmiPortInfo[2] =
+            new HdmiPortInfo(
+                1, HdmiPortInfo.PORT_INPUT, HDMI_2_PHYSICAL_ADDRESS, true, false, false);
+        mHdmiPortInfo[3] =
+            new HdmiPortInfo(
+                4, HdmiPortInfo.PORT_INPUT, HDMI_3_PHYSICAL_ADDRESS, true, false, false);
+        mNativeWrapper.setPortInfo(mHdmiPortInfo);
         mHdmiControlService.initPortInfo();
         // No TV device interacts with AVR so system audio control won't be turned on here
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mTestLooper.dispatchAll();
         mNativeWrapper.clearResultMessages();
-        mAvrPhysicalAddress  = 0x2000;
-        mNativeWrapper.setPhysicalAddress(mAvrPhysicalAddress);
-        SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "true");
-        SystemProperties.set(Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, "true");
+        mMutingEnabled = true;
+        mArcSupport = true;
         mInvokeDeviceEventState = 0;
         mDeviceInfo = null;
     }
@@ -244,6 +280,8 @@
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
     }
 
+    // Testing device has sadConfig.xml
+    @Ignore("b/120845532")
     @Test
     public void handleRequestShortAudioDescriptor_noAudioDeviceInfo() throws Exception {
         HdmiCecMessage expectedMessage =
@@ -414,51 +452,6 @@
     }
 
     @Test
-    public void pathToPort_isMe() throws Exception {
-        int targetPhysicalAddress = 0x1000;
-        mNativeWrapper.setPhysicalAddress(0x1000);
-        assertThat(mHdmiCecLocalDeviceAudioSystem
-                .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
-                .isEqualTo(0);
-    }
-
-    @Test
-    public void pathToPort_isBelow() throws Exception {
-        int targetPhysicalAddress = 0x1100;
-        mNativeWrapper.setPhysicalAddress(0x1000);
-        assertThat(mHdmiCecLocalDeviceAudioSystem
-                .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
-                .isEqualTo(1);
-    }
-
-    @Test
-    public void pathToPort_neitherMeNorBelow() throws Exception {
-        int targetPhysicalAddress = 0x3000;
-        mNativeWrapper.setPhysicalAddress(0x2000);
-        assertThat(mHdmiCecLocalDeviceAudioSystem
-                .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
-                .isEqualTo(-1);
-
-        targetPhysicalAddress = 0x2200;
-        mNativeWrapper.setPhysicalAddress(0x3300);
-        assertThat(mHdmiCecLocalDeviceAudioSystem
-                .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
-                .isEqualTo(-1);
-
-        targetPhysicalAddress = 0x2213;
-        mNativeWrapper.setPhysicalAddress(0x2212);
-        assertThat(mHdmiCecLocalDeviceAudioSystem
-                .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
-                .isEqualTo(-1);
-
-        targetPhysicalAddress = 0x2340;
-        mNativeWrapper.setPhysicalAddress(0x2310);
-        assertThat(mHdmiCecLocalDeviceAudioSystem
-                .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
-                .isEqualTo(-1);
-    }
-
-    @Test
     public void handleRequestArcInitiate_isNotDirectConnectedToTv() throws Exception {
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
@@ -530,7 +523,7 @@
                         ADDR_TV,
                         Constants.MESSAGE_REQUEST_ARC_INITIATION,
                         Constants.ABORT_UNRECOGNIZED_OPCODE);
-        SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "false");
+        mArcSupport = false;
 
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)).isTrue();
         mTestLooper.dispatchAll();
@@ -541,7 +534,7 @@
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildSystemAudioModeRequest(
                         ADDR_TUNER_1, ADDR_AUDIO_SYSTEM,
-                        mAvrPhysicalAddress, true);
+                        SELF_PHYSICAL_ADDRESS, true);
         HdmiCecMessage expectedMessage =
                 HdmiCecMessageBuilder.buildFeatureAbortCommand(
                         ADDR_AUDIO_SYSTEM,
@@ -559,7 +552,7 @@
         HdmiCecMessage message =
                 HdmiCecMessageBuilder.buildSystemAudioModeRequest(
                         ADDR_TUNER_1, ADDR_AUDIO_SYSTEM,
-                        mAvrPhysicalAddress, true);
+                        SELF_PHYSICAL_ADDRESS, true);
         HdmiCecMessage expectedMessage =
                 HdmiCecMessageBuilder.buildSetSystemAudioMode(
                         ADDR_AUDIO_SYSTEM, Constants.ADDR_BROADCAST, true);
@@ -585,15 +578,14 @@
             .isEqualTo(expectedActiveSource);
     }
 
-    @Ignore("b/110413065 Support multiple device types 4 and 5.")
     @Test
     public void handleRoutingChange_currentActivePortIsHome() {
         HdmiCecMessage message =
-                HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x3000, mAvrPhysicalAddress);
+                HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x3000, SELF_PHYSICAL_ADDRESS);
 
         HdmiCecMessage expectedMessage =
-                HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, mAvrPhysicalAddress);
-        ActiveSource expectedActiveSource = ActiveSource.of(ADDR_PLAYBACK_1, mAvrPhysicalAddress);
+                HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, SELF_PHYSICAL_ADDRESS);
+        ActiveSource expectedActiveSource = ActiveSource.of(ADDR_PLAYBACK_1, SELF_PHYSICAL_ADDRESS);
         int expectedLocalActivePort = Constants.CEC_SWITCH_HOME;
 
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingChange(message)).isTrue();
@@ -608,17 +600,18 @@
     @Test
     public void handleRoutingInformation_currentActivePortIsHDMI1() {
         HdmiCecMessage message =
-                HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x2000);
-        mHdmiCecLocalDeviceAudioSystem.setRoutingPort(Constants.CEC_SWITCH_HDMI1);
+                HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, SELF_PHYSICAL_ADDRESS);
+        mHdmiCecLocalDeviceAudioSystem.setRoutingPort(mHdmiPortInfo[1].getId());
         HdmiCecMessage expectedMessage =
-                HdmiCecMessageBuilder.buildRoutingInformation(ADDR_AUDIO_SYSTEM, 0x2100);
+                HdmiCecMessageBuilder.buildRoutingInformation(
+                        ADDR_AUDIO_SYSTEM, HDMI_1_PHYSICAL_ADDRESS);
 
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingInformation(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
     }
 
-    @Ignore("b/110413065 Support multiple device types 4 and 5.")
+    @Ignore("b/120845532")
     @Test
     public void handleRoutingChange_homeIsActive_playbackSendActiveSource() {
         HdmiCecMessage message =
@@ -667,7 +660,7 @@
         mHdmiCecLocalDeviceAudioSystem.addDeviceInfo(oldDevice);
 
         HdmiDeviceInfo differentDevice = new HdmiDeviceInfo(
-                ADDR_PLAYBACK_1, 0x2100, 4, HdmiDeviceInfo.DEVICE_PLAYBACK,
+                ADDR_PLAYBACK_1, 0x2300, 4, HdmiDeviceInfo.DEVICE_PLAYBACK,
                 Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_1));
 
         mHdmiCecLocalDeviceAudioSystem.updateCecDevice(differentDevice);
@@ -686,14 +679,13 @@
         mHdmiCecLocalDeviceAudioSystem.addDeviceInfo(oldDevice);
 
         HdmiDeviceInfo differentDevice = new HdmiDeviceInfo(
-                ADDR_PLAYBACK_1, 0x2200, 1, HdmiDeviceInfo.DEVICE_PLAYBACK,
-                Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_1));
+                ADDR_PLAYBACK_2, 0x2200, 1, HdmiDeviceInfo.DEVICE_PLAYBACK,
+                Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_2));
         HdmiCecMessage reportPhysicalAddress = HdmiCecMessageBuilder
                 .buildReportPhysicalAddressCommand(
-                        ADDR_PLAYBACK_1, 0x2200, HdmiDeviceInfo.DEVICE_PLAYBACK);
+                        ADDR_PLAYBACK_2, 0x2200, HdmiDeviceInfo.DEVICE_PLAYBACK);
         mHdmiCecLocalDeviceAudioSystem.handleReportPhysicalAddress(reportPhysicalAddress);
 
-        mHdmiCecLocalDeviceAudioSystem.addDeviceInfo(oldDevice);
         mTestLooper.dispatchAll();
         assertThat(mDeviceInfo).isEqualTo(differentDevice);
         assertThat(mHdmiCecLocalDeviceAudioSystem
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 792c617..feae4ee 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -81,7 +81,8 @@
         mNativeWrapper.setPhysicalAddress(mPlaybackPhysicalAddress);
     }
 
-    @Ignore
+    // Playback device does not handle routing control related feature right now
+    @Ignore("b/120845532")
     @Test
     public void handleSetStreamPath_underCurrentDevice() {
         assertThat(mHdmiCecLocalDevicePlayback.getLocalActivePath()).isEqualTo(0);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 67ce13f..1f66074 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -179,6 +179,7 @@
     @Test
     public void pathToPort_pathExists_weAreNonTv() {
         mNativeWrapper.setPhysicalAddress(0x2000);
+        mHdmiControlService.initPortInfo();
         assertThat(mHdmiControlService.pathToPortId(0x2120)).isEqualTo(1);
         assertThat(mHdmiControlService.pathToPortId(0x2234)).isEqualTo(2);
     }
@@ -186,6 +187,7 @@
     @Test
     public void pathToPort_pathExists_weAreTv() {
         mNativeWrapper.setPhysicalAddress(0x0000);
+        mHdmiControlService.initPortInfo();
         assertThat(mHdmiControlService.pathToPortId(0x2120)).isEqualTo(3);
         assertThat(mHdmiControlService.pathToPortId(0x3234)).isEqualTo(4);
     }
@@ -193,6 +195,7 @@
     @Test
     public void pathToPort_pathInvalid() {
         mNativeWrapper.setPhysicalAddress(0x2000);
+        mHdmiControlService.initPortInfo();
         assertThat(mHdmiControlService.pathToPortId(0x1000)).isEqualTo(Constants.INVALID_PORT_ID);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
new file mode 100644
index 0000000..985c647
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.hdmi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.util.Slog;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.hdmi.HdmiUtils.CodecSad;
+import com.android.server.hdmi.HdmiUtils.DeviceConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/** Tests for {@link HdmiUtils} class. */
+public class HdmiUtilsTest {
+
+    private static final String TAG = "HdmiUtilsTest";
+
+    private final String mExampleXML =
+            "<!-- A sample Short Audio Descriptor configuration xml -->"
+                    + "<config version=\"1.0\" xmlns:xi=\"http://www.w3.org/2001/XInclude\">"
+                    + "<device type=\"VX_AUDIO_DEVICE_IN_HDMI_ARC\">"
+                    + "<supportedFormat format=\"AUDIO_FORMAT_LPCM\" descriptor=\"011a03\"/>"
+                    + "<supportedFormat format=\"AUDIO_FORMAT_DD\" descriptor=\"0d0506\"/>"
+                    + "</device>"
+                    + "<device type=\"AUDIO_DEVICE_IN_SPDIF\">"
+                    + "<supportedFormat format=\"AUDIO_FORMAT_LPCM\" descriptor=\"010203\"/>"
+                    + "<supportedFormat format=\"AUDIO_FORMAT_DD\" descriptor=\"040506\"/>"
+                    + "</device>"
+                    + "</config>";
+
+    @Test
+    public void pathToPort_isMe() {
+        int targetPhysicalAddress = 0x1000;
+        int myPhysicalAddress = 0x1000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                        HdmiUtils.TARGET_SAME_PHYSICAL_ADDRESS);
+    }
+
+    @Test
+    public void pathToPort_isDirectlyBelow() {
+        int targetPhysicalAddress = 0x1100;
+        int myPhysicalAddress = 0x1000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+    }
+
+    @Test
+    public void pathToPort_isBelow() {
+        int targetPhysicalAddress = 0x1110;
+        int myPhysicalAddress = 0x1000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+    }
+
+    @Test
+    public void pathToPort_neitherMeNorBelow() {
+        int targetPhysicalAddress = 0x3000;
+        int myPhysicalAddress = 0x2000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                        HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+        targetPhysicalAddress = 0x2200;
+        myPhysicalAddress = 0x3300;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                        HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+        targetPhysicalAddress = 0x2213;
+        myPhysicalAddress = 0x2212;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                        HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+        targetPhysicalAddress = 0x2340;
+        myPhysicalAddress = 0x2310;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                        HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+    }
+
+    @Test
+    public void parseSampleXML() {
+        List<DeviceConfig> config = new ArrayList<>();
+        try {
+            config = HdmiUtils.ShortAudioDescriptorXmlParser.parse(
+                    new ByteArrayInputStream(mExampleXML.getBytes(StandardCharsets.UTF_8)));
+        } catch (IOException e) {
+            Slog.e(TAG, e.getMessage(), e);
+        } catch (XmlPullParserException e) {
+            Slog.e(TAG, e.getMessage(), e);
+        }
+
+        CodecSad expectedCodec1 = new CodecSad(Constants.AUDIO_CODEC_LPCM, "011a03");
+        CodecSad expectedCodec2 = new CodecSad(Constants.AUDIO_CODEC_DD, "0d0506");
+        CodecSad expectedCodec3 = new CodecSad(Constants.AUDIO_CODEC_LPCM, "010203");
+        CodecSad expectedCodec4 = new CodecSad(Constants.AUDIO_CODEC_DD, "040506");
+
+        List<CodecSad> expectedList1 = new ArrayList<>();
+        expectedList1.add(expectedCodec1);
+        expectedList1.add(expectedCodec2);
+
+        List<CodecSad> expectedList2 = new ArrayList<>();
+        expectedList2.add(expectedCodec3);
+        expectedList2.add(expectedCodec4);
+
+        DeviceConfig expectedDevice1 = new DeviceConfig(
+                "VX_AUDIO_DEVICE_IN_HDMI_ARC", expectedList1);
+        DeviceConfig expectedDevice2 = new DeviceConfig(
+                "AUDIO_DEVICE_IN_SPDIF", expectedList2);
+
+        List<DeviceConfig> expectedConfig = new ArrayList<>();
+        expectedConfig.add(expectedDevice1);
+        expectedConfig.add(expectedDevice2);
+
+        assertThat(config).isEqualTo(expectedConfig);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index bd297ee..440a49a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -31,6 +31,7 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -150,6 +151,11 @@
                             int sourceAddress, int physicalAddress) {
                         mBroadcastActiveSource = true;
                     }
+
+                    @Override
+                    int pathToPortId(int path) {
+                        return -1;
+                    }
                 };
         mHdmiCecLocalDeviceAudioSystem =
                 new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
@@ -270,6 +276,7 @@
         assertTrue(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated());
     }
 
+    @Ignore("b/120845532")
     @Test
     public void testIsPlaybackDevice_cannotReceiveActiveSource() {
         resetTestVariables();
@@ -282,10 +289,10 @@
         mTestLooper.dispatchAll();
 
         assertThat(mMsgRequestActiveSourceCount).isEqualTo(1);
-        assertThat(mMsgSetSystemAudioModeCount).isEqualTo(1);
-        assertThat(mQueryTvSystemAudioModeSupportCount).isEqualTo(1);
-        assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isTrue();
         assertThat(mBroadcastActiveSource).isTrue();
+        assertThat(mQueryTvSystemAudioModeSupportCount).isEqualTo(1);
+        assertThat(mMsgSetSystemAudioModeCount).isEqualTo(1);
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isTrue();
     }
 
     private void resetTestVariables() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 1f5c64e..bc1f798 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -42,6 +42,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.IUidObserver;
+import android.app.Person;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -1588,6 +1589,14 @@
     }
 
     /**
+     * Make a Person.
+     */
+    protected Person makePerson(CharSequence name, String key, String uri) {
+        final Person.Builder builder = new Person.Builder();
+        return builder.setName(name).setKey(key).setUri(uri).build();
+    }
+
+    /**
      * Make an component name, with the client context.
      */
     @NonNull
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 9b59f91..8d0365b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -248,6 +248,8 @@
                 .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
                 .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
                 .setRank(123)
+                .setPerson(makePerson("person", "personKey", "personUri"))
+                .setLongLived()
                 .setExtras(pb)
                 .build();
         si.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -267,9 +269,12 @@
         assertEquals("action", si.getIntent().getAction());
         assertEquals("val", si.getIntent().getStringExtra("key"));
         assertEquals(123, si.getRank());
+        assertEquals("person", si.getPersons()[0].getName());
+        assertEquals("personKey", si.getPersons()[0].getKey());
+        assertEquals("personUri", si.getPersons()[0].getUri());
         assertEquals(1, si.getExtras().getInt("k"));
 
-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
         assertEquals("abc", si.getBitmapPath());
         assertEquals(456, si.getIconResourceId());
 
@@ -345,6 +350,8 @@
                 .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
                 .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
                 .setRank(123)
+                .setPerson(makePerson("person", "personKey", "personUri"))
+                .setLongLived()
                 .setExtras(pb)
                 .build();
         sorig.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -368,9 +375,12 @@
         assertEquals("action", si.getIntent().getAction());
         assertEquals("val", si.getIntent().getStringExtra("key"));
         assertEquals(123, si.getRank());
+        assertEquals("person", si.getPersons()[0].getName());
+        assertEquals("personKey", si.getPersons()[0].getKey());
+        assertEquals("personUri", si.getPersons()[0].getUri());
         assertEquals(1, si.getExtras().getInt("k"));
 
-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
         assertEquals("abc", si.getBitmapPath());
         assertEquals(456, si.getIconResourceId());
         assertEquals("string/r456", si.getIconResName());
@@ -388,9 +398,12 @@
         assertEquals("action", si.getIntent().getAction());
         assertEquals("val", si.getIntent().getStringExtra("key"));
         assertEquals(123, si.getRank());
+        assertEquals("person", si.getPersons()[0].getName());
+        assertEquals("personKey", si.getPersons()[0].getKey());
+        assertEquals("personUri", si.getPersons()[0].getUri());
         assertEquals(1, si.getExtras().getInt("k"));
 
-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
         assertEquals(null, si.getBitmapPath());
 
         assertEquals(456, si.getIconResourceId());
@@ -408,9 +421,12 @@
         assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
         assertEquals(null, si.getIntent());
         assertEquals(123, si.getRank());
+        assertEquals("person", si.getPersons()[0].getName());
+        assertEquals("personKey", si.getPersons()[0].getKey());
+        assertEquals("personUri", si.getPersons()[0].getUri());
         assertEquals(1, si.getExtras().getInt("k"));
 
-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
         assertEquals(null, si.getBitmapPath());
 
         assertEquals(456, si.getIconResourceId());
@@ -428,9 +444,11 @@
         assertEquals(null, si.getCategories());
         assertEquals(null, si.getIntent());
         assertEquals(0, si.getRank());
+        assertEquals(null, si.getPersons());
         assertEquals(null, si.getExtras());
 
-        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY
+                | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
         assertEquals(null, si.getBitmapPath());
 
         assertEquals(456, si.getIconResourceId());
@@ -692,6 +710,12 @@
 
         si = sorig.clone(/* flags=*/ 0);
         si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setPerson(makePerson("person", "", "")).build());
+        assertEquals("text", si.getText());
+        assertEquals("person", si.getPersons()[0].getName());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
                 .setIntent(makeIntent("action2", ShortcutActivity.class)).build());
         assertEquals("text", si.getText());
         assertEquals("action2", si.getIntent().getAction());
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 823b7a5..3ebc6ad 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -544,6 +544,18 @@
         switchUser(-1, UserHandle.of(startUser), false);
     }
 
+    public void testSwitchUserByHandle_ThrowsException() {
+        synchronized (mUserSwitchLock) {
+            try {
+                ActivityManager am = getContext().getSystemService(ActivityManager.class);
+                am.switchUser(null);
+                fail("Expected IllegalArgumentException on passing in a null UserHandle.");
+            } catch (IllegalArgumentException expected) {
+                // Do nothing - exception is expected.
+            }
+        }
+    }
+
     @MediumTest
     public void testConcurrentUserCreate() throws Exception {
         int userCount = mUserManager.getUserCount();
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java
index 3b6b48b..f817e8e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java
@@ -77,7 +77,6 @@
 
     @Mock IPackageManager mPM;
     @Mock Installer mInstaller;
-    private final Object mInstallLock = new Object();
 
     private PackageDynamicCodeLoading mPackageDynamicCodeLoading;
     private DexLogger mDexLogger;
@@ -103,7 +102,7 @@
         };
 
         // For test purposes capture log messages as well as sending to the event log.
-        mDexLogger = new DexLogger(mPM, mInstaller, mInstallLock, mPackageDynamicCodeLoading) {
+        mDexLogger = new DexLogger(mPM, mInstaller, mPackageDynamicCodeLoading) {
             @Override
                 void writeDclEvent(int uid, String message) {
                     super.writeDclEvent(uid, message);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 41d5691..8171469 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -61,6 +61,7 @@
 import android.view.Display;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -416,6 +417,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 119774928)
     public void testEnabledState() throws Exception {
         TestParoleListener paroleListener = new TestParoleListener();
         mController.addListener(paroleListener);
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 83c1c76..94b21af 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3511,9 +3511,9 @@
     }
 
     @Test
-    public void testAppOverlay() throws Exception {
-        mBinderService.setAppOverlaysAllowed(PKG, mUid, false);
-        assertFalse(mBinderService.areAppOverlaysAllowedForPackage(PKG, mUid));
+    public void testBubble() throws Exception {
+        mBinderService.setBubblesAllowed(PKG, mUid, false);
+        assertFalse(mBinderService.areBubblesAllowedForPackage(PKG, mUid));
     }
 
     @Test
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 0fcfea7..24a1f8c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -809,7 +809,7 @@
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
         channel.setShowBadge(true);
-        channel.setAllowAppOverlay(false);
+        channel.setAllowBubbles(false);
         int lockMask = 0;
         for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
             lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
@@ -826,7 +826,7 @@
         assertFalse(savedChannel.canBypassDnd());
         assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
         assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
-        assertEquals(channel.canOverlayApps(), savedChannel.canOverlayApps());
+        assertEquals(channel.canBubble(), savedChannel.canBubble());
 
         verify(mHandler, never()).requestSort();
     }
@@ -840,7 +840,7 @@
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
         channel.setShowBadge(true);
-        channel.setAllowAppOverlay(false);
+        channel.setAllowBubbles(false);
         int lockMask = 0;
         for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
             lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
@@ -857,7 +857,7 @@
         assertFalse(savedChannel.canBypassDnd());
         assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
         assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
-        assertEquals(channel.canOverlayApps(), savedChannel.canOverlayApps());
+        assertEquals(channel.canBubble(), savedChannel.canBubble());
     }
 
     @Test
@@ -969,16 +969,16 @@
     }
 
     @Test
-    public void testLockFields_appOverlay() {
+    public void testLockFields_allowBubble() {
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
         assertEquals(0,
                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false)
                         .getUserLockedFields());
 
         final NotificationChannel update = getChannel();
-        update.setAllowAppOverlay(false);
+        update.setAllowBubbles(false);
         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true);
-        assertEquals(NotificationChannel.USER_LOCKED_ALLOW_APP_OVERLAY,
+        assertEquals(NotificationChannel.USER_LOCKED_ALLOW_BUBBLE,
                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update.getId(), false)
                         .getUserLockedFields());
     }
@@ -2161,30 +2161,30 @@
     }
 
     @Test
-    public void testAllowAppOverlay_defaults() throws Exception {
-        assertTrue(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
+    public void testAllowBubbles_defaults() throws Exception {
+        assertTrue(mHelper.areBubblessAllowed(PKG_O, UID_O));
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
         loadStreamXml(baos, false);
 
-        assertTrue(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
+        assertTrue(mHelper.areBubblessAllowed(PKG_O, UID_O));
         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
     }
 
     @Test
-    public void testAllowAppOverlay_xml() throws Exception {
-        mHelper.setAppOverlaysAllowed(PKG_O, UID_O, false);
-        assertFalse(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
-        assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_APP_OVERLAY,
+    public void testAllowBubbles_xml() throws Exception {
+        mHelper.setBubblesAllowed(PKG_O, UID_O, false);
+        assertFalse(mHelper.areBubblessAllowed(PKG_O, UID_O));
+        assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
                 mHelper.getAppLockedFields(PKG_O, UID_O));
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
         loadStreamXml(baos, false);
 
-        assertFalse(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
-        assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_APP_OVERLAY,
+        assertFalse(mHelper.areBubblessAllowed(PKG_O, UID_O));
+        assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
                 mHelper.getAppLockedFields(PKG_O, UID_O));
     }
 
@@ -2290,14 +2290,14 @@
         mHelper.lockChannelsForOEM(new String[] {PKG_O});
 
         NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
-        update.setAllowAppOverlay(false);
+        update.setAllowBubbles(false);
 
         mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
 
         assertEquals(IMPORTANCE_HIGH,
                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
         assertEquals(false,
-                mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canOverlayApps());
+                mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
 
         mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 5bf3d2d..56f4a85 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -36,6 +36,9 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 
 import android.platform.test.annotations.Presubmit;
 
@@ -54,11 +57,6 @@
 @Presubmit
 public class ActivityDisplayTests extends ActivityTestsBase {
 
-    @Before
-    public void setUp() throws Exception {
-        setupActivityTaskManagerService();
-    }
-
     @Test
     public void testLastFocusedStackIsUpdatedWhenMovingStack() {
         // Create a stack at bottom.
@@ -277,4 +275,60 @@
         assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
         assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 1));
     }
+
+    @Test
+    public void testRemoveStackInWindowingModes() {
+        removeStackTests(() -> mRootActivityContainer.removeStacksInWindowingModes(
+                WINDOWING_MODE_FULLSCREEN));
+    }
+
+    @Test
+    public void testRemoveStackWithActivityTypes() {
+        removeStackTests(
+                () -> mRootActivityContainer.removeStacksWithActivityTypes(ACTIVITY_TYPE_STANDARD));
+    }
+
+    private void removeStackTests(Runnable runnable) {
+        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        final ActivityStack stack1 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, ON_TOP);
+        final ActivityStack stack2 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, ON_TOP);
+        final ActivityStack stack3 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, ON_TOP);
+        final ActivityStack stack4 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, ON_TOP);
+        final TaskRecord task1 = new TaskBuilder(mService.mStackSupervisor).setStack(
+                stack1).setTaskId(1).build();
+        final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack(
+                stack2).setTaskId(2).build();
+        final TaskRecord task3 = new TaskBuilder(mService.mStackSupervisor).setStack(
+                stack3).setTaskId(3).build();
+        final TaskRecord task4 = new TaskBuilder(mService.mStackSupervisor).setStack(
+                stack4).setTaskId(4).build();
+
+        // Reordering stacks while removing stacks.
+        doAnswer(invocation -> {
+            display.positionChildAtTop(stack3, false);
+            return true;
+        }).when(mSupervisor).removeTaskByIdLocked(eq(task4.taskId), anyBoolean(), anyBoolean(),
+                any());
+
+        // Removing stacks from the display while removing stacks.
+        doAnswer(invocation -> {
+            display.removeChild(stack2);
+            return true;
+        }).when(mSupervisor).removeTaskByIdLocked(eq(task2.taskId), anyBoolean(), anyBoolean(),
+                any());
+
+        runnable.run();
+        verify(mSupervisor).removeTaskByIdLocked(eq(task4.taskId), anyBoolean(), anyBoolean(),
+                any());
+        verify(mSupervisor).removeTaskByIdLocked(eq(task3.taskId), anyBoolean(), anyBoolean(),
+                any());
+        verify(mSupervisor).removeTaskByIdLocked(eq(task2.taskId), anyBoolean(), anyBoolean(),
+                any());
+        verify(mSupervisor).removeTaskByIdLocked(eq(task1.taskId), anyBoolean(), anyBoolean(),
+                any());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index cac9cf6..ee22861 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -70,8 +70,6 @@
 
     @Before
     public void setUpAMLO() throws Exception {
-        setupActivityTaskManagerService();
-
         mLaunchObserver = mock(ActivityMetricsLaunchObserver.class);
 
         // ActivityStackSupervisor always creates its own instance of ActivityMetricsLogger.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 8f9d2ba..8be63fc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -19,8 +19,10 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
@@ -39,11 +41,14 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.ActivityOptions;
+import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.PauseActivityItem;
+import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
+import android.util.MergedConfiguration;
 import android.util.MutableBoolean;
 
 import androidx.test.filters.MediumTest;
@@ -67,8 +72,7 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
-        mStack = new StackBuilder(mRootActivityContainer).build();
+        mStack = (TestActivityStack) new StackBuilder(mRootActivityContainer).build();
         mTask = mStack.getChildAt(0);
         mActivity = mTask.getTopActivity();
     }
@@ -251,4 +255,112 @@
         assertEquals(prevSeq + 1, appWindowTokenRequestedOrientation.seq);
         verify(mActivity.mAppWindowToken).onMergedOverrideConfigurationChanged();
     }
+
+    @Test
+    public void testSetsRelaunchReason_NotDragResizing() {
+        mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
+
+        mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
+        mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
+                mActivity.getConfiguration()));
+
+        mActivity.info.configChanges &= ~ActivityInfo.CONFIG_ORIENTATION;
+        final Configuration newConfig = new Configuration(mTask.getConfiguration());
+        newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
+                ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+        mTask.onRequestedOverrideConfigurationChanged(newConfig);
+
+        mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+
+        mActivity.ensureActivityConfiguration(0, false, false);
+
+        assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
+                mActivity.mRelaunchReason);
+    }
+
+    @Test
+    public void testSetsRelaunchReason_DragResizing() {
+        mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
+
+        mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
+        mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
+                mActivity.getConfiguration()));
+
+        mActivity.info.configChanges &= ~ActivityInfo.CONFIG_ORIENTATION;
+        final Configuration newConfig = new Configuration(mTask.getConfiguration());
+        newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
+                ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+        mTask.onRequestedOverrideConfigurationChanged(newConfig);
+
+        doReturn(true).when(mTask.getTask()).isDragResizing();
+
+        mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+
+        mActivity.ensureActivityConfiguration(0, false, false);
+
+        assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
+                mActivity.mRelaunchReason);
+    }
+
+    @Test
+    public void testSetsRelaunchReason_NonResizeConfigChanges() {
+        mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
+
+        mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
+        mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
+                mActivity.getConfiguration()));
+
+        mActivity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE;
+        final Configuration newConfig = new Configuration(mTask.getConfiguration());
+        newConfig.fontScale = 5;
+        mTask.onRequestedOverrideConfigurationChanged(newConfig);
+
+        mActivity.mRelaunchReason =
+                ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+
+        mActivity.ensureActivityConfiguration(0, false, false);
+
+        assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
+                mActivity.mRelaunchReason);
+    }
+
+    @Test
+    public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
+        mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
+
+        mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
+        mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
+                mActivity.getConfiguration()));
+
+        mActivity.info.configChanges |= ActivityInfo.CONFIG_ORIENTATION;
+        final Configuration newConfig = new Configuration(mActivity.getConfiguration());
+        newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
+                ? Configuration.ORIENTATION_LANDSCAPE
+                : Configuration.ORIENTATION_PORTRAIT;
+
+        // Mimic the behavior that display doesn't handle app's requested orientation.
+        doAnswer(invocation -> {
+            mTask.onConfigurationChanged(newConfig);
+            return null;
+        }).when(mActivity.mAppWindowToken).setOrientation(anyInt(), any(), any());
+
+        final int requestedOrientation;
+        switch (newConfig.orientation) {
+            case Configuration.ORIENTATION_LANDSCAPE:
+                requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+                break;
+            case Configuration.ORIENTATION_PORTRAIT:
+                requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+                break;
+            default:
+                throw new IllegalStateException("Orientation in new config should be either"
+                        + "landscape or portrait.");
+        }
+        mActivity.setRequestedOrientation(requestedOrientation);
+
+        final ActivityConfigurationChangeItem expected =
+                ActivityConfigurationChangeItem.obtain(newConfig);
+        verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
+                eq(mActivity.appToken), eq(expected));
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index f7b5d26..59e71c4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -64,7 +64,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mFullscreenStack = mRootActivityContainer.getDefaultDisplay().createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index b2a2869..35c1ede 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -36,6 +36,8 @@
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
+import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
+import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -73,7 +75,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mDefaultDisplay = mRootActivityContainer.getDefaultDisplay();
         mStack = spy(mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */));
@@ -264,13 +265,13 @@
 
         // Do not move display to back because there is still another stack.
         stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.topTask());
-        verify(stack2.getWindowContainerController()).positionChildAtBottom(any(),
+        verify(stack2.getTaskStack()).positionChildAtBottom(any(),
                 eq(false) /* includingParents */);
 
         // Also move display to back because there is only one stack left.
         display.removeChild(stack1);
         stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.topTask());
-        verify(stack2.getWindowContainerController()).positionChildAtBottom(any(),
+        verify(stack2.getTaskStack()).positionChildAtBottom(any(),
                 eq(true) /* includingParents */);
     }
 
@@ -687,6 +688,62 @@
     }
 
     @Test
+    public void testHandleAppDied_RelaunchesAfterCrashDuringWindowingModeResize() {
+        final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+
+        activity.mRelaunchReason = RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+        activity.launchCount = 1;
+        activity.haveState = false;
+
+        mStack.handleAppDiedLocked(activity.app);
+
+        assertEquals(1, mTask.mActivities.size());
+        assertEquals(1, mStack.getAllTasks().size());
+    }
+
+    @Test
+    public void testHandleAppDied_NotRelaunchAfterThreeCrashesDuringWindowingModeResize() {
+        final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+
+        activity.mRelaunchReason = RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+        activity.launchCount = 3;
+        activity.haveState = false;
+
+        mStack.handleAppDiedLocked(activity.app);
+
+        assertThat(mTask.mActivities).isEmpty();
+        assertThat(mStack.getAllTasks()).isEmpty();
+    }
+
+    @Test
+    public void testHandleAppDied_RelaunchesAfterCrashDuringFreeResize() {
+        final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+
+        activity.mRelaunchReason = RELAUNCH_REASON_FREE_RESIZE;
+        activity.launchCount = 1;
+        activity.haveState = false;
+
+        mStack.handleAppDiedLocked(activity.app);
+
+        assertEquals(1, mTask.mActivities.size());
+        assertEquals(1, mStack.getAllTasks().size());
+    }
+
+    @Test
+    public void testHandleAppDied_NotRelaunchAfterThreeCrashesDuringFreeResize() {
+        final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+
+        activity.mRelaunchReason = RELAUNCH_REASON_FREE_RESIZE;
+        activity.launchCount = 3;
+        activity.haveState = false;
+
+        mStack.handleAppDiedLocked(activity.app);
+
+        assertThat(mTask.mActivities).isEmpty();
+        assertThat(mStack.getAllTasks()).isEmpty();
+    }
+
+    @Test
     public void testFinishCurrentActivity() {
         // Create 2 activities on a new display.
         final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
index 2ba2fdb..96db38b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
@@ -56,7 +56,6 @@
 
     @Before
     public void setUp() throws Exception {
-        mService = createActivityTaskManagerService();
         mFactory = mock(Factory.class);
         mController = new ActivityStartController(mService, mService.mStackSupervisor, mFactory);
         mStarter = spy(new ActivityStarter(mController, mService,
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 ec88718..a381023 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -117,7 +117,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mController = mock(ActivityStartController.class);
         mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
         clearInvocations(mActivityMetricsLogger);
@@ -143,7 +142,7 @@
                 .setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
                         WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */))
                 .build();
-        assertThat((Object) task2.getStack()).isInstanceOf(PinnedActivityStack.class);
+        assertThat((Object) task2.getStack()).isInstanceOf(ActivityStack.class);
         mStarter.updateBounds(task2, bounds);
 
         verify(mService, times(1)).resizeStack(eq(task2.getStack().mStackId),
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 5589ca1..68df87e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -39,9 +39,6 @@
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doCallRealMethod;
-
 import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
 import android.app.IApplicationThread;
@@ -66,11 +63,11 @@
 import android.view.DisplayInfo;
 
 import com.android.internal.app.IVoiceInteractor;
-import com.android.server.appop.AppOpsService;
 import com.android.server.AttributeCache;
 import com.android.server.ServiceThread;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.PendingIntentController;
+import com.android.server.appop.AppOpsService;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.uri.UriGrantsManagerInternal;
 
@@ -114,6 +111,10 @@
     @Before
     public void setUpBase() {
         mTestInjector.setUp();
+
+        mService = new TestActivityTaskManagerService(mContext);
+        mSupervisor = mService.mStackSupervisor;
+        mRootActivityContainer = mService.mRootActivityContainer;
     }
 
     @After
@@ -125,17 +126,6 @@
         }
     }
 
-    ActivityTaskManagerService createActivityTaskManagerService() {
-        mService = new TestActivityTaskManagerService(mContext);
-        mSupervisor = mService.mStackSupervisor;
-        mRootActivityContainer = mService.mRootActivityContainer;
-        return mService;
-    }
-
-    void setupActivityTaskManagerService() {
-        createActivityTaskManagerService();
-    }
-
     /** Creates a {@link TestActivityDisplay}. */
     TestActivityDisplay createNewActivityDisplay() {
         return TestActivityDisplay.create(mSupervisor, sNextDisplayId++);
@@ -377,7 +367,7 @@
                 mStack.addTask(task, true, "creating test task");
                 task.setStack(mStack);
                 task.setTask();
-                mStack.getWindowContainerController().mContainer.addChild(task.mTask, 0);
+                mStack.getTaskStack().addChild(task.mTask, 0);
             }
 
             task.touchActiveTime();
@@ -632,7 +622,7 @@
 
         @SuppressWarnings("TypeParameterUnusedInFormals")
         @Override
-        <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
+        ActivityStack createStackUnchecked(int windowingMode, int activityType,
                 int stackId, boolean onTop) {
             return new StackBuilder(mSupervisor.mRootActivityContainer).setDisplay(this)
                     .setWindowingMode(windowingMode).setActivityType(activityType)
@@ -681,10 +671,9 @@
      * method is called. Note that its functionality depends on the implementations of the
      * construction arguments.
      */
-    protected static class TestActivityStack<T extends StackWindowController>
-            extends ActivityStack<T> {
+    protected static class TestActivityStack
+            extends ActivityStack {
         private int mOnActivityRemovedFromStackCount = 0;
-        private T mContainerController;
 
         static final int IS_TRANSLUCENT_UNSET = 0;
         static final int IS_TRANSLUCENT_FALSE = 1;
@@ -724,20 +713,20 @@
         }
 
         @Override
-        protected T createStackWindowController(int displayId, boolean onTop, Rect outBounds) {
-            mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController();
+        protected void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
+            mTaskStack = WindowTestUtils.createMockTaskStack();
 
             // Primary pinned stacks require a non-empty out bounds to be set or else all tasks
             // will be moved to the full screen stack.
             if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                 outBounds.set(0, 0, 100, 100);
             }
-            return mContainerController;
+
         }
 
         @Override
-        T getWindowContainerController() {
-            return mContainerController;
+        TaskStack getTaskStack() {
+            return mTaskStack;
         }
 
         void setIsTranslucent(boolean isTranslucent) {
@@ -827,27 +816,23 @@
         }
 
         @SuppressWarnings("TypeParameterUnusedInFormals")
-        <T extends ActivityStack> T build() {
+        ActivityStack build() {
             final int stackId = mStackId >= 0 ? mStackId : mDisplay.getNextStackId();
             if (mWindowingMode == WINDOWING_MODE_PINNED) {
-                return (T) new PinnedActivityStack(mDisplay, stackId,
-                        mRootActivityContainer.mStackSupervisor, mOnTop) {
+                return new ActivityStack(mDisplay, stackId, mRootActivityContainer.mStackSupervisor,
+                        mWindowingMode, ACTIVITY_TYPE_STANDARD, mOnTop) {
                     @Override
                     Rect getDefaultPictureInPictureBounds(float aspectRatio) {
                         return new Rect(50, 50, 100, 100);
                     }
 
                     @Override
-                    PinnedStackWindowController createStackWindowController(int displayId,
-                            boolean onTop, Rect outBounds) {
-                        PinnedStackWindowController controller =
-                                mock(PinnedStackWindowController.class);
-                        controller.mContainer = mock(TaskStack.class);
-                        return controller;
+                    void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
+                        mTaskStack = mock(TaskStack.class);
                     }
                 };
             } else {
-                return (T) new TestActivityStack(mDisplay, stackId,
+                return new TestActivityStack(mDisplay, stackId,
                         mRootActivityContainer.mStackSupervisor, mWindowingMode,
                         mActivityType, mOnTop, mCreateActivity);
             }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index fa42289..123de2d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -39,7 +39,9 @@
 
 import androidx.test.filters.SmallTest;
 
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 /**
@@ -52,15 +54,34 @@
 @Presubmit
 public class AppTransitionTests extends WindowTestsBase {
 
+    private static RootWindowContainer sOriginalRootWindowContainer;
+
     private DisplayContent mDc;
 
+    @BeforeClass
+    public static void setUpRootWindowContainerMock() {
+        final WindowManagerService wm = TestSystemServices.getWindowManagerService();
+        // For unit test, we don't need to test performSurfacePlacement to prevent some abnormal
+        // interaction with surfaceflinger native side.
+        sOriginalRootWindowContainer = wm.mRoot;
+        // Creating spied mock of RootWindowContainer shouldn't be done in @Before, since it will
+        // create unnecessary nested spied objects chain, because WindowManagerService object under
+        // test is a single instance shared among all tests that extend WindowTestsBase class.
+        // Instead it should be done once before running all tests in this test class.
+        wm.mRoot = spy(wm.mRoot);
+        doNothing().when(wm.mRoot).performSurfacePlacement(anyBoolean());
+    }
+
+    @AfterClass
+    public static void tearDownRootWindowContainerMock() {
+        final WindowManagerService wm = TestSystemServices.getWindowManagerService();
+        wm.mRoot = sOriginalRootWindowContainer;
+        sOriginalRootWindowContainer = null;
+    }
+
     @Before
     public void setUp() throws Exception {
         mDc = mWm.getDefaultDisplayContentLocked();
-        // For unit test,  we don't need to test performSurfacePlacement to prevent some
-        // abnormal interaction with surfaceflinger native side.
-        mWm.mRoot = spy(mWm.mRoot);
-        doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
     }
 
     @Test
@@ -160,7 +181,7 @@
         assertTrue(dc1.mOpeningApps.size() > 0);
 
         // Move stack to another display.
-        stack1.getController().reparent(dc2.getDisplayId(),  new Rect(), true);
+        stack1.reparent(dc2.getDisplayId(),  new Rect(), true);
 
         // Verify if token are cleared from both pending transition list in former display.
         assertFalse(dc1.mOpeningApps.contains(token1));
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 3826fac..f399463 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -59,6 +59,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.util.DisplayMetrics;
 import android.view.DisplayCutout;
+import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.Surface;
@@ -584,15 +585,17 @@
 
     @Test
     public void testOnDescendantOrientationRequestChanged() {
-        final DisplayContent dc = createNewDisplay();
+        final DisplayInfo info = new DisplayInfo();
+        info.logicalWidth = 1080;
+        info.logicalHeight = 1920;
+        info.logicalDensityDpi = 240;
+        final DisplayContent dc = createNewDisplay(info);
+        dc.configureDisplayPolicy();
         mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
-        final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
-                ? SCREEN_ORIENTATION_PORTRAIT
-                : SCREEN_ORIENTATION_LANDSCAPE;
 
         final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
         window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS);
-        window.mAppToken.setOrientation(newOrientation);
+        window.mAppToken.mOrientation = SCREEN_ORIENTATION_LANDSCAPE;
 
         ActivityRecord activityRecord = mock(ActivityRecord.class);
 
@@ -603,21 +606,22 @@
         verify(mWm.mAtmService).updateDisplayOverrideConfigurationLocked(captor.capture(),
                 same(activityRecord), anyBoolean(), eq(dc.getDisplayId()));
         final Configuration newDisplayConfig = captor.getValue();
-        assertEquals(Configuration.ORIENTATION_PORTRAIT, newDisplayConfig.orientation);
+        assertEquals(Configuration.ORIENTATION_LANDSCAPE, newDisplayConfig.orientation);
     }
 
     @Test
     public void testOnDescendantOrientationRequestChanged_FrozenToUserRotation() {
-        final DisplayContent dc = createNewDisplay();
+        final DisplayInfo info = new DisplayInfo();
+        info.logicalWidth = 1080;
+        info.logicalHeight = 1920;
+        info.logicalDensityDpi = 240;
+        final DisplayContent dc = createNewDisplay(info);
         dc.getDisplayRotation().setFixedToUserRotation(true);
         mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
-        final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
-                ? SCREEN_ORIENTATION_PORTRAIT
-                : SCREEN_ORIENTATION_LANDSCAPE;
 
         final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
         window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS);
-        window.mAppToken.setOrientation(newOrientation);
+        window.mAppToken.mOrientation = SCREEN_ORIENTATION_LANDSCAPE;
 
         ActivityRecord activityRecord = mock(ActivityRecord.class);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 198e7ce..d05711e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -33,7 +33,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.content.ContentResolver;
@@ -612,23 +611,6 @@
     // ========================
     // Non-rotation API Tests
     // ========================
-    @Test
-    public void testRespectsAppRequestedOrientationByDefault() throws Exception {
-        mBuilder.build();
-
-        assertTrue("Display rotation should respect app requested orientation by"
-                + " default.", mTarget.respectAppRequestedOrientation());
-    }
-
-    @Test
-    public void testNotRespectAppRequestedOrientation_FixedToUserRotation() throws Exception {
-        mBuilder.build();
-        mTarget.setFixedToUserRotation(true);
-
-        assertFalse("Display rotation shouldn't respect app requested orientation if"
-                + " fixed to user rotation.", mTarget.respectAppRequestedOrientation());
-    }
-
     /**
      * Call {@link DisplayRotation#configure(int, int, int, int)} to configure {@link #mTarget}
      * according to given parameters.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index bb3ab35..68d8bc0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -94,8 +94,8 @@
     private WindowState createDropTargetWindow(String name, int ownerId) {
         final WindowTestUtils.TestAppWindowToken token = WindowTestUtils.createTestAppWindowToken(
                 mDisplayContent);
-        final TaskStack stack = createStackControllerOnStackOnDisplay(
-                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
+        final TaskStack stack = createTaskStackOnDisplay(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent);
         final Task task = createTaskInStack(stack, ownerId);
         task.addChild(token, 0);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index 8c3dec7..b28ae40 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -71,7 +71,6 @@
 
     @Before
     public void setUp() throws Exception {
-        mService = createActivityTaskManagerService();
         mPersister = new TestLaunchParamsPersister();
         mController = new LaunchParamsController(mService, mPersister);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 8635364..aeda473 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -102,8 +102,6 @@
         mFolder = new File(cacheFolder, "launch_params_tests");
         deleteRecursively(mFolder);
 
-        setupActivityTaskManagerService();
-
         mDisplayUniqueId = "test:" + Integer.toString(sNextUniqueId++);
         final DisplayInfo info = new DisplayInfo();
         info.uniqueId = mDisplayUniqueId;
diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
index efd7d25..beaac8e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
@@ -52,7 +52,6 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mService = createActivityTaskManagerService();
         mService.mH.runWithScissors(() -> {
             mHandler = new TestHandler(null, mClock);
         }, 0);
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 58302d6..e3bacf9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -82,7 +82,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mFullscreenStack = mRootActivityContainer.getDefaultDisplay().createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
     }
@@ -323,8 +322,8 @@
     public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
         // Create stack/task on default display.
         final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
-        final TestActivityStack targetStack =
-                new StackBuilder(mRootActivityContainer).setOnTop(false).build();
+        final TestActivityStack targetStack = (TestActivityStack) new StackBuilder(
+                mRootActivityContainer).setOnTop(false).build();
         final TaskRecord targetTask = targetStack.getChildAt(0);
 
         // Create Recents on top of the display.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index a8b6dc3..dc96480 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -49,7 +49,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mRunningTasks = new RunningTasks();
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java
deleted file mode 100644
index 5690b58..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Test class for {@link StackWindowController}.
- *
- * Build/Install/Run:
- *  atest FrameworksServicesTests:StackWindowControllerTests
- */
-@SmallTest
-@Presubmit
-public class StackWindowControllerTests extends WindowTestsBase {
-    @Test
-    public void testRemoveContainer() {
-        final StackWindowController stackController =
-                createStackControllerOnDisplay(mDisplayContent);
-        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController);
-
-        final TaskStack stack = stackController.mContainer;
-        assertNotNull(stack);
-        assertNotNull(task);
-        stackController.removeContainer();
-        // Assert that the container was removed.
-        assertNull(stackController.mContainer);
-        assertNull(stack.getDisplayContent());
-        assertNull(task.getDisplayContent());
-        assertNull(task.mStack);
-    }
-
-    @Test
-    public void testRemoveContainer_deferRemoval() {
-        final StackWindowController stackController =
-                createStackControllerOnDisplay(mDisplayContent);
-        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController);
-
-        final TaskStack stack = stackController.mContainer;
-        // Stack removal is deferred if one of its child is animating.
-        task.setLocalIsAnimating(true);
-
-        stackController.removeContainer();
-        // For the case of deferred removal the stack controller will no longer be connected to the
-        // container, but the task controller will still be connected to the its container until
-        // the stack window container is removed.
-        assertNull(stackController.mContainer);
-        assertNull(stack.getController());
-        assertNotNull(task);
-
-        stack.removeImmediately();
-        // After removing, the task will be isolated.
-        assertNull(task.getParent());
-        assertEquals(task.getChildCount(), 0);
-        assertNull(task.getController());
-    }
-
-    @Test
-    public void testReparent() {
-        // Create first stack on primary display.
-        final StackWindowController stack1Controller =
-                createStackControllerOnDisplay(mDisplayContent);
-        final TaskStack stack1 = stack1Controller.mContainer;
-        final WindowTestUtils.TestTask task1 = WindowTestUtils.createTestTask(stack1Controller);
-        task1.mOnDisplayChangedCalled = false;
-
-        // Create second display and put second stack on it.
-        final DisplayContent dc = createNewDisplay();
-        final StackWindowController stack2Controller =
-                createStackControllerOnDisplay(dc);
-        final TaskStack stack2 = stack2Controller.mContainer;
-
-        // Reparent
-        stack1Controller.reparent(dc.getDisplayId(), new Rect(), true /* onTop */);
-        assertEquals(dc, stack1.getDisplayContent());
-        final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
-        final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
-        assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
-        assertTrue(task1.mOnDisplayChangedCalled);
-    }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 53e99fa..ace179a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -75,10 +75,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
-        mService.mSupportsFreeformWindowManagement = true;
-        when(mSupervisor.canUseActivityOptionsLaunchBounds(any())).thenCallRealMethod();
-
         mActivity = new ActivityBuilder(mService).build();
         mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
         mActivity.info.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 8a98cbe..e182c45 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -25,6 +25,13 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import static org.hamcrest.Matchers.not;
@@ -46,6 +53,7 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.util.Xml;
 import android.view.DisplayInfo;
+import android.view.Surface;
 
 import androidx.test.filters.MediumTest;
 
@@ -82,7 +90,6 @@
     @Before
     public void setUp() throws Exception {
         TaskRecord.setTaskRecordFactory(null);
-        setupActivityTaskManagerService();
         mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
     }
 
@@ -217,12 +224,17 @@
         info.logicalHeight = fullScreenBounds.height();
         ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP);
         assertTrue(mRootActivityContainer.getActivityDisplay(display.mDisplayId) != null);
+        // Override display orientation. Normally this is available via DisplayContent, but DC
+        // is mocked-out.
+        display.getRequestedOverrideConfiguration().orientation =
+                Configuration.ORIENTATION_LANDSCAPE;
+        display.onRequestedOverrideConfigurationChanged(
+                display.getRequestedOverrideConfiguration());
         ActivityStack stack = new StackBuilder(mRootActivityContainer)
                 .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
         TaskRecord task = stack.getChildAt(0);
-        ActivityRecord root = task.getRootActivity();
-        ActivityRecord top = new ActivityBuilder(mService).setTask(task).setStack(stack).build();
-        assertEquals(root, task.getRootActivity());
+        ActivityRecord root = task.getTopActivity();
+        assertEquals(root, task.getTopActivity());
 
         assertEquals(fullScreenBounds, task.getBounds());
 
@@ -233,16 +245,22 @@
         assertTrue(task.getBounds().width() < task.getBounds().height());
         assertEquals(fullScreenBounds.height(), task.getBounds().height());
 
-        // Setting non-root app has no effect
-        setActivityRequestedOrientation(root, SCREEN_ORIENTATION_LANDSCAPE);
-        assertTrue(task.getBounds().width() < task.getBounds().height());
+        // Top activity gets used
+        ActivityRecord top = new ActivityBuilder(mService).setTask(task).setStack(stack).build();
+        assertEquals(top, task.getTopActivity());
+        setActivityRequestedOrientation(top, SCREEN_ORIENTATION_LANDSCAPE);
+        assertTrue(task.getBounds().width() > task.getBounds().height());
+        assertEquals(task.getBounds().width(), fullScreenBounds.width());
 
         // Setting app to unspecified restores
-        setActivityRequestedOrientation(root, SCREEN_ORIENTATION_UNSPECIFIED);
+        setActivityRequestedOrientation(top, SCREEN_ORIENTATION_UNSPECIFIED);
         assertEquals(fullScreenBounds, task.getBounds());
 
         // Setting app to fixed landscape and changing display
-        setActivityRequestedOrientation(root, SCREEN_ORIENTATION_LANDSCAPE);
+        setActivityRequestedOrientation(top, SCREEN_ORIENTATION_LANDSCAPE);
+        // simulate display orientation changing (normally done via DisplayContent)
+        display.getRequestedOverrideConfiguration().orientation =
+                Configuration.ORIENTATION_PORTRAIT;
         display.setBounds(fullScreenBoundsPort);
         assertTrue(task.getBounds().width() > task.getBounds().height());
         assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
@@ -265,6 +283,51 @@
         assertEquals(freeformBounds, task.getBounds());
     }
 
+    @Test
+    public void testUpdatesForcedOrientationInBackground() {
+        final DisplayInfo info = new DisplayInfo();
+        info.logicalWidth = 1920;
+        info.logicalHeight = 1080;
+        final ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP);
+        doCallRealMethod().when(display.mDisplayContent).setDisplayRotation(any());
+        display.mDisplayContent.setDisplayRotation(mock(DisplayRotation.class));
+        doCallRealMethod().when(display.mDisplayContent).onDescendantOrientationChanged(any(),
+                any());
+        doCallRealMethod().when(display.mDisplayContent).setRotation(anyInt());
+        doAnswer(invocation -> {
+            display.mDisplayContent.setRotation(Surface.ROTATION_0);
+            return null;
+        }).when(display.mDisplayContent).updateOrientationFromAppTokens(any(), any(), anyBoolean());
+
+        final ActivityStack stack = new StackBuilder(mRootActivityContainer)
+                .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
+        final TaskRecord task = stack.getChildAt(0);
+        final ActivityRecord activity = task.getRootActivity();
+
+        // Wire up app window token and task.
+        doCallRealMethod().when(activity.mAppWindowToken).setOrientation(anyInt(), any(), any());
+        doCallRealMethod().when(activity.mAppWindowToken).onDescendantOrientationChanged(any(),
+                any());
+        doReturn(task.mTask).when(activity.mAppWindowToken).getParent();
+
+        // Wire up task and stack.
+        task.mTask.mTaskRecord = task;
+        doCallRealMethod().when(task.mTask).onDescendantOrientationChanged(any(), any());
+        doReturn(stack.getTaskStack()).when(task.mTask).getParent();
+
+        // Wire up stack and display content.
+        doCallRealMethod().when(stack.mTaskStack).onDescendantOrientationChanged(any(), any());
+        doReturn(display.mDisplayContent).when(stack.mTaskStack).getParent();
+
+        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+        assertTrue("Bounds of the task should be pillarboxed.",
+                task.getBounds().width() < task.getBounds().height());
+
+        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+        assertTrue("Bounds of the task should be fullscreen.",
+                task.getBounds().equals(new Rect(0, 0, 1920, 1080)));
+    }
+
     /** Ensures that the alias intent won't have target component resolved. */
     @Test
     public void testTaskIntentActivityAlias() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
index f01e9f0..74ccccc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -47,8 +47,8 @@
 
     @Before
     public void setUp() throws Exception {
-        mPinnedStack = createStackControllerOnStackOnDisplay(
-                WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
+        mPinnedStack = createTaskStackOnDisplay(
+                WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
         // Stack should contain visible app window to be considered visible.
         final Task pinnedTask = createTaskInStack(mPinnedStack, 0 /* userId */);
         assertFalse(mPinnedStack.isVisible());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 7ac3318..2554237 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -20,8 +20,12 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
+import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
@@ -106,4 +110,62 @@
         assertNull(stack.getDisplayContent());
         assertNull(task.mStack);
     }
+
+    @Test
+    public void testRemoveContainer() {
+        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack);
+
+        assertNotNull(stack);
+        assertNotNull(task);
+        stack.removeIfPossible();
+        // Assert that the container was removed.
+        assertNull(stack.getParent());
+        assertEquals(0, stack.getChildCount());
+        assertNull(stack.getDisplayContent());
+        assertNull(task.getDisplayContent());
+        assertNull(task.mStack);
+    }
+
+    @Test
+    public void testRemoveContainer_deferRemoval() {
+        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack);
+
+        // Stack removal is deferred if one of its child is animating.
+        task.setLocalIsAnimating(true);
+
+        stack.removeIfPossible();
+        // For the case of deferred removal the task controller will still be connected to the its
+        // container until the stack window container is removed.
+        assertNotNull(stack.getParent());
+        assertNotEquals(0, stack.getChildCount());
+        assertNotNull(task);
+
+        stack.removeImmediately();
+        // After removing, the task will be isolated.
+        assertNull(task.getParent());
+        assertEquals(0, task.getChildCount());
+        assertNull(task.getController());
+    }
+
+    @Test
+    public void testReparent() {
+        // Create first stack on primary display.
+        final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
+        final WindowTestUtils.TestTask task1 = WindowTestUtils.createTestTask(stack1);
+        task1.mOnDisplayChangedCalled = false;
+
+        // Create second display and put second stack on it.
+        final DisplayContent dc = createNewDisplay();
+        final TaskStack stack2 = createTaskStackOnDisplay(dc);
+
+        // Reparent
+        stack1.reparent(dc.getDisplayId(), new Rect(), true /* onTop */);
+        assertEquals(dc, stack1.getDisplayContent());
+        final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
+        final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
+        assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
+        assertTrue(task1.mOnDisplayChangedCalled);
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 3e32ed3..ae211d3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -40,8 +40,7 @@
 
     @Test
     public void testRemoveContainer() {
-        final StackWindowController stackController1 =
-                createStackControllerOnDisplay(mDisplayContent);
+        final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
         final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
         final WindowTestUtils.TestAppWindowToken appToken =
                 WindowTestUtils.createAppWindowTokenInTask(mDisplayContent, task);
@@ -49,14 +48,13 @@
         task.removeIfPossible();
         // Assert that the container was removed.
         assertNull(task.getParent());
-        assertEquals(task.getChildCount(), 0);
+        assertEquals(0, task.getChildCount());
         assertNull(appToken.getParent());
     }
 
     @Test
     public void testRemoveContainer_deferRemoval() {
-        final StackWindowController stackController1 =
-                createStackControllerOnDisplay(mDisplayContent);
+        final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
         final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
         final WindowTestUtils.TestAppWindowToken appToken =
                 WindowTestUtils.createAppWindowTokenInTask(mDisplayContent, task);
@@ -67,22 +65,20 @@
         // For the case of deferred removal the task will still be connected to the its app token
         // until the task window container is removed.
         assertNotNull(task.getParent());
-        assertNotEquals(task.getChildCount(), 0);
+        assertNotEquals(0, task.getChildCount());
         assertNotNull(appToken.getParent());
 
         task.removeImmediately();
         assertNull(task.getParent());
-        assertEquals(task.getChildCount(), 0);
+        assertEquals(0, task.getChildCount());
         assertNull(appToken.getParent());
     }
 
     @Test
     public void testReparent() {
-        final StackWindowController stackController1 =
-                createStackControllerOnDisplay(mDisplayContent);
+        final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
         final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
-        final StackWindowController stackController2 =
-                createStackControllerOnDisplay(mDisplayContent);
+        final TaskStack stackController2 = createTaskStackOnDisplay(mDisplayContent);
         final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stackController2);
 
         boolean gotException = false;
@@ -93,20 +89,17 @@
         }
         assertTrue("Should not be able to reparent to the same parent", gotException);
 
-        final StackWindowController stackController3 =
-                createStackControllerOnDisplay(mDisplayContent);
-        stackController3.setContainer(null);
         gotException = false;
         try {
-            task.reparent(stackController3, 0, false/* moveParents */);
+            task.reparent(null, 0, false/* moveParents */);
         } catch (IllegalArgumentException e) {
             gotException = true;
         }
-        assertTrue("Should not be able to reparent to a stack that doesn't have a container",
+        assertTrue("Should not be able to reparent to a stack that doesn't exist",
                 gotException);
 
         task.reparent(stackController2, 0, false/* moveParents */);
-        assertEquals(stackController2.mContainer, task.getParent());
+        assertEquals(stackController2, task.getParent());
         assertEquals(0, task.positionInParent());
         assertEquals(1, task2.positionInParent());
     }
@@ -114,20 +107,17 @@
     @Test
     public void testReparent_BetweenDisplays() {
         // Create first stack on primary display.
-        final StackWindowController stack1Controller =
-                createStackControllerOnDisplay(mDisplayContent);
-        final TaskStack stack1 = stack1Controller.mContainer;
-        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack1Controller);
+        final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
+        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack1);
         task.mOnDisplayChangedCalled = false;
         assertEquals(mDisplayContent, stack1.getDisplayContent());
 
         // Create second display and put second stack on it.
         final DisplayContent dc = createNewDisplay();
-        final StackWindowController stack2Controller = createStackControllerOnDisplay(dc);
-        final TaskStack stack2 = stack2Controller.mContainer;
-        final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stack2Controller);
+        final TaskStack stack2 = createTaskStackOnDisplay(dc);
+        final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stack2);
         // Reparent and check state
-        task.reparent(stack2Controller, 0, false /* moveParents */);
+        task.reparent(stack2, 0, false /* moveParents */);
         assertEquals(stack2, task.getParent());
         assertEquals(0, task.positionInParent());
         assertEquals(1, task2.positionInParent());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
similarity index 97%
rename from services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java
rename to services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
index 05ac8c1..b151fb7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
@@ -66,7 +66,7 @@
 /**
  * A Test utility class to create a mock {@link WindowManagerService} instance for tests.
  */
-class WmServiceUtils {
+class TestSystemServices {
     private static StaticMockitoSession sMockitoSession;
     private static WindowManagerService sService;
     private static TestWindowManagerPolicy sPolicy;
@@ -78,7 +78,7 @@
                 .strictness(Strictness.LENIENT)
                 .startMocking();
 
-        runWithDexmakerShareClassLoader(WmServiceUtils::setUpTestWindowService);
+        runWithDexmakerShareClassLoader(TestSystemServices::setUpTestWindowService);
     }
 
     static void tearDownWindowManagerService() {
@@ -147,7 +147,7 @@
         final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock();
         doReturn(wmLock).when(atms).getGlobalLock();
 
-        sPolicy = new TestWindowManagerPolicy(WmServiceUtils::getWindowManagerService);
+        sPolicy = new TestWindowManagerPolicy(TestSystemServices::getWindowManagerService);
         sService = WindowManagerService.main(context, ims, false, false, sPolicy, atms);
 
         sService.onInitReady();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index d9ef10d..0a4a8a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -16,12 +16,15 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
 import static android.view.DisplayCutout.fromBoundingRect;
 import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
 
 import android.app.ActivityManager.TaskDescription;
 import android.content.res.Configuration;
@@ -58,7 +61,7 @@
         boolean mDockedResizingForTest = false;
         WindowStateWithTask(WindowManagerService wm, IWindow iWindow, WindowToken windowToken,
                 WindowManager.LayoutParams attrs, Task t) {
-            super(wm, null, iWindow, windowToken, null, 0, 0, attrs, 0, 0,
+            super(wm, mock(Session.class), iWindow, windowToken, null, 0, 0, attrs, 0, 0,
                     false /* ownerCanAddInternalSystemWindow */);
             mTask = t;
         }
@@ -113,9 +116,9 @@
 
     @Before
     public void setUp() throws Exception {
-        mWindowToken = WindowTestUtils.createTestAppWindowToken(
-                mWm.getDefaultDisplayContentLocked());
-        mStubStack = new TaskStack(mWm, 0, null);
+        mWindowToken = createAppWindowToken(mWm.getDefaultDisplayContentLocked(),
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        mStubStack = WindowTestUtils.createMockTaskStack();
     }
 
     // Do not use this function directly in the tests below. Instead, use more explicit function
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 20fc5ae..44e998b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -103,12 +103,10 @@
     }
 
     /**
-     * Creates a mock instance of {@link StackWindowController}.
+     * Creates a mock instance of {@link TestTaskStack}.
      */
-    public static StackWindowController createMockStackWindowContainerController() {
-        StackWindowController controller = mock(StackWindowController.class);
-        controller.mContainer = mock(TestTaskStack.class);
-        return controller;
+    public static TaskStack createMockTaskStack() {
+        return mock(TestTaskStack.class);
     }
 
     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
@@ -201,6 +199,11 @@
         }
 
         @Override
+        void onParentSet() {
+            // Do nothing.
+        }
+
+        @Override
         boolean isOnTop() {
             return mOnTop;
         }
@@ -283,10 +286,9 @@
         }
     }
 
-    public static TestTask createTestTask(StackWindowController stackWindowController) {
-        return new TestTask(sNextTaskId++, stackWindowController.mContainer, 0,
-                stackWindowController.mService, RESIZE_MODE_UNRESIZEABLE, false,
-                mock(TaskRecord.class));
+    public static TestTask createTestTask(TaskStack stack) {
+        return new TestTask(sNextTaskId++, stack, 0, stack.mWmService, RESIZE_MODE_UNRESIZEABLE,
+                false, mock(TaskRecord.class));
     }
 
     public static class TestIApplicationToken implements IApplicationToken {
@@ -334,5 +336,10 @@
 
             mHasSurface = hadSurface;
         }
+
+        @Override
+        void onParentSet() {
+            // Do nothing;
+        }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index cdc0a47..e38118e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -41,7 +41,6 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
-import android.graphics.Rect;
 import android.hardware.display.DisplayManagerGlobal;
 import android.testing.DexmakerShareClassLoaderRule;
 import android.util.Log;
@@ -102,14 +101,14 @@
     public static void setUpOnceBase() {
         AttributeCache.init(getInstrumentation().getTargetContext());
 
-        WmServiceUtils.setUpWindowManagerService();
+        TestSystemServices.setUpWindowManagerService();
 
         sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
     }
 
     @AfterClass
     public static void tearDonwOnceBase() {
-        WmServiceUtils.tearDownWindowManagerService();
+        TestSystemServices.tearDownWindowManagerService();
     }
 
     @Before
@@ -121,7 +120,7 @@
 
             final Context context = getInstrumentation().getTargetContext();
 
-            mWm = WmServiceUtils.getWindowManagerService();
+            mWm = TestSystemServices.getWindowManagerService();
             beforeCreateDisplay();
 
             context.getDisplay().getDisplayInfo(mDisplayInfo);
@@ -199,7 +198,7 @@
             }
 
             // Cleaned up everything in Handler.
-            WmServiceUtils.cleanupWindowManagerHandlers();
+            TestSystemServices.cleanupWindowManagerHandlers();
         } catch (Exception e) {
             Log.e(TAG, "Failed to tear down test", e);
             throw e;
@@ -220,7 +219,7 @@
      * Waits until the main handler for WM has processed all messages.
      */
     void waitUntilHandlersIdle() {
-        WmServiceUtils.waitUntilWindowManagerHandlersIdle();
+        TestSystemServices.waitUntilWindowManagerHandlersIdle();
     }
 
     private WindowToken createWindowToken(
@@ -240,8 +239,7 @@
 
     WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
             windowingMode, int activityType) {
-        final TaskStack stack = createStackControllerOnStackOnDisplay(windowingMode, activityType,
-                dc).mContainer;
+        final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
         final Task task = createTaskInStack(stack, 0 /* userId */);
         final WindowTestUtils.TestAppWindowToken appWindowToken =
                 WindowTestUtils.createTestAppWindowToken(dc);
@@ -350,28 +348,20 @@
     /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
     TaskStack createTaskStackOnDisplay(DisplayContent dc) {
         synchronized (mWm.mGlobalLock) {
-            return createStackControllerOnDisplay(dc).mContainer;
+            return createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
         }
     }
 
-    StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
-        synchronized (mWm.mGlobalLock) {
-            return createStackControllerOnStackOnDisplay(
-                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
-        }
-    }
-
-    StackWindowController createStackControllerOnStackOnDisplay(
-            int windowingMode, int activityType, DisplayContent dc) {
+    TaskStack createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) {
         synchronized (mWm.mGlobalLock) {
             final Configuration overrideConfig = new Configuration();
             overrideConfig.windowConfiguration.setWindowingMode(windowingMode);
             overrideConfig.windowConfiguration.setActivityType(activityType);
             final int stackId = ++sNextStackId;
-            final StackWindowController controller = new StackWindowController(stackId, null,
-                    dc.getDisplayId(), true /* onTop */, new Rect(), mWm);
-            controller.onRequestedOverrideConfigurationChanged(overrideConfig);
-            return controller;
+            final TaskStack stack = new TaskStack(mWm, stackId, mock(ActivityStack.class));
+            dc.setStackOnDisplay(stackId, true, stack);
+            stack.onRequestedOverrideConfigurationChanged(overrideConfig);
+            return stack;
         }
     }
 
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index 94cc650..9a5bd13 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -22,6 +22,7 @@
 import static android.app.usage.UsageEvents.Event.CONFIGURATION_CHANGE;
 import static android.app.usage.UsageEvents.Event.CONTINUE_PREVIOUS_DAY;
 import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE;
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
 import static android.app.usage.UsageEvents.Event.END_OF_DAY;
 import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK;
 import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START;
@@ -66,7 +67,7 @@
     public final ArrayMap<String, UsageStats> packageStats = new ArrayMap<>();
     public final ArrayMap<Configuration, ConfigurationStats> configurations = new ArrayMap<>();
     public Configuration activeConfiguration;
-    public EventList events;
+    public EventList events = new EventList();
 
     // A string cache. This is important as when we're parsing XML files, we don't want to
     // keep hundreds of strings that have the same contents. We will read the string
@@ -112,6 +113,9 @@
 
     }
 
+    public IntervalStats() {
+    }
+
     /**
      * Gets the UsageStats object for the given package, or creates one and adds it internally.
      */
@@ -253,6 +257,7 @@
             case ROLLOVER_FOREGROUND_SERVICE:
             case CONTINUE_PREVIOUS_DAY:
             case CONTINUING_FOREGROUND_SERVICE:
+            case DEVICE_SHUTDOWN:
                 return true;
         }
         return false;
@@ -281,8 +286,9 @@
     @VisibleForTesting
     public void update(String packageName, String className, long timeStamp, int eventType,
             int instanceId) {
-        if (eventType == FLUSH_TO_DISK) {
-            // FLUSH_TO_DISK are sent to all packages.
+        if (eventType == DEVICE_SHUTDOWN
+                || eventType == FLUSH_TO_DISK) {
+            // DEVICE_SHUTDOWN and FLUSH_TO_DISK are sent to all packages.
             final int size = packageStats.size();
             for (int i = 0; i < size; i++) {
                 UsageStats usageStats = packageStats.valueAt(i);
@@ -321,9 +327,6 @@
      */
     @VisibleForTesting
     public void addEvent(Event event) {
-        if (events == null) {
-            events = new EventList();
-        }
         // Cache common use strings
         event.mPackage = getCachedStringRef(event.mPackage);
         if (event.mClass != null) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index f146370..76a3aa8 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -18,6 +18,7 @@
 
 import static android.app.usage.UsageEvents.Event.CHOOSER_ACTION;
 import static android.app.usage.UsageEvents.Event.CONFIGURATION_CHANGE;
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
 import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK;
 import static android.app.usage.UsageEvents.Event.NOTIFICATION_INTERRUPTION;
 import static android.app.usage.UsageEvents.Event.SHORTCUT_INVOCATION;
@@ -416,11 +417,30 @@
      */
     void shutdown() {
         synchronized (mLock) {
+            mHandler.removeMessages(MSG_REPORT_EVENT);
+            Event event = new Event(DEVICE_SHUTDOWN, SystemClock.elapsedRealtime());
+            // orderly shutdown, the last event is DEVICE_SHUTDOWN.
+            reportEventToAllUserId(event);
             flushToDiskLocked();
         }
     }
 
     /**
+     * After power button is pressed for 3.5 seconds
+     * (as defined in {@link com.android.internal.R.integer#config_veryLongPressTimeout}),
+     * report DEVICE_SHUTDOWN event and persist the database. If the power button is pressed for 10
+     * seconds and the device is shutdown, the database is already persisted and we are not losing
+     * data.
+     * This method is called from PhoneWindowManager, do not synchronize on mLock otherwise
+     * PhoneWindowManager may be blocked.
+     */
+    void prepareForPossibleShutdown() {
+        Event event = new Event(DEVICE_SHUTDOWN, SystemClock.elapsedRealtime());
+        mHandler.obtainMessage(MSG_REPORT_EVENT_TO_ALL_USERID, event).sendToTarget();
+        mHandler.sendEmptyMessage(MSG_FLUSH_TO_DISK);
+    }
+
+    /**
      * Called by the Binder stub.
      */
     void reportEvent(Event event, int userId) {
@@ -1487,6 +1507,11 @@
         }
 
         @Override
+        public void prepareForPossibleShutdown() {
+            UsageStatsService.this.prepareForPossibleShutdown();
+        }
+
+        @Override
         public void addAppIdleStateChangeListener(AppIdleStateChangeListener listener) {
             mAppStandby.addListener(listener);
             listener.onParoleStateChanged(isAppIdleParoleOn());
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 5128ae1..2d1098c7 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.usage;
 
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
 import static android.app.usage.UsageStatsManager.INTERVAL_BEST;
 import static android.app.usage.UsageStatsManager.INTERVAL_COUNT;
 import static android.app.usage.UsageStatsManager.INTERVAL_DAILY;
@@ -134,6 +135,18 @@
             updateRolloverDeadline();
         }
 
+        // During system reboot, add a DEVICE_SHUTDOWN event to the end of event list, the timestamp
+        // is last time UsageStatsDatabase is persisted to disk.
+        final IntervalStats currentDailyStats = mCurrentStats[INTERVAL_DAILY];
+        if (currentDailyStats != null) {
+            final int size = currentDailyStats.events.size();
+            if (size == 0 || currentDailyStats.events.get(size - 1).mEventType != DEVICE_SHUTDOWN) {
+                // The last event in event list is not DEVICE_SHUTDOWN, then we insert one.
+                final Event event = new Event(DEVICE_SHUTDOWN, currentDailyStats.lastTimeSaved);
+                currentDailyStats.addEvent(event);
+            }
+        }
+
         if (mDatabase.isNewUpdate()) {
             notifyNewUpdate();
         }
@@ -175,7 +188,9 @@
                 // ACTIVITY_STOPPED.
                 && event.mEventType != Event.ACTIVITY_DESTROYED
                 // FLUSH_TO_DISK is a private event.
-                && event.mEventType != Event.FLUSH_TO_DISK) {
+                && event.mEventType != Event.FLUSH_TO_DISK
+                // DEVICE_SHUTDOWN is added to event list after reboot.
+                && event.mEventType != Event.DEVICE_SHUTDOWN) {
             currentDailyStats.addEvent(event);
         }
 
@@ -393,10 +408,6 @@
                     @Override
                     public void combine(IntervalStats stats, boolean mutable,
                             List<Event> accumulatedResult) {
-                        if (stats.events == null) {
-                            return;
-                        }
-
                         final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
                         final int size = stats.events.size();
                         for (int i = startIndex; i < size; i++) {
@@ -434,10 +445,6 @@
         names.add(packageName);
         final List<Event> results = queryStats(INTERVAL_DAILY,
                 beginTime, endTime, (stats, mutable, accumulatedResult) -> {
-                    if (stats.events == null) {
-                        return;
-                    }
-
                     final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
                     final int size = stats.events.size();
                     for (int i = startIndex; i < size; i++) {
@@ -696,10 +703,6 @@
                     @Override
                     public void combine(IntervalStats stats, boolean mutable,
                             List<Event> accumulatedResult) {
-                        if (stats.events == null) {
-                            return;
-                        }
-
                         final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
                         final int size = stats.events.size();
                         for (int i = startIndex; i < size; i++) {
@@ -925,10 +928,12 @@
                 return "SCREEN_INTERACTIVE";
             case Event.SCREEN_NON_INTERACTIVE:
                 return "SCREEN_NON_INTERACTIVE";
-            case UsageEvents.Event.KEYGUARD_SHOWN:
+            case Event.KEYGUARD_SHOWN:
                 return "KEYGUARD_SHOWN";
-            case UsageEvents.Event.KEYGUARD_HIDDEN:
+            case Event.KEYGUARD_HIDDEN:
                 return "KEYGUARD_HIDDEN";
+            case Event.DEVICE_SHUTDOWN:
+                return "DEVICE_SHUTDOWN";
             default:
                 return "UNKNOWN_TYPE_" + eventType;
         }
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 904d55e..00c7548 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -418,12 +418,10 @@
                         parser.getRawDescriptors());
 
                 // Stats collection
-                if (parser.hasAudioInterface()) {
-                    StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, newDevice.getVendorId(),
-                            newDevice.getProductId(), parser.hasAudioInterface(),
-                            parser.hasHIDInterface(), parser.hasStorageInterface(),
-                            StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_CONNECTED, 0);
-                }
+                StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, newDevice.getVendorId(),
+                        newDevice.getProductId(), parser.hasAudioInterface(),
+                        parser.hasHIDInterface(), parser.hasStorageInterface(),
+                        StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_CONNECTED, 0);
             }
         }
 
@@ -455,14 +453,12 @@
                 if (current != null) {
                     UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress,
                             current.mDescriptors);
-                    if (parser.hasAudioInterface()) {
                         // Stats collection
-                        StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, device.getVendorId(),
-                                device.getProductId(), parser.hasAudioInterface(),
-                                parser.hasHIDInterface(),  parser.hasStorageInterface(),
-                                StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_DISCONNECTED,
-                                System.currentTimeMillis() - current.mTimestamp);
-                    }
+                    StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, device.getVendorId(),
+                            device.getProductId(), parser.hasAudioInterface(),
+                            parser.hasHIDInterface(),  parser.hasStorageInterface(),
+                            StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_DISCONNECTED,
+                            System.currentTimeMillis() - current.mTimestamp);
                 }
             } else {
                 Slog.d(TAG, "Removed device at " + deviceAddress + " was already gone");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index bbf3d45..613c4ff 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -371,14 +371,15 @@
         }
 
         private boolean shouldEnableService(Context context) {
-            // VoiceInteractionService should not be enabled on any low RAM devices
-            // or devices that have not declared the recognition feature, unless the
-            // device's configuration has explicitly set the config flag for a fixed
+            // VoiceInteractionService should not be enabled on devices that have not declared the
+            // recognition feature (including low-ram devices where notLowRam="true" takes effect),
+            // unless the device's configuration has explicitly set the config flag for a fixed
             // voice interaction service.
-            return (!ActivityManager.isLowRamDeviceStatic()
-                            && context.getPackageManager().hasSystemFeature(
-                                    PackageManager.FEATURE_VOICE_RECOGNIZERS)) ||
-                    getForceVoiceInteractionServicePackage(context.getResources()) != null;
+            if (getForceVoiceInteractionServicePackage(context.getResources()) != null) {
+                return true;
+            }
+            return context.getPackageManager()
+                    .hasSystemFeature(PackageManager.FEATURE_VOICE_RECOGNIZERS);
         }
 
         private String getForceVoiceInteractionServicePackage(Resources res) {
diff --git a/startop/view_compiler/apk_layout_compiler.cc b/startop/view_compiler/apk_layout_compiler.cc
index e95041b..09cdbd5 100644
--- a/startop/view_compiler/apk_layout_compiler.cc
+++ b/startop/view_compiler/apk_layout_compiler.cc
@@ -79,9 +79,9 @@
   return visitor.can_compile();
 }
 
-void CompileApkLayouts(const std::string& filename, CompilationTarget target,
-                       std::ostream& target_out) {
-  auto assets = android::ApkAssets::Load(filename);
+namespace {
+void CompileApkAssetsLayouts(const std::unique_ptr<const android::ApkAssets>& assets,
+                             CompilationTarget target, std::ostream& target_out) {
   android::AssetManager2 resources;
   resources.SetApkAssets({assets.get()});
 
@@ -155,5 +155,20 @@
     target_out.write(image.ptr<const char>(), image.size());
   }
 }
+}  // namespace
+
+void CompileApkLayouts(const std::string& filename, CompilationTarget target,
+                       std::ostream& target_out) {
+  auto assets = android::ApkAssets::Load(filename);
+  CompileApkAssetsLayouts(assets, target, target_out);
+}
+
+void CompileApkLayoutsFd(android::base::unique_fd fd, CompilationTarget target,
+                         std::ostream& target_out) {
+  constexpr const char* friendly_name{"viewcompiler assets"};
+  auto assets = android::ApkAssets::LoadFromFd(
+      std::move(fd), friendly_name, /*system=*/false, /*force_shared_lib=*/false);
+  CompileApkAssetsLayouts(assets, target, target_out);
+}
 
 }  // namespace startop
diff --git a/startop/view_compiler/apk_layout_compiler.h b/startop/view_compiler/apk_layout_compiler.h
index c85ddd6..03bd545 100644
--- a/startop/view_compiler/apk_layout_compiler.h
+++ b/startop/view_compiler/apk_layout_compiler.h
@@ -19,12 +19,16 @@
 
 #include <string>
 
+#include "android-base/unique_fd.h"
+
 namespace startop {
 
 enum class CompilationTarget { kJavaLanguage, kDex };
 
 void CompileApkLayouts(const std::string& filename, CompilationTarget target,
                        std::ostream& target_out);
+void CompileApkLayoutsFd(android::base::unique_fd fd, CompilationTarget target,
+                         std::ostream& target_out);
 
 }  // namespace startop
 
diff --git a/startop/view_compiler/main.cc b/startop/view_compiler/main.cc
index 871a421..11ecde2 100644
--- a/startop/view_compiler/main.cc
+++ b/startop/view_compiler/main.cc
@@ -49,6 +49,7 @@
 
 DEFINE_bool(apk, false, "Compile layouts in an APK");
 DEFINE_bool(dex, false, "Generate a DEX file instead of Java");
+DEFINE_int32(infd, -1, "Read input from the given file descriptor");
 DEFINE_string(out, kStdoutFilename, "Where to write the generated class");
 DEFINE_string(package, "", "The package name for the generated class (required)");
 
@@ -95,7 +96,7 @@
 int main(int argc, char** argv) {
   constexpr size_t kProgramName = 0;
   constexpr size_t kFileNameParam = 1;
-  constexpr size_t kNumRequiredArgs = 2;
+  constexpr size_t kNumRequiredArgs = 1;
 
   gflags::SetUsageMessage(
       "Compile XML layout files into equivalent Java language code\n"
@@ -104,12 +105,11 @@
   gflags::ParseCommandLineFlags(&argc, &argv, /*remove_flags*/ true);
 
   gflags::CommandLineFlagInfo cmd = gflags::GetCommandLineFlagInfoOrDie("package");
-  if (argc != kNumRequiredArgs || cmd.is_default) {
+  if (argc < kNumRequiredArgs || cmd.is_default) {
     gflags::ShowUsageWithFlags(argv[kProgramName]);
     return 1;
   }
 
-  const char* const filename = argv[kFileNameParam];
   const bool is_stdout = FLAGS_out == kStdoutFilename;
 
   std::ofstream outfile;
@@ -118,13 +118,23 @@
   }
 
   if (FLAGS_apk) {
-    startop::CompileApkLayouts(
-        filename,
-        FLAGS_dex ? startop::CompilationTarget::kDex : startop::CompilationTarget::kJavaLanguage,
-        is_stdout ? std::cout : outfile);
+    const startop::CompilationTarget target =
+        FLAGS_dex ? startop::CompilationTarget::kDex : startop::CompilationTarget::kJavaLanguage;
+    if (FLAGS_infd >= 0) {
+      startop::CompileApkLayoutsFd(
+          android::base::unique_fd{FLAGS_infd}, target, is_stdout ? std::cout : outfile);
+    } else {
+      if (argc < 2) {
+        gflags::ShowUsageWithFlags(argv[kProgramName]);
+        return 1;
+      }
+      const char* const filename = argv[kFileNameParam];
+      startop::CompileApkLayouts(filename, target, is_stdout ? std::cout : outfile);
+    }
     return 0;
   }
 
+  const char* const filename = argv[kFileNameParam];
   const string layout_name = startop::util::FindLayoutNameFromFilename(filename);
 
   XMLDocument xml;
diff --git a/telephony/java/android/telephony/AvailableNetworkInfo.java b/telephony/java/android/telephony/AvailableNetworkInfo.java
index fe07370..4da79b3 100644
--- a/telephony/java/android/telephony/AvailableNetworkInfo.java
+++ b/telephony/java/android/telephony/AvailableNetworkInfo.java
@@ -110,6 +110,7 @@
     private AvailableNetworkInfo(Parcel in) {
         mSubId = in.readInt();
         mPriority = in.readInt();
+        mMccMncs = new ArrayList<>();
         in.readStringList(mMccMncs);
     }
 
diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.aidl b/telephony/java/android/telephony/CarrierRestrictionRules.aidl
new file mode 100644
index 0000000..8b1f0b9
--- /dev/null
+++ b/telephony/java/android/telephony/CarrierRestrictionRules.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/** @hide */
+package android.telephony;
+
+parcelable CarrierRestrictionRules;
diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java
new file mode 100644
index 0000000..37847ae
--- /dev/null
+++ b/telephony/java/android/telephony/CarrierRestrictionRules.java
@@ -0,0 +1,277 @@
+/*
+ * 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.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.service.carrier.CarrierIdentifier;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Contains the list of carrier restrictions.
+ * Allowed list: it indicates the list of carriers that are allowed.
+ * Excluded list: it indicates the list of carriers that are excluded.
+ * Default carrier restriction: it indicates the default behavior and the priority between the two
+ * lists:
+ *  - not allowed: the device only allows usage of carriers that are present in the allowed list
+ *    and not present in the excluded list. This implies that if a carrier is not present in either
+ *    list, it is not allowed.
+ *  - allowed: the device allows all carriers, except those present in the excluded list and not
+ *    present in the allowed list. This implies that if a carrier is not present in either list,
+ *    it is allowed.
+ * MultiSim policy: it indicates the behavior in case of devices with two or more SIM cards.
+ *  - MULTISIM_POLICY_NONE: the same configuration is applied to all SIM slots independently. This
+ *    is the default value if none is set.
+ *  - MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT: it indicates that any SIM card can be used
+ *    as far as one SIM card matching the configuration is present in the device.
+ *
+ * Both lists support the character '?' as wild character. For example, an entry indicating
+ * MCC=310 and MNC=??? will match all networks with MCC=310.
+ *
+ * Example 1: Allowed list contains MCC and MNC of operator A. Excluded list contains operator B,
+ *            which has same MCC and MNC, but also GID1 value. The priority allowed list is set
+ *            to true. Only SIM cards of operator A are allowed, but not those of B or any other
+ *            operator.
+ * Example 2: Allowed list contains MCC and MNC of operator A. Excluded list contains an entry
+ *            with same MCC, and '???' as MNC. The priority allowed list is set to false.
+ *            SIM cards of operator A and all SIM cards with a different MCC value are allowed.
+ *            SIM cards of operators with same MCC value and different MNC are not allowed.
+ * @hide
+ */
+@SystemApi
+public final class CarrierRestrictionRules implements Parcelable {
+    /**
+     * The device only allows usage of carriers that are present in the allowed list and not
+     * present in the excluded list. This implies that if a carrier is not present in either list,
+     * it is not allowed.
+     */
+    public static final int CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED = 0;
+
+    /**
+     * The device allows all carriers, except those present in the excluded list and not present
+     * in the allowed list. This implies that if a carrier is not present in either list, it is
+     * allowed.
+     */
+    public static final int CARRIER_RESTRICTION_DEFAULT_ALLOWED = 1;
+
+    /** The same configuration is applied to all SIM slots independently. */
+    public static final int MULTISIM_POLICY_NONE = 0;
+
+    /** Any SIM card can be used as far as one SIM card matching the configuration is present. */
+    public static final int MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT = 1;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "MULTISIM_POLICY_",
+            value = {MULTISIM_POLICY_NONE, MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT})
+    public @interface MultiSimPolicy {}
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "CARRIER_RESTRICTION_DEFAULT_",
+            value = {CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED, CARRIER_RESTRICTION_DEFAULT_ALLOWED})
+    public @interface CarrierRestrictionDefault {}
+
+    private List<CarrierIdentifier> mAllowedCarriers;
+    private List<CarrierIdentifier> mExcludedCarriers;
+    @CarrierRestrictionDefault
+    private int mCarrierRestrictionDefault;
+    @MultiSimPolicy
+    private int mMultiSimPolicy;
+
+    private CarrierRestrictionRules() {
+        mAllowedCarriers = new ArrayList<CarrierIdentifier>();
+        mExcludedCarriers = new ArrayList<CarrierIdentifier>();
+        mCarrierRestrictionDefault = CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED;
+        mMultiSimPolicy = MULTISIM_POLICY_NONE;
+    }
+
+    private CarrierRestrictionRules(Parcel in) {
+        mAllowedCarriers = new ArrayList<CarrierIdentifier>();
+        mExcludedCarriers = new ArrayList<CarrierIdentifier>();
+
+        in.readTypedList(mAllowedCarriers, CarrierIdentifier.CREATOR);
+        in.readTypedList(mExcludedCarriers, CarrierIdentifier.CREATOR);
+        mCarrierRestrictionDefault = in.readInt();
+        mMultiSimPolicy = in.readInt();
+    }
+
+    /**
+     * Creates a new builder for this class
+     * @hide
+     */
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /**
+     * Indicates if all carriers are allowed
+     */
+    public boolean isAllCarriersAllowed() {
+        return (mAllowedCarriers.isEmpty() && mExcludedCarriers.isEmpty()
+                && mCarrierRestrictionDefault == CARRIER_RESTRICTION_DEFAULT_ALLOWED);
+    }
+
+    /**
+     * Retrieves list of allowed carriers
+     *
+     * @return the list of allowed carriers
+     */
+    public @NonNull List<CarrierIdentifier> getAllowedCarriers() {
+        return mAllowedCarriers;
+    }
+
+    /**
+     * Retrieves list of excluded carriers
+     *
+     * @return the list of excluded carriers
+     */
+    public @NonNull List<CarrierIdentifier> getExcludedCarriers() {
+        return mExcludedCarriers;
+    }
+
+    /**
+     * Retrieves the default behavior of carrier restrictions
+     */
+    public @CarrierRestrictionDefault int getDefaultCarrierRestriction() {
+        return mCarrierRestrictionDefault;
+    }
+
+    /**
+     * @return The policy used for multi-SIM devices
+     */
+    public @MultiSimPolicy int getMultiSimPolicy() {
+        return mMultiSimPolicy;
+    }
+
+    /**
+     * {@link Parcelable#writeToParcel}
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeTypedList(mAllowedCarriers);
+        out.writeTypedList(mExcludedCarriers);
+        out.writeInt(mCarrierRestrictionDefault);
+        out.writeInt(mMultiSimPolicy);
+    }
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@link Parcelable.Creator}
+     */
+    public static final Creator<CarrierRestrictionRules> CREATOR =
+            new Creator<CarrierRestrictionRules>() {
+        @Override
+        public CarrierRestrictionRules createFromParcel(Parcel in) {
+            return new CarrierRestrictionRules(in);
+        }
+
+        @Override
+        public CarrierRestrictionRules[] newArray(int size) {
+            return new CarrierRestrictionRules[size];
+        }
+    };
+
+    @Override
+    public String toString() {
+        return "CarrierRestrictionRules(allowed:" + mAllowedCarriers + ", excluded:"
+                + mExcludedCarriers + ", default:" + mCarrierRestrictionDefault
+                + ", multisim policy:" + mMultiSimPolicy + ")";
+    }
+
+    /**
+     * Builder for a {@link CarrierRestrictionRules}.
+     */
+    public static class Builder {
+        private final CarrierRestrictionRules mRules;
+
+        /** {@hide} */
+        public Builder() {
+            mRules = new CarrierRestrictionRules();
+        }
+
+        /** build command */
+        public CarrierRestrictionRules build() {
+            return mRules;
+        }
+
+        /**
+         * Indicate that all carriers are allowed.
+         */
+        public Builder setAllCarriersAllowed() {
+            mRules.mAllowedCarriers.clear();
+            mRules.mExcludedCarriers.clear();
+            mRules.mCarrierRestrictionDefault = CARRIER_RESTRICTION_DEFAULT_ALLOWED;
+            return this;
+        }
+
+        /**
+         * Set list of allowed carriers.
+         *
+         * @param allowedCarriers list of allowed carriers
+         */
+        public Builder setAllowedCarriers(List<CarrierIdentifier> allowedCarriers) {
+            mRules.mAllowedCarriers = new ArrayList<CarrierIdentifier>(allowedCarriers);
+            return this;
+        }
+
+        /**
+         * Set list of excluded carriers.
+         *
+         * @param excludedCarriers list of excluded carriers
+         */
+        public Builder setExcludedCarriers(List<CarrierIdentifier> excludedCarriers) {
+            mRules.mExcludedCarriers = new ArrayList<CarrierIdentifier>(excludedCarriers);
+            return this;
+        }
+
+        /**
+         * Set the default behavior of the carrier restrictions
+         *
+         * @param carrierRestrictionDefault prioritized carrier list
+         */
+        public Builder setDefaultCarrierRestriction(
+                @CarrierRestrictionDefault int carrierRestrictionDefault) {
+            mRules.mCarrierRestrictionDefault = carrierRestrictionDefault;
+            return this;
+        }
+
+        /**
+         * Set the policy to be used for multi-SIM devices
+         *
+         * @param multiSimPolicy multi SIM policy
+         */
+        public Builder setMultiSimPolicy(@MultiSimPolicy int multiSimPolicy) {
+            mRules.mMultiSimPolicy = multiSimPolicy;
+            return this;
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/CellConfigLte.java b/telephony/java/android/telephony/CellConfigLte.java
index 35769f0..eafbfbc 100644
--- a/telephony/java/android/telephony/CellConfigLte.java
+++ b/telephony/java/android/telephony/CellConfigLte.java
@@ -34,6 +34,11 @@
     }
 
     /** @hide */
+    public CellConfigLte(android.hardware.radio.V1_4.CellConfigLte cellConfig) {
+        mIsEndcAvailable = cellConfig.isEndcAvailable;
+    }
+
+    /** @hide */
     public CellConfigLte(boolean isEndcAvailable) {
         mIsEndcAvailable = isEndcAvailable;
     }
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index b761bd7..8ce5c54 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -19,8 +19,10 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
+import android.hardware.radio.V1_4.CellInfo.Info;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.SystemClock;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -318,6 +320,13 @@
     }
 
     /** @hide */
+    protected CellInfo(android.hardware.radio.V1_4.CellInfo ci) {
+        this.mRegistered = ci.isRegistered;
+        this.mTimeStamp = SystemClock.elapsedRealtimeNanos();
+        this.mCellConnectionStatus = ci.connectionStatus;
+    }
+
+    /** @hide */
     public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) {
         if (ci == null) return null;
         switch(ci.cellInfoType) {
@@ -342,4 +351,17 @@
             default: return null;
         }
     }
+
+    /** @hide */
+    public static CellInfo create(android.hardware.radio.V1_4.CellInfo ci) {
+        if (ci == null) return null;
+        switch (ci.info.getDiscriminator()) {
+            case Info.hidl_discriminator.gsm: return new CellInfoGsm(ci);
+            case Info.hidl_discriminator.cdma: return new CellInfoCdma(ci);
+            case Info.hidl_discriminator.lte: return new CellInfoLte(ci);
+            case Info.hidl_discriminator.wcdma: return new CellInfoWcdma(ci);
+            case Info.hidl_discriminator.tdscdma: return new CellInfoTdscdma(ci);
+            default: return null;
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index c9f07da..4440108 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -67,6 +67,15 @@
             new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
     }
 
+    /** @hide */
+    public CellInfoCdma(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoCdma cic = ci.info.cdma();
+        mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
+        mCellSignalStrengthCdma =
+                new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
+    }
+
     @Override
     public CellIdentityCdma getCellIdentity() {
         return mCellIdentityCdma;
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index ad16dfa..248adfc 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -63,6 +63,14 @@
         mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
     }
 
+    /** @hide */
+    public CellInfoGsm(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoGsm cig = ci.info.gsm();
+        mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
+        mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
+    }
+
     @Override
     public CellIdentityGsm getCellIdentity() {
         return mCellIdentityGsm;
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 7593831..8e8ce8a 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -70,6 +70,15 @@
         mCellConfig = new CellConfigLte();
     }
 
+    /** @hide */
+    public CellInfoLte(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_4.CellInfoLte cil = ci.info.lte();
+        mCellIdentityLte = new CellIdentityLte(cil.base.cellIdentityLte);
+        mCellSignalStrengthLte = new CellSignalStrengthLte(cil.base.signalStrengthLte);
+        mCellConfig = new CellConfigLte(cil.cellConfig);
+    }
+
     @Override
     public CellIdentityLte getCellIdentity() {
         if (DBG) log("getCellIdentity: " + mCellIdentityLte);
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index a8c49b7..2ab38fb 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -64,6 +64,14 @@
         mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
     }
 
+    /** @hide */
+    public CellInfoTdscdma(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoTdscdma cit = ci.info.tdscdma();
+        mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
+        mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
+    }
+
     @Override public CellIdentityTdscdma getCellIdentity() {
         return mCellIdentityTdscdma;
     }
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index a427e80..65e0470 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -63,6 +63,14 @@
         mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
     }
 
+    /** @hide */
+    public CellInfoWcdma(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoWcdma ciw = ci.info.wcdma();
+        mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
+        mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
+    }
+
     @Override
     public CellIdentityWcdma getCellIdentity() {
         return mCellIdentityWcdma;
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index c816701..9fee593 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -805,9 +805,11 @@
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
             if (psl == null) return;
 
-            Binder.withCleanCallingIdentity(
-                    () -> mExecutor.execute(
-                            () -> psl.onDataConnectionStateChanged(state, networkType)));
+            Binder.withCleanCallingIdentity(() -> mExecutor.execute(
+                    () -> {
+                        psl.onDataConnectionStateChanged(state, networkType);
+                        psl.onDataConnectionStateChanged(state);
+                    }));
         }
 
         public void onDataActivity(int direction) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index babeb7b..75b1177 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9055,6 +9055,8 @@
      * <p>This method works only on devices with {@link
      * android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled.
      *
+     * @deprecated use setCarrierRestrictionRules instead
+     *
      * @return The number of carriers set successfully. Should be length of
      * carrierList on success; -1 if carrierList null or on error.
      * @hide
@@ -9062,44 +9064,144 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public int setAllowedCarriers(int slotIndex, List<CarrierIdentifier> carriers) {
+        // Execute the method setCarrierRestrictionRules with an empty excluded list and
+        // indicating priority for the allowed list.
+        CarrierRestrictionRules carrierRestrictionRules = CarrierRestrictionRules.newBuilder()
+                .setAllowedCarriers(carriers)
+                .setDefaultCarrierRestriction(
+                    CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED)
+                .build();
+
+        int result = setCarrierRestrictionRules(carrierRestrictionRules);
+
+        // Convert boolean result into int, as required by this method.
+        if (result == SET_CARRIER_RESTRICTION_SUCCESS) {
+            return carriers.size();
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * The carrier restrictions were successfully set.
+     * @hide
+     */
+    @SystemApi
+    public static final int SET_CARRIER_RESTRICTION_SUCCESS = 0;
+
+    /**
+     * The carrier restrictions were not set due to lack of support in the modem. This can happen
+     * if the modem does not support setting the carrier restrictions or if the configuration
+     * passed in the {@code setCarrierRestrictionRules} is not supported by the modem.
+     * @hide
+     */
+    @SystemApi
+    public static final int SET_CARRIER_RESTRICTION_NOT_SUPPORTED = 1;
+
+    /**
+     * The setting of carrier restrictions failed.
+     * @hide
+     */
+    @SystemApi
+    public static final int SET_CARRIER_RESTRICTION_ERROR = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"SET_CARRIER_RESTRICTION_"},
+            value = {
+                    SET_CARRIER_RESTRICTION_SUCCESS,
+                    SET_CARRIER_RESTRICTION_NOT_SUPPORTED,
+                    SET_CARRIER_RESTRICTION_ERROR
+            })
+    public @interface SetCarrierRestrictionResult {}
+
+    /**
+     * Set the allowed carrier list and the excluded carrier list indicating the priority between
+     * the two lists.
+     * Requires system privileges.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+     *
+     * <p>This method works only on devices with {@link
+     * android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled.
+     *
+     * @return {@link #SET_CARRIER_RESTRICTION_SUCCESS} in case of success.
+     * {@link #SET_CARRIER_RESTRICTION_NOT_SUPPORTED} if the modem does not support the
+     * configuration. {@link #SET_CARRIER_RESTRICTION_ERROR} in all other error cases.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @SetCarrierRestrictionResult
+    public int setCarrierRestrictionRules(@NonNull CarrierRestrictionRules rules) {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                return service.setAllowedCarriers(slotIndex, carriers);
+                return service.setAllowedCarriers(rules);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#setAllowedCarriers", e);
         } catch (NullPointerException e) {
             Log.e(TAG, "Error calling ITelephony#setAllowedCarriers", e);
         }
-        return -1;
+        return SET_CARRIER_RESTRICTION_ERROR;
     }
 
     /**
      * Get the allowed carrier list for slotIndex.
-     * Require system privileges. In the future we may add this to carrier APIs.
+     * Requires system privileges.
      *
      * <p>This method returns valid data on devices with {@link
      * android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled.
      *
+     * @deprecated Apps should use {@link getCarriersRestrictionRules} to retrieve the list of
+     * allowed and excliuded carriers, as the result of this API is valid only when the excluded
+     * list is empty. This API could return an empty list, even if some restrictions are present.
+     *
      * @return List of {@link android.telephony.CarrierIdentifier}; empty list
      * means all carriers are allowed.
      * @hide
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public List<CarrierIdentifier> getAllowedCarriers(int slotIndex) {
+        CarrierRestrictionRules carrierRestrictionRule = getCarrierRestrictionRules();
+        if (carrierRestrictionRule != null) {
+            return carrierRestrictionRule.getAllowedCarriers();
+        }
+        return new ArrayList<CarrierIdentifier>(0);
+    }
+
+    /**
+     * Get the allowed carrier list and the excluded carrier list indicating the priority between
+     * the two lists.
+     * Require system privileges. In the future we may add this to carrier APIs.
+     *
+     * <p>This method returns valid data on devices with {@link
+     * android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled.
+     *
+     * @return {@link CarrierRestrictionRules} which contains the allowed carrier list and the
+     * excluded carrier list with the priority between the two lists. Returns {@code null}
+     * in case of error.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @Nullable
+    public CarrierRestrictionRules getCarrierRestrictionRules() {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                return service.getAllowedCarriers(slotIndex);
+                return service.getAllowedCarriers();
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#getAllowedCarriers", e);
         } catch (NullPointerException e) {
             Log.e(TAG, "Error calling ITelephony#getAllowedCarriers", e);
         }
-        return new ArrayList<CarrierIdentifier>(0);
+        return null;
     }
 
     /**
@@ -9963,7 +10065,7 @@
         boolean ret = false;
         try {
             IOns iOpportunisticNetworkService = getIOns();
-            if (iOpportunisticNetworkService != null) {
+            if (iOpportunisticNetworkService != null && availableNetworks != null) {
                 ret = iOpportunisticNetworkService.updateAvailableNetworks(availableNetworks,
                         pkgForDebug);
             }
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index a5f56bb..e68256d 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -27,6 +27,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
@@ -176,6 +177,12 @@
      * Bit-field which indicates the number is from the platform-maintained database.
      */
     public static final int EMERGENCY_NUMBER_SOURCE_DATABASE =  1 << 4;
+    /**
+     * Bit-field which indicates the number is from test mode.
+     *
+     * @hide
+     */
+    public static final int EMERGENCY_NUMBER_SOURCE_TEST =  1 << 5;
     /** Bit-field which indicates the number is from the modem config. */
     public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG =
             EmergencyNumberSource.MODEM_CONFIG;
@@ -327,6 +334,21 @@
     }
 
     /**
+     * Returns the bitmask of emergency service categories of the emergency number for
+     * internal dialing.
+     *
+     * @return bitmask of the emergency service categories
+     *
+     * @hide
+     */
+    public @EmergencyServiceCategories int getEmergencyServiceCategoryBitmaskInternalDial() {
+        if (mEmergencyNumberSourceBitmask == EMERGENCY_NUMBER_SOURCE_DATABASE) {
+            return EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED;
+        }
+        return mEmergencyServiceCategoryBitmask;
+    }
+
+    /**
      * Returns the emergency service categories of the emergency number.
      *
      * Note: if the emergency number is in {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}, only
@@ -577,6 +599,7 @@
                 emergencyNumberList.remove(i--);
             }
         }
+        Collections.sort(emergencyNumberList);
     }
 
     /**
@@ -613,6 +636,12 @@
         if (first.getEmergencyCallRouting() != second.getEmergencyCallRouting()) {
             return false;
         }
+        // Never merge two numbers if one of them is from test mode but the other one is not;
+        // This supports to remove a number from the test mode.
+        if (first.isFromSources(EMERGENCY_NUMBER_SOURCE_TEST)
+                ^ second.isFromSources(EMERGENCY_NUMBER_SOURCE_TEST)) {
+            return false;
+        }
         return true;
     }
 
@@ -638,4 +667,13 @@
         }
         return null;
     }
+
+    /**
+     * Validate Emergency Number address that only allows '0'-'9', '*', or '#'
+     *
+     * @hide
+     */
+    public static boolean validateEmergencyNumberAddress(String address) {
+        return address.matches("[0-9*#]+");
+    }
 }
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index cc9befe..42a788d 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -30,6 +30,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.telephony.TelephonyManager;
 
 import com.android.internal.telephony.euicc.IEuiccController;
 
@@ -40,7 +41,11 @@
  * EuiccManager is the application interface to eUICCs, or eSIMs/embedded SIMs.
  *
  * <p>You do not instantiate this class directly; instead, you retrieve an instance through
- * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}.
+ * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}. This instance will be
+ * created using the default eUICC.
+ *
+ * <p>On a device with multiple eUICCs, you may want to create multiple EuiccManagers. To do this
+ * you can call {@link #createForCardId}.
  *
  * <p>See {@link #isEnabled} before attempting to use these APIs.
  */
@@ -318,10 +323,29 @@
     public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5;
 
     private final Context mContext;
+    private final int mCardId;
 
     /** @hide */
     public EuiccManager(Context context) {
         mContext = context;
+        TelephonyManager tm = (TelephonyManager)
+                context.getSystemService(Context.TELEPHONY_SERVICE);
+        mCardId = tm.getCardIdForDefaultEuicc();
+    }
+
+    /** @hide */
+    private EuiccManager(Context context, int cardId) {
+        mContext = context;
+        mCardId = cardId;
+    }
+
+    /**
+     * Create a new EuiccManager object pinned to the given card ID.
+     *
+     * @return an EuiccManager that uses the given card ID for all calls.
+     */
+    public EuiccManager createForCardId(int cardId) {
+        return new EuiccManager(mContext, cardId);
     }
 
     /**
@@ -344,7 +368,8 @@
      * Returns the EID identifying the eUICC hardware.
      *
      * <p>Requires that the calling app has carrier privileges on the active subscription on the
-     * eUICC.
+     * current eUICC. A calling app with carrier privileges for one eUICC may not necessarily have
+     * access to the EID of another eUICC.
      *
      * @return the EID. May be null if {@link #isEnabled()} is false or the eUICC is not ready.
      */
@@ -354,7 +379,7 @@
             return null;
         }
         try {
-            return getIEuiccController().getEid();
+            return getIEuiccController().getEid(mCardId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -377,7 +402,7 @@
             return EUICC_OTA_STATUS_UNAVAILABLE;
         }
         try {
-            return getIEuiccController().getOtaStatus();
+            return getIEuiccController().getOtaStatus(mCardId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -387,10 +412,10 @@
      * Attempt to download the given {@link DownloadableSubscription}.
      *
      * <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
-     * or the calling app must be authorized to manage both the currently-active subscription and
-     * the subscription to be downloaded according to the subscription metadata. Without the former,
-     * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
-     * intent to prompt the user to accept the download.
+     * or the calling app must be authorized to manage both the currently-active subscription on the
+     * current eUICC and the subscription to be downloaded according to the subscription metadata.
+     * Without the former, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be
+     * returned in the callback intent to prompt the user to accept the download.
      *
      * @param subscription the subscription to download.
      * @param switchAfterDownload if true, the profile will be activated upon successful download.
@@ -404,7 +429,7 @@
             return;
         }
         try {
-            getIEuiccController().downloadSubscription(subscription, switchAfterDownload,
+            getIEuiccController().downloadSubscription(mCardId, subscription, switchAfterDownload,
                     mContext.getOpPackageName(), null /* resolvedBundle */, callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -471,7 +496,7 @@
             return;
         }
         try {
-            getIEuiccController().continueOperation(resolutionIntent, resolutionExtras);
+            getIEuiccController().continueOperation(mCardId, resolutionIntent, resolutionExtras);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -503,8 +528,8 @@
             return;
         }
         try {
-            getIEuiccController().getDownloadableSubscriptionMetadata(
-                    subscription, mContext.getOpPackageName(), callbackIntent);
+            getIEuiccController().getDownloadableSubscriptionMetadata(mCardId, subscription,
+                    mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -533,7 +558,7 @@
             return;
         }
         try {
-            getIEuiccController().getDefaultDownloadableSubscriptionList(
+            getIEuiccController().getDefaultDownloadableSubscriptionList(mCardId,
                     mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -552,7 +577,7 @@
             return null;
         }
         try {
-            return getIEuiccController().getEuiccInfo();
+            return getIEuiccController().getEuiccInfo(mCardId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -578,7 +603,7 @@
             return;
         }
         try {
-            getIEuiccController().deleteSubscription(
+            getIEuiccController().deleteSubscription(mCardId,
                     subscriptionId, mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -606,7 +631,7 @@
             return;
         }
         try {
-            getIEuiccController().switchToSubscription(
+            getIEuiccController().switchToSubscription(mCardId,
                     subscriptionId, mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -632,7 +657,7 @@
             return;
         }
         try {
-            getIEuiccController().updateSubscriptionNickname(
+            getIEuiccController().updateSubscriptionNickname(mCardId,
                     subscriptionId, nickname, mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -656,7 +681,7 @@
             return;
         }
         try {
-            getIEuiccController().eraseSubscriptions(callbackIntent);
+            getIEuiccController().eraseSubscriptions(mCardId, callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -686,7 +711,7 @@
             return;
         }
         try {
-            getIEuiccController().retainSubscriptionsForFactoryReset(callbackIntent);
+            getIEuiccController().retainSubscriptionsForFactoryReset(mCardId, callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 525a96a..59167b7 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -347,6 +347,9 @@
     private @EmergencyCallRouting int mEmergencyCallRouting =
             EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN;
 
+    /** Indicates if the call is for testing purpose */
+    private boolean mEmergencyCallTesting = false;
+
     /**
      * Extras associated with this {@link ImsCallProfile}.
      * <p>
@@ -534,9 +537,10 @@
                 + ", callType=" + mCallType
                 + ", restrictCause=" + mRestrictCause
                 + ", mediaProfile=" + mMediaProfile.toString()
-                + ", emergencyServiceCategories=" + mEmergencyCallRouting
+                + ", emergencyServiceCategories=" + mEmergencyServiceCategories
                 + ", emergencyUrns=" + mEmergencyUrns
-                + ", emergencyCallRouting=" + mEmergencyCallRouting + " }";
+                + ", emergencyCallRouting=" + mEmergencyCallRouting
+                + ", emergencyCallTesting=" + mEmergencyCallTesting + " }";
     }
 
     @Override
@@ -554,6 +558,7 @@
         out.writeInt(mEmergencyServiceCategories);
         out.writeStringList(mEmergencyUrns);
         out.writeInt(mEmergencyCallRouting);
+        out.writeBoolean(mEmergencyCallTesting);
     }
 
     private void readFromParcel(Parcel in) {
@@ -564,6 +569,7 @@
         mEmergencyServiceCategories = in.readInt();
         mEmergencyUrns = in.createStringArrayList();
         mEmergencyCallRouting = in.readInt();
+        mEmergencyCallTesting = in.readBoolean();
     }
 
     public static final Creator<ImsCallProfile> CREATOR = new Creator<ImsCallProfile>() {
@@ -784,9 +790,11 @@
      * @hide
      */
     public void setEmergencyCallInfo(EmergencyNumber num) {
-        setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmask());
+        setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmaskInternalDial());
         setEmergencyUrns(num.getEmergencyUrns());
         setEmergencyCallRouting(num.getEmergencyCallRouting());
+        setEmergencyCallTesting(num.getEmergencyNumberSourceBitmask()
+                == EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST);
     }
 
     /**
@@ -843,6 +851,15 @@
     }
 
     /**
+     * Set if this is for testing emergency call, only valid if {@link #getServiceType} returns
+     * {@link #SERVICE_TYPE_EMERGENCY}.
+     */
+    @VisibleForTesting
+    public void setEmergencyCallTesting(boolean isTesting) {
+        mEmergencyCallTesting = isTesting;
+    }
+
+    /**
      * Get the emergency service categories, only valid if {@link #getServiceType} returns
      * {@link #SERVICE_TYPE_EMERGENCY}
      *
@@ -892,4 +909,11 @@
     public @EmergencyCallRouting int getEmergencyCallRouting() {
         return mEmergencyCallRouting;
     }
+
+    /**
+     * Get if the emergency call is for testing purpose.
+     */
+    public boolean isEmergencyCallTesting() {
+        return mEmergencyCallTesting;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index e2350fe..9414abd 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -92,7 +92,7 @@
     public static final int WIFI_MODE_WIFI_PREFERRED = 2;
 
     /**
-     * Callback class for receiving Registration callback events.
+     * Callback class for receiving IMS network Registration callback events.
      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback)
      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
      */
@@ -241,7 +241,8 @@
     }
 
     /**
-     * Receives IMS capability status updates from the ImsService.
+     * Receives IMS capability status updates from the ImsService. This information is also
+     * available via the {@link #isAvailable(int, int)} method below.
      *
      * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback)
      * @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
@@ -290,6 +291,8 @@
          * If unavailable, the feature is not able to support the unavailable capability at this
          * time.
          *
+         * This information can also be queried using the {@link #isAvailable(int, int)} API.
+         *
          * @param capabilities The new availability of the capabilities.
          */
         public void onCapabilitiesStatusChanged(
@@ -304,7 +307,7 @@
         /**@hide*/
         // Only exposed as public method for compatibility with deprecated ImsManager APIs.
         // TODO: clean up dependencies and change back to private visibility.
-        public void setExecutor(Executor executor) {
+        public final void setExecutor(Executor executor) {
             mBinder.setExecutor(executor);
         }
     }
@@ -342,8 +345,7 @@
      * Registers a {@link RegistrationCallback} with the system, which will provide registration
      * updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}. Use
      * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
-     * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up
-     * after a subscription is removed.
+     * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
      *
      * When the callback is registered, it will initiate the callback c to be called with the
      * current registration state.
@@ -351,6 +353,12 @@
      * @param executor The executor the callback events should be run on.
      * @param c The {@link RegistrationCallback} to be added.
      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
+     * @throws IllegalArgumentException if the subscription associated with this callback is not
+     * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
+     * {@link CapabilityCallback} callback.
+     * @throws IllegalStateException if the subscription associated with this callback is valid, but
+     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the service crashed, for example.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void registerImsRegistrationCallback(@CallbackExecutor Executor executor,
@@ -370,11 +378,17 @@
     }
 
     /**
-     * Removes an existing {@link RegistrationCallback}. Ensure to call this method when cleaning
-     * up to avoid memory leaks or when the subscription is removed.
+     * Removes an existing {@link RegistrationCallback}.
+     *
+     * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+     * etc...), this callback will automatically be removed. If this method is called for an
+     * inactive subscription, it will result in a no-op.
+     *
      * @param c The {@link RegistrationCallback} to be removed.
      * @see SubscriptionManager.OnSubscriptionsChangedListener
      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
+     * @throws IllegalArgumentException if the subscription ID associated with this callback is
+     * invalid.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
@@ -389,12 +403,14 @@
     }
 
     /**
-     * Registers a {@link CapabilityCallback} with the system, which will provide MmTel capability
-     * updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}.
+     * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
+     * availability updates for the subscription specified in
+     * {@link #createForSubscriptionId(Context, int)}. The method {@link #isAvailable(int, int)}
+     * can also be used to query this information at any time.
+     *
      * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
      * subscription changed events and call
-     * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up after a
-     * subscription is removed.
+     * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
      *
      * When the callback is registered, it will initiate the callback c to be called with the
      * current capabilities.
@@ -402,9 +418,15 @@
      * @param executor The executor the callback events should be run on.
      * @param c The MmTel {@link CapabilityCallback} to be registered.
      * @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
+     * @throws IllegalArgumentException if the subscription associated with this callback is not
+     * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
+     * {@link CapabilityCallback} callback.
+     * @throws IllegalStateException if the subscription associated with this callback is valid, but
+     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the service crashed, for example.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void registerMmTelCapabilityCallback(@CallbackExecutor Executor executor,
+    public void registerMmTelCapabilityCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull CapabilityCallback c) {
         if (c == null) {
             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
@@ -421,10 +443,15 @@
     }
 
     /**
-     * Removes an existing MmTel {@link CapabilityCallback}. Be sure to call this when cleaning
-     * up to avoid memory leaks.
+     * Removes an existing MmTel {@link CapabilityCallback}.
+     *
+     * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+     * etc...), this callback will automatically be removed. If this method is called for an
+     * inactive subscription, it will result in a no-op.
      * @param c The MmTel {@link CapabilityCallback} to be removed.
      * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback)
+     * @throws IllegalArgumentException if the subscription ID associated with this callback is
+     * invalid.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 916e282..d37198a 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -133,33 +133,40 @@
     }
 
     /**
-     * Register a new {@link Callback} to listen to changes to changes in
-     * IMS provisioning. Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
-     * Subscription changed events and call
-     * {@link #unregisterProvisioningChangedCallback(Callback)} to clean up after a
-     * subscription is removed.
+     * Register a new {@link Callback} to listen to changes to changes in IMS provisioning.
+     *
+     * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+     * etc...), this callback will automatically be removed.
      * @param executor The {@link Executor} to call the callback methods on
      * @param callback The provisioning callbackto be registered.
      * @see #unregisterProvisioningChangedCallback(Callback)
      * @see SubscriptionManager.OnSubscriptionsChangedListener
+     * @throws IllegalArgumentException if the subscription associated with this callback is not
+     * active (SIM is not inserted, ESIM inactive) or the subscription is invalid.
+     * @throws IllegalStateException if the subscription associated with this callback is valid, but
+     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the service crashed, for example.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void registerProvisioningChangedCallback(@CallbackExecutor Executor executor,
             @NonNull Callback callback) {
         callback.setExecutor(executor);
         try {
-            getITelephony().registerImsProvisioningChangedCallback(mSubId,
-                    callback.getBinder());
+            getITelephony().registerImsProvisioningChangedCallback(mSubId, callback.getBinder());
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
     }
 
     /**
-     * Unregister an existing {@link Callback}. Ensure to call this method when cleaning
-     * up to avoid memory leaks or when the subscription is removed.
+     * Unregister an existing {@link Callback}. When the subscription associated with this
+     * callback is removed (SIM removed, ESIM swap, etc...), this callback will automatically be
+     * removed. If this method is called for an inactive subscription, it will result in a no-op.
      * @param callback The existing {@link Callback} to be removed.
      * @see #registerProvisioningChangedCallback(Executor, Callback)
+     *
+     * @throws IllegalArgumentException if the subscription associated with this callback is
+     * invalid.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterProvisioningChangedCallback(@NonNull Callback callback) {
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 96f7a1b..17516bc2 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -66,7 +66,8 @@
     public static final int EVENT_DATA_CONNECTION_DETACHED = BASE + 9;
     public static final int EVENT_ROAMING_ON = BASE + 11;
     public static final int EVENT_ROAMING_OFF = BASE + 12;
-    public static final int EVENT_ENABLE_NEW_APN = BASE + 13;
+    public static final int EVENT_ENABLE_APN = BASE + 13;
+    public static final int EVENT_DISABLE_APN = BASE + 14;
     public static final int EVENT_DISCONNECT_DONE = BASE + 15;
     public static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16;
     public static final int EVENT_DATA_STALL_ALARM = BASE + 17;
@@ -92,6 +93,7 @@
     public static final int EVENT_DATA_RECONNECT = BASE + 47;
     public static final int EVENT_ROAMING_SETTING_CHANGE = BASE + 48;
     public static final int EVENT_DATA_SERVICE_BINDING_CHANGED = BASE + 49;
+    public static final int EVENT_DEVICE_PROVISIONED_CHANGE = BASE + 50;
 
     /***** Constants *****/
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index c5d82c5..62b9d36 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -28,6 +28,7 @@
 import android.service.carrier.CarrierIdentifier;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telephony.CarrierRestrictionRules;
 import android.telephony.CellInfo;
 import android.telephony.ClientRequestStats;
 import android.telephony.IccOpenLogicalChannelResponse;
@@ -41,6 +42,7 @@
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyHistogram;
 import android.telephony.VisualVoicemailSmsFilterSettings;
+import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
 import android.telephony.ims.aidl.IImsConfig;
 import android.telephony.ims.aidl.IImsConfigCallback;
@@ -1292,22 +1294,27 @@
     List<TelephonyHistogram> getTelephonyHistograms();
 
     /**
-     * Set the allowed carrier list for slotIndex
-     * Require system privileges. In the future we may add this to carrier APIs.
+     * Set the allowed carrier list and the excluded carrier list, indicating the priority between
+     * the two lists.
      *
-     * @return The number of carriers set successfully. Should match length of
-     * carriers on success.
+     * <p>Requires system privileges. In the future we may add this to carrier APIs.
+     *
+     * @return {@link #SET_CARRIER_RESTRICTION_SUCCESS} in case of success.
+     * {@link #SET_CARRIER_RESTRICTION_NOT_SUPPORTED} if the modem does not support the
+     * configuration. {@link #SET_CARRIER_RESTRICTION_ERROR} in all other error cases.
      */
-    int setAllowedCarriers(int slotIndex, in List<CarrierIdentifier> carriers);
+    int setAllowedCarriers(in CarrierRestrictionRules carrierRestrictionRules);
 
     /**
-     * Get the allowed carrier list for slotIndex.
-     * Require system privileges. In the future we may add this to carrier APIs.
+     * Get the allowed carrier list and the excluded carrier list indicating the priority between
+     * the two lists.
      *
-     * @return List of {@link android.service.carrier.CarrierIdentifier}; empty list
-     * means all carriers are allowed.
+     * <p>Requires system privileges. In the future we may add this to carrier APIs.
+     *
+     * @return {@link CarrierRestrictionRules}; empty lists mean all carriers are allowed. It
+     * returns null in case of error.
      */
-    List<CarrierIdentifier> getAllowedCarriers(int slotIndex);
+    CarrierRestrictionRules getAllowedCarriers();
 
    /**
      * Returns carrier id of the given subscription.
@@ -1776,4 +1783,14 @@
      * Set the String provisioning value for the provisioning key specified.
      */
     int setImsProvisioningString(int subId, int key, String value);
+
+    /**
+     * Update Emergency Number List for Test Mode.
+     */
+    void updateEmergencyNumberListTestMode(int action, in EmergencyNumber num);
+
+    /**
+     * Get the full emergency number list for Test Mode.
+     */
+    List<String> getEmergencyNumberListTestMode();
 }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 2a648bd..8523554 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -501,4 +501,18 @@
      */
     public static final String ACTION_LINE1_NUMBER_ERROR_DETECTED =
             "com.android.internal.telephony.ACTION_LINE1_NUMBER_ERROR_DETECTED";
+
+    /**
+     * Broadcast action to notify radio bug.
+     *
+     * Requires the READ_PRIVILEGED_PHONE_STATE permission.
+     *
+     * @hide
+     */
+    public static final String ACTION_REPORT_RADIO_BUG =
+            "com.android.internal.telephony.ACTION_REPORT_RADIO_BUG";
+
+    // ACTION_REPORT_RADIO_BUG extra keys
+    public static final String EXTRA_SLOT_ID = "slotId";
+    public static final String EXTRA_RADIO_BUG_TYPE = "radioBugType";
 }
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index dd40d56..14a36c8 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -24,22 +24,25 @@
 
 /** @hide */
 interface IEuiccController {
-    oneway void continueOperation(in Intent resolutionIntent, in Bundle resolutionExtras);
-    oneway void getDownloadableSubscriptionMetadata(in DownloadableSubscription subscription,
+    oneway void continueOperation(int cardId, in Intent resolutionIntent,
+            in Bundle resolutionExtras);
+    oneway void getDownloadableSubscriptionMetadata(int cardId,
+            in DownloadableSubscription subscription,
         String callingPackage, in PendingIntent callbackIntent);
-    oneway void getDefaultDownloadableSubscriptionList(
+    oneway void getDefaultDownloadableSubscriptionList(int cardId,
         String callingPackage, in PendingIntent callbackIntent);
-    String getEid();
-    int getOtaStatus();
-    oneway void downloadSubscription(in DownloadableSubscription subscription,
-        boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle, in PendingIntent callbackIntent);
-    EuiccInfo getEuiccInfo();
-    oneway void deleteSubscription(int subscriptionId, String callingPackage,
+    String getEid(int cardId);
+    int getOtaStatus(int cardId);
+    oneway void downloadSubscription(int cardId, in DownloadableSubscription subscription,
+        boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle,
         in PendingIntent callbackIntent);
-    oneway void switchToSubscription(int subscriptionId, String callingPackage,
+    EuiccInfo getEuiccInfo(int cardId);
+    oneway void deleteSubscription(int cardId, int subscriptionId, String callingPackage,
         in PendingIntent callbackIntent);
-    oneway void updateSubscriptionNickname(int subscriptionId, String nickname,
+    oneway void switchToSubscription(int cardId, int subscriptionId, String callingPackage,
+        in PendingIntent callbackIntent);
+    oneway void updateSubscriptionNickname(int cardId, int subscriptionId, String nickname,
         String callingPackage, in PendingIntent callbackIntent);
-    oneway void eraseSubscriptions(in PendingIntent callbackIntent);
-    oneway void retainSubscriptionsForFactoryReset(in PendingIntent callbackIntent);
-}
\ No newline at end of file
+    oneway void eraseSubscriptions(int cardId, in PendingIntent callbackIntent);
+    oneway void retainSubscriptionsForFactoryReset(int cardId, in PendingIntent callbackIntent);
+}
diff --git a/test-base/api/current.txt b/test-base/api/current.txt
index 7ebd6aa..91fcca5 100644
--- a/test-base/api/current.txt
+++ b/test-base/api/current.txt
@@ -48,6 +48,9 @@
     method public abstract void startTiming(boolean);
   }
 
+  public abstract deprecated class RepetitiveTest implements java.lang.annotation.Annotation {
+  }
+
   public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation {
   }
 
diff --git a/test-base/src/android/test/RepetitiveTest.java b/test-base/src/android/test/RepetitiveTest.java
index 6a7130e..13e89d2 100644
--- a/test-base/src/android/test/RepetitiveTest.java
+++ b/test-base/src/android/test/RepetitiveTest.java
@@ -26,8 +26,10 @@
  * When the annotation is present, the test method is executed the number of times specified by
  * numIterations and defaults to 1.
  *
- * {@hide} Not needed for public API.
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Target(ElementType.METHOD)
 @Retention(RetentionPolicy.RUNTIME)
 public @interface RepetitiveTest {
@@ -37,4 +39,4 @@
      * @return The total number of iterations, the default is 1.
      */
     int numIterations() default 1;
-}
\ No newline at end of file
+}
diff --git a/test-legacy/Android.bp b/test-legacy/Android.bp
index 833c714..a69f422 100644
--- a/test-legacy/Android.bp
+++ b/test-legacy/Android.bp
@@ -25,7 +25,7 @@
     static_libs: [
         "android.test.base-minus-junit",
         "android.test.runner-minus-junit",
-        "android.test.mock.impl",
+        "android.test.mock_static",
     ],
 
     no_framework_libs: true,
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index e1d6e01..43b765d 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -30,3 +30,19 @@
     srcs_lib_whitelist_pkgs: ["android"],
     compile_dex: true,
 }
+
+// Build the android.test.mock_static library
+// ==========================================
+// This is only intended for inclusion in the legacy-android-test.
+// Must not be used elewhere.
+java_library_static {
+    name: "android.test.mock_static",
+
+    java_version: "1.8",
+    srcs: ["src/**/*.java"],
+
+    no_framework_libs: true,
+    libs: [
+        "framework",
+    ],
+}
diff --git a/tests/ActivityViewTest/AndroidManifest.xml b/tests/ActivityViewTest/AndroidManifest.xml
index 0be1ea0..17eb029 100644
--- a/tests/ActivityViewTest/AndroidManifest.xml
+++ b/tests/ActivityViewTest/AndroidManifest.xml
@@ -57,5 +57,10 @@
                   android:exported="true"
                   android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
         </activity>
+
+        <activity android:name=".ActivityViewVisibilityActivity"
+                  android:label="AV Visibility"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
+        </activity>
     </application>
 </manifest>
diff --git a/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml
index ba2e911..efcaef6 100644
--- a/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml
+++ b/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml
@@ -41,4 +41,10 @@
         android:text="Test Resize ActivityView"
         android:textAllCaps="false"/>
 
+    <Button
+        android:id="@+id/visibility_activity_view_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Test ActivityView Visibility"
+        android:textAllCaps="false"/>
 </LinearLayout>
diff --git a/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml
new file mode 100644
index 0000000..d29d4df
--- /dev/null
+++ b/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:background="#cfd8dc">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/activity_launch_button"
+            android:layout_width="200dp"
+            android:layout_height="wrap_content"
+            android:text="Launch test activity" />
+
+        <Spinner
+            android:id="@+id/visibility_spinner"
+            android:layout_width="200dp"
+            android:layout_height="match_parent"/>
+
+    </LinearLayout>
+
+    <ActivityView
+        android:id="@+id/activity_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
index 66f0c6a..4f09c28 100644
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
@@ -35,5 +35,8 @@
 
         findViewById(R.id.resize_activity_view_button).setOnClickListener(
                 v -> startActivity(new Intent(this, ActivityViewResizeActivity.class)));
+
+        findViewById(R.id.visibility_activity_view_button).setOnClickListener(
+                v -> startActivity(new Intent(this, ActivityViewVisibilityActivity.class)));
     }
 }
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
index ba2c764..52aba2b 100644
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
@@ -24,12 +24,14 @@
 import android.app.Activity;
 import android.content.res.Configuration;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.widget.TextView;
 
 public class ActivityViewTestActivity extends Activity {
+    private static final String TAG = "ActivityViewTestActivity";
 
     private View mRoot;
     private TextView mTextView;
@@ -84,6 +86,7 @@
     }
 
     private void updateStateText(String state) {
+        Log.d(TAG, state);
         mTextView.setText(state);
     }
 
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java
new file mode 100644
index 0000000..ecd2cf3
--- /dev/null
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java
@@ -0,0 +1,75 @@
+/**
+ * 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.google.android.test.activityview;
+
+import static android.view.View.GONE;
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+
+import android.app.Activity;
+import android.app.ActivityView;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Spinner;
+
+public class ActivityViewVisibilityActivity extends Activity {
+    private static final String[] sVisibilityOptions = {"VISIBLE", "INVISIBLE", "GONE"};
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_view_visibility_activity);
+
+        final ActivityView activityView = findViewById(R.id.activity_view);
+        final Button launchButton = findViewById(R.id.activity_launch_button);
+        launchButton.setOnClickListener(v -> {
+            final Intent intent = new Intent(this, ActivityViewTestActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+            activityView.startActivity(intent);
+        });
+
+        final Spinner visibilitySpinner = findViewById(R.id.visibility_spinner);
+        final ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
+                android.R.layout.simple_spinner_item, sVisibilityOptions);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        visibilitySpinner.setAdapter(adapter);
+        visibilitySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+                switch (position) {
+                    case 0:
+                        activityView.setVisibility(VISIBLE);
+                        break;
+                    case 1:
+                        activityView.setVisibility(INVISIBLE);
+                        break;
+                    case 2:
+                        activityView.setVisibility(GONE);
+                        break;
+                }
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> parent) {
+            }
+        });
+    }
+}
diff --git a/tests/PackageWatchdog/Android.mk b/tests/PackageWatchdog/Android.mk
index b53f27d..1c1c2a4 100644
--- a/tests/PackageWatchdog/Android.mk
+++ b/tests/PackageWatchdog/Android.mk
@@ -23,7 +23,7 @@
     junit \
     frameworks-base-testutils \
     android-support-test \
-    services
+    services.core
 
 LOCAL_JAVA_LIBRARIES := \
     android.test.runner
diff --git a/tests/net/java/android/net/LinkPropertiesTest.java b/tests/net/java/android/net/LinkPropertiesTest.java
index 932fee0..299fbef 100644
--- a/tests/net/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/java/android/net/LinkPropertiesTest.java
@@ -849,6 +849,18 @@
         assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed)));
     }
 
+    private void assertParcelingIsLossless(LinkProperties source) {
+        Parcel p = Parcel.obtain();
+        source.writeToParcel(p, /* flags */ 0);
+        p.setDataPosition(0);
+        final byte[] marshalled = p.marshall();
+        p = Parcel.obtain();
+        p.unmarshall(marshalled, 0, marshalled.length);
+        p.setDataPosition(0);
+        LinkProperties dest = LinkProperties.CREATOR.createFromParcel(p);
+        assertEquals(source, dest);
+    }
+
     @Test
     public void testLinkPropertiesParcelable() throws Exception {
         LinkProperties source = new LinkProperties();
@@ -870,15 +882,12 @@
 
         source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
 
-        Parcel p = Parcel.obtain();
-        source.writeToParcel(p, /* flags */ 0);
-        p.setDataPosition(0);
-        final byte[] marshalled = p.marshall();
-        p = Parcel.obtain();
-        p.unmarshall(marshalled, 0, marshalled.length);
-        p.setDataPosition(0);
-        LinkProperties dest = LinkProperties.CREATOR.createFromParcel(p);
+        assertParcelingIsLossless(source);
+    }
 
-        assertEquals(source, dest);
+    @Test
+    public void testParcelUninitialized() throws Exception {
+        LinkProperties empty = new LinkProperties();
+        assertParcelingIsLossless(empty);
     }
 }
diff --git a/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
new file mode 100644
index 0000000..4cabfc9
--- /dev/null
+++ b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.LinkPropertiesParcelableUtil.fromStableParcelable;
+import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.ProxyInfo;
+import android.net.RouteInfo;
+import android.net.Uri;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Tests for {@link LinkPropertiesParcelableUtil}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LinkPropertiesParcelableUtilTest {
+    private LinkProperties mLinkProperties;
+
+    private static final String TEST_LINKPROPS_IFACE = "TEST_IFACE";
+    private static final String TEST_STACKED_LINK_1_IFACE = "TEST_STACKED_IFACE_1";
+    private static final String TEST_STACKED_LINK_2_IFACE = "TEST_STACKED_IFACE_2";
+
+    @Before
+    public void setUp() {
+        mLinkProperties = makeLinkProperties(TEST_LINKPROPS_IFACE);
+        mLinkProperties.addStackedLink(makeLinkProperties(TEST_STACKED_LINK_1_IFACE));
+        mLinkProperties.addStackedLink(makeLinkProperties(TEST_STACKED_LINK_2_IFACE));
+    }
+
+    private static LinkProperties makeLinkProperties(String iface) {
+        final LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(iface);
+        lp.setLinkAddresses(Arrays.asList(
+                new LinkAddress(InetAddresses.parseNumericAddress("192.168.0.42"), 16),
+                new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::7"), 42)));
+        lp.setDnsServers(Arrays.asList(
+                InetAddresses.parseNumericAddress("2001:db8::42"),
+                InetAddresses.parseNumericAddress("192.168.1.1")
+        ));
+        lp.setValidatedPrivateDnsServers(Arrays.asList(
+                InetAddresses.parseNumericAddress("2001:db8::43"),
+                InetAddresses.parseNumericAddress("192.168.42.43")
+        ));
+        lp.setPcscfServers(Arrays.asList(
+                InetAddresses.parseNumericAddress("2001:db8::47"),
+                InetAddresses.parseNumericAddress("192.168.42.47")
+        ));
+        lp.setUsePrivateDns(true);
+        lp.setPrivateDnsServerName("test.example.com");
+        lp.setDomains("test1.example.com,test2.example.com");
+        lp.addRoute(new RouteInfo(
+                new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::44"), 45),
+                InetAddresses.parseNumericAddress("2001:db8::45"),
+                iface,
+                RouteInfo.RTN_UNICAST
+        ));
+        lp.addRoute(new RouteInfo(
+                new IpPrefix(InetAddresses.parseNumericAddress("192.168.44.45"), 16),
+                InetAddresses.parseNumericAddress("192.168.45.1"),
+                iface,
+                RouteInfo.RTN_THROW
+        ));
+        lp.setHttpProxy(new ProxyInfo("test3.example.com", 8000,
+                "excl1.example.com,excl2.example.com"));
+        lp.setMtu(5000);
+        lp.setTcpBufferSizes("1,2,3,4,5,6");
+        lp.setNat64Prefix(new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::48"), 96));
+
+        // Verify that this test does not miss any new field added later.
+        // If any added field is not included in LinkProperties#equals, assertLinkPropertiesEquals
+        // must also be updated.
+        assertEquals(14, Arrays.stream(LinkProperties.class.getDeclaredFields())
+                .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
+
+        return lp;
+    }
+
+    @Test
+    public void testParcelUnparcel() {
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullInterface() {
+        mLinkProperties.setInterfaceName(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullPrivateDnsServer() {
+        mLinkProperties.setPrivateDnsServerName(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullDomains() {
+        mLinkProperties.setDomains(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullProxy() {
+        mLinkProperties.setHttpProxy(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullTcpBufferSizes() {
+        mLinkProperties.setTcpBufferSizes(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyLinkAddresses() {
+        mLinkProperties.setLinkAddresses(Collections.emptyList());
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyDnses() {
+        mLinkProperties.setDnsServers(Collections.emptyList());
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyValidatedPrivateDnses() {
+        mLinkProperties.setValidatedPrivateDnsServers(Collections.emptyList());
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyRoutes() {
+        for (RouteInfo r : mLinkProperties.getAllRoutes()) {
+            mLinkProperties.removeRoute(r);
+        }
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_PacFileProxyInfo() {
+        mLinkProperties.setHttpProxy(new ProxyInfo(Uri.parse("http://pacfile.example.com")));
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullNat64Prefix() {
+        mLinkProperties.setNat64Prefix(null);
+        doParcelUnparcelTest();
+    }
+
+    private void doParcelUnparcelTest() {
+        final LinkProperties unparceled = fromStableParcelable(toStableParcelable(mLinkProperties));
+        assertLinkPropertiesEquals(mLinkProperties, unparceled);
+    }
+
+    private static void assertLinkPropertiesEquals(LinkProperties expected, LinkProperties actual) {
+        assertEquals(expected, actual);
+
+        // LinkProperties equals() does not include stacked links
+        assertEquals(expected.getStackedLinks(), actual.getStackedLinks());
+    }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index bf39644..2a92a7d 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -4683,7 +4683,7 @@
         mCellNetworkAgent.sendLinkProperties(cellLp);
         mCellNetworkAgent.connect(true);
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-        verify(mNetworkManagementService, times(1)).startClatd(MOBILE_IFNAME);
+        verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME);
         Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
 
         // Clat iface up, expect stack link updated.
@@ -4710,7 +4710,7 @@
         mCellNetworkAgent.sendLinkProperties(cellLp);
         waitForIdle();
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
-        verify(mNetworkManagementService, times(1)).stopClatd(MOBILE_IFNAME);
+        verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
 
         // Clat iface removed, expect linkproperties revert to original one
         clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 4c52d81..9578ded 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -32,11 +32,13 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
+import android.net.INetd;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkMisc;
 import android.net.NetworkStack;
+import android.os.INetworkManagementService;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.format.DateUtils;
@@ -66,6 +68,8 @@
     LingerMonitor mMonitor;
 
     @Mock ConnectivityService mConnService;
+    @Mock INetd mNetd;
+    @Mock INetworkManagementService mNMS;
     @Mock Context mCtx;
     @Mock NetworkMisc mMisc;
     @Mock NetworkNotificationManager mNotifier;
@@ -352,7 +356,7 @@
         caps.addCapability(0);
         caps.addTransportType(transport);
         NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
-                caps, 50, mCtx, null, mMisc, mConnService);
+                caps, 50, mCtx, null, mMisc, mConnService, mNetd, mNMS);
         nai.everValidated = true;
         return nai;
     }
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index bf42412..07b1d05 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -17,9 +17,7 @@
 package com.android.server.connectivity;
 
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -27,6 +25,7 @@
 import static org.mockito.Mockito.when;
 
 import android.net.ConnectivityManager;
+import android.net.INetd;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -57,6 +56,7 @@
 
     @Mock ConnectivityService mConnectivity;
     @Mock NetworkMisc mMisc;
+    @Mock INetd mNetd;
     @Mock INetworkManagementService mNms;
     @Mock InterfaceConfiguration mConfig;
     @Mock NetworkAgentInfo mNai;
@@ -65,7 +65,7 @@
     Handler mHandler;
 
     Nat464Xlat makeNat464Xlat() {
-        return new Nat464Xlat(mNms, mNai);
+        return new Nat464Xlat(mNai, mNetd, mNms);
     }
 
     @Before
@@ -129,7 +129,7 @@
         nat.start();
 
         verify(mNms).registerObserver(eq(nat));
-        verify(mNms).startClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStart(eq(BASE_IFACE));
 
         // Stacked interface up notification arrives.
         nat.interfaceLinkStateChanged(STACKED_IFACE, true);
@@ -144,7 +144,7 @@
         // ConnectivityService stops clat (Network disconnects, IPv4 addr appears, ...).
         nat.stop();
 
-        verify(mNms).stopClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStop(eq(BASE_IFACE));
 
         // Stacked interface removed notification arrives.
         nat.interfaceRemoved(STACKED_IFACE);
@@ -156,7 +156,7 @@
         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
         assertIdle(nat);
 
-        verifyNoMoreInteractions(mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
     }
 
     @Test
@@ -168,7 +168,7 @@
         nat.start();
 
         verify(mNms).registerObserver(eq(nat));
-        verify(mNms).startClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStart(eq(BASE_IFACE));
 
         // Stacked interface up notification arrives.
         nat.interfaceLinkStateChanged(STACKED_IFACE, true);
@@ -185,7 +185,7 @@
         mLooper.dispatchNext();
 
         verify(mNms).unregisterObserver(eq(nat));
-        verify(mNms).stopClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStop(eq(BASE_IFACE));
         verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
         assertTrue(c.getValue().getStackedLinks().isEmpty());
         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
@@ -194,7 +194,7 @@
         // ConnectivityService stops clat: no-op.
         nat.stop();
 
-        verifyNoMoreInteractions(mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
     }
 
     @Test
@@ -205,13 +205,13 @@
         nat.start();
 
         verify(mNms).registerObserver(eq(nat));
-        verify(mNms).startClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStart(eq(BASE_IFACE));
 
         // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
         nat.stop();
 
         verify(mNms).unregisterObserver(eq(nat));
-        verify(mNms).stopClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStop(eq(BASE_IFACE));
         assertIdle(nat);
 
         // In-flight interface up notification arrives: no-op
@@ -225,7 +225,7 @@
 
         assertIdle(nat);
 
-        verifyNoMoreInteractions(mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
     }
 
     @Test
@@ -236,16 +236,16 @@
         nat.start();
 
         verify(mNms).registerObserver(eq(nat));
-        verify(mNms).startClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStart(eq(BASE_IFACE));
 
         // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
         nat.stop();
 
         verify(mNms).unregisterObserver(eq(nat));
-        verify(mNms).stopClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStop(eq(BASE_IFACE));
         assertIdle(nat);
 
-        verifyNoMoreInteractions(mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
     }
 
     static void assertIdle(Nat464Xlat nat) {
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
index 859a54d..e63c3b0 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -16,6 +16,9 @@
 
 package com.android.server.net.ipmemorystore;
 
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+
 import android.content.Context;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -26,6 +29,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.io.File;
+
 /** Unit tests for {@link IpMemoryStoreServiceTest}. */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -36,6 +41,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        doReturn(new File("/tmp/test.db")).when(mMockContext).getDatabasePath(anyString());
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java b/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
new file mode 100644
index 0000000..8d367e2
--- /dev/null
+++ b/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
@@ -0,0 +1,149 @@
+/*
+ * 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.net.ipmemorystore;
+
+import static com.android.server.net.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit tests for {@link RelevanceUtils}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RelevanceUtilsTests {
+    @Test
+    public void testComputeRelevanceForTargetDate() {
+        final long dayInMillis = 24L * 60 * 60 * 1000;
+        final long base = 1_000_000L; // any given point in time
+        // Relevance when the network expires in 1000 years must be capped
+        assertEquals(CAPPED_RELEVANCE, RelevanceUtils.computeRelevanceForTargetDate(
+                base + 1000L * dayInMillis, base));
+        // Relevance when expiry is before the date must be 0
+        assertEquals(0, RelevanceUtils.computeRelevanceForTargetDate(base - 1, base));
+        // Make sure the relevance for a given target date is higher if the expiry is further
+        // in the future
+        assertTrue(RelevanceUtils.computeRelevanceForTargetDate(base + 100 * dayInMillis, base)
+                < RelevanceUtils.computeRelevanceForTargetDate(base + 150 * dayInMillis, base));
+
+        // Make sure the relevance falls slower as the expiry is closing in. This is to ensure
+        // the decay is indeed logarithmic.
+        final int relevanceAtExpiry = RelevanceUtils.computeRelevanceForTargetDate(base, base);
+        final int relevance50DaysBeforeExpiry =
+                RelevanceUtils.computeRelevanceForTargetDate(base + 50 * dayInMillis, base);
+        final int relevance100DaysBeforeExpiry =
+                RelevanceUtils.computeRelevanceForTargetDate(base + 100 * dayInMillis, base);
+        final int relevance150DaysBeforeExpiry =
+                RelevanceUtils.computeRelevanceForTargetDate(base + 150 * dayInMillis, base);
+        assertEquals(0, relevanceAtExpiry);
+        assertTrue(relevance50DaysBeforeExpiry - relevanceAtExpiry
+                < relevance100DaysBeforeExpiry - relevance50DaysBeforeExpiry);
+        assertTrue(relevance100DaysBeforeExpiry - relevance50DaysBeforeExpiry
+                < relevance150DaysBeforeExpiry - relevance100DaysBeforeExpiry);
+    }
+
+    @Test
+    public void testIncreaseRelevance() {
+        long expiry = System.currentTimeMillis();
+
+        final long firstBump = RelevanceUtils.bumpExpiryDate(expiry);
+        // Though a few milliseconds might have elapsed, the first bump should push the duration
+        // to days in the future, so unless this test takes literal days between these two lines,
+        // this should always pass.
+        assertTrue(firstBump > expiry);
+
+        expiry = 0;
+        long lastDifference = Long.MAX_VALUE;
+        // The relevance should be capped in at most this many steps. Otherwise, fail.
+        final int steps = 1000;
+        for (int i = 0; i < steps; ++i) {
+            final long newExpiry = RelevanceUtils.bumpExpiryDuration(expiry);
+            if (newExpiry == expiry) {
+                // The relevance should be capped. Make sure it is, then exit without failure.
+                assertEquals(newExpiry, RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS);
+                return;
+            }
+            // Make sure the new expiry is further in the future than last time.
+            assertTrue(newExpiry > expiry);
+            // Also check that it was not bumped as much as the last bump, because the
+            // decay must be exponential.
+            assertTrue(newExpiry - expiry < lastDifference);
+            lastDifference = newExpiry - expiry;
+            expiry = newExpiry;
+        }
+        fail("Relevance failed to go to the maximum value after " + steps + " bumps");
+    }
+
+    @Test
+    public void testContinuity() {
+        final long expiry = System.currentTimeMillis();
+
+        // Relevance at expiry and after expiry should be the cap.
+        final int relevanceBeforeMaxLifetime = RelevanceUtils.computeRelevanceForTargetDate(expiry,
+                expiry - (RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS + 1_000_000));
+        assertEquals(relevanceBeforeMaxLifetime, CAPPED_RELEVANCE);
+        final int relevanceForMaxLifetime = RelevanceUtils.computeRelevanceForTargetDate(expiry,
+                expiry - RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS);
+        assertEquals(relevanceForMaxLifetime, CAPPED_RELEVANCE);
+
+        // If the max relevance is reached at the cap lifetime, one millisecond less than this
+        // should be very close. Strictly speaking this is a bit brittle, but it should be
+        // good enough for the purposes of the memory store.
+        final int relevanceForOneMillisecLessThanCap = RelevanceUtils.computeRelevanceForTargetDate(
+                expiry, expiry - RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS + 1);
+        assertTrue(relevanceForOneMillisecLessThanCap <= CAPPED_RELEVANCE);
+        assertTrue(relevanceForOneMillisecLessThanCap >= CAPPED_RELEVANCE - 10);
+
+        // Likewise the relevance one millisecond before expiry should be very close to 0. It's
+        // fine if it rounds down to 0.
+        final int relevanceOneMillisecBeforeExpiry = RelevanceUtils.computeRelevanceForTargetDate(
+                expiry, expiry - 1);
+        assertTrue(relevanceOneMillisecBeforeExpiry <= 10);
+        assertTrue(relevanceOneMillisecBeforeExpiry >= 0);
+
+        final int relevanceAtExpiry = RelevanceUtils.computeRelevanceForTargetDate(expiry, expiry);
+        assertEquals(relevanceAtExpiry, 0);
+        final int relevanceAfterExpiry = RelevanceUtils.computeRelevanceForTargetDate(expiry,
+                expiry + 1_000_000);
+        assertEquals(relevanceAfterExpiry, 0);
+    }
+
+    // testIncreaseRelevance makes sure bumping the expiry continuously always yields a
+    // monotonically increasing date as a side effect, but this tests that the relevance (as
+    // opposed to the expiry date) increases monotonically with increasing periods.
+    @Test
+    public void testMonotonicity() {
+        // Hopefully the relevance is granular enough to give a different value for every one
+        // of this number of steps.
+        final int steps = 40;
+        final long expiry = System.currentTimeMillis();
+
+        int lastRelevance = -1;
+        for (int i = 0; i < steps; ++i) {
+            final long date = expiry - i * (RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS / steps);
+            final int relevance = RelevanceUtils.computeRelevanceForTargetDate(expiry, date);
+            assertTrue(relevance > lastRelevance);
+            lastRelevance = relevance;
+        }
+    }
+}
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 0580df6..7783e10 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -115,6 +115,7 @@
         "optimize/MultiApkGenerator.cpp",
         "optimize/ResourceDeduper.cpp",
         "optimize/ResourceFilter.cpp",
+        "optimize/ResourcePathShortener.cpp",
         "optimize/VersionCollapser.cpp",
         "process/SymbolTable.cpp",
         "split/TableSplitter.cpp",
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index b353ff0..45719ef 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -223,8 +223,17 @@
     io::IFile* file = iterator->Next();
     std::string path = file->GetSource().path;
 
+    std::string output_path = path;
+    bool is_resource = path.find("res/") == 0;
+    if (is_resource) {
+      auto it = options.shortened_path_map.find(path);
+      if (it != options.shortened_path_map.end()) {
+        output_path = it->second;
+      }
+    }
+
     // Skip resources that are not referenced if requested.
-    if (path.find("res/") == 0 && referenced_resources.find(path) == referenced_resources.end()) {
+    if (is_resource && referenced_resources.find(output_path) == referenced_resources.end()) {
       if (context->IsVerbose()) {
         context->GetDiagnostics()->Note(DiagMessage()
                                         << "Removing resource '" << path << "' from APK.");
@@ -283,7 +292,8 @@
         return false;
       }
     } else {
-      if (!io::CopyFileToArchivePreserveCompression(context, file, path, writer)) {
+      if (!io::CopyFileToArchivePreserveCompression(
+              context, file, output_path, writer)) {
         return false;
       }
     }
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 58702dc..e0d2f48 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -1164,8 +1164,6 @@
             current_policies |= OverlayableItem::Policy::kPublic;
           } else if (trimmed_part == "product") {
             current_policies |= OverlayableItem::Policy::kProduct;
-          } else if (trimmed_part == "product_services") {
-            current_policies |= OverlayableItem::Policy::kProductServices;
           } else if (trimmed_part == "system") {
             current_policies |= OverlayableItem::Policy::kSystem;
           } else if (trimmed_part == "vendor") {
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index debca9c..827c7de 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -935,9 +935,6 @@
         <policy type="product">
           <item type="string" name="bar" />
         </policy>
-        <policy type="product_services">
-          <item type="string" name="baz" />
-        </policy>
         <policy type="system">
           <item type="string" name="fiz" />
         </policy>
@@ -966,14 +963,6 @@
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
   EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct));
 
-  search_result = table_.FindResource(test::ParseNameOrDie("string/baz"));
-  ASSERT_TRUE(search_result);
-  ASSERT_THAT(search_result.value().entry, NotNull());
-  ASSERT_TRUE(search_result.value().entry->overlayable_item);
-  result_overlayable_item = search_result.value().entry->overlayable_item.value();
-  EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProductServices));
-
   search_result = table_.FindResource(test::ParseNameOrDie("string/fiz"));
   ASSERT_TRUE(search_result);
   ASSERT_THAT(search_result.value().entry, NotNull());
@@ -1028,7 +1017,7 @@
 TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) {
   std::string input = R"(
       <overlayable name="Name">
-        <policy type="vendor|product_services">
+        <policy type="vendor|public">
           <item type="string" name="foo" />
         </policy>
         <policy type="product|system">
@@ -1044,7 +1033,7 @@
   OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
   EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kVendor
-                                                   | OverlayableItem::Policy::kProductServices));
+                                                   | OverlayableItem::Policy::kPublic));
 
   search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
   ASSERT_TRUE(search_result);
@@ -1139,7 +1128,7 @@
   std::string input = R"(
       <overlayable name="Name">
         <policy type="vendor|product">
-          <policy type="product_services">
+          <policy type="public">
             <item type="string" name="foo" />
           </policy>
         </policy>
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index eaf6a47..7ca99ea 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -92,9 +92,6 @@
 
     // The resource can be overlaid by any overlay on the product partition.
     kProduct = 0x08,
-
-    // The resource can be overlaid by any overlay on the product services partition.
-    kProductServices = 0x10
   };
 
   std::shared_ptr<Overlayable> overlayable;
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index a733134..b97dc6b 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -248,7 +248,7 @@
                                                    Source("res/values/overlayable.xml", 40));
   OverlayableItem overlayable_item(overlayable);
   overlayable_item.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_item.policies |= OverlayableItem::Policy::kProductServices;
+  overlayable_item.policies |= OverlayableItem::Policy::kVendor;
   overlayable_item.comment = "comment";
   overlayable_item.source = Source("res/values/overlayable.xml", 42);
 
@@ -265,7 +265,7 @@
   EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml"));
   EXPECT_THAT(result_overlayable_item.overlayable->source.line, 40);
   EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct
-                                                   | OverlayableItem::Policy::kProductServices));
+                                                   | OverlayableItem::Policy::kVendor));
   ASSERT_THAT(result_overlayable_item.comment, StrEq("comment"));
   EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml"));
   EXPECT_THAT(result_overlayable_item.source.line, 42);
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index c6f9152..ab4805f 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -16,6 +16,7 @@
 
 #include "ResourceUtils.h"
 
+#include <algorithm>
 #include <sstream>
 
 #include "android-base/stringprintf.h"
@@ -503,6 +504,14 @@
   if (entry.first == trimmed_str) {
     return entry.second;
   }
+
+  // Try parsing codename from "[codename].[preview_sdk_fingerprint]" value.
+  const StringPiece::const_iterator begin = std::begin(trimmed_str);
+  const StringPiece::const_iterator end = std::end(trimmed_str);
+  const StringPiece::const_iterator codename_end = std::find(begin, end, '.');
+  if (codename_end != end && entry.first == trimmed_str.substr(begin, codename_end)) {
+    return entry.second;
+  }
   return {};
 }
 
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index 5ce4640..9018b0f 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -16,6 +16,7 @@
 
 #include "ResourceUtils.h"
 
+#include "SdkConstants.h"
 #include "Resource.h"
 #include "test/Test.h"
 
@@ -212,6 +213,17 @@
               Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, expected_float_flattened))));
 }
 
+TEST(ResourceUtilsTest, ParseSdkVersionWithCodename) {
+  const android::StringPiece codename =
+      GetDevelopmentSdkCodeNameAndVersion().first;
+  const int version = GetDevelopmentSdkCodeNameAndVersion().second;
+
+  EXPECT_THAT(ResourceUtils::ParseSdkVersion(codename), Eq(Maybe<int>(version)));
+  EXPECT_THAT(
+      ResourceUtils::ParseSdkVersion(codename.to_string() + ".fingerprint"),
+      Eq(Maybe<int>(version)));
+}
+
 TEST(ResourceUtilsTest, StringBuilderWhitespaceRemoval) {
   EXPECT_THAT(ResourceUtils::StringBuilder()
                   .AppendText("    hey guys ")
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index da541be..73b568e 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -155,7 +155,6 @@
     SYSTEM = 1;
     VENDOR = 2;
     PRODUCT = 3;
-    PRODUCT_SERVICES = 4;
   }
 
   // The location of the <item> declaration in source.
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 328b0be..2e6af18 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -41,6 +41,7 @@
 #include "optimize/MultiApkGenerator.h"
 #include "optimize/ResourceDeduper.h"
 #include "optimize/ResourceFilter.h"
+#include "optimize/ResourcePathShortener.h"
 #include "optimize/VersionCollapser.h"
 #include "split/TableSplitter.h"
 #include "util/Files.h"
@@ -52,6 +53,7 @@
 using ::android::ResTable_config;
 using ::android::StringPiece;
 using ::android::base::ReadFileToString;
+using ::android::base::WriteStringToFile;
 using ::android::base::StringAppendF;
 using ::android::base::StringPrintf;
 
@@ -143,6 +145,21 @@
       return 1;
     }
 
+    if (options_.shorten_resource_paths) {
+      ResourcePathShortener shortener(options_.table_flattener_options.shortened_path_map);
+      if (!shortener.Consume(context_, apk->GetResourceTable())) {
+        context_->GetDiagnostics()->Error(DiagMessage() << "failed shortening resource paths");
+        return 1;
+      }
+      if (options_.shortened_paths_map_path
+          && !WriteShortenedPathsMap(options_.table_flattener_options.shortened_path_map,
+                                      options_.shortened_paths_map_path.value())) {
+        context_->GetDiagnostics()->Error(DiagMessage()
+                                          << "failed to write shortened resource paths to file");
+        return 1;
+      }
+    }
+
     // Adjust the SplitConstraints so that their SDK version is stripped if it is less than or
     // equal to the minSdk.
     options_.split_constraints =
@@ -264,6 +281,15 @@
                                         ArchiveEntry::kAlign, writer);
   }
 
+  bool WriteShortenedPathsMap(const std::map<std::string, std::string> &path_map,
+                               const std::string &file_path) {
+    std::stringstream ss;
+    for (auto it = path_map.cbegin(); it != path_map.cend(); ++it) {
+      ss << it->first << " -> " << it->second << "\n";
+    }
+    return WriteStringToFile(ss.str(), file_path);
+  }
+
   OptimizeOptions options_;
   OptimizeContext* context_;
 };
diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h
index d07305b..7f4a3ed 100644
--- a/tools/aapt2/cmd/Optimize.h
+++ b/tools/aapt2/cmd/Optimize.h
@@ -55,6 +55,12 @@
   // Set of artifacts to keep when generating multi-APK splits. If the list is empty, all artifacts
   // are kept and will be written as output.
   std::unordered_set<std::string> kept_artifacts;
+
+  // Whether or not to shorten resource paths in the APK.
+  bool shorten_resource_paths;
+
+  // Path to the output map of original resource paths to shortened paths.
+  Maybe<std::string> shortened_paths_map_path;
 };
 
 class OptimizeCommand : public Command {
@@ -101,6 +107,12 @@
     AddOptionalSwitch("--enable-resource-obfuscation",
         "Enables obfuscation of key string pool to single value",
         &options_.table_flattener_options.collapse_key_stringpool);
+    AddOptionalSwitch("--enable-resource-path-shortening",
+        "Enables shortening of the path of the resources inside the APK.",
+        &options_.shorten_resource_paths);
+    AddOptionalFlag("--resource-path-shortening-map",
+        "Path to output the map of old resource paths to shortened paths.",
+        &options_.shortened_paths_map_path);
     AddOptionalSwitch("-v", "Enables verbose logging", &verbose_);
   }
 
@@ -109,6 +121,9 @@
  private:
   OptimizeOptions options_;
 
+  bool WriteObfuscatedPathsMap(const std::map<std::string, std::string> &path_map,
+                               const std::string &file_path);
+
   Maybe<std::string> config_path_;
   Maybe<std::string> whitelist_path_;
   Maybe<std::string> resources_config_path_;
@@ -122,4 +137,4 @@
 
 }// namespace aapt
 
-#endif //AAPT2_OPTIMIZE_H
\ No newline at end of file
+#endif //AAPT2_OPTIMIZE_H
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index c496ff0..40aaa05 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -42,6 +42,19 @@
 
 namespace {
 
+static std::u16string strcpy16_dtoh(const char16_t* src, size_t len) {
+  size_t utf16_len = strnlen16(src, len);
+  if (utf16_len == 0) {
+    return {};
+  }
+  std::u16string dst;
+  dst.resize(utf16_len);
+  for (size_t i = 0; i < utf16_len; i++) {
+    dst[i] = util::DeviceToHost16(src[i]);
+  }
+  return dst;
+}
+
 // Visitor that converts a reference's resource ID to a resource name, given a mapping from
 // resource ID to resource name.
 class ReferenceIdToNameVisitor : public DescendingValueVisitor {
@@ -176,12 +189,8 @@
   }
 
   // Extract the package name.
-  size_t len = strnlen16((const char16_t*)package_header->name, arraysize(package_header->name));
-  std::u16string package_name;
-  package_name.resize(len);
-  for (size_t i = 0; i < len; i++) {
-    package_name[i] = util::DeviceToHost16(package_header->name[i]);
-  }
+  std::u16string package_name = strcpy16_dtoh((const char16_t*)package_header->name,
+                                              arraysize(package_header->name));
 
   ResourceTablePackage* package =
       table_->CreatePackage(util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id));
@@ -435,6 +444,11 @@
   }
 
   auto overlayable = std::make_shared<Overlayable>();
+  overlayable->name = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->name,
+                                                      arraysize(header->name)));
+  overlayable->actor = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->actor,
+                                                       arraysize(header->name)));
+  overlayable->source = source_.WithLine(0);
 
   ResChunkPullParser parser(GetChunkData(chunk),
                             GetChunkDataLen(chunk));
@@ -459,10 +473,6 @@
           & ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION) {
         policies |= OverlayableItem::Policy::kProduct;
       }
-      if (policy_header->policy_flags
-          & ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION) {
-        policies |= OverlayableItem::Policy::kProductServices;
-      }
 
       const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>(
           ((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize));
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 931d57b..9d341cc 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -217,9 +217,10 @@
   size_t entry_count_ = 0;
 };
 
-struct PolicyChunk {
-  uint32_t policy_flags;
-  std::set<ResourceId> ids;
+struct OverlayableChunk {
+  std::string actor;
+  Source source;
+  std::map<OverlayableItem::PolicyFlags, std::set<ResourceId>> policy_ids;
 };
 
 class PackageFlattener {
@@ -421,8 +422,9 @@
     return sorted_entries;
   }
 
-  void FlattenOverlayable(BigBuffer* buffer) {
-    std::vector<PolicyChunk> policies;
+  bool FlattenOverlayable(BigBuffer* buffer) {
+    std::set<ResourceId> seen_ids;
+    std::map<std::string, OverlayableChunk> overlayable_chunks;
 
     CHECK(bool(package_->id)) << "package must have an ID set when flattening <overlayable>";
     for (auto& type : package_->types) {
@@ -433,79 +435,116 @@
           continue;
         }
 
-        OverlayableItem& overlayable = entry->overlayable_item.value();
-        uint32_t policy_flags = OverlayableItem::Policy::kNone;
-        if (overlayable.policies & OverlayableItem::Policy::kPublic) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
-        }
-        if (overlayable.policies & OverlayableItem::Policy::kSystem) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
-        }
-        if (overlayable.policies & OverlayableItem::Policy::kVendor) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
-        }
-        if (overlayable.policies & OverlayableItem::Policy::kProduct) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
-        }
-        if (overlayable.policies & OverlayableItem::Policy::kProductServices) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION;
+        OverlayableItem& item = entry->overlayable_item.value();
+
+        // Resource ids should only appear once in the resource table
+        ResourceId id = android::make_resid(package_->id.value(), type->id.value(),
+                                            entry->id.value());
+        CHECK(seen_ids.find(id) == seen_ids.end())
+            << "multiple overlayable definitions found for resource "
+            << ResourceName(package_->name, type->type, entry->name).to_string();
+        seen_ids.insert(id);
+
+        // Find the overlayable chunk with the specified name
+        OverlayableChunk* overlayable_chunk = nullptr;
+        auto iter = overlayable_chunks.find(item.overlayable->name);
+        if (iter == overlayable_chunks.end()) {
+          OverlayableChunk chunk{item.overlayable->actor, item.overlayable->source};
+          overlayable_chunk =
+              &overlayable_chunks.insert({item.overlayable->name, chunk}).first->second;
+        } else {
+          OverlayableChunk& chunk = iter->second;
+          if (!(chunk.source == item.overlayable->source)) {
+            // The name of an overlayable set of resources must be unique
+            context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source)
+                                                  << "duplicate overlayable name"
+                                                  << item.overlayable->name << "'");
+            context_->GetDiagnostics()->Error(DiagMessage(chunk.source)
+                                                  << "previous declaration here");
+            return false;
+          }
+
+          CHECK(chunk.actor == item.overlayable->actor);
+          overlayable_chunk = &chunk;
         }
 
-        if (overlayable.policies == OverlayableItem::Policy::kNone) {
+        uint32_t policy_flags = 0;
+        if (item.policies == OverlayableItem::Policy::kNone) {
           // Encode overlayable entries defined without a policy as publicly overlayable
           policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
-        }
-
-        // Find the overlayable policy chunk with the same policies as the entry
-        PolicyChunk* policy_chunk = nullptr;
-        for (PolicyChunk& policy : policies) {
-          if (policy.policy_flags == policy_flags) {
-            policy_chunk = &policy;
-            break;
+        } else {
+          if (item.policies & OverlayableItem::Policy::kPublic) {
+            policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
+          }
+          if (item.policies & OverlayableItem::Policy::kSystem) {
+            policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
+          }
+          if (item.policies & OverlayableItem::Policy::kVendor) {
+            policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
+          }
+          if (item.policies & OverlayableItem::Policy::kProduct) {
+            policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
           }
         }
 
-        // Create a new policy chunk if an existing one with the same policy cannot be found
-        if (policy_chunk == nullptr) {
-          PolicyChunk p;
-          p.policy_flags = policy_flags;
-          policies.push_back(p);
-          policy_chunk = &policies.back();
+        auto policy = overlayable_chunk->policy_ids.find(policy_flags);
+        if (policy != overlayable_chunk->policy_ids.end()) {
+          policy->second.insert(id);
+        } else {
+          overlayable_chunk->policy_ids.insert(
+              std::make_pair(policy_flags, std::set<ResourceId>{id}));
         }
-
-        policy_chunk->ids.insert(android::make_resid(package_->id.value(), type->id.value(),
-                                                     entry->id.value()));
       }
     }
 
-    if (policies.empty()) {
-      // Only write the overlayable chunk if the APK has overlayable entries
-      return;
-    }
+    for (auto& overlayable_pair : overlayable_chunks) {
+      std::string name = overlayable_pair.first;
+      OverlayableChunk& overlayable = overlayable_pair.second;
 
-    ChunkWriter writer(buffer);
-    writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE);
-
-    // Write each policy block for the overlayable
-    for (PolicyChunk& policy : policies) {
-      ChunkWriter policy_writer(buffer);
-      ResTable_overlayable_policy_header* policy_type =
-          policy_writer.StartChunk<ResTable_overlayable_policy_header>(
-              RES_TABLE_OVERLAYABLE_POLICY_TYPE);
-      policy_type->policy_flags = util::HostToDevice32(policy.policy_flags);
-      policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(policy.ids.size()));
-
-      // Write the ids after the policy header
-      ResTable_ref* id_block = policy_writer.NextBlock<ResTable_ref>(policy.ids.size());
-      for (const ResourceId& id : policy.ids) {
-        id_block->ident = util::HostToDevice32(id.id);
-        id_block++;
+      // Write the header of the overlayable chunk
+      ChunkWriter overlayable_writer(buffer);
+      auto* overlayable_type =
+          overlayable_writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE);
+      if (name.size() >= arraysize(overlayable_type->name)) {
+        diag_->Error(DiagMessage() << "overlayable name '" << name
+                                   << "' exceeds maximum length ("
+                                   << arraysize(overlayable_type->name)
+                                   << " utf16 characters)");
+        return false;
       }
+      strcpy16_htod(overlayable_type->name, arraysize(overlayable_type->name),
+                    util::Utf8ToUtf16(name));
 
-      policy_writer.Finish();
+      if (overlayable.actor.size() >= arraysize(overlayable_type->actor)) {
+        diag_->Error(DiagMessage() << "overlayable name '" << overlayable.actor
+                                   << "' exceeds maximum length ("
+                                   << arraysize(overlayable_type->actor)
+                                   << " utf16 characters)");
+        return false;
+      }
+      strcpy16_htod(overlayable_type->actor, arraysize(overlayable_type->actor),
+                    util::Utf8ToUtf16(overlayable.actor));
+
+      // Write each policy block for the overlayable
+      for (auto& policy_ids : overlayable.policy_ids) {
+        ChunkWriter policy_writer(buffer);
+        auto* policy_type = policy_writer.StartChunk<ResTable_overlayable_policy_header>(
+            RES_TABLE_OVERLAYABLE_POLICY_TYPE);
+        policy_type->policy_flags = util::HostToDevice32(static_cast<uint32_t>(policy_ids.first));
+        policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(
+                                                            policy_ids.second.size()));
+        // Write the ids after the policy header
+        auto* id_block = policy_writer.NextBlock<ResTable_ref>(policy_ids.second.size());
+        for (const ResourceId& id : policy_ids.second) {
+          id_block->ident = util::HostToDevice32(id.id);
+          id_block++;
+        }
+        policy_writer.Finish();
+      }
+      overlayable_writer.Finish();
     }
 
-    writer.Finish();
+    return true;
   }
 
   bool FlattenTypeSpec(ResourceTableType* type, std::vector<ResourceEntry*>* sorted_entries,
diff --git a/tools/aapt2/format/binary/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h
index 635cb21..71330e3 100644
--- a/tools/aapt2/format/binary/TableFlattener.h
+++ b/tools/aapt2/format/binary/TableFlattener.h
@@ -46,6 +46,9 @@
 
   // When true, sort the entries in the values string pool by priority and configuration.
   bool sort_stringpool_entries = true;
+
+  // Map from original resource paths to shortened resource paths.
+  std::map<std::string, std::string> shortened_path_map;
 };
 
 class TableFlattener : public IResourceTableConsumer {
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index a5fb6fd..ddc1173 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -657,36 +657,34 @@
 TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) {
   auto overlayable = std::make_shared<Overlayable>("TestName", "overlay://theme");
   std::string name_zero = "com.app.test:integer/overlayable_zero_item";
-  OverlayableItem overlayable_zero_item(overlayable);
-  overlayable_zero_item.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_zero_item.policies |= OverlayableItem::Policy::kSystem;
-  overlayable_zero_item.policies |= OverlayableItem::Policy::kProductServices;
+  OverlayableItem overlayable_item_zero(overlayable);
+  overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem;
 
   std::string name_one = "com.app.test:integer/overlayable_one_item";
-  OverlayableItem overlayable_one_item(overlayable);
-  overlayable_one_item.policies |= OverlayableItem::Policy::kPublic;
-  overlayable_one_item.policies |= OverlayableItem::Policy::kProductServices;
+  OverlayableItem overlayable_item_one(overlayable);
+  overlayable_item_one.policies |= OverlayableItem::Policy::kPublic;
 
   std::string name_two = "com.app.test:integer/overlayable_two_item";
-  OverlayableItem overlayable_two_item(overlayable);
-  overlayable_two_item.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_two_item.policies |= OverlayableItem::Policy::kSystem;
-  overlayable_two_item.policies |= OverlayableItem::Policy::kVendor;
+  OverlayableItem overlayable_item_two(overlayable);
+  overlayable_item_two.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_two.policies |= OverlayableItem::Policy::kSystem;
+  overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
 
   std::string name_three = "com.app.test:integer/overlayable_three_item";
-  OverlayableItem overlayable_three_item(overlayable);
+  OverlayableItem overlayable_item_three(overlayable);
 
   std::unique_ptr<ResourceTable> table =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.test", 0x7f)
           .AddSimple(name_zero, ResourceId(0x7f020000))
-          .SetOverlayable(name_zero, overlayable_zero_item)
+          .SetOverlayable(name_zero, overlayable_item_zero)
           .AddSimple(name_one, ResourceId(0x7f020001))
-          .SetOverlayable(name_one, overlayable_one_item)
+          .SetOverlayable(name_one, overlayable_item_one)
           .AddSimple(name_two, ResourceId(0x7f020002))
-          .SetOverlayable(name_two, overlayable_two_item)
+          .SetOverlayable(name_two, overlayable_item_two)
           .AddSimple(name_three, ResourceId(0x7f020003))
-          .SetOverlayable(name_three, overlayable_three_item)
+          .SetOverlayable(name_three, overlayable_item_three)
           .Build();
 
   ResourceTable output_table;
@@ -698,16 +696,14 @@
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem
-                                       | OverlayableItem::Policy::kProduct
-                                       | OverlayableItem::Policy::kProductServices);
+                                       | OverlayableItem::Policy::kProduct);
 
   search_result = output_table.FindResource(test::ParseNameOrDie(name_one));
   ASSERT_TRUE(search_result);
   ASSERT_THAT(search_result.value().entry, NotNull());
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   overlayable_item = search_result.value().entry->overlayable_item.value();
-  EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic
-                                       | OverlayableItem::Policy::kProductServices);
+  EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
 
   search_result = output_table.FindResource(test::ParseNameOrDie(name_two));
   ASSERT_TRUE(search_result);
@@ -724,6 +720,80 @@
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
+  EXPECT_EQ(overlayable_item.overlayable->name, "TestName");
+  EXPECT_EQ(overlayable_item.overlayable->actor, "overlay://theme");
+  EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
+}
+
+TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) {
+  auto group = std::make_shared<Overlayable>("TestName", "overlay://theme");
+  std::string name_zero = "com.app.test:integer/overlayable_zero";
+  OverlayableItem overlayable_item_zero(group);
+  overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem;
+
+  auto group_one = std::make_shared<Overlayable>("OtherName", "overlay://customization");
+  std::string name_one = "com.app.test:integer/overlayable_one";
+  OverlayableItem overlayable_item_one(group_one);
+  overlayable_item_one.policies |= OverlayableItem::Policy::kPublic;
+
+  std::string name_two = "com.app.test:integer/overlayable_two";
+  OverlayableItem overlayable_item_two(group);
+  overlayable_item_two.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_two.policies |= OverlayableItem::Policy::kSystem;
+  overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
+
+  std::string name_three = "com.app.test:integer/overlayable_three";
+  OverlayableItem overlayable_item_three(group_one);
+  std::unique_ptr<ResourceTable> table =
+      test::ResourceTableBuilder()
+          .SetPackageId("com.app.test", 0x7f)
+          .AddSimple(name_zero, ResourceId(0x7f020000))
+          .SetOverlayable(name_zero, overlayable_item_zero)
+          .AddSimple(name_one, ResourceId(0x7f020001))
+          .SetOverlayable(name_one, overlayable_item_one)
+          .AddSimple(name_two, ResourceId(0x7f020002))
+          .SetOverlayable(name_two, overlayable_item_two)
+          .AddSimple(name_three, ResourceId(0x7f020003))
+          .SetOverlayable(name_three, overlayable_item_three)
+          .Build();
+  ResourceTable output_table;
+  ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &output_table));
+  auto search_result = output_table.FindResource(test::ParseNameOrDie(name_zero));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  OverlayableItem& result_overlayable = search_result.value().entry->overlayable_item.value();
+  EXPECT_EQ(result_overlayable.overlayable->name, "TestName");
+  EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
+  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem
+                                         | OverlayableItem::Policy::kProduct);
+  search_result = output_table.FindResource(test::ParseNameOrDie(name_one));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  result_overlayable = search_result.value().entry->overlayable_item.value();
+  EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
+  EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
+  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic);
+  search_result = output_table.FindResource(test::ParseNameOrDie(name_two));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  result_overlayable = search_result.value().entry->overlayable_item.value();
+  EXPECT_EQ(result_overlayable.overlayable->name, "TestName");
+  EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
+  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem
+                                         | OverlayableItem::Policy::kProduct
+                                         | OverlayableItem::Policy::kVendor);
+  search_result = output_table.FindResource(test::ParseNameOrDie(name_three));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  result_overlayable = search_result.value().entry->overlayable_item.value();
+  EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
+  EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
+  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic);
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 6b5746d..aff1b39 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -390,9 +390,6 @@
       case pb::OverlayableItem::PRODUCT:
         out_overlayable->policies |= OverlayableItem::Policy::kProduct;
         break;
-      case pb::OverlayableItem::PRODUCT_SERVICES:
-        out_overlayable->policies |= OverlayableItem::Policy::kProductServices;
-        break;
       default:
         *out_error = "unknown overlayable policy";
         return false;
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index 76fbb46..b549e23 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -303,9 +303,6 @@
   if (overlayable_item.policies & OverlayableItem::Policy::kProduct) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT);
   }
-  if (overlayable_item.policies & OverlayableItem::Policy::kProductServices) {
-    pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT_SERVICES);
-  }
   if (overlayable_item.policies & OverlayableItem::Policy::kSystem) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::SYSTEM);
   }
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index 4a3c1b8..cce3939 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -519,7 +519,7 @@
 
   OverlayableItem overlayable_item_bar(std::make_shared<Overlayable>(
       "TaskBar", "overlay://theme"));
-  overlayable_item_bar.policies |= OverlayableItem::Policy::kProductServices;
+  overlayable_item_bar.policies |= OverlayableItem::Policy::kPublic;
   overlayable_item_bar.policies |= OverlayableItem::Policy::kVendor;
 
   OverlayableItem overlayable_item_baz(std::make_shared<Overlayable>(
@@ -565,7 +565,7 @@
   overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(overlayable_item.overlayable->name, Eq("TaskBar"));
   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
-  EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kProductServices
+  EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic
                                               | OverlayableItem::Policy::kVendor));
 
   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz"));
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 85bf6f2..5812ec4 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -213,6 +213,27 @@
   return true;
 }
 
+static bool AddDeprecatedUsesFeatures(xml::Element* el, SourcePathDiagnostics* diag) {
+  if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
+    if (attr->value.empty()) {
+      return true;
+    }
+
+    // Add "android.hardware.fingerprint" when "android.hardware.biometric.fingerprint" is found,
+    // since the former is deprecated in Q and the latter is not present pre-Q. (see b/115639644)
+    if (attr->value == "android.hardware.biometrics.fingerprint") {
+      auto element = el->CloneElement([&](const xml::Element& el, xml::Element* out_el) {
+        xml::Attribute* cloned_attr = out_el->FindOrCreateAttribute(xml::kSchemaAndroid, "name");
+        cloned_attr->value = "android.hardware.fingerprint";
+      });
+
+      el->parent->AppendChild(std::move(element));
+    }
+  }
+
+  return true;
+}
+
 bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
                                IDiagnostics* diag) {
   // First verify some options.
@@ -247,6 +268,7 @@
   // Common <uses-feature> actions.
   xml::XmlNodeAction uses_feature_action;
   uses_feature_action.Action(VerifyUsesFeature);
+  uses_feature_action.Action(AddDeprecatedUsesFeatures);
 
   // Common component actions.
   xml::XmlNodeAction component_action;
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index adea627..fcc9f55 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -832,4 +832,36 @@
   EXPECT_THAT(Verify(input), NotNull());
 }
 
+TEST_F(ManifestFixerTest, UsesFeatureAddDeprecated) {
+  std::string input = R"(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android">
+        <uses-feature android:name="android.hardware.biometrics.fingerprint" />
+        <feature-group>
+          <uses-feature android:name="android.hardware.biometrics.fingerprint" />
+        </feature-group>
+      </manifest>)";
+
+  std::unique_ptr<xml::XmlResource> manifest = Verify(input);
+  ASSERT_THAT(manifest, NotNull());
+  EXPECT_THAT(manifest->root->FindChildWithAttribute("", "uses-feature",
+                                                     xml::kSchemaAndroid, "name",
+                                                     "android.hardware.biometrics.fingerprint"),
+              Ne(nullptr));
+  EXPECT_THAT(manifest->root->FindChildWithAttribute("", "uses-feature",
+                                                     xml::kSchemaAndroid, "name",
+                                                     "android.hardware.fingerprint"),
+              Ne(nullptr));
+
+  xml::Element* feature_group = manifest->root->FindChild("", "feature-group");
+  ASSERT_THAT(feature_group, Ne(nullptr));
+
+  EXPECT_THAT(feature_group->FindChildWithAttribute("", "uses-feature", xml::kSchemaAndroid, "name",
+                                                    "android.hardware.biometrics.fingerprint"),
+              Ne(nullptr));
+  EXPECT_THAT(feature_group->FindChildWithAttribute("", "uses-feature", xml::kSchemaAndroid, "name",
+                                                    "android.hardware.fingerprint"),
+              Ne(nullptr));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 921d634..ad3674e 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -484,7 +484,7 @@
 
   OverlayableItem overlayable_item(overlayable);
   overlayable_item.policies |= OverlayableItem::Policy::kPublic;
-  overlayable_item.policies |= OverlayableItem::Policy::kProductServices;
+  overlayable_item.policies |= OverlayableItem::Policy::kSystem;
   std::unique_ptr<ResourceTable> table_b =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.a", 0x7f)
@@ -506,7 +506,7 @@
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources"));
   EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization"));
   EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic
-                                                   | OverlayableItem::Policy::kProductServices));
+                                                   | OverlayableItem::Policy::kSystem));
 }
 
 TEST_F(TableMergerTest, SameResourceDifferentNameFail) {
diff --git a/tools/aapt2/optimize/ResourcePathShortener.cpp b/tools/aapt2/optimize/ResourcePathShortener.cpp
new file mode 100644
index 0000000..c5df3dd
--- /dev/null
+++ b/tools/aapt2/optimize/ResourcePathShortener.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#include "optimize/ResourcePathShortener.h"
+
+#include <math.h>
+#include <unordered_set>
+
+#include "androidfw/StringPiece.h"
+
+#include "ResourceTable.h"
+#include "ValueVisitor.h"
+
+
+static const std::string base64_chars =
+             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+             "abcdefghijklmnopqrstuvwxyz"
+             "0123456789-_";
+
+namespace aapt {
+
+ResourcePathShortener::ResourcePathShortener(
+    std::map<std::string, std::string>& path_map_out)
+    : path_map_(path_map_out) {
+}
+
+std::string ShortenFileName(const android::StringPiece& file_path, int output_length) {
+  std::size_t hash_num = std::hash<android::StringPiece>{}(file_path);
+  std::string result = "";
+  // Convert to (modified) base64 so that it is a proper file path.
+  for (int i = 0; i < output_length; i++) {
+    uint8_t sextet = hash_num & 0x3f;
+    hash_num >>= 6;
+    result += base64_chars[sextet];
+  }
+  return result;
+}
+
+
+// Calculate the optimal hash length such that an average of 10% of resources
+// collide in their shortened path.
+// Reference: http://matt.might.net/articles/counting-hash-collisions/
+int OptimalShortenedLength(int num_resources) {
+  int num_chars = 2;
+  double N = 64*64; // hash space when hash is 2 chars long
+  double max_collisions = num_resources * 0.1;
+  while (num_resources - N + N * pow((N - 1) / N, num_resources) > max_collisions) {
+    N *= 64;
+    num_chars++;
+  }
+  return num_chars;
+}
+
+std::string GetShortenedPath(const android::StringPiece& shortened_filename,
+    const android::StringPiece& extension, int collision_count) {
+  std::string shortened_path = "res/" + shortened_filename.to_string();
+  if (collision_count > 0) {
+    shortened_path += std::to_string(collision_count);
+  }
+  shortened_path += extension;
+  return shortened_path;
+}
+
+bool ResourcePathShortener::Consume(IAaptContext* context, ResourceTable* table) {
+  // used to detect collisions
+  std::unordered_set<std::string> shortened_paths;
+  std::unordered_set<FileReference*> file_refs;
+  for (auto& package : table->packages) {
+    for (auto& type : package->types) {
+      for (auto& entry : type->entries) {
+        for (auto& config_value : entry->values) {
+          FileReference* file_ref = ValueCast<FileReference>(config_value->value.get());
+          if (file_ref) {
+            file_refs.insert(file_ref);
+          }
+        }
+      }
+    }
+  }
+  int num_chars = OptimalShortenedLength(file_refs.size());
+  for (auto& file_ref : file_refs) {
+    android::StringPiece res_subdir, actual_filename, extension;
+    util::ExtractResFilePathParts(*file_ref->path, &res_subdir, &actual_filename, &extension);
+
+    std::string shortened_filename = ShortenFileName(*file_ref->path, num_chars);
+    int collision_count = 0;
+    std::string shortened_path = GetShortenedPath(shortened_filename, extension, collision_count);
+    while (shortened_paths.find(shortened_path) != shortened_paths.end()) {
+      collision_count++;
+      shortened_path = GetShortenedPath(shortened_filename, extension, collision_count);
+    }
+    shortened_paths.insert(shortened_path);
+    path_map_.insert({*file_ref->path, shortened_path});
+    file_ref->path = table->string_pool.MakeRef(shortened_path, file_ref->path.GetContext());
+  }
+  return true;
+}
+
+}  // namespace aapt
diff --git a/tools/aapt2/optimize/ResourcePathShortener.h b/tools/aapt2/optimize/ResourcePathShortener.h
new file mode 100644
index 0000000..f1074ef
--- /dev/null
+++ b/tools/aapt2/optimize/ResourcePathShortener.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#ifndef AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H
+#define AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H
+
+#include <map>
+
+#include "android-base/macros.h"
+
+#include "process/IResourceTableConsumer.h"
+
+namespace aapt {
+
+class ResourceTable;
+
+// Maps resources in the apk to shortened paths.
+class ResourcePathShortener : public IResourceTableConsumer {
+ public:
+  explicit ResourcePathShortener(std::map<std::string, std::string>& path_map_out);
+
+  bool Consume(IAaptContext* context, ResourceTable* table) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ResourcePathShortener);
+  std::map<std::string, std::string>& path_map_;
+};
+
+} // namespace aapt
+
+#endif  // AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H
diff --git a/tools/aapt2/optimize/ResourcePathShortener_test.cpp b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
new file mode 100644
index 0000000..88cadc7
--- /dev/null
+++ b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#include "optimize/ResourcePathShortener.h"
+
+#include "ResourceTable.h"
+#include "test/Test.h"
+
+using ::aapt::test::GetValue;
+using ::testing::Not;
+using ::testing::NotNull;
+using ::testing::Eq;
+
+namespace aapt {
+
+TEST(ResourcePathShortenerTest, FileRefPathsChangedInResourceTable) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+  std::unique_ptr<ResourceTable> table =
+      test::ResourceTableBuilder()
+          .AddFileReference("android:drawable/xmlfile", "res/drawables/xmlfile.xml")
+          .AddFileReference("android:drawable/xmlfile2", "res/drawables/xmlfile2.xml")
+          .AddString("android:string/string", "res/should/still/be/the/same.png")
+          .Build();
+
+  std::map<std::string, std::string> path_map;
+  ASSERT_TRUE(ResourcePathShortener(path_map).Consume(context.get(), table.get()));
+
+  // Expect that the path map is populated
+  ASSERT_THAT(path_map.find("res/drawables/xmlfile.xml"), Not(Eq(path_map.end())));
+  ASSERT_THAT(path_map.find("res/drawables/xmlfile2.xml"), Not(Eq(path_map.end())));
+
+  // The file paths were changed
+  EXPECT_THAT(path_map.at("res/drawables/xmlfile.xml"), Not(Eq("res/drawables/xmlfile.xml")));
+  EXPECT_THAT(path_map.at("res/drawables/xmlfile2.xml"), Not(Eq("res/drawables/xmlfile2.xml")));
+
+  // Different file paths should remain different
+  EXPECT_THAT(path_map["res/drawables/xmlfile.xml"],
+              Not(Eq(path_map["res/drawables/xmlfile2.xml"])));
+
+  FileReference* ref =
+      GetValue<FileReference>(table.get(), "android:drawable/xmlfile");
+  ASSERT_THAT(ref, NotNull());
+  // The map correctly points to the new location of the file
+  EXPECT_THAT(path_map["res/drawables/xmlfile.xml"], Eq(*ref->path));
+
+  // Strings should not be affected, only file paths
+  EXPECT_THAT(
+      *GetValue<String>(table.get(), "android:string/string")->value,
+              Eq("res/should/still/be/the/same.png"));
+  EXPECT_THAT(path_map.find("res/should/still/be/the/same.png"), Eq(path_map.end()));
+}
+
+}   // namespace aapt
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index acf1f1e..d1fe43e 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -297,7 +297,7 @@
 class V2LineParser(object):
     __slots__ = ["tokenized", "current", "len"]
 
-    MODIFIERS = set("public protected internal private abstract default static final transient volatile synchronized".split())
+    MODIFIERS = set("public protected internal private abstract default static final transient volatile synchronized native operator sealed strictfp infix inline suspend vararg".split())
     JAVA_LANG_TYPES = set("AbstractMethodError AbstractStringBuilder Appendable ArithmeticException ArrayIndexOutOfBoundsException ArrayStoreException AssertionError AutoCloseable Boolean BootstrapMethodError Byte Character CharSequence Class ClassCastException ClassCircularityError ClassFormatError ClassLoader ClassNotFoundException Cloneable CloneNotSupportedException Comparable Compiler Deprecated Double Enum EnumConstantNotPresentException Error Exception ExceptionInInitializerError Float FunctionalInterface IllegalAccessError IllegalAccessException IllegalArgumentException IllegalMonitorStateException IllegalStateException IllegalThreadStateException IncompatibleClassChangeError IndexOutOfBoundsException InheritableThreadLocal InstantiationError InstantiationException Integer InternalError InterruptedException Iterable LinkageError Long Math NegativeArraySizeException NoClassDefFoundError NoSuchFieldError NoSuchFieldException NoSuchMethodError NoSuchMethodException NullPointerException Number NumberFormatException Object OutOfMemoryError Override Package package-info.java Process ProcessBuilder ProcessEnvironment ProcessImpl Readable ReflectiveOperationException Runnable Runtime RuntimeException RuntimePermission SafeVarargs SecurityException SecurityManager Short StackOverflowError StackTraceElement StrictMath String StringBuffer StringBuilder StringIndexOutOfBoundsException SuppressWarnings System Thread ThreadDeath ThreadGroup ThreadLocal Throwable TypeNotPresentException UNIXProcess UnknownError UnsatisfiedLinkError UnsupportedClassVersionError UnsupportedOperationException VerifyError VirtualMachineError Void".split())
 
     def __init__(self, raw):
@@ -355,7 +355,7 @@
         self.parse_eof()
 
     def parse_into_field(self, field):
-        kind = self.parse_token("field")
+        kind = self.parse_one_of("field", "property")
         field.split = [kind]
         annotations = self.parse_annotations()
         if "@Deprecated" in annotations:
@@ -442,13 +442,19 @@
         return None
 
     def parse_type(self):
+        self.parse_annotations()
         type = self.parse_token()
+        if type[-1] == '.':
+            self.parse_annotations()
+            type += self.parse_token()
         if type in V2LineParser.JAVA_LANG_TYPES:
             type = "java.lang." + type
         self.parse_matching_paren("<", ">")
         while True:
             t = self.lookahead()
-            if t == "[]":
+            if t == "@":
+                self.parse_annotation()
+            elif t == "[]":
                 type += self.parse_token()
             elif self.parse_kotlin_nullability() is not None:
                 pass  # discard nullability for now
@@ -478,17 +484,23 @@
             self.parse_token(",")
 
     def parse_arg(self):
+        self.parse_if("vararg")  # kotlin vararg
         self.parse_annotations()
         type = self.parse_arg_type()
         l = self.lookahead()
         if l != "," and l != ")":
-            self.parse_token()  # kotlin argument name
+            if self.lookahead() != '=':
+                self.parse_token()  # kotlin argument name
             if self.parse_if('='): # kotlin default value
-                (self.parse_matching_paren('(', ')') or
-                 self.parse_matching_paren('{', '}') or
-                 self.parse_token() and self.parse_matching_paren('(', ')'))
+                self.parse_expression()
         return type
 
+    def parse_expression(self):
+        while not self.lookahead() in [')', ',', ';']:
+            (self.parse_matching_paren('(', ')') or
+            self.parse_matching_paren('{', '}') or
+            self.parse_token())
+
     def parse_throws(self):
         ret = []
         if self.parse_if("throws"):
@@ -516,7 +528,7 @@
 
     def parse_annotation_default(self):
         if self.parse_if("default"):
-            self.parse_value()
+            self.parse_expression()
 
     def parse_value(self):
         if self.lookahead() == "{":
@@ -599,7 +611,7 @@
             clazz.ctors.append(Method(clazz, line, raw, blame, sig_format=sig_format))
         elif raw.startswith("    method"):
             clazz.methods.append(Method(clazz, line, raw, blame, sig_format=sig_format))
-        elif raw.startswith("    field"):
+        elif raw.startswith("    field") or raw.startswith("    property"):
             clazz.fields.append(Field(clazz, line, raw, blame, sig_format=sig_format))
         elif raw.startswith("  }") and clazz:
             yield clazz
@@ -942,7 +954,7 @@
             else:
                 error(clazz, f, "F2", "Bare fields must be marked final, or add accessors if mutable")
 
-        if not "static" in f.split:
+        if "static" not in f.split and "property" not in f.split:
             if not re.match("[a-z]([a-zA-Z]+)?", f.name):
                 error(clazz, f, "S1", "Non-static fields must be named using myField style")
 
@@ -1650,7 +1662,7 @@
         binary.add(op)
 
     for m in clazz.methods:
-        if 'static' in m.split:
+        if 'static' in m.split or 'operator' in m.split:
             continue
 
         # https://kotlinlang.org/docs/reference/operator-overloading.html#unary-prefix-operators
diff --git a/tools/apilint/apilint_test.py b/tools/apilint/apilint_test.py
index 081e98d..fde61a9 100644
--- a/tools/apilint/apilint_test.py
+++ b/tools/apilint/apilint_test.py
@@ -225,11 +225,12 @@
         self.assertEquals('pkg.SuppressLint', cls.fullname)
 
     def test_parse_method(self):
-        m = self._method("method @Deprecated public static <T> Class<T>[][] name("
+        m = self._method("method @Deprecated public static native <T> Class<T>[][] name("
                          + "Class<T[]>[][], Class<T[][][]>[][]...) throws Exception, T;")
         self.assertTrue('static' in m.split)
         self.assertTrue('public' in m.split)
         self.assertTrue('method' in m.split)
+        self.assertTrue('native' in m.split)
         self.assertTrue('deprecated' in m.split)
         self.assertEquals('java.lang.Class[][]', m.typ)
         self.assertEquals('name', m.name)
@@ -248,6 +249,7 @@
         self._method('method abstract String category() default "";', cls=cls)
         self._method('method abstract boolean deepExport() default false;', cls=cls)
         self._method('method abstract ViewDebug.FlagToString[] flagMapping() default {};', cls=cls)
+        self._method('method abstract ViewDebug.FlagToString[] flagMapping() default (double)java.lang.Float.NEGATIVE_INFINITY;', cls=cls)
 
     def test_parse_string_field(self):
         f = self._field('field @Deprecated public final String SOME_NAME = "value";')
@@ -286,5 +288,44 @@
         self._method("method <T> T name(T a = 1, T b = A(1), Lambda f = { false }, N? n = null, "
                          + """double c = (1/0), float d = 1.0f, String s = "heyo", char c = 'a');""")
 
+    def test_kotlin_operator(self):
+        self._method('method public operator void unaryPlus(androidx.navigation.NavDestination);')
+        self._method('method public static operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, @IdRes int id);')
+        self._method('method public static operator <T> T get(androidx.navigation.NavigatorProvider, kotlin.reflect.KClass<T> clazz);')
+
+    def test_kotlin_property(self):
+        self._field('property public VM value;')
+        self._field('property public final String? action;')
+
+    def test_kotlin_varargs(self):
+        self._method('method public void error(int p = "42", Integer int2 = "null", int p1 = "42", vararg String args);')
+
+    def test_kotlin_default_values(self):
+        self._method('method public void foo(String! = null, String! = "Hello World", int = 42);')
+        self._method('method void method(String, String firstArg = "hello", int secondArg = "42", String thirdArg = "world");')
+        self._method('method void method(String, String firstArg = "hello", int secondArg = "42");')
+        self._method('method void method(String, String firstArg = "hello");')
+        self._method('method void edit(android.Type, boolean commit = false, Function1<? super Editor,kotlin.Unit> action);')
+        self._method('method <K, V> LruCache<K,V> lruCache(int maxSize, Function2<? super K,? super V,java.lang.Integer> sizeOf = { _, _ -> 1 }, Function1<? extends V> create = { (V)null }, Function4<kotlin.Unit> onEntryRemoved = { _, _, _, _ ->  });')
+        self._method('method android.Bitmap? drawToBitmap(android.View, android.Config config = android.graphics.Bitmap.Config.ARGB_8888);')
+        self._method('method void emptyLambda(Function0<kotlin.Unit> sizeOf = {});')
+        self._method('method void method1(int p = 42, Integer? int2 = null, int p1 = 42, String str = "hello world", java.lang.String... args);')
+        self._method('method void method2(int p, int int2 = (2 * int) * some.other.pkg.Constants.Misc.SIZE);')
+        self._method('method void method3(String str, int p, int int2 = double(int) + str.length);')
+        self._method('method void print(test.pkg.Foo foo = test.pkg.Foo());')
+
+    def test_type_use_annotation(self):
+        self._method('method public static int codePointAt(char @NonNull [], int);')
+        self._method('method @NonNull public java.util.Set<java.util.Map.@NonNull Entry<K,V>> entrySet();')
+
+        m = self._method('method @NonNull public java.lang.annotation.@NonNull Annotation @NonNull [] getAnnotations();')
+        self.assertEquals('java.lang.annotation.Annotation[]', m.typ)
+
+        m = self._method('method @NonNull public abstract java.lang.annotation.@NonNull Annotation @NonNull [] @NonNull [] getParameterAnnotations();')
+        self.assertEquals('java.lang.annotation.Annotation[][]', m.typ)
+
+        m = self._method('method @NonNull public @NonNull String @NonNull [] split(@NonNull String, int);')
+        self.assertEquals('java.lang.String[]', m.typ)
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/signedconfig/prod_public.pem b/tools/signedconfig/prod_public.pem
new file mode 100644
index 0000000..8c10215
--- /dev/null
+++ b/tools/signedconfig/prod_public.pem
@@ -0,0 +1,5 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+lky6wKyGL6lE1VrD0YTMHwb0Xwc
++tzC8MvnrzVxodvTpVY/jV7V+Zktcx+pry43XPABFRXtbhTo+qykhyBA1g==
+-----END PUBLIC KEY-----
+
diff --git a/tools/signedconfig/verify_b64.sh b/tools/signedconfig/verify_b64.sh
index 8e1f58c..a4ac6a8 100755
--- a/tools/signedconfig/verify_b64.sh
+++ b/tools/signedconfig/verify_b64.sh
@@ -7,4 +7,30 @@
 # The arg values can be taken from the debug log for SignedConfigService when verbose logging is
 # enabled.
 
-openssl dgst -sha256 -verify $(dirname $0)/debug_public.pem -signature <(echo $2 | base64 -d) <(echo $1 | base64 -d)
+function verify() {
+  D=${1}
+  S=${2}
+  K=${3}
+  echo Trying ${K}
+  openssl dgst -sha256 -verify $(dirname $0)/${K} -signature <(echo ${S} | base64 -d) <(echo ${D} | base64 -d)
+}
+
+
+PROD_KEY_NAME=prod_public.pem
+DEBUG_KEY_NAME=debug_public.pem
+SIGNATURE="$2"
+DATA="$1"
+
+echo DATA: ${DATA}
+echo SIGNATURE: ${SIGNATURE}
+
+if verify "${DATA}" "${SIGNATURE}" "${PROD_KEY_NAME}"; then
+  echo Verified with ${PROD_KEY_NAME}
+  exit 0
+fi
+
+if verify "${DATA}" "${SIGNATURE}" "${DEBUG_KEY_NAME}"; then
+  echo Verified with ${DEBUG_KEY_NAME}
+  exit 0
+fi
+exit 1
diff --git a/wifi/java/android/net/wifi/DppStatusCallback.java b/wifi/java/android/net/wifi/DppStatusCallback.java
deleted file mode 100644
index fa2ab30..0000000
--- a/wifi/java/android/net/wifi/DppStatusCallback.java
+++ /dev/null
@@ -1,166 +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.net.wifi;
-
-import android.annotation.IntDef;
-import android.annotation.SystemApi;
-import android.os.Handler;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * DPP Status Callback. Use this callback to get status updates (success, failure, progress)
- * from the DPP operation started with {@link WifiManager#startDppAsConfiguratorInitiator(String,
- * int, int, Handler, DppStatusCallback)} or {@link WifiManager#startDppAsEnrolleeInitiator(String,
- * Handler, DppStatusCallback)}
- * @hide
- */
-@SystemApi
-public abstract class DppStatusCallback {
-    /**
-     * DPP Success event: Configuration sent (Configurator mode).
-     */
-    public static final int DPP_EVENT_SUCCESS_CONFIGURATION_SENT = 0;
-
-    /** @hide */
-    @IntDef(prefix = { "DPP_EVENT_SUCCESS_" }, value = {
-            DPP_EVENT_SUCCESS_CONFIGURATION_SENT,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface DppSuccessStatusCode {}
-
-    /**
-     * DPP Progress event: Initial authentication with peer succeeded.
-     */
-    public static final int DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0;
-
-    /**
-     * DPP Progress event: Peer requires more time to process bootstrapping.
-     */
-    public static final int DPP_EVENT_PROGRESS_RESPONSE_PENDING = 1;
-
-    /** @hide */
-    @IntDef(prefix = { "DPP_EVENT_PROGRESS_" }, value = {
-            DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS,
-            DPP_EVENT_PROGRESS_RESPONSE_PENDING,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface DppProgressStatusCode {}
-
-    /**
-     * DPP Failure event: Scanned QR code is either not a DPP URI, or the DPP URI has errors.
-     */
-    public static final int DPP_EVENT_FAILURE_INVALID_URI = -1;
-
-    /**
-     * DPP Failure event: Bootstrapping/Authentication initialization process failure.
-     */
-    public static final int DPP_EVENT_FAILURE_AUTHENTICATION = -2;
-
-    /**
-     * DPP Failure event: Both devices are implementing the same role and are incompatible.
-     */
-    public static final int DPP_EVENT_FAILURE_NOT_COMPATIBLE = -3;
-
-    /**
-     * DPP Failure event: Configuration process has failed due to malformed message.
-     */
-    public static final int DPP_EVENT_FAILURE_CONFIGURATION = -4;
-
-    /**
-     * DPP Failure event: DPP request while in another DPP exchange.
-     */
-    public static final int DPP_EVENT_FAILURE_BUSY = -5;
-
-    /**
-     * DPP Failure event: No response from the peer.
-     */
-    public static final int DPP_EVENT_FAILURE_TIMEOUT = -6;
-
-    /**
-     * DPP Failure event: General protocol failure.
-     */
-    public static final int DPP_EVENT_FAILURE = -7;
-
-    /**
-     * DPP Failure event: Feature or option is not supported.
-     */
-    public static final int DPP_EVENT_FAILURE_NOT_SUPPORTED = -8;
-
-    /**
-     * DPP Failure event: Invalid network provided to DPP configurator.
-     * Network must either be WPA3-Personal (SAE) or WPA2-Personal (PSK).
-     */
-    public static final int DPP_EVENT_FAILURE_INVALID_NETWORK = -9;
-
-
-    /** @hide */
-    @IntDef(prefix = {"DPP_EVENT_FAILURE_"}, value = {
-            DPP_EVENT_FAILURE_INVALID_URI,
-            DPP_EVENT_FAILURE_AUTHENTICATION,
-            DPP_EVENT_FAILURE_NOT_COMPATIBLE,
-            DPP_EVENT_FAILURE_CONFIGURATION,
-            DPP_EVENT_FAILURE_BUSY,
-            DPP_EVENT_FAILURE_TIMEOUT,
-            DPP_EVENT_FAILURE,
-            DPP_EVENT_FAILURE_NOT_SUPPORTED,
-            DPP_EVENT_FAILURE_INVALID_NETWORK,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface DppFailureStatusCode {
-    }
-
-    /**
-     * Called when local DPP Enrollee successfully receives a new Wi-Fi configuration from the
-     * peer DPP configurator. This callback marks the successful end of the DPP current DPP
-     * session, and no further callbacks will be called. This callback is the successful outcome
-     * of a DPP flow starting with {@link WifiManager#startDppAsEnrolleeInitiator(String, Handler,
-     * DppStatusCallback)}.
-     *
-     * @param newNetworkId New Wi-Fi configuration with a network ID received from the configurator
-     */
-    public abstract void onEnrolleeSuccess(int newNetworkId);
-
-    /**
-     * Called when a DPP success event takes place, except for when configuration is received from
-     * an external Configurator. The callback onSuccessConfigReceived will be used in this case.
-     * This callback marks the successful end of the current DPP session, and no further
-     * callbacks will be called. This callback is the successful outcome of a DPP flow starting with
-     * {@link WifiManager#startDppAsConfiguratorInitiator(String, int, int, Handler,
-     * DppStatusCallback)}.
-     *
-     * @param code DPP success status code.
-     */
-    public abstract void onConfiguratorSuccess(@DppSuccessStatusCode int code);
-
-    /**
-     * Called when a DPP Failure event takes place. This callback marks the unsuccessful end of the
-     * current DPP session, and no further callbacks will be called.
-     *
-     * @param code DPP failure status code.
-     */
-    public abstract void onFailure(@DppFailureStatusCode int code);
-
-    /**
-     * Called when DPP events that indicate progress take place. Can be used by UI elements
-     * to show progress.
-     *
-     * @param code DPP progress status code.
-     */
-    public abstract void onProgress(@DppProgressStatusCode int code);
-}
diff --git a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
new file mode 100644
index 0000000..3b4a6cd
--- /dev/null
+++ b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
@@ -0,0 +1,179 @@
+/*
+ * 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.net.wifi;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.os.Handler;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Easy Connect (DPP) Status Callback. Use this callback to get status updates (success, failure,
+ * progress) from the Easy Connect operation started with
+ * {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String,
+ * int, int, Handler, EasyConnectStatusCallback)} or
+ * {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String,
+ * Handler, EasyConnectStatusCallback)}
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class EasyConnectStatusCallback {
+    /**
+     * Easy Connect Success event: Configuration sent (Configurator mode).
+     */
+    public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 0;
+
+    /** @hide */
+    @IntDef(prefix = {"EASY_CONNECT_EVENT_SUCCESS_"}, value = {
+            EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EasyConnectSuccessStatusCode {
+    }
+
+    /**
+     * Easy Connect Progress event: Initial authentication with peer succeeded.
+     */
+    public static final int EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0;
+
+    /**
+     * Easy Connect Progress event: Peer requires more time to process bootstrapping.
+     */
+    public static final int EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING = 1;
+
+    /** @hide */
+    @IntDef(prefix = {"EASY_CONNECT_EVENT_PROGRESS_"}, value = {
+            EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS,
+            EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EasyConnectProgressStatusCode {
+    }
+
+    /**
+     * Easy Connect Failure event: Scanned QR code is either not a Easy Connect URI, or the Easy
+     * Connect URI has errors.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_URI = -1;
+
+    /**
+     * Easy Connect Failure event: Bootstrapping/Authentication initialization process failure.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION = -2;
+
+    /**
+     * Easy Connect Failure event: Both devices are implementing the same role and are incompatible.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE = -3;
+
+    /**
+     * Easy Connect Failure event: Configuration process has failed due to malformed message.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_CONFIGURATION = -4;
+
+    /**
+     * Easy Connect Failure event: Easy Connect request while in another Easy Connect exchange.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_BUSY = -5;
+
+    /**
+     * Easy Connect Failure event: No response from the peer.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_TIMEOUT = -6;
+
+    /**
+     * Easy Connect Failure event: General protocol failure.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE = -7;
+
+    /**
+     * Easy Connect Failure event: Feature or option is not supported.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED = -8;
+
+    /**
+     * Easy Connect Failure event: Invalid network provided to Easy Connect configurator.
+     * Network must either be WPA3-Personal (SAE) or WPA2-Personal (PSK).
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = -9;
+
+
+    /** @hide */
+    @IntDef(prefix = {"EASY_CONNECT_EVENT_FAILURE_"}, value = {
+            EASY_CONNECT_EVENT_FAILURE_INVALID_URI,
+            EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION,
+            EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE,
+            EASY_CONNECT_EVENT_FAILURE_CONFIGURATION,
+            EASY_CONNECT_EVENT_FAILURE_BUSY,
+            EASY_CONNECT_EVENT_FAILURE_TIMEOUT,
+            EASY_CONNECT_EVENT_FAILURE,
+            EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED,
+            EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EasyConnectFailureStatusCode {
+    }
+
+    /**
+     * Called when local Easy Connect Enrollee successfully receives a new Wi-Fi configuration from
+     * the
+     * peer Easy Connect configurator. This callback marks the successful end of the Easy Connect
+     * current Easy Connect
+     * session, and no further callbacks will be called. This callback is the successful outcome
+     * of a Easy Connect flow starting with
+     * {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String,
+     * Handler,
+     * EasyConnectStatusCallback)}.
+     *
+     * @param newNetworkId New Wi-Fi configuration with a network ID received from the configurator
+     */
+    public abstract void onEnrolleeSuccess(int newNetworkId);
+
+    /**
+     * Called when a Easy Connect success event takes place, except for when configuration is
+     * received from
+     * an external Configurator. The callback onSuccessConfigReceived will be used in this case.
+     * This callback marks the successful end of the current Easy Connect session, and no further
+     * callbacks will be called. This callback is the successful outcome of a Easy Connect flow
+     * starting with
+     * {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String, int, int, Handler,
+     * EasyConnectStatusCallback)}.
+     *
+     * @param code Easy Connect success status code.
+     */
+    public abstract void onConfiguratorSuccess(@EasyConnectSuccessStatusCode int code);
+
+    /**
+     * Called when a Easy Connect Failure event takes place. This callback marks the unsuccessful
+     * end of the
+     * current Easy Connect session, and no further callbacks will be called.
+     *
+     * @param code Easy Connect failure status code.
+     */
+    public abstract void onFailure(@EasyConnectFailureStatusCode int code);
+
+    /**
+     * Called when Easy Connect events that indicate progress take place. Can be used by UI elements
+     * to show progress.
+     *
+     * @param code Easy Connect progress status code.
+     */
+    public abstract void onProgress(@EasyConnectProgressStatusCode int code);
+}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 28dd9b4..e019f28 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -145,11 +145,23 @@
          */
         public static final int SUITE_B_192 = 10;
 
+        /**
+         * WPA pre-shared key with stronger SHA256-based algorithms.
+         * @hide
+         */
+        public static final int WPA_PSK_SHA256 = 11;
+
+        /**
+         * WPA using EAP authentication with stronger SHA256-based algorithms.
+         * @hide
+         */
+        public static final int WPA_EAP_SHA256 = 12;
+
         public static final String varName = "key_mgmt";
 
         public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP",
                 "IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP",
-                "SAE", "OWE", "SUITE_B_192"};
+                "SAE", "OWE", "SUITE_B_192", "WPA_PSK_SHA256", "WPA_EAP_SHA256" };
     }
 
     /**
@@ -1886,6 +1898,7 @@
         if (creatorName != null) sbuf.append(" cname=" + creatorName);
         if (lastUpdateUid != 0) sbuf.append(" luid=" + lastUpdateUid);
         if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName);
+        if (updateIdentifier != null) sbuf.append(" updateIdentifier=" + updateIdentifier);
         sbuf.append(" lcuid=" + lastConnectUid);
         sbuf.append(" userApproved=" + userApprovedAsString(userApproved));
         sbuf.append(" noInternetAccessExpected=" + noInternetAccessExpected);
@@ -2281,6 +2294,7 @@
             mRandomizedMacAddress = source.mRandomizedMacAddress;
             macRandomizationSetting = source.macRandomizationSetting;
             requirePMF = source.requirePMF;
+            updateIdentifier = source.updateIdentifier;
         }
     }
 
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index af5ad51..35fba3d 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -16,6 +16,7 @@
 
 package android.net.wifi;
 
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkUtils;
@@ -93,12 +94,22 @@
     private int mRssi;
 
     /**
-     * Link speed in Mbps
+     * The unit in which links speeds are expressed.
      */
     public static final String LINK_SPEED_UNITS = "Mbps";
     private int mLinkSpeed;
 
     /**
+     * Tx(transmit) Link speed in Mbps
+     */
+    private int mTxLinkSpeed;
+
+    /**
+     * Rx(receive) Link speed in Mbps
+     */
+    private int mRxLinkSpeed;
+
+    /**
      * Frequency in MHz
      */
     public static final String FREQUENCY_UNITS = "MHz";
@@ -192,6 +203,8 @@
         setNetworkId(-1);
         setRssi(INVALID_RSSI);
         setLinkSpeed(-1);
+        setTxLinkSpeedMbps(-1);
+        setRxLinkSpeedMbps(-1);
         setFrequency(-1);
         setMeteredHint(false);
         setEphemeral(false);
@@ -219,6 +232,8 @@
             mNetworkId = source.mNetworkId;
             mRssi = source.mRssi;
             mLinkSpeed = source.mLinkSpeed;
+            mTxLinkSpeed = source.mTxLinkSpeed;
+            mRxLinkSpeed = source.mRxLinkSpeed;
             mFrequency = source.mFrequency;
             mIpAddress = source.mIpAddress;
             mMacAddress = source.mMacAddress;
@@ -313,7 +328,7 @@
 
     /**
      * Returns the current link speed in {@link #LINK_SPEED_UNITS}.
-     * @return the link speed.
+     * @return the link speed or -1 if there is no valid value.
      * @see #LINK_SPEED_UNITS
      */
     public int getLinkSpeed() {
@@ -323,7 +338,39 @@
     /** @hide */
     @UnsupportedAppUsage
     public void setLinkSpeed(int linkSpeed) {
-        this.mLinkSpeed = linkSpeed;
+        mLinkSpeed = linkSpeed;
+    }
+
+    /**
+     * Returns the current transmit link speed in Mbps.
+     * @return the Tx link speed or -1 if there is no valid value.
+     */
+    public int getTxLinkSpeedMbps() {
+        return mTxLinkSpeed;
+    }
+
+    /**
+     * Update the last transmitted packet bit rate in Mbps.
+     * @hide
+     */
+    public void setTxLinkSpeedMbps(int txLinkSpeed) {
+        mTxLinkSpeed = txLinkSpeed;
+    }
+
+    /**
+     * Returns the current receive link speed in Mbps.
+     * @return the Rx link speed or -1 if there is no valid value.
+     */
+    public int getRxLinkSpeedMbps() {
+        return mRxLinkSpeed;
+    }
+
+    /**
+     * Update the last received packet bit rate in Mbps.
+     * @hide
+     */
+    public void setRxLinkSpeedMbps(int rxLinkSpeed) {
+        mRxLinkSpeed = rxLinkSpeed;
     }
 
     /**
@@ -424,6 +471,7 @@
     }
 
     /** {@hide} */
+    @SystemApi
     public boolean isOsuAp() {
         return mOsuAp;
     }
@@ -529,17 +577,19 @@
         StringBuffer sb = new StringBuffer();
         String none = "<none>";
 
-        sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid).
-            append(", BSSID: ").append(mBSSID == null ? none : mBSSID).
-            append(", MAC: ").append(mMacAddress == null ? none : mMacAddress).
-            append(", Supplicant state: ").
-            append(mSupplicantState == null ? none : mSupplicantState).
-            append(", RSSI: ").append(mRssi).
-            append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS).
-            append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS).
-            append(", Net ID: ").append(mNetworkId).
-            append(", Metered hint: ").append(mMeteredHint).
-            append(", score: ").append(Integer.toString(score));
+        sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid)
+                .append(", BSSID: ").append(mBSSID == null ? none : mBSSID)
+                .append(", MAC: ").append(mMacAddress == null ? none : mMacAddress)
+                .append(", Supplicant state: ")
+                .append(mSupplicantState == null ? none : mSupplicantState)
+                .append(", RSSI: ").append(mRssi)
+                .append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS)
+                .append(", Tx Link speed: ").append(mTxLinkSpeed).append(LINK_SPEED_UNITS)
+                .append(", Rx Link speed: ").append(mRxLinkSpeed).append(LINK_SPEED_UNITS)
+                .append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS)
+                .append(", Net ID: ").append(mNetworkId)
+                .append(", Metered hint: ").append(mMeteredHint)
+                .append(", score: ").append(Integer.toString(score));
         return sb.toString();
     }
 
@@ -553,6 +603,8 @@
         dest.writeInt(mNetworkId);
         dest.writeInt(mRssi);
         dest.writeInt(mLinkSpeed);
+        dest.writeInt(mTxLinkSpeed);
+        dest.writeInt(mRxLinkSpeed);
         dest.writeInt(mFrequency);
         if (mIpAddress != null) {
             dest.writeByte((byte)1);
@@ -593,6 +645,8 @@
                 info.setNetworkId(in.readInt());
                 info.setRssi(in.readInt());
                 info.setLinkSpeed(in.readInt());
+                info.setTxLinkSpeedMbps(in.readInt());
+                info.setRxLinkSpeedMbps(in.readInt());
                 info.setFrequency(in.readInt());
                 if (in.readByte() == 1) {
                     try {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 517bf3b..801342d 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -236,9 +236,11 @@
     public static final int WIFI_CREDENTIAL_FORGOT = 1;
 
     /** @hide */
+    @SystemApi
     public static final int PASSPOINT_HOME_NETWORK = 0;
 
     /** @hide */
+    @SystemApi
     public static final int PASSPOINT_ROAMING_NETWORK = 1;
 
     /**
@@ -1219,7 +1221,11 @@
      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD
+    })
     public List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> getAllMatchingWifiConfigs(
             @NonNull List<ScanResult> scanResults) {
         List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
@@ -1258,7 +1264,11 @@
      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD
+    })
     public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
             List<ScanResult> scanResults) {
         try {
@@ -1281,7 +1291,11 @@
      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD
+    })
     public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
             @NonNull Set<OsuProvider> osuProviders) {
         try {
@@ -1727,7 +1741,13 @@
      * @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.
+     * @deprecated This is no longer supported.
      */
+    @Deprecated
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD
+    })
     public void removePasspointConfiguration(String fqdn) {
         try {
             if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
@@ -1745,7 +1765,13 @@
      *
      * @return A list of {@link PasspointConfiguration}
      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
+     * @deprecated This is no longer supported.
      */
+    @Deprecated
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD
+    })
     public List<PasspointConfiguration> getPasspointConfigurations() {
         try {
             return mService.getPasspointConfigurations();
@@ -4323,6 +4349,11 @@
      * @param callback {@link ProvisioningCallback} for updates regarding provisioning flow
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD
+    })
     public void startSubscriptionProvisioning(OsuProvider provider, ProvisioningCallback callback,
             @Nullable Handler handler) {
         Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
@@ -4586,93 +4617,100 @@
         }
     }
 
-    /* DPP - Device Provisioning Protocol AKA "Easy Connect" */
+    /* Easy Connect - AKA Device Provisioning Protocol (DPP) */
 
     /**
-     * DPP Network role: Station.
+     * Easy Connect Network role: Station.
+     *
      * @hide
      */
     @SystemApi
-    public static final int DPP_NETWORK_ROLE_STA = 0;
+    public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0;
 
     /**
-     * DPP Network role: Access Point.
+     * Easy Connect Network role: Access Point.
+     *
      * @hide
      */
     @SystemApi
-    public static final int DPP_NETWORK_ROLE_AP = 1;
+    public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1;
 
     /** @hide */
-    @IntDef(prefix = {"DPP_NETWORK_ROLE_"}, value = {
-            DPP_NETWORK_ROLE_STA,
-            DPP_NETWORK_ROLE_AP,
+    @IntDef(prefix = {"EASY_CONNECT_NETWORK_ROLE_"}, value = {
+            EASY_CONNECT_NETWORK_ROLE_STA,
+            EASY_CONNECT_NETWORK_ROLE_AP,
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface DppNetworkRole {}
+    public @interface EasyConnectNetworkRole {
+    }
 
     /**
-     * Start DPP in Configurator-Initiator role. The current device will initiate DPP bootstrapping
-     * with a peer, and configure the peer with the SSID and password of the specified network using
-     * the DPP protocol on an encrypted link.
+     * Start Easy Connect (DPP) in Configurator-Initiator role. The current device will initiate
+     * Easy Connect bootstrapping with a peer, and configure the peer with the SSID and password of
+     * the specified network using the Easy Connect protocol on an encrypted link.
      *
-     * @param enrolleeUri URI of the Enrollee obtained separately (e.g. QR code scanning)
-     * @param selectedNetworkId Selected network ID to be sent to the peer
+     * @param enrolleeUri         URI of the Enrollee obtained separately (e.g. QR code scanning)
+     * @param selectedNetworkId   Selected network ID to be sent to the peer
      * @param enrolleeNetworkRole The network role of the enrollee
-     * @param callback Callback for status updates
-     * @param handler The handler on whose thread to execute the callbacks. Null for main thread.
+     * @param callback            Callback for status updates
+     * @param handler             The handler on whose thread to execute the callbacks. Null for
+     *                            main thread.
      * @hide
      */
     @SystemApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.NETWORK_SETTINGS,
             android.Manifest.permission.NETWORK_SETUP_WIZARD})
-    public void startDppAsConfiguratorInitiator(@NonNull String enrolleeUri,
-            int selectedNetworkId, @DppNetworkRole int enrolleeNetworkRole,
-            @Nullable Handler handler, @NonNull DppStatusCallback callback) {
+    public void startEasyConnectAsConfiguratorInitiator(@NonNull String enrolleeUri,
+            int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole,
+            @Nullable Handler handler, @NonNull EasyConnectStatusCallback callback) {
         Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
         Binder binder = new Binder();
         try {
             mService.startDppAsConfiguratorInitiator(binder, enrolleeUri, selectedNetworkId,
-                    enrolleeNetworkRole, new DppCallbackProxy(looper, callback));
+                    enrolleeNetworkRole, new EasyConnectCallbackProxy(looper, callback));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Start DPP in Enrollee-Initiator role. The current device will initiate DPP bootstrapping
-     * with a peer, and receive the SSID and password from the peer configurator.
+     * Start Easy Connect (DPP) in Enrollee-Initiator role. The current device will initiate Easy
+     * Connect bootstrapping with a peer, and receive the SSID and password from the peer
+     * configurator.
      *
      * @param configuratorUri URI of the Configurator obtained separately (e.g. QR code scanning)
-     * @param callback Callback for status updates
-     * @param handler The handler on whose thread to execute the callbacks. Null for main thread.
+     * @param callback        Callback for status updates
+     * @param handler         The handler on whose thread to execute the callbacks. Null for main
+     *                        thread.
      * @hide
      */
     @SystemApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.NETWORK_SETTINGS,
             android.Manifest.permission.NETWORK_SETUP_WIZARD})
-    public void startDppAsEnrolleeInitiator(@NonNull String configuratorUri,
-            @Nullable Handler handler, @NonNull DppStatusCallback callback) {
+    public void startEasyConnectAsEnrolleeInitiator(@NonNull String configuratorUri,
+            @Nullable Handler handler, @NonNull EasyConnectStatusCallback callback) {
         Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
         Binder binder = new Binder();
         try {
             mService.startDppAsEnrolleeInitiator(binder, configuratorUri,
-                     new DppCallbackProxy(looper, callback));
+                    new EasyConnectCallbackProxy(looper, callback));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Stop or abort a current DPP session.
+     * Stop or abort a current Easy Connect (DPP) session.
+     *
      * @hide
      */
     @SystemApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.NETWORK_SETTINGS,
             android.Manifest.permission.NETWORK_SETUP_WIZARD})
-    public void stopDppSession() {
+    public void stopEasyConnectSession() {
         try {
             /* Request lower layers to stop/abort and clear resources */
             mService.stopDppSession();
@@ -4682,48 +4720,50 @@
     }
 
     /**
-     * Helper class to support DPP callbacks
+     * Helper class to support Easy Connect (DPP) callbacks
+     *
      * @hide
      */
     @SystemApi
-    private static class DppCallbackProxy extends IDppCallback.Stub {
+    private static class EasyConnectCallbackProxy extends IDppCallback.Stub {
         private final Handler mHandler;
-        private final DppStatusCallback mDppStatusCallback;
+        private final EasyConnectStatusCallback mEasyConnectStatusCallback;
 
-        DppCallbackProxy(Looper looper, DppStatusCallback dppStatusCallback) {
+        EasyConnectCallbackProxy(Looper looper,
+                EasyConnectStatusCallback easyConnectStatusCallback) {
             mHandler = new Handler(looper);
-            mDppStatusCallback = dppStatusCallback;
+            mEasyConnectStatusCallback = easyConnectStatusCallback;
         }
 
         @Override
         public void onSuccessConfigReceived(int newNetworkId) {
-            Log.d(TAG, "DPP onSuccessConfigReceived callback");
+            Log.d(TAG, "Easy Connect onSuccessConfigReceived callback");
             mHandler.post(() -> {
-                mDppStatusCallback.onEnrolleeSuccess(newNetworkId);
+                mEasyConnectStatusCallback.onEnrolleeSuccess(newNetworkId);
             });
         }
 
         @Override
         public void onSuccess(int status) {
-            Log.d(TAG, "DPP onSuccess callback");
+            Log.d(TAG, "Easy Connect onSuccess callback");
             mHandler.post(() -> {
-                mDppStatusCallback.onConfiguratorSuccess(status);
+                mEasyConnectStatusCallback.onConfiguratorSuccess(status);
             });
         }
 
         @Override
         public void onFailure(int status) {
-            Log.d(TAG, "DPP onFailure callback");
+            Log.d(TAG, "Easy Connect onFailure callback");
             mHandler.post(() -> {
-                mDppStatusCallback.onFailure(status);
+                mEasyConnectStatusCallback.onFailure(status);
             });
         }
 
         @Override
         public void onProgress(int status) {
-            Log.d(TAG, "DPP onProgress callback");
+            Log.d(TAG, "Easy Connect onProgress callback");
             mHandler.post(() -> {
-                mDppStatusCallback.onProgress(status);
+                mEasyConnectStatusCallback.onProgress(status);
             });
         }
     }
diff --git a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
index 6d82ca1..f91790f 100644
--- a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
+++ b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
@@ -16,6 +16,7 @@
 
 package android.net.wifi.hotspot2;
 
+import android.annotation.SystemApi;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.net.wifi.WifiSsid;
@@ -36,16 +37,19 @@
  *
  * @hide
  */
+@SystemApi
 public final class OsuProvider implements Parcelable {
     /**
      * OSU (Online Sign-Up) method: OMA DM (Open Mobile Alliance Device Management).
      * For more info, refer to Section 8.3 of the Hotspot 2.0 Release 2 Technical Specification.
+     * @hide
      */
     public static final int METHOD_OMA_DM = 0;
 
     /**
      * OSU (Online Sign-Up) method: SOAP XML SPP (Subscription Provisioning Protocol).
      * For more info, refer to Section 8.4 of the Hotspot 2.0 Release 2 Technical Specification.
+     * @hide
      */
     public static final int METHOD_SOAP_XML_SPP = 1;
 
@@ -84,6 +88,7 @@
      */
     private final Icon mIcon;
 
+    /** @hide */
     public OsuProvider(WifiSsid osuSsid, Map<String, String> friendlyNames,
             String serviceDescription, Uri serverUri, String nai, List<Integer> methodList,
             Icon icon) {
@@ -104,6 +109,7 @@
      * Copy constructor.
      *
      * @param source The source to copy from
+     * @hide
      */
     public OsuProvider(OsuProvider source) {
         if (source == null) {
@@ -130,10 +136,12 @@
         mIcon = source.mIcon;
     }
 
+    /** @hide */
     public WifiSsid getOsuSsid() {
         return mOsuSsid;
     }
 
+    /** @hide */
     public void setOsuSsid(WifiSsid osuSsid) {
         mOsuSsid = osuSsid;
     }
@@ -162,10 +170,12 @@
         return mFriendlyNames.get(mFriendlyNames.keySet().stream().findFirst().get());
     }
 
+    /** @hide */
     public Map<String, String> getFriendlyNameList() {
         return mFriendlyNames;
     }
 
+    /** @hide */
     public String getServiceDescription() {
         return mServiceDescription;
     }
@@ -174,14 +184,17 @@
         return mServerUri;
     }
 
+    /** @hide */
     public String getNetworkAccessIdentifier() {
         return mNetworkAccessIdentifier;
     }
 
+    /** @hide */
     public List<Integer> getMethodList() {
         return mMethodList;
     }
 
+    /** @hide */
     public Icon getIcon() {
         return mIcon;
     }
diff --git a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
index a62d63c..1ee874a 100644
--- a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
+++ b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
@@ -16,6 +16,7 @@
 
 package android.net.wifi.hotspot2;
 
+import android.annotation.SystemApi;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 
@@ -25,6 +26,7 @@
  *
  * @hide
  */
+@SystemApi
 public abstract class ProvisioningCallback {
 
     /**
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index c744f18..7bff68a 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -59,6 +59,7 @@
         WifiConfiguration config = new WifiConfiguration();
         config.setPasspointManagementObjectTree(cookie);
         config.trusted = false;
+        config.updateIdentifier = "1234";
         MacAddress macBeforeParcel = config.getOrCreateRandomizedMacAddress();
         Parcel parcelW = Parcel.obtain();
         config.writeToParcel(parcelW, 0);
@@ -73,6 +74,7 @@
         // lacking a useful config.equals, check two fields near the end.
         assertEquals(cookie, reconfig.getMoTree());
         assertEquals(macBeforeParcel, reconfig.getOrCreateRandomizedMacAddress());
+        assertEquals(config.updateIdentifier, reconfig.updateIdentifier);
         assertFalse(reconfig.trusted);
 
         Parcel parcelWW = Parcel.obtain();
@@ -251,6 +253,18 @@
     }
 
     /**
+     * Verifies that updateIdentifier should be copied for copy constructor.
+     */
+    @Test
+    public void testUpdateIdentifierForCopyConstructor() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.updateIdentifier = "1234";
+        WifiConfiguration copyConfig = new WifiConfiguration(config);
+
+        assertEquals(config.updateIdentifier, copyConfig.updateIdentifier);
+    }
+
+    /**
      * Verifies that the serialization/de-serialization for softap config works.
      */
     @Test