Merge "Remove TestApi use from WindowContainer"
diff --git a/api/current.txt b/api/current.txt
index f8aa04b..3948c69 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16935,6 +16935,7 @@
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING = 4; // 0x4
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_RAW = 3; // 0x3
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS = 5; // 0x5
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA = 13; // 0xd
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING = 7; // 0x7
     field public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0; // 0x0
     field public static final int SCALER_CROPPING_TYPE_FREEFORM = 1; // 0x1
@@ -24142,8 +24143,10 @@
     field public static final int INFO_OUTPUT_FORMAT_CHANGED = -2; // 0xfffffffe
     field public static final int INFO_TRY_AGAIN_LATER = -1; // 0xffffffff
     field public static final String PARAMETER_KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
+    field public static final String PARAMETER_KEY_OFFSET_TIME = "time-offset-us";
     field public static final String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
     field public static final String PARAMETER_KEY_SUSPEND = "drop-input-frames";
+    field public static final String PARAMETER_KEY_SUSPEND_TIME = "drop-start-time-us";
     field public static final String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
@@ -24988,6 +24991,7 @@
     field public static final String KEY_COLOR_STANDARD = "color-standard";
     field public static final String KEY_COLOR_TRANSFER = "color-transfer";
     field public static final String KEY_COMPLEXITY = "complexity";
+    field public static final String KEY_CREATE_INPUT_SURFACE_SUSPENDED = "create-input-buffers-suspended";
     field public static final String KEY_DURATION = "durationUs";
     field public static final String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
     field public static final String KEY_FRAME_RATE = "frame-rate";
@@ -44133,7 +44137,7 @@
   }
 
   public final class AvailableNetworkInfo implements android.os.Parcelable {
-    ctor public AvailableNetworkInfo(int, int, java.util.ArrayList<java.lang.String>);
+    ctor public AvailableNetworkInfo(int, int, java.util.List<java.lang.String>);
     method public int describeContents();
     method public java.util.List<java.lang.String> getMccMncs();
     method public int getPriority();
@@ -45095,7 +45099,7 @@
     method public int getNetworkType();
     method public int getPhoneCount();
     method public int getPhoneType();
-    method public int getPreferredOpportunisticDataSubscription();
+    method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public int getPreferredOpportunisticDataSubscription();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.ServiceState getServiceState();
     method @Nullable public android.telephony.SignalStrength getSignalStrength();
     method public int getSimCarrierId();
@@ -45131,6 +45135,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isNetworkRoaming();
+    method public boolean isRttSupported();
     method public boolean isSmsCapable();
     method @Deprecated public boolean isTtyModeSupported();
     method public boolean isVoiceCapable();
@@ -45663,9 +45668,9 @@
   }
 
   public interface GroupCallCallback {
-    method public void onBroadcastSignalStrengthUpdated(@IntRange(from=0xffffffff, to=4) int);
-    method public void onError(int, @Nullable String);
-    method public void onGroupCallStateChanged(int, int);
+    method public default void onBroadcastSignalStrengthUpdated(@IntRange(from=0xffffffff, to=4) int);
+    method public default void onError(int, @Nullable String);
+    method public default void onGroupCallStateChanged(int, int);
     field public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; // 0xffffffff
   }
 
@@ -45723,10 +45728,10 @@
   }
 
   public interface MbmsGroupCallSessionCallback {
-    method public void onAvailableSaisUpdated(@NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.util.List<java.lang.Integer>>);
-    method public void onError(int, @Nullable String);
-    method public void onMiddlewareReady();
-    method public void onServiceInterfaceAvailable(@NonNull String, int);
+    method public default void onAvailableSaisUpdated(@NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.util.List<java.lang.Integer>>);
+    method public default void onError(int, @Nullable String);
+    method public default void onMiddlewareReady();
+    method public default void onServiceInterfaceAvailable(@NonNull String, int);
   }
 
   public class MbmsStreamingSessionCallback {
@@ -50665,7 +50670,7 @@
     method public void setClickable(boolean);
     method public void setClipBounds(android.graphics.Rect);
     method public void setClipToOutline(boolean);
-    method public void setContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSession);
+    method public void setContentCaptureSession(@Nullable android.view.contentcapture.ContentCaptureSession);
     method public void setContentDescription(CharSequence);
     method public void setContextClickable(boolean);
     method public void setDefaultFocusHighlightEnabled(boolean);
@@ -53407,6 +53412,11 @@
 
 package android.view.inspector {
 
+  public class GeneratedInspectionCompanionProvider implements android.view.inspector.InspectionCompanionProvider {
+    ctor public GeneratedInspectionCompanionProvider();
+    method @Nullable public <T> android.view.inspector.InspectionCompanion<T> provide(@NonNull Class<T>);
+  }
+
   public interface InspectionCompanion<T> {
     method @Nullable public default String getNodeName();
     method public void mapProperties(@NonNull android.view.inspector.PropertyMapper);
@@ -53417,6 +53427,10 @@
     ctor public InspectionCompanion.UninitializedPropertyMapException();
   }
 
+  public interface InspectionCompanionProvider {
+    method @Nullable public <T> android.view.inspector.InspectionCompanion<T> provide(@NonNull Class<T>);
+  }
+
   public final class IntEnumMapping {
     method @Nullable public String get(int);
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index f9403ff..fb039bc 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3322,6 +3322,7 @@
     method public boolean isLocationControllerExtraPackageEnabled();
     method public boolean isLocationEnabledForUser(android.os.UserHandle);
     method public boolean isProviderEnabledForUser(String, android.os.UserHandle);
+    method public boolean isProviderPackage(String);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, android.location.BatchedLocationCallback, android.os.Handler);
     method @Deprecated public void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
     method @Deprecated public void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
@@ -5769,6 +5770,10 @@
     field public static final String NAMESPACE = "runtime_native";
   }
 
+  public static interface DeviceConfig.RuntimeNativeBoot {
+    field public static final String NAMESPACE = "runtime_native_boot";
+  }
+
   public static interface DeviceConfig.Storage {
     field public static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
     field public static final String NAMESPACE = "storage";
@@ -5962,7 +5967,6 @@
     field public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
     field public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
     field public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
-    field public static final String CONTENT_CAPTURE_ENABLED = "content_capture_enabled";
     field public static final String DOZE_ALWAYS_ON = "doze_always_on";
     field public static final String HUSH_GESTURE_USED = "hush_gesture_used";
     field public static final String INSTANT_APPS_ENABLED = "instant_apps_enabled";
@@ -6026,6 +6030,7 @@
     method public abstract void onClearRoleHolders(@NonNull String, @NonNull android.app.role.RoleManagerCallback);
     method public abstract void onGrantDefaultRoles(@NonNull android.app.role.RoleManagerCallback);
     method public abstract void onRemoveRoleHolder(@NonNull String, @NonNull String, @NonNull android.app.role.RoleManagerCallback);
+    method public abstract void onSmsKillSwitchToggled(boolean);
     field public static final String SERVICE_INTERFACE = "android.rolecontrollerservice.RoleControllerService";
   }
 
@@ -6304,8 +6309,6 @@
 
   public abstract class ContentCaptureService extends android.app.Service {
     ctor public ContentCaptureService();
-    method @NonNull public final java.util.Set<android.content.ComponentName> getContentCaptureDisabledActivities();
-    method @NonNull public final java.util.Set<java.lang.String> getContentCaptureDisabledPackages();
     method public void onActivitySnapshot(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.SnapshotData);
     method public void onConnected();
     method public void onContentCaptureEvent(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.view.contentcapture.ContentCaptureEvent);
@@ -6314,9 +6317,7 @@
     method public void onDestroyContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSessionId);
     method public void onDisconnected();
     method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest);
-    method public final void setActivityContentCaptureEnabled(@NonNull android.content.ComponentName, boolean);
     method public final void setContentCaptureWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>);
-    method public final void setPackageContentCaptureEnabled(@NonNull String, boolean);
     field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService";
   }
 
@@ -9298,6 +9299,8 @@
     method @Nullable public android.view.contentcapture.ViewNode getViewNode();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureEvent> CREATOR;
+    field public static final int TYPE_INITIAL_VIEW_TREE_APPEARED = 5; // 0x5
+    field public static final int TYPE_INITIAL_VIEW_TREE_APPEARING = 4; // 0x4
     field public static final int TYPE_VIEW_APPEARED = 1; // 0x1
     field public static final int TYPE_VIEW_DISAPPEARED = 2; // 0x2
     field public static final int TYPE_VIEW_TEXT_CHANGED = 3; // 0x3
diff --git a/api/test-current.txt b/api/test-current.txt
index 2a9a149..3a31a50 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -322,6 +322,14 @@
 
 }
 
+package android.app.assist {
+
+  public static class AssistStructure.ViewNode {
+    ctor public AssistStructure.ViewNode();
+  }
+
+}
+
 package android.app.backup {
 
   public class BackupManager {
@@ -1761,6 +1769,7 @@
     method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
     method @NonNull public static java.io.File getVolumePath(@NonNull String) throws java.io.FileNotFoundException;
     method @NonNull public static java.util.Collection<java.io.File> getVolumeScanPaths(@NonNull String) throws java.io.FileNotFoundException;
+    field public static final String EXTRA_ORIGINATED_FROM_SHELL = "android.intent.extra.originated_from_shell";
     field public static final String SCAN_FILE_CALL = "scan_file";
     field public static final String SCAN_VOLUME_CALL = "scan_volume";
   }
@@ -2042,6 +2051,40 @@
 
 }
 
+package android.service.contentcapture {
+
+  @Deprecated public final class ContentCaptureEventsRequest implements android.os.Parcelable {
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public java.util.List<android.view.contentcapture.ContentCaptureEvent> getEvents();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.service.contentcapture.ContentCaptureEventsRequest> CREATOR;
+  }
+
+  public abstract class ContentCaptureService extends android.app.Service {
+    ctor public ContentCaptureService();
+    method public void onActivitySnapshot(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.SnapshotData);
+    method public void onConnected();
+    method public void onContentCaptureEvent(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.view.contentcapture.ContentCaptureEvent);
+    method @Deprecated public void onContentCaptureEventsRequest(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.ContentCaptureEventsRequest);
+    method public void onCreateContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureContext, @NonNull android.view.contentcapture.ContentCaptureSessionId);
+    method public void onDestroyContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSessionId);
+    method public void onDisconnected();
+    method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest);
+    method public final void setContentCaptureWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>);
+    field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService";
+  }
+
+  public final class SnapshotData implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.app.assist.AssistContent getAssistContent();
+    method public android.os.Bundle getAssistData();
+    method public android.app.assist.AssistStructure getAssistStructure();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.contentcapture.SnapshotData> CREATOR;
+  }
+
+}
+
 package android.service.notification {
 
   @Deprecated public abstract class ConditionProviderService extends android.app.Service {
@@ -2122,7 +2165,6 @@
   public class TelephonyManager {
     method public int checkCarrierPrivilegesForPackage(String);
     method public int getCarrierIdListVersion();
-    method public boolean isRttSupported();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
     method public void setCarrierTestOverride(String, String, String, String, String, String, String);
     field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
@@ -2608,6 +2650,49 @@
 
 }
 
+package android.view.contentcapture {
+
+  public final class ContentCaptureContext implements android.os.Parcelable {
+    method @Nullable public String getAction();
+    method @Nullable public android.content.ComponentName getActivityComponent();
+    method public int getDisplayId();
+    method @Nullable public android.os.Bundle getExtras();
+    method public int getFlags();
+    method @Nullable public android.view.contentcapture.ContentCaptureSessionId getParentSessionId();
+    method public int getTaskId();
+    method @Nullable public android.net.Uri getUri();
+    field public static final int FLAG_DISABLED_BY_APP = 1; // 0x1
+    field public static final int FLAG_DISABLED_BY_FLAG_SECURE = 2; // 0x2
+  }
+
+  public final class ContentCaptureEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getEventTime();
+    method @Nullable public android.view.autofill.AutofillId getId();
+    method @Nullable public java.util.List<android.view.autofill.AutofillId> getIds();
+    method @Nullable public CharSequence getText();
+    method public int getType();
+    method @Nullable public android.view.contentcapture.ViewNode getViewNode();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureEvent> CREATOR;
+    field public static final int TYPE_INITIAL_VIEW_TREE_APPEARED = 5; // 0x5
+    field public static final int TYPE_INITIAL_VIEW_TREE_APPEARING = 4; // 0x4
+    field public static final int TYPE_VIEW_APPEARED = 1; // 0x1
+    field public static final int TYPE_VIEW_DISAPPEARED = 2; // 0x2
+    field public static final int TYPE_VIEW_TEXT_CHANGED = 3; // 0x3
+  }
+
+  public final class ContentCaptureManager {
+    method public boolean isContentCaptureFeatureEnabled();
+    method public void setContentCaptureFeatureEnabled(boolean);
+  }
+
+  public final class ViewNode extends android.app.assist.AssistStructure.ViewNode {
+    method @Nullable public android.view.autofill.AutofillId getParentAutofillId();
+  }
+
+}
+
 package android.view.inputmethod {
 
   public final class InputMethodManager {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 5f47e06..63f9b59 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -2144,30 +2144,24 @@
     }
     optional HardwareType hardware_type = 1;
 
-    /* hardware_location allows vendors to differentiate between multiple instances of
+   /**
+    * hardware_location allows vendors to differentiate between multiple instances of
     * the same hardware_type.  The specific locations are vendor defined integers,
     * referring to board-specific numbering schemes.
     */
     optional int32 hardware_location = 2;
 
-    /* failure_code is specific to the HardwareType of the failed hardware.
-     * It should use the enum values defined below.
+    /**
+     * failure_code is specific to the HardwareType of the failed hardware.
+     * It should use one of the enum values defined below.
      */
-    enum MicrophoneFailureCode {
-        MICROPHONE_FAILURE_COMPLETE = 0;
-    }
-    enum CodecFailureCode {
-        CODEC_FAILURE_COMPLETE = 0;
-    }
-    enum SpeakerFailureCode {
-        SPEAKER_FAILURE_COMPLETE = 0;
-        SPEAKER_FAILURE_HIGH_Z = 1;
-        SPEAKER_FAILURE_SHORT = 2;
-    }
-    enum FingerprintFailureCode {
-        FINGERPRINT_FAILURE_COMPLETE = 0;
-        FINGERPRINT_SENSOR_BROKEN = 1;
-        FINGERPRINT_TOO_MANY_DEAD_PIXELS = 2;
+    enum HardwareErrorCode {
+        UNKNOWN = 0;
+        COMPLETE = 1;
+        SPEAKER_HIGH_Z = 2;
+        SPEAKER_SHORT = 3;
+        FINGERPRINT_SENSOR_BROKEN = 4;
+        FINGERPRINT_TOO_MANY_DEAD_PIXELS = 5;
     }
     optional int32 failure_code = 3;
 }
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index eaba9be..40a4070 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -559,7 +559,7 @@
 
                 // Handles the oneof field in KeyValuePair atom.
                 if (isKeyValuePairAtom && depth == 2) {
-                    pos[depth] = 4;
+                    pos[depth] = 5;
                 }
 
                 mValues.push_back(FieldValue(Field(mTagId, pos, depth), Value(elem.data.float32)));
@@ -575,7 +575,7 @@
 
                 // Handles the oneof field in KeyValuePair atom.
                 if (isKeyValuePairAtom && depth == 2) {
-                    pos[depth] = 3;
+                    pos[depth] = 4;
                 }
                 mValues.push_back(FieldValue(Field(mTagId, pos, depth),
                                              Value(string(elem.data.string, elem.len))));
@@ -593,7 +593,7 @@
                     }
                     // Handles the oneof field in KeyValuePair atom.
                     if (isKeyValuePairAtom && depth == 2) {
-                        pos[depth] = 2;
+                        pos[depth] = 3;
                     }
                     mValues.push_back(
                             FieldValue(Field(mTagId, pos, depth), Value((int64_t)elem.data.int64)));
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index 3a5be43..eec3c73 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -155,7 +155,7 @@
     EXPECT_EQ(33, item5.mValue.int_value);
 
     const FieldValue& item6 = event1.getValues()[6];
-    EXPECT_EQ(0x2010482, item6.mField.getField());
+    EXPECT_EQ(0x2010483, item6.mField.getField());
     EXPECT_EQ(Type::LONG, item6.mValue.getType());
     EXPECT_EQ(678L, item6.mValue.int_value);
 
@@ -165,7 +165,7 @@
     EXPECT_EQ(44, item7.mValue.int_value);
 
     const FieldValue& item8 = event1.getValues()[8];
-    EXPECT_EQ(0x2010582, item8.mField.getField());
+    EXPECT_EQ(0x2010583, item8.mField.getField());
     EXPECT_EQ(Type::LONG, item8.mValue.getType());
     EXPECT_EQ(890L, item8.mValue.int_value);
 
@@ -175,7 +175,7 @@
     EXPECT_EQ(1, item9.mValue.int_value);
 
     const FieldValue& item10 = event1.getValues()[10];
-    EXPECT_EQ(0x2010683, item10.mField.getField());
+    EXPECT_EQ(0x2010684, item10.mField.getField());
     EXPECT_EQ(Type::STRING, item10.mValue.getType());
     EXPECT_EQ("test2", item10.mValue.str_value);
 
@@ -185,7 +185,7 @@
     EXPECT_EQ(2, item11.mValue.int_value);
 
     const FieldValue& item12 = event1.getValues()[12];
-    EXPECT_EQ(0x2010783, item12.mField.getField());
+    EXPECT_EQ(0x2010784, item12.mField.getField());
     EXPECT_EQ(Type::STRING, item12.mValue.getType());
     EXPECT_EQ("test1", item12.mValue.str_value);
 
@@ -195,7 +195,7 @@
     EXPECT_EQ(111, item13.mValue.int_value);
 
     const FieldValue& item14 = event1.getValues()[14];
-    EXPECT_EQ(0x2010884, item14.mField.getField());
+    EXPECT_EQ(0x2010885, item14.mField.getField());
     EXPECT_EQ(Type::FLOAT, item14.mValue.getType());
     EXPECT_EQ(2.2f, item14.mValue.float_value);
 
@@ -205,7 +205,7 @@
     EXPECT_EQ(222, item15.mValue.int_value);
 
     const FieldValue& item16 = event1.getValues()[16];
-    EXPECT_EQ(0x2018984, item16.mField.getField());
+    EXPECT_EQ(0x2018985, item16.mField.getField());
     EXPECT_EQ(Type::FLOAT, item16.mValue.getType());
     EXPECT_EQ(1.1f, item16.mValue.float_value);
 }
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 5b3813d..c753710 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -17,6 +17,7 @@
 package android.animation;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
@@ -1071,7 +1072,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public void cancel() {
         if (currentChangingAnimations.size() > 0) {
             LinkedHashMap<View, Animator> currentAnimCopy =
@@ -1107,7 +1108,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public void cancel(int transitionType) {
         switch (transitionType) {
             case CHANGE_APPEARING:
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index aac8f08..0eadd1d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -7155,7 +7155,8 @@
         mInstrumentation.onEnterAnimationComplete();
         onEnterAnimationComplete();
         if (getWindow() != null && getWindow().getDecorView() != null) {
-            getWindow().getDecorView().getViewTreeObserver().dispatchOnEnterAnimationComplete();
+            View decorView = getWindow().getDecorView();
+            decorView.getViewTreeObserver().dispatchOnEnterAnimationComplete();
         }
     }
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 9ee2f03..ea145f0 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -4485,6 +4485,7 @@
      * @hide
      */
     public int noteProxyOpNoThrow(int op, String proxiedPackageName) {
+        logOperationIfNeeded(op, mContext.getOpPackageName(), proxiedPackageName);
         try {
             return mService.noteProxyOperation(op, Process.myUid(), mContext.getOpPackageName(),
                     Binder.getCallingUid(), proxiedPackageName);
@@ -4500,7 +4501,7 @@
      */
     @UnsupportedAppUsage
     public int noteOpNoThrow(int op, int uid, String packageName) {
-        logNoteOpIfNeeded(op, packageName);
+        logOperationIfNeeded(op, packageName, null);
         try {
             return mService.noteOperation(op, uid, packageName);
         } catch (RemoteException e) {
@@ -4608,6 +4609,7 @@
      * @hide
      */
     public int startOpNoThrow(int op, int uid, String packageName, boolean startIfModeDefault) {
+        logOperationIfNeeded(op, packageName, null);
         try {
             return mService.startOperation(getToken(mService), op, uid, packageName,
                     startIfModeDefault);
@@ -4624,6 +4626,7 @@
      * @hide
      */
     public void finishOp(int op, int uid, String packageName) {
+        logOperationIfNeeded(op, packageName, null);
         try {
             mService.finishOperation(getToken(mService), op, uid, packageName);
         } catch (RemoteException e) {
@@ -4870,7 +4873,7 @@
         return AppOpsManager.MODE_DEFAULT;
     }
 
-    private static void logNoteOpIfNeeded(int op, String callingPackage) {
+    private static void logOperationIfNeeded(int op, String callingPackage, String proxiedPackage) {
         // Check if debug logging propety is enabled.
         if (!SystemProperties.getBoolean(DEBUG_LOGGING_ENABLE_PROP, false)) {
             return;
@@ -4908,6 +4911,6 @@
         // Log a stack trace
         Exception here = new Exception("HERE!");
         android.util.Log.i(DEBUG_LOGGING_TAG, "Note operation package= " + callingPackage
-                + " op= " + opStr, here);
+                + " proxied= " + proxiedPackage + " op= " + opStr, here);
     }
 }
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 6006ad2..2b1e7cd 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -3,6 +3,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
@@ -715,9 +716,10 @@
         ViewNode[] mChildren;
 
         // TODO(b/111276913): temporarily made public / @hide until we decide what will be used by
-        // ScreenObservation.
+        // COntent Capture.
         /** @hide */
         @SystemApi
+        @TestApi
         public ViewNode() {
         }
 
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 8cbe7a3..fafea34 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -52,6 +52,14 @@
         public static final int NONE = 0;
 
         /**
+         * A device level event like {@link #DEVICE_SHUTDOWN} does not have package name, but some
+         * user code always expect a non-null {@link #mPackage} for every event. Use
+         * {@link #DEVICE_EVENT_PACKAGE_NAME} as packageName for these device level events.
+         * @hide
+         */
+        public static final String DEVICE_EVENT_PACKAGE_NAME = "android";
+
+        /**
          * @deprecated by {@link #ACTIVITY_RESUMED}
          */
         @Deprecated
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e2907e2..6e52b33 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -866,6 +866,14 @@
      */
     public static final int INSTALL_ENABLE_ROLLBACK = 0x00040000;
 
+    /**
+     * Flag parameter for {@link #installPackage} to indicate that package verification should be
+     * disabled for this package.
+     *
+     * @hide
+     */
+    public static final int INSTALL_DISABLE_VERIFICATION = 0x00080000;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = {
             DONT_KILL_APP
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index c443d2a..cfe35b0 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -137,6 +137,32 @@
     }
 
     /**
+     * Provider for default browser
+     */
+    public interface DefaultBrowserProvider {
+
+        /**
+         * Get the package name of the default browser.
+         *
+         * @param userId the user id
+         *
+         * @return the package name of the default browser, or {@code null} if none
+         */
+        @Nullable
+        String getDefaultBrowser(@UserIdInt int userId);
+
+        /**
+         * Set the package name of the default browser.
+         *
+         * @param packageName package name of the default browser, or {@code null} to remove
+         * @param userId the user id
+         *
+         * @return whether the default browser was successfully set.
+         */
+        boolean setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId);
+    }
+
+    /**
      * Sets the location provider packages provider.
      * @param provider The packages provider.
      */
@@ -853,4 +879,11 @@
      */
     @Nullable
     public abstract String removeLegacyDefaultBrowserPackageName(int userId);
+
+    /**
+     * Sets the default browser provider.
+     *
+     * @param provider the provider
+     */
+    public abstract void setDefaultBrowserProvider(@NonNull DefaultBrowserProvider provider);
 }
diff --git a/core/java/android/content/rollback/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl
index 104661f..d951756 100644
--- a/core/java/android/content/rollback/IRollbackManager.aidl
+++ b/core/java/android/content/rollback/IRollbackManager.aidl
@@ -40,4 +40,11 @@
 
     // Exposed for test purposes only.
     void expireRollbackForPackage(String packageName);
+
+    // Used by the staging manager to notify the RollbackManager that a session is
+    // being staged. In the case of multi-package sessions, the specified sessionId
+    // is that of the parent session.
+    //
+    // NOTE: This call is synchronous.
+    boolean notifyStagedSession(int sessionId);
 }
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index d4ed35a..0ec4018 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -69,6 +69,11 @@
     private final ArrayList<RestoreInfo> mPendingRestores;
 
     /**
+     * Whether this instance represents the PackageRollbackInfo for an APEX module.
+     */
+    private final boolean mIsApex;
+
+    /**
      * Returns the name of the package to roll back from.
      */
     public String getPackageName() {
@@ -116,18 +121,26 @@
     }
 
     /** @hide */
+    public boolean isApex() {
+        return mIsApex;
+    }
+
+    /** @hide */
     public PackageRollbackInfo(VersionedPackage packageRolledBackFrom,
             VersionedPackage packageRolledBackTo,
-            @NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores) {
+            @NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores,
+            boolean isApex) {
         this.mVersionRolledBackFrom = packageRolledBackFrom;
         this.mVersionRolledBackTo = packageRolledBackTo;
         this.mPendingBackups = pendingBackups;
         this.mPendingRestores = pendingRestores;
+        this.mIsApex = isApex;
     }
 
     private PackageRollbackInfo(Parcel in) {
         this.mVersionRolledBackFrom = VersionedPackage.CREATOR.createFromParcel(in);
         this.mVersionRolledBackTo = VersionedPackage.CREATOR.createFromParcel(in);
+        this.mIsApex = in.readBoolean();
         this.mPendingRestores = null;
         this.mPendingBackups = null;
     }
@@ -141,6 +154,7 @@
     public void writeToParcel(Parcel out, int flags) {
         mVersionRolledBackFrom.writeToParcel(out, flags);
         mVersionRolledBackTo.writeToParcel(out, flags);
+        out.writeBoolean(mIsApex);
     }
 
     public static final Parcelable.Creator<PackageRollbackInfo> CREATOR =
diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java
index b2288fc..87568e8 100644
--- a/core/java/android/ddm/DdmHandleHello.java
+++ b/core/java/android/ddm/DdmHandleHello.java
@@ -16,13 +16,15 @@
 
 package android.ddm;
 
+import android.os.Debug;
+import android.os.UserHandle;
+import android.util.Log;
+
+import dalvik.system.VMRuntime;
+
 import org.apache.harmony.dalvik.ddmc.Chunk;
 import org.apache.harmony.dalvik.ddmc.ChunkHandler;
 import org.apache.harmony.dalvik.ddmc.DdmServer;
-import android.util.Log;
-import android.os.Debug;
-import android.os.UserHandle;
-import dalvik.system.VMRuntime;
 
 import java.nio.ByteBuffer;
 
@@ -35,6 +37,8 @@
     public static final int CHUNK_WAIT = type("WAIT");
     public static final int CHUNK_FEAT = type("FEAT");
 
+    private static final int CLIENT_PROTOCOL_VERSION = 1;
+
     private static DdmHandleHello mInstance = new DdmHandleHello();
 
     private static final String[] FRAMEWORK_FEATURES = new String[] {
@@ -145,7 +149,7 @@
                             + vmFlags.length() * 2
                             + 1);
         out.order(ChunkHandler.CHUNK_ORDER);
-        out.putInt(DdmServer.CLIENT_PROTOCOL_VERSION);
+        out.putInt(CLIENT_PROTOCOL_VERSION);
         out.putInt(android.os.Process.myPid());
         out.putInt(vmIdent.length());
         out.putInt(appName.length());
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 4bc2702..1881a0cd 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1901,6 +1901,7 @@
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING MOTION_TRACKING}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA LOGICAL_MULTI_CAMERA}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME MONOCHROME}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA SECURE_IMAGE_DATA}</li>
      * </ul></p>
      * <p>This key is available on all devices.</p>
      *
@@ -1918,6 +1919,7 @@
      * @see #REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING
      * @see #REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
      * @see #REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA
      */
     @PublicKey
     public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES =
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 6302aa5..a3e561c 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -972,6 +972,14 @@
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME = 12;
 
+    /**
+     * <p>The camera device is capable of writing image data into a region of memory
+     * inaccessible to Android userspace or the Android kernel, and only accessible to
+     * trusted execution environments (TEE).</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA = 13;
+
     //
     // Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE
     //
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index 843db6d..ffae361e 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -51,6 +51,7 @@
     private static final int DO_TOGGLE_SOFT_INPUT = 105;
     private static final int DO_FINISH_SESSION = 110;
     private static final int DO_VIEW_CLICKED = 115;
+    private static final int DO_NOTIFY_IME_HIDDEN = 120;
 
     HandlerCaller mCaller;
     InputMethodSession mInputMethodSession;
@@ -129,6 +130,10 @@
                 mInputMethodSession.viewClicked(msg.arg1 == 1);
                 return;
             }
+            case DO_NOTIFY_IME_HIDDEN: {
+                mInputMethodSession.notifyImeHidden();
+                return;
+            }
         }
         Log.w(TAG, "Unhandled message code: " + msg.what);
     }
@@ -172,6 +177,11 @@
     }
 
     @Override
+    public void notifyImeHidden() {
+        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_NOTIFY_IME_HIDDEN));
+    }
+
+    @Override
     public void updateCursor(Rect newCursor) {
         mCaller.executeOrSendMessage(
                 mCaller.obtainMessageO(DO_UPDATE_CURSOR, newCursor));
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 333cfbd..ab630fd 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -592,7 +592,6 @@
             final boolean wasVisible = mIsPreRendered
                     ? mDecorViewVisible && mWindowVisible : isInputViewShown();
             if (mIsPreRendered) {
-                // TODO: notify visibility to insets consumer.
                 if (DEBUG) {
                     Log.v(TAG, "Making IME window invisible");
                 }
@@ -658,6 +657,11 @@
         }
     }
 
+    private void notifyImeHidden() {
+        setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition);
+        onPreRenderedWindowVisibilityChanged(false /* setVisible */);
+    }
+
     private void setImeWindowStatus(int visibilityFlags, int backDisposition) {
         mPrivOps.setImeWindowStatus(visibilityFlags, backDisposition);
     }
@@ -760,6 +764,14 @@
             }
             InputMethodService.this.onUpdateCursorAnchorInfo(info);
         }
+
+        /**
+         * Notify IME that window is hidden.
+         * @hide
+         */
+        public final void notifyImeHidden() {
+            InputMethodService.this.notifyImeHidden();
+        }
     }
     
     /**
diff --git a/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java b/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
index b4b541d..31c948a 100644
--- a/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
+++ b/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
@@ -290,6 +290,12 @@
                         CallbackImpl::updateCursorAnchorInfo, mCallbackImpl, info));
             }
         }
+
+        @Override
+        public final void notifyImeHidden() {
+            // no-op for multi-session since IME is responsible controlling navigation bar buttons.
+            reportNotSupported();
+        }
     }
 
     private static final class MultiClientInputMethodSessionImpl
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 141d33b..1f33693 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -19,6 +19,7 @@
 import android.annotation.MainThread;
 import android.annotation.Nullable;
 import android.annotation.WorkerThread;
+
 import java.util.ArrayDeque;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Callable;
@@ -70,7 +71,7 @@
  *     protected Long doInBackground(URL... urls) {
  *         int count = urls.length;
  *         long totalSize = 0;
- *         for (int i = 0; i < count; i++) {
+ *         for (int i = 0; i &lt; count; i++) {
  *             totalSize += Downloader.downloadFile(urls[i]);
  *             publishProgress((int) ((i / (float) count) * 100));
  *             // Escape early if cancel() is called
@@ -158,13 +159,22 @@
  * </ul>
  *
  * <h2>Memory observability</h2>
- * <p>AsyncTask guarantees that all callback calls are synchronized in such a way that the following
- * operations are safe without explicit synchronizations.</p>
+ * <p>AsyncTask guarantees that all callback calls are synchronized to ensure the following
+ * without explicit synchronizations.</p>
  * <ul>
- *     <li>Set member fields in the constructor or {@link #onPreExecute}, and refer to them
- *     in {@link #doInBackground}.
- *     <li>Set member fields in {@link #doInBackground}, and refer to them in
- *     {@link #onProgressUpdate} and {@link #onPostExecute}.
+ *     <li>The memory effects of {@link #onPreExecute}, and anything else
+ *     executed before the call to {@link #execute}, including the construction
+ *     of the AsyncTask object, are visible to {@link #doInBackground}.
+ *     <li>The memory effects of {@link #doInBackground} are visible to
+ *     {@link #onPostExecute}.
+ *     <li>Any memory effects of {@link #doInBackground} preceding a call
+ *     to {@link #publishProgress} are visible to the corresponding
+ *     {@link #onProgressUpdate} call. (But {@link #doInBackground} continues to
+ *     run, and care needs to be taken that later updates in {@link #doInBackground}
+ *     do not interfere with an in-progress {@link #onProgressUpdate} call.)
+ *     <li>Any memory effects preceding a call to {@link #cancel} are visible
+ *     after a call to {@link #isCancelled} that returns true as a result, or
+ *     during and after a resulting call to {@link #onCancelled}.
  * </ul>
  *
  * <h2>Order of execution</h2>
@@ -388,6 +398,10 @@
      * specified parameters are the parameters passed to {@link #execute}
      * by the caller of this task.
      *
+     * This will normally run on a background thread. But to better
+     * support testing frameworks, it is recommended that this also tolerates
+     * direct execution on the foreground thread, as part of the {@link #execute} call.
+     *
      * This method can call {@link #publishProgress} to publish updates
      * on the UI thread.
      *
@@ -404,6 +418,8 @@
 
     /**
      * Runs on the UI thread before {@link #doInBackground}.
+     * Invoked directly by {@link #execute} or {@link #executeOnExecutor}.
+     * The default version does nothing.
      *
      * @see #onPostExecute
      * @see #doInBackground
@@ -414,7 +430,10 @@
 
     /**
      * <p>Runs on the UI thread after {@link #doInBackground}. The
-     * specified result is the value returned by {@link #doInBackground}.</p>
+     * specified result is the value returned by {@link #doInBackground}.
+     * To better support testing frameworks, it is recommended that this be
+     * written to tolerate direct execution as part of the execute() call.
+     * The default version does nothing.</p>
      * 
      * <p>This method won't be invoked if the task was cancelled.</p>
      *
@@ -432,6 +451,7 @@
     /**
      * Runs on the UI thread after {@link #publishProgress} is invoked.
      * The specified values are the values passed to {@link #publishProgress}.
+     * The default version does nothing.
      *
      * @param values The values indicating progress.
      *
@@ -466,7 +486,8 @@
     /**
      * <p>Applications should preferably override {@link #onCancelled(Object)}.
      * This method is invoked by the default implementation of
-     * {@link #onCancelled(Object)}.</p>
+     * {@link #onCancelled(Object)}.
+     * The default version does nothing.</p>
      * 
      * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
      * {@link #doInBackground(Object[])} has finished.</p>
@@ -504,12 +525,16 @@
      * an attempt to stop the task.</p>
      * 
      * <p>Calling this method will result in {@link #onCancelled(Object)} being
-     * invoked on the UI thread after {@link #doInBackground(Object[])}
-     * returns. Calling this method guarantees that {@link #onPostExecute(Object)}
-     * is never invoked. After invoking this method, you should check the
-     * value returned by {@link #isCancelled()} periodically from
-     * {@link #doInBackground(Object[])} to finish the task as early as
-     * possible.</p>
+     * invoked on the UI thread after {@link #doInBackground(Object[])} returns.
+     * Calling this method guarantees that onPostExecute(Object) is never
+     * subsequently invoked, even if <tt>cancel</tt> returns false, but
+     * {@link #onPostExecute} has not yet run.  To finish the
+     * task as early as possible, check {@link #isCancelled()} periodically from
+     * {@link #doInBackground(Object[])}.</p>
+     *
+     * <p>This only requests cancellation. It never waits for a running
+     * background task to terminate, even if <tt>mayInterruptIfRunning</tt> is
+     * true.</p>
      *
      * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
      *        task should be interrupted; otherwise, in-progress tasks are allowed
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 3a5b8a8..27f7e22 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -24,7 +24,8 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
-import android.os.IBinder.DeathRecipient;
+
+import com.android.internal.util.Preconditions;
 
 import java.io.FileDescriptor;
 import java.lang.annotation.Retention;
@@ -127,13 +128,16 @@
             @NonNull BugreportParams params,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull BugreportCallback callback) {
-        // TODO(b/111441001): Enforce android.Manifest.permission.DUMP if necessary.
+        Preconditions.checkNotNull(bugreportFd);
+        Preconditions.checkNotNull(params);
+        Preconditions.checkNotNull(executor);
+        Preconditions.checkNotNull(callback);
         DumpstateListener dsListener = new DumpstateListener(executor, callback);
         try {
             // Note: mBinder can get callingUid from the binder transaction.
             mBinder.startBugreport(-1 /* callingUid */,
                     mContext.getOpPackageName(),
-                    (bugreportFd != null ? bugreportFd.getFileDescriptor() : new FileDescriptor()),
+                    bugreportFd.getFileDescriptor(),
                     (screenshotFd != null
                             ? screenshotFd.getFileDescriptor() : new FileDescriptor()),
                     params.getMode(), dsListener);
@@ -154,8 +158,7 @@
         }
     }
 
-    private final class DumpstateListener extends IDumpstateListener.Stub
-            implements DeathRecipient {
+    private final class DumpstateListener extends IDumpstateListener.Stub {
         private final Executor mExecutor;
         private final BugreportCallback mCallback;
 
@@ -165,11 +168,6 @@
         }
 
         @Override
-        public void binderDied() {
-            // TODO(b/111441001): implement
-        }
-
-        @Override
         public void onProgress(int progress) throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index ddec688..68f9288 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -103,7 +103,7 @@
      * Return the debug layer app's on-disk and in-APK lib directories
      */
     private static String getDebugLayerAppPaths(Context context, String app) {
-        ApplicationInfo appInfo;
+        final ApplicationInfo appInfo;
         try {
             appInfo = context.getPackageManager().getApplicationInfo(
                     app, PackageManager.MATCH_ALL);
@@ -113,15 +113,15 @@
             return null;
         }
 
-        String abi = chooseAbi(appInfo);
+        final String abi = chooseAbi(appInfo);
 
-        StringBuilder sb = new StringBuilder();
+        final StringBuilder sb = new StringBuilder();
         sb.append(appInfo.nativeLibraryDir)
             .append(File.pathSeparator);
         sb.append(appInfo.sourceDir)
             .append("!/lib/")
             .append(abi);
-        String paths = sb.toString();
+        final String paths = sb.toString();
 
         if (DEBUG) Log.v(TAG, "Debug layer app libs: " + paths);
 
@@ -143,13 +143,13 @@
 
         if (isDebuggable(context) || (getCanLoadSystemLibraries() == 1)) {
 
-            int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
+            final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
 
             if (enable != 0) {
 
-                String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);
+                final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);
 
-                String packageName = context.getPackageName();
+                final String packageName = context.getPackageName();
 
                 if ((gpuDebugApp != null && packageName != null)
                         && (!gpuDebugApp.isEmpty() && !packageName.isEmpty())
@@ -163,12 +163,12 @@
 
 
                     // If there is a debug layer app specified, add its path.
-                    String gpuDebugLayerApp =
+                    final String gpuDebugLayerApp =
                             coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP);
 
                     if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
                         Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
-                        String paths = getDebugLayerAppPaths(context, gpuDebugLayerApp);
+                        final String paths = getDebugLayerAppPaths(context, gpuDebugLayerApp);
                         if (paths != null) {
                             // Append the path so files placed in the app's base directory will
                             // override the external path
@@ -176,14 +176,14 @@
                         }
                     }
 
-                    String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
+                    final String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
 
                     Log.i(TAG, "Vulkan debug layer list: " + layers);
                     if (layers != null && !layers.isEmpty()) {
                         setDebugLayers(layers);
                     }
 
-                    String layersGLES =
+                    final String layersGLES =
                             coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES);
 
                     Log.i(TAG, "GLES debug layer list: " + layersGLES);
@@ -208,7 +208,7 @@
 
     private static final Map<OpenGlDriverChoice, String> sDriverMap = buildMap();
     private static Map<OpenGlDriverChoice, String> buildMap() {
-        Map<OpenGlDriverChoice, String> map = new HashMap<>();
+        final Map<OpenGlDriverChoice, String> map = new HashMap<>();
         map.put(OpenGlDriverChoice.DEFAULT, "default");
         map.put(OpenGlDriverChoice.ANGLE, "angle");
         map.put(OpenGlDriverChoice.NATIVE, "native");
@@ -219,7 +219,7 @@
 
     private static List<String> getGlobalSettingsString(Bundle bundle, String globalSetting) {
         List<String> valueList = null;
-        String settingsValue = bundle.getString(globalSetting);
+        final String settingsValue = bundle.getString(globalSetting);
 
         if (settingsValue != null) {
             valueList = new ArrayList<>(Arrays.asList(settingsValue.split(",")));
@@ -242,18 +242,16 @@
     }
 
     private static String getDriverForPkg(Bundle bundle, String packageName) {
-        String allUseAngle =
+        final String allUseAngle =
                 bundle.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
         if ((allUseAngle != null) && allUseAngle.equals("1")) {
             return sDriverMap.get(OpenGlDriverChoice.ANGLE);
         }
 
-        List<String> globalSettingsDriverPkgs =
-                getGlobalSettingsString(bundle,
-                        Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS);
-        List<String> globalSettingsDriverValues =
-                getGlobalSettingsString(bundle,
-                        Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES);
+        final List<String> globalSettingsDriverPkgs = getGlobalSettingsString(
+                bundle, Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS);
+        final List<String> globalSettingsDriverValues = getGlobalSettingsString(
+                bundle, Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES);
 
         // Make sure we have a good package name
         if ((packageName == null) || (packageName.isEmpty())) {
@@ -270,7 +268,7 @@
             return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
         }
 
-        int pkgIndex = getGlobalSettingsPkgIndex(packageName, globalSettingsDriverPkgs);
+        final int pkgIndex = getGlobalSettingsPkgIndex(packageName, globalSettingsDriverPkgs);
 
         if (pkgIndex < 0) {
             return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
@@ -283,10 +281,10 @@
      * Get the ANGLE package name.
      */
     private String getAnglePackageName(Context context) {
-        Intent intent = new Intent(ACTION_ANGLE_FOR_ANDROID);
+        final Intent intent = new Intent(ACTION_ANGLE_FOR_ANDROID);
 
-        List<ResolveInfo> resolveInfos = context.getPackageManager()
-                .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
+        final List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentActivities(
+                intent, PackageManager.MATCH_SYSTEM_ONLY);
         if (resolveInfos.size() != 1) {
             Log.e(TAG, "Invalid number of ANGLE packages. Required: 1, Found: "
                     + resolveInfos.size());
@@ -315,8 +313,8 @@
          *  - 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;
+        final boolean appIsDebuggable = isDebuggable(context);
+        final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
         if (!(appIsDebuggable || deviceIsDebuggable)) {
             Log.v(TAG, "Skipping loading temporary rules file: "
                     + "appIsDebuggable = " + appIsDebuggable + ", "
@@ -324,7 +322,7 @@
             return false;
         }
 
-        String angleTempRules = SystemProperties.get(ANGLE_TEMP_RULES);
+        final String angleTempRules = SystemProperties.get(ANGLE_TEMP_RULES);
 
         if ((angleTempRules == null) || angleTempRules.isEmpty()) {
             Log.v(TAG, "System property '" + ANGLE_TEMP_RULES + "' is not set or is empty");
@@ -333,16 +331,16 @@
 
         Log.i(TAG, "Detected system property " + ANGLE_TEMP_RULES + ": " + angleTempRules);
 
-        File tempRulesFile = new File(angleTempRules);
+        final File tempRulesFile = new File(angleTempRules);
         if (tempRulesFile.exists()) {
             Log.i(TAG, angleTempRules + " exists, loading file.");
             try {
-                FileInputStream stream = new FileInputStream(angleTempRules);
+                final FileInputStream stream = new FileInputStream(angleTempRules);
 
                 try {
-                    FileDescriptor rulesFd = stream.getFD();
-                    long rulesOffset = 0;
-                    long rulesLength = stream.getChannel().size();
+                    final FileDescriptor rulesFd = stream.getFD();
+                    final long rulesOffset = 0;
+                    final long rulesLength = stream.getChannel().size();
                     Log.i(TAG, "Loaded temporary ANGLE rules from " + angleTempRules);
 
                     setAngleInfo(paths, packageName, devOptIn, rulesFd, rulesOffset, rulesLength);
@@ -377,11 +375,11 @@
             String devOptIn) {
         // Pass the rules file to loader for ANGLE decisions
         try {
-            AssetManager angleAssets =
+            final AssetManager angleAssets =
                     context.getPackageManager().getResourcesForApplication(angleInfo).getAssets();
 
             try {
-                AssetFileDescriptor assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
+                final AssetFileDescriptor assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
 
                 setAngleInfo(paths, packageName, devOptIn, assetsFd.getFileDescriptor(),
                         assetsFd.getStartOffset(), assetsFd.getLength());
@@ -404,9 +402,8 @@
      * Pull ANGLE whitelist from GlobalSettings and compare against current package
      */
     private boolean checkAngleWhitelist(Bundle bundle, String packageName) {
-        List<String> angleWhitelist =
-                getGlobalSettingsString(bundle,
-                    Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST);
+        final List<String> angleWhitelist =
+                getGlobalSettingsString(bundle, Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST);
 
         return angleWhitelist.contains(packageName);
     }
@@ -420,7 +417,7 @@
             return;
         }
 
-        String devOptIn = getDriverForPkg(bundle, packageName);
+        final String devOptIn = getDriverForPkg(bundle, packageName);
         if (DEBUG) {
             Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
                     + "set to: '" + devOptIn + "'");
@@ -438,9 +435,9 @@
         // load a driver, GraphicsEnv::shouldUseAngle() has seen the package name before
         // and can confidently answer yes/no based on the previously set developer
         // option value.
-        boolean whitelisted = checkAngleWhitelist(bundle, packageName);
-        boolean defaulted = devOptIn.equals(sDriverMap.get(OpenGlDriverChoice.DEFAULT));
-        boolean rulesCheck = (whitelisted || !defaulted);
+        final boolean whitelisted = checkAngleWhitelist(bundle, packageName);
+        final boolean defaulted = devOptIn.equals(sDriverMap.get(OpenGlDriverChoice.DEFAULT));
+        final boolean rulesCheck = (whitelisted || !defaulted);
         if (!rulesCheck) {
             return;
         }
@@ -452,13 +449,13 @@
             Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
         }
 
-        String anglePkgName = getAnglePackageName(context);
+        final String anglePkgName = getAnglePackageName(context);
         if (anglePkgName.isEmpty()) {
             Log.e(TAG, "Failed to find ANGLE package.");
             return;
         }
 
-        ApplicationInfo angleInfo;
+        final ApplicationInfo angleInfo;
         try {
             angleInfo = context.getPackageManager().getApplicationInfo(anglePkgName,
                 PackageManager.MATCH_SYSTEM_ONLY);
@@ -467,10 +464,10 @@
             return;
         }
 
-        String abi = chooseAbi(angleInfo);
+        final String abi = chooseAbi(angleInfo);
 
         // Build a path that includes installed native libs and APK
-        String paths = angleInfo.nativeLibraryDir
+        final String paths = angleInfo.nativeLibraryDir
                 + File.pathSeparator
                 + angleInfo.sourceDir
                 + "!/lib/"
@@ -493,12 +490,12 @@
      * Choose whether the current process should use the builtin or an updated driver.
      */
     private static void chooseDriver(Context context, Bundle coreSettings) {
-        String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
+        final String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
         if (driverPackageName == null || driverPackageName.isEmpty()) {
             return;
         }
 
-        ApplicationInfo driverInfo;
+        final ApplicationInfo driverInfo;
         try {
             driverInfo = context.getPackageManager().getApplicationInfo(driverPackageName,
                     PackageManager.MATCH_SYSTEM_ONLY);
@@ -519,7 +516,7 @@
         // To minimize risk of driver updates crippling the device beyond user repair, never use an
         // updated driver for privileged or non-updated system apps. Presumably pre-installed apps
         // were tested thoroughly with the pre-installed driver.
-        ApplicationInfo ai = context.getApplicationInfo();
+        final ApplicationInfo ai = context.getApplicationInfo();
         if (ai.isPrivilegedApp() || (ai.isSystemApp() && !ai.isUpdatedSystemApp())) {
             if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app");
             return;
@@ -529,7 +526,7 @@
         // 0: Default (Invalid values fallback to default as well)
         // 1: All apps use Game Driver
         // 2: All apps use system graphics driver
-        int gameDriverAllApps = coreSettings.getInt(Settings.Global.GAME_DRIVER_ALL_APPS, 0);
+        final int gameDriverAllApps = coreSettings.getInt(Settings.Global.GAME_DRIVER_ALL_APPS, 0);
         if (gameDriverAllApps == 2) {
             if (DEBUG) {
                 Log.w(TAG, "Game Driver is turned off on this device");
@@ -546,7 +543,7 @@
                 }
                 return;
             }
-            boolean isOptIn =
+            final boolean isOptIn =
                     getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_OPT_IN_APPS)
                             .contains(ai.packageName);
             if (!isOptIn
@@ -563,13 +560,13 @@
                 // on the blacklist, terminate early when it's on the blacklist.
                 try {
                     // TODO(b/121350991) Switch to DeviceConfig with property listener.
-                    String base64String =
+                    final String base64String =
                             coreSettings.getString(Settings.Global.GAME_DRIVER_BLACKLIST);
                     if (base64String != null && !base64String.isEmpty()) {
-                        Blacklists blacklistsProto = Blacklists.parseFrom(
-                                Base64.decode(base64String, BASE64_FLAGS));
-                        List<Blacklist> blacklists = blacklistsProto.getBlacklistsList();
-                        long driverVersionCode = driverInfo.longVersionCode;
+                        final Blacklists blacklistsProto =
+                                Blacklists.parseFrom(Base64.decode(base64String, BASE64_FLAGS));
+                        final List<Blacklist> blacklists = blacklistsProto.getBlacklistsList();
+                        final long driverVersionCode = driverInfo.longVersionCode;
                         for (Blacklist blacklist : blacklists) {
                             if (blacklist.getVersionCode() == driverVersionCode) {
                                 for (String packageName : blacklist.getPackageNamesList()) {
@@ -589,7 +586,7 @@
             }
         }
 
-        String abi = chooseAbi(driverInfo);
+        final String abi = chooseAbi(driverInfo);
         if (abi == null) {
             if (DEBUG) {
                 // This is the normal case for the pre-installed empty driver package, don't spam
@@ -600,13 +597,13 @@
             return;
         }
 
-        StringBuilder sb = new StringBuilder();
+        final StringBuilder sb = new StringBuilder();
         sb.append(driverInfo.nativeLibraryDir)
           .append(File.pathSeparator);
         sb.append(driverInfo.sourceDir)
           .append("!/lib/")
           .append(abi);
-        String paths = sb.toString();
+        final String paths = sb.toString();
 
         if (DEBUG) Log.v(TAG, "gfx driver package libs: " + paths);
         setDriverPath(paths);
@@ -623,7 +620,7 @@
      * Should only be called after chooseDriver().
      */
     public static void earlyInitEGL() {
-        Thread eglInitThread = new Thread(
+        final Thread eglInitThread = new Thread(
                 () -> {
                     EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
                 },
@@ -632,7 +629,7 @@
     }
 
     private static String chooseAbi(ApplicationInfo ai) {
-        String isa = VMRuntime.getCurrentInstructionSet();
+        final String isa = VMRuntime.getCurrentInstructionSet();
         if (ai.primaryCpuAbi != null &&
                 isa.equals(VMRuntime.getInstructionSet(ai.primaryCpuAbi))) {
             return ai.primaryCpuAbi;
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index e8704af..e6c12c7 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -469,6 +469,11 @@
         return sendMessageDelayed(getPostMessage(r), delayMillis);
     }
     
+    /** @hide */
+    public final boolean postDelayed(Runnable r, int what, long delayMillis) {
+        return sendMessageDelayed(getPostMessage(r).setWhat(what), delayMillis);
+    }
+
     /**
      * Causes the Runnable r to be added to the message queue, to be run
      * after the specified amount of time elapses.
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 92650e1..ed3026c 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -160,6 +160,17 @@
     }
 
     /**
+     * Namespace for all runtime native boot related features. Boot in this case refers to the
+     * fact that the properties only take affect after rebooting the device.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface RuntimeNativeBoot {
+        String NAMESPACE = "runtime_native_boot";
+    }
+
+    /**
      * Namespace for all activity manager related features that are used at the native level.
      * These features are applied at reboot.
      *
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 0743c23..67c8400 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -110,6 +110,16 @@
     public static final String SCAN_VOLUME_CALL = "scan_volume";
 
     /**
+     * Extra used with {@link #SCAN_FILE_CALL} or {@link #SCAN_VOLUME_CALL} to indicate that
+     * the file path originated from shell.
+     *
+     * {@hide}
+     */
+    @TestApi
+    public static final String EXTRA_ORIGINATED_FROM_SHELL =
+            "android.intent.extra.originated_from_shell";
+
+    /**
      * The method name used by the media scanner and mtp to tell the media provider to
      * rescan and reclassify that have become unhidden because of renaming folders or
      * removing nomedia files
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e14bb66..3a02e85 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5704,7 +5704,6 @@
          * Defines whether Content Capture is enabled  for the user.
          * @hide
          */
-        @SystemApi
         @TestApi
         public static final String CONTENT_CAPTURE_ENABLED = "content_capture_enabled";
 
diff --git a/core/java/android/rolecontrollerservice/IRoleControllerService.aidl b/core/java/android/rolecontrollerservice/IRoleControllerService.aidl
index ac5be06..4e98201 100644
--- a/core/java/android/rolecontrollerservice/IRoleControllerService.aidl
+++ b/core/java/android/rolecontrollerservice/IRoleControllerService.aidl
@@ -32,4 +32,6 @@
     void onClearRoleHolders(in String roleName, in IRoleManagerCallback callback);
 
     void onGrantDefaultRoles(in IRoleManagerCallback callback);
+
+    void onSmsKillSwitchToggled(boolean smsRestrictionEnabled);
 }
diff --git a/core/java/android/rolecontrollerservice/RoleControllerService.java b/core/java/android/rolecontrollerservice/RoleControllerService.java
index 6eda504..5403cfa 100644
--- a/core/java/android/rolecontrollerservice/RoleControllerService.java
+++ b/core/java/android/rolecontrollerservice/RoleControllerService.java
@@ -96,6 +96,11 @@
                 RoleControllerService.this.onGrantDefaultRoles(new RoleManagerCallbackDelegate(
                         callback));
             }
+
+            @Override
+            public void onSmsKillSwitchToggled(boolean smsRestrictionEnabled) {
+                RoleControllerService.this.onSmsKillSwitchToggled(smsRestrictionEnabled);
+            }
         };
     }
 
@@ -141,6 +146,14 @@
             @NonNull RoleManagerCallback callback);
 
     /**
+     * Cleanup appop/permissions state in response to sms kill switch toggle
+     *
+     * @param smsRestrictionEnabled whether kill switch was turned on
+     */
+    //STOPSHIP: remove this api before shipping a final version
+    public abstract void onSmsKillSwitchToggled(boolean smsRestrictionEnabled);
+
+    /**
      * Called by system to grant default permissions and roles.
      * <p>
      * This is typically when creating a new user or upgrading either system or
diff --git a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
index db242a2..ca6676d 100644
--- a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
+++ b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
@@ -17,6 +17,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.view.contentcapture.ContentCaptureEvent;
@@ -32,6 +33,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 @Deprecated
 public final class ContentCaptureEventsRequest implements Parcelable {
 // TODO(b/121051220): remove .java and .aidl once service implementation doesn't use it anymore
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 020de7f..c98f09e 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.Service;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -48,9 +49,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.Collections;
 import java.util.List;
-import java.util.Set;
 
 /**
  * A service used to capture the content of the screen to provide contextual data in other areas of
@@ -59,6 +58,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public abstract class ContentCaptureService extends Service {
 
     private static final String TAG = ContentCaptureService.class.getSimpleName();
@@ -166,10 +166,6 @@
     /**
      * Explicitly limits content capture to the given packages and activities.
      *
-     * <p>When the whitelist is set, it overrides the values passed to
-     * {@link #setActivityContentCaptureEnabled(ComponentName, boolean)}
-     * and {@link #setPackageContentCaptureEnabled(String, boolean)}.
-     *
      * <p>To reset the whitelist, call it passing {@code null} to both arguments.
      *
      * <p>Useful when the service wants to restrict content capture to a category of apps, like
@@ -194,76 +190,6 @@
     }
 
     /**
-     * Defines whether content capture should be enabled for activities with such
-     * {@link android.content.ComponentName}.
-     *
-     * <p>Useful to blacklist a particular activity.
-     */
-    public final void setActivityContentCaptureEnabled(@NonNull ComponentName activity,
-            boolean enabled) {
-        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();
-        }
-    }
-
-    /**
-     * Defines whether content capture should be enabled for activities of the app with such
-     * {@code packageName}.
-     *
-     * <p>Useful to blacklist any activity from a particular app.
-     */
-    public final void setPackageContentCaptureEnabled(@NonNull String packageName,
-            boolean enabled) {
-        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();
-        }
-    }
-
-    /**
-     * Gets the activities where content capture was disabled by
-     * {@link #setActivityContentCaptureEnabled(ComponentName, boolean)}.
-     */
-    @NonNull
-    public final Set<ComponentName> getContentCaptureDisabledActivities() {
-        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;
-    }
-
-    /**
-     * Gets the apps where content capture was disabled by
-     * {@link #setPackageContentCaptureEnabled(String, boolean)}.
-     */
-    @NonNull
-    public final Set<String> getContentCaptureDisabledPackages() {
-        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;
-    }
-
-    /**
      * Called when the Android system connects to service.
      *
      * <p>You should generally do initialization here rather than in {@link #onCreate}.
diff --git a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
index e84bd6f..2a729b6 100644
--- a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
@@ -28,8 +28,4 @@
  */
 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/contentcapture/SnapshotData.java b/core/java/android/service/contentcapture/SnapshotData.java
index bc2116a..c3af1f0 100644
--- a/core/java/android/service/contentcapture/SnapshotData.java
+++ b/core/java/android/service/contentcapture/SnapshotData.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.os.Bundle;
@@ -31,6 +32,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public final class SnapshotData implements Parcelable {
 
     private final @NonNull Bundle mAssistData;
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 44353b1..81643e9 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -2182,6 +2182,13 @@
         return Character.isWhitespace(codePoint) || codePoint == NBSP_CODE_POINT;
     }
 
+    /** @hide */
+    @Nullable
+    public static String withoutPrefix(@Nullable String prefix, @Nullable String str) {
+        if (prefix == null || str == null) return str;
+        return str.startsWith(prefix) ? str.substring(prefix.length()) : str;
+    }
+
     /**
      * Remove html, remove bad characters, and truncate string.
      *
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 7026d2b..2ba1e01 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -18,10 +18,10 @@
 
 import static android.view.InsetsState.TYPE_IME;
 
+import android.inputmethodservice.InputMethodService;
 import android.os.Parcel;
 import android.text.TextUtils;
 import android.view.SurfaceControl.Transaction;
-import android.view.WindowInsets.Type;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 
@@ -73,11 +73,7 @@
             return;
         }
 
-        if (setVisible) {
-            mController.show(Type.IME);
-        } else {
-            mController.hide(Type.IME);
-        }
+        mController.applyImeVisibility(setVisible);
     }
 
     @Override
@@ -91,6 +87,30 @@
         mHasWindowFocus = false;
     }
 
+    /**
+     * Request {@link InputMethodManager} to show the IME.
+     * @return @see {@link android.view.InsetsSourceConsumer.ShowResult}.
+     */
+    @Override
+    @ShowResult int requestShow(boolean fromIme) {
+        // TODO: ResultReceiver for IME.
+        // TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag.
+        if (fromIme) {
+            return ShowResult.SHOW_IMMEDIATELY;
+        }
+
+        return getImm().requestImeShow(null /* resultReceiver */)
+                ? ShowResult.SHOW_DELAYED : ShowResult.SHOW_FAILED;
+    }
+
+    /**
+     * Notify {@link InputMethodService} that IME window is hidden.
+     */
+    @Override
+    void notifyHidden() {
+        getImm().notifyImeHidden();
+    }
+
     private boolean isDummyOrEmptyEditor(EditorInfo info) {
         // TODO(b/123044812): Handle dummy input gracefully in IME Insets API
         return info == null || (info.fieldId <= 0 && info.inputType <= 0);
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 625ddc2..583651d 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -180,9 +180,10 @@
         for (int i = items.size() - 1; i >= 0; i--) {
             final InsetsSourceConsumer consumer = items.valueAt(i);
             final InsetsSource source = mInitialInsetsState.getSource(consumer.getType());
+            final InsetsSourceControl control = consumer.getControl();
             final SurfaceControl leash = consumer.getControl().getLeash();
-            mTmpMatrix.setTranslate(source.getFrame().left, source.getFrame().top);
 
+            mTmpMatrix.setTranslate(control.getSurfacePosition().x, control.getSurfacePosition().y);
             mTmpFrame.set(source.getFrame());
             addTranslationToMatrix(side, offset, mTmpMatrix, mTmpFrame);
 
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 8e77379..7ad97a6 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -29,11 +29,16 @@
 import android.os.RemoteException;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Property;
 import android.util.SparseArray;
+import android.view.InsetsSourceConsumer.ShowResult;
 import android.view.InsetsState.InternalInsetType;
 import android.view.SurfaceControl.Transaction;
+import android.view.WindowInsets.Type;
 import android.view.WindowInsets.Type.InsetType;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -46,11 +51,13 @@
  */
 public class InsetsController implements WindowInsetsController {
 
-    // TODO: Use animation scaling and more optimal duration.
-    private static final int ANIMATION_DURATION_MS = 400;
+    private static final int ANIMATION_DURATION_SHOW_MS = 275;
+    private static final int ANIMATION_DURATION_HIDE_MS = 340;
+    private static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
     private static final int DIRECTION_NONE = 0;
     private static final int DIRECTION_SHOW = 1;
     private static final int DIRECTION_HIDE = 2;
+
     @IntDef ({DIRECTION_NONE, DIRECTION_SHOW, DIRECTION_HIDE})
     private @interface AnimationDirection{}
 
@@ -103,6 +110,8 @@
     private ObjectAnimator mAnimator;
     private @AnimationDirection int mAnimationDirection;
 
+    private int mPendingTypesToShow;
+
     public InsetsController(ViewRootImpl viewRoot) {
         mViewRoot = viewRoot;
         mAnimCallback = () -> {
@@ -193,6 +202,12 @@
 
     @Override
     public void show(@InsetType int types) {
+        show(types, false /* fromIme */);
+    }
+
+    private void show(@InsetType int types, boolean fromIme) {
+        // TODO: Support a ResultReceiver for IME.
+        // TODO(b/123718661): Make show() work for multi-session IME.
         int typesReady = 0;
         final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
         for (int i = internalTypes.size() - 1; i >= 0; i--) {
@@ -201,15 +216,18 @@
                 // Only one animator (with multiple InsetType) can run at a time.
                 // previous one should be cancelled for simplicity.
                 cancelExistingAnimation();
-            } else if (consumer.isVisible() || mAnimationDirection == DIRECTION_SHOW) {
-                // no-op: already shown or animating in.
+            } else if (consumer.isVisible()
+                    && (mAnimationDirection == DIRECTION_NONE
+                    || mAnimationDirection == DIRECTION_HIDE)) {
+                // no-op: already shown or animating in (because window visibility is
+                // applied before starting animation).
                 // TODO: When we have more than one types: handle specific case when
                 // show animation is going on, but the current type is not becoming visible.
                 continue;
             }
             typesReady |= InsetsState.toPublicType(consumer.getType());
         }
-        applyAnimation(typesReady, true /* show */);
+        applyAnimation(typesReady, true /* show */, fromIme);
     }
 
     @Override
@@ -220,35 +238,114 @@
             InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i));
             if (mAnimationDirection == DIRECTION_SHOW) {
                 cancelExistingAnimation();
-            } else if (!consumer.isVisible() || mAnimationDirection == DIRECTION_HIDE) {
+            } else if (!consumer.isVisible()
+                    && (mAnimationDirection == DIRECTION_NONE
+                    || mAnimationDirection == DIRECTION_HIDE)) {
                 // no-op: already hidden or animating out.
                 continue;
             }
             typesReady |= InsetsState.toPublicType(consumer.getType());
         }
-        applyAnimation(typesReady, false /* show */);
+        applyAnimation(typesReady, false /* show */, false /* fromIme */);
     }
 
     @Override
     public void controlWindowInsetsAnimation(@InsetType int types,
             WindowInsetsAnimationControlListener listener) {
+        controlWindowInsetsAnimation(types, listener, false /* fromIme */);
+    }
+
+    private void controlWindowInsetsAnimation(@InsetType int types,
+            WindowInsetsAnimationControlListener listener, boolean fromIme) {
+        if (types == 0) {
+            // nothing to animate.
+            return;
+        }
 
         // TODO: Check whether we already have a controller.
         final ArraySet<Integer> internalTypes = mState.toInternalType(types);
         final SparseArray<InsetsSourceConsumer> consumers = new SparseArray<>();
+
+        Pair<Integer, Boolean> typesReadyPair = collectConsumers(fromIme, internalTypes, consumers);
+        int typesReady = typesReadyPair.first;
+        boolean isReady = typesReadyPair.second;
+        if (!isReady) {
+            // IME isn't ready, all requested types would be shown once IME is ready.
+            mPendingTypesToShow = typesReady;
+            // TODO: listener for pending types.
+            return;
+        }
+
+        // pending types from previous request.
+        typesReady = collectPendingConsumers(typesReady, consumers);
+
+        if (typesReady == 0) {
+            listener.onCancelled();
+            return;
+        }
+
+        final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(consumers,
+                mFrame, mState, listener, typesReady,
+                () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView), this);
+        mAnimationControls.add(controller);
+    }
+
+    /**
+     * @return Pair of (types ready to animate, is ready to animate).
+     */
+    private Pair<Integer, Boolean> collectConsumers(boolean fromIme,
+            ArraySet<Integer> internalTypes, SparseArray<InsetsSourceConsumer> consumers) {
+        int typesReady = 0;
+        boolean isReady = true;
         for (int i = internalTypes.size() - 1; i >= 0; i--) {
             InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i));
             if (consumer.getControl() != null) {
+                if (!consumer.isVisible()) {
+                    // Show request
+                    switch(consumer.requestShow(fromIme)) {
+                        case ShowResult.SHOW_IMMEDIATELY:
+                            typesReady |= InsetsState.toPublicType(TYPE_IME);
+                            break;
+                        case ShowResult.SHOW_DELAYED:
+                            isReady = false;
+                            break;
+                        case ShowResult.SHOW_FAILED:
+                            // IME cannot be shown (since it didn't have focus), proceed
+                            // with animation of other types.
+                            if (mPendingTypesToShow != 0) {
+                                // remove IME from pending because view no longer has focus.
+                                mPendingTypesToShow &= ~InsetsState.toPublicType(TYPE_IME);
+                            }
+                            break;
+                    }
+                } else {
+                    // Hide request
+                    // TODO: Move notifyHidden() to beginning of the hide animation
+                    // (when visibility actually changes using hideDirectly()).
+                    consumer.notifyHidden();
+                    typesReady |= InsetsState.toPublicType(consumer.getType());
+                }
                 consumers.put(consumer.getType(), consumer);
             } else {
                 // TODO: Let calling app know it's not possible, or wait
                 // TODO: Remove it from types
             }
         }
-        final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(consumers,
-                mFrame, mState, listener, types,
-                () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView), this);
-        mAnimationControls.add(controller);
+        return new Pair<>(typesReady, isReady);
+    }
+
+    private int collectPendingConsumers(@InsetType int typesReady,
+            SparseArray<InsetsSourceConsumer> consumers) {
+        if (mPendingTypesToShow != 0) {
+            typesReady |= mPendingTypesToShow;
+            final ArraySet<Integer> internalTypes = mState.toInternalType(mPendingTypesToShow);
+            for (int i = internalTypes.size() - 1; i >= 0; i--) {
+                InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i));
+                consumers.put(consumer.getType(), consumer);
+            }
+            mPendingTypesToShow = 0;
+        }
+        return typesReady;
     }
 
     private void applyLocalVisibilityOverride() {
@@ -293,6 +390,19 @@
         return mViewRoot;
     }
 
+    /**
+     * Used by {@link ImeInsetsSourceConsumer} when IME decides to be shown/hidden.
+     * @hide
+     */
+    @VisibleForTesting
+    public void applyImeVisibility(boolean setVisible) {
+        if (setVisible) {
+            show(Type.IME, true /* fromIme */);
+        } else {
+            hide(Type.IME);
+        }
+    }
+
     private InsetsSourceConsumer createConsumerOfType(int type) {
         if (type == TYPE_IME) {
             return new ImeInsetsSourceConsumer(mState, Transaction::new, this);
@@ -321,7 +431,7 @@
         }
     }
 
-    private void applyAnimation(@InsetType final int types, boolean show) {
+    private void applyAnimation(@InsetType final int types, boolean show, boolean fromIme) {
         if (types == 0) {
             // nothing to animate.
             return;
@@ -341,7 +451,10 @@
                         show ? controller.getHiddenStateInsets() : controller.getShownStateInsets(),
                         show ? controller.getShownStateInsets() : controller.getHiddenStateInsets()
                 );
-                mAnimator.setDuration(ANIMATION_DURATION_MS);
+                mAnimator.setDuration(show
+                        ? ANIMATION_DURATION_SHOW_MS
+                        : ANIMATION_DURATION_HIDE_MS);
+                mAnimator.setInterpolator(INTERPOLATOR);
                 mAnimator.addListener(new AnimatorListenerAdapter() {
                     @Override
                     public void onAnimationCancel(Animator animation) {
@@ -366,7 +479,7 @@
         // TODO: Instead of clearing this here, properly wire up
         // InsetsAnimationControlImpl.finish() to remove this from mAnimationControls.
         mAnimationControls.clear();
-        controlWindowInsetsAnimation(types, listener);
+        controlWindowInsetsAnimation(types, listener, fromIme);
     }
 
     private void hideDirectly(@InsetType int types) {
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index cccfd87..eab83ce 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -16,12 +16,15 @@
 
 package android.view;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.view.InsetsState.InternalInsetType;
 import android.view.SurfaceControl.Transaction;
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.function.Supplier;
 
 /**
@@ -30,6 +33,25 @@
  */
 public class InsetsSourceConsumer {
 
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {ShowResult.SHOW_IMMEDIATELY, ShowResult.SHOW_DELAYED, ShowResult.SHOW_FAILED})
+    @interface ShowResult {
+        /**
+         * Window type is ready to be shown, will be shown immidiately.
+         */
+        int SHOW_IMMEDIATELY = 0;
+        /**
+         * Result will be delayed. Window needs to be prepared or request is not from controller.
+         * Request will be delegated to controller and may or may not be shown.
+         */
+        int SHOW_DELAYED = 1;
+        /**
+         * Window will not be shown because one of the conditions couldn't be met.
+         * (e.g. in IME's case, when no editor is focused.)
+         */
+        int SHOW_FAILED = 2;
+    }
+
     protected final InsetsController mController;
     protected boolean mVisible;
     private final Supplier<Transaction> mTransactionSupplier;
@@ -104,6 +126,25 @@
         return mVisible;
     }
 
+    /**
+     * Request to show current window type.
+     *
+     * @param fromController {@code true} if request is coming from controller.
+     *                       (e.g. in IME case, controller is
+     *                       {@link android.inputmethodservice.InputMethodService}).
+     * @return @see {@link ShowResult}.
+     */
+    @ShowResult int requestShow(boolean fromController) {
+        return ShowResult.SHOW_IMMEDIATELY;
+    }
+
+    /**
+     * Notify listeners that window is now hidden.
+     */
+    void notifyHidden() {
+        // no-op for types that always return ShowResult#SHOW_IMMEDIATELY.
+    }
+
     private void setVisible(boolean visible) {
         if (mVisible == visible) {
             return;
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 9383e6c..9fb6bdb 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -29,10 +29,13 @@
 
     private final @InternalInsetType int mType;
     private final SurfaceControl mLeash;
+    private final Point mSurfacePosition;
 
-    public InsetsSourceControl(@InternalInsetType int type, SurfaceControl leash) {
+    public InsetsSourceControl(@InternalInsetType int type, SurfaceControl leash,
+            Point surfacePosition) {
         mType = type;
         mLeash = leash;
+        mSurfacePosition = surfacePosition;
     }
 
     public int getType() {
@@ -46,6 +49,19 @@
     public InsetsSourceControl(Parcel in) {
         mType = in.readInt();
         mLeash = in.readParcelable(null /* loader */);
+        mSurfacePosition = in.readParcelable(null /* loader */);
+    }
+
+    public boolean setSurfacePosition(int left, int top) {
+        if (mSurfacePosition.equals(left, top)) {
+            return false;
+        }
+        mSurfacePosition.set(left, top);
+        return true;
+    }
+
+    public Point getSurfacePosition() {
+        return mSurfacePosition;
     }
 
     @Override
@@ -57,6 +73,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mType);
         dest.writeParcelable(mLeash, 0 /* flags*/);
+        dest.writeParcelable(mSurfacePosition, 0 /* flags*/);
     }
 
     public static final Creator<InsetsSourceControl> CREATOR
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index ecbec65..cd5207c 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -492,7 +492,7 @@
         if (mBackgroundControl == null) {
             return;
         }
-        if ((mSurfaceFlags & PixelFormat.OPAQUE) != 0) {
+        if ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) {
             mBackgroundControl.show();
             mBackgroundControl.setLayer(Integer.MIN_VALUE);
         } else {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 992b996..0295dc8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -82,6 +82,7 @@
 import android.sysprop.DisplayProperties;
 import android.text.InputType;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.LayoutDirection;
@@ -126,7 +127,6 @@
 import android.widget.ScrollBarDrawable;
 
 import com.android.internal.R;
-import com.android.internal.util.Preconditions;
 import com.android.internal.view.TooltipPopup;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.widget.ScrollBarUtils;
@@ -813,6 +813,8 @@
      */
     private static final String CONTENT_CAPTURE_LOG_TAG = "View.ContentCapture";
 
+    private static final boolean DEBUG_CONTENT_CAPTURE = false;
+
     /**
      * When set to true, this view will save its attribute data.
      *
@@ -3393,9 +3395,12 @@
      * Masks for mPrivateFlags4, as generated by dumpFlags():
      *
      * |-------|-------|-------|-------|
-     *                              1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK
-     *                             1     PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED
-     *                            1      PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED
+     *                             1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK
+     *                            1     PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED
+     *                           1      PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED
+     *                          1       PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED
+     *                         1        PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE
+     *                         11       PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK
      * |-------|-------|-------|-------|
      */
 
@@ -3422,6 +3427,17 @@
     private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10;
     private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20;
 
+    /*
+     * Flags used to cache the value returned by isImportantForContentCapture while the view
+     * hierarchy is being traversed.
+     */
+    private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED = 0x40;
+    private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE = 0x80;
+
+    private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK =
+            PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED
+            | PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE;
+
     /* End of masks for mPrivateFlags4 */
 
     /** @hide */
@@ -4140,9 +4156,13 @@
      * The layout parameters associated with this view and used by the parent
      * {@link android.view.ViewGroup} to determine how this view should be
      * laid out.
+     *
+     * The field should not be used directly. Instead {@link #getLayoutParams()} and {@link
+     * #setLayoutParams(ViewGroup.LayoutParams)} should be used. The setter guarantees internal
+     * state correctness of the class.
      * {@hide}
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     protected ViewGroup.LayoutParams mLayoutParams;
 
     /**
@@ -5042,12 +5062,17 @@
      * view (through {@link #setContentCaptureSession(ContentCaptureSession)}.
      */
     @Nullable
-    private WeakReference<ContentCaptureSession> mContentCaptureSession;
+    private ContentCaptureSession mContentCaptureSession;
 
     @LayoutRes
     private int mSourceLayoutId = ID_NULL;
 
     /**
+     * Cached reference to the {@link ContentCaptureSession}, is reset on {@link #invalidate()}.
+     */
+    private ContentCaptureSession mCachedContentCaptureSession;
+
+    /**
      * Simple constructor to use when creating a view from code.
      *
      * @param context The Context the view is running in, through which it can
@@ -8233,15 +8258,7 @@
      * </ul>
      */
     public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) {
-        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
-            Trace.traceBegin(Trace.TRACE_TAG_VIEW,
-                    "onProvideContentCaptureStructure() for " + getClass().getSimpleName());
-        }
-        try {
-            onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags);
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-        }
+        onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags);
     }
 
     /** @hide */
@@ -8952,6 +8969,27 @@
      * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS
      */
     public final boolean isImportantForContentCapture() {
+        boolean isImportant;
+        if ((mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED) != 0) {
+            isImportant = (mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE) != 0;
+            return isImportant;
+        }
+
+        isImportant = calculateIsImportantForContentCapture();
+
+        mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE;
+        if (isImportant) {
+            mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE;
+        }
+        mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED;
+        return isImportant;
+    }
+
+    /**
+     * Calculates whether the flag is important for content capture so it can be used by
+     * {@link #isImportantForContentCapture()} while the tree is traversed.
+     */
+    private boolean calculateIsImportantForContentCapture() {
         // Check parent mode to ensure we're important
         ViewParent parent = mParent;
         while (parent instanceof View) {
@@ -8992,9 +9030,6 @@
         }
 
         // View group is important if at least one children also is
-        //TODO(b/111276913): decide if we really need to send the relevant parents or just the
-        // leaves (with absolute coordinates). If it's the latter, then we need to update this
-        // javadoc and ViewGroup's implementation.
         if (this instanceof ViewGroup) {
             final ViewGroup group = (ViewGroup) this;
             for (int i = 0; i < group.getChildCount(); i++) {
@@ -9031,6 +9066,10 @@
      * </ol>
      */
     private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) {
+        AttachInfo ai = mAttachInfo;
+        // Skip it while the view is being laided out for the first time
+        if (ai != null && !ai.mReadyForContentCaptureUpdates) return;
+
         if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
             Trace.traceBegin(Trace.TRACE_TAG_VIEW,
                     "notifyContentCapture(" + appeared + ") for " + getClass().getSimpleName());
@@ -9043,24 +9082,27 @@
     }
 
     private void notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(boolean appeared) {
+        AttachInfo ai = mAttachInfo;
+
         // First check if context has client, so it saves a service lookup when it doesn't
         if (!mContext.isContentCaptureSupported()) return;
 
         // Then check if it's enabled in the context...
-        final ContentCaptureManager ccm = mContext.getSystemService(ContentCaptureManager.class);
+        final ContentCaptureManager ccm = ai != null ? ai.getContentCaptureManager(mContext)
+                : mContext.getSystemService(ContentCaptureManager.class);
         if (ccm == null || !ccm.isContentCaptureEnabled()) return;
 
         // ... and finally at the view level
         // NOTE: isImportantForContentCapture() is more expensive than cm.isContentCaptureEnabled()
         if (!isImportantForContentCapture()) return;
 
-        final ContentCaptureSession session = getContentCaptureSession(ccm);
+        ContentCaptureSession session = getContentCaptureSession();
         if (session == null) return;
 
         if (appeared) {
             if (!isLaidOut() || getVisibility() != VISIBLE
                     || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) {
-                if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) {
+                if (DEBUG_CONTENT_CAPTURE) {
                     Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid="
                             + isLaidOut() + ", visibleToUser=" + isVisibleToUser()
                             + ", visible=" + (getVisibility() == VISIBLE)
@@ -9071,8 +9113,12 @@
                 }
                 return;
             }
-            mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED;
-            mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED;
+            setNotifiedContentCaptureAppeared();
+
+            // TODO(b/123307965): instead of post, we should queue it on AttachInfo and then
+            // dispatch on RootImpl, as we're doing with the removed ones (in that case, we should
+            // merge the delayNotifyContentCaptureDisappeared() into a more generic method that
+            // takes a session and a command, where the command is either view added or removed
 
             // The code below doesn't take much for a unique view, but it's called for all views
             // the first time the view hiearchy is laid off, which could acccumulative delay the
@@ -9086,7 +9132,7 @@
         } else {
             if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) == 0
                     || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0) {
-                if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) {
+                if (DEBUG_CONTENT_CAPTURE) {
                     Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid="
                             + isLaidOut() + ", visibleToUser=" + isVisibleToUser()
                             + ", visible=" + (getVisibility() == VISIBLE)
@@ -9099,11 +9145,24 @@
             }
             mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED;
             mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED;
-            Choreographer.getInstance().postCallback(Choreographer.CALLBACK_COMMIT,
-                    () -> session.notifyViewDisappeared(getAutofillId()), /* token= */ null);
+
+            if (ai != null) {
+                ai.delayNotifyContentCaptureDisappeared(session, getAutofillId());
+            } else {
+                if (DEBUG_CONTENT_CAPTURE) {
+                    Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on gone for " + this);
+                }
+                Choreographer.getInstance().postCallback(Choreographer.CALLBACK_COMMIT,
+                        () -> session.notifyViewDisappeared(getAutofillId()), /* token= */ null);
+            }
         }
     }
 
+    private void setNotifiedContentCaptureAppeared() {
+        mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED;
+        mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED;
+    }
+
     /**
      * Sets the (optional) {@link ContentCaptureSession} associated with this view.
      *
@@ -9127,9 +9186,8 @@
      * {@link ContentCaptureSession#createContentCaptureSession(
      *        android.view.contentcapture.ContentCaptureContext)}.
      */
-    public void setContentCaptureSession(@NonNull ContentCaptureSession contentCaptureSession) {
-        mContentCaptureSession = new WeakReference<>(
-                Preconditions.checkNotNull(contentCaptureSession));
+    public void setContentCaptureSession(@Nullable ContentCaptureSession contentCaptureSession) {
+        mContentCaptureSession = contentCaptureSession;
     }
 
     /**
@@ -9141,8 +9199,18 @@
      */
     @Nullable
     public final ContentCaptureSession getContentCaptureSession() {
+        if (mCachedContentCaptureSession != null) {
+            return mCachedContentCaptureSession;
+        }
+
+        mCachedContentCaptureSession = getAndCacheContentCaptureSession();
+        return mCachedContentCaptureSession;
+    }
+
+    @Nullable
+    private ContentCaptureSession getAndCacheContentCaptureSession() {
         // First try the session explicitly set by setContentCaptureSession()
-        if (mContentCaptureSession != null) return mContentCaptureSession.get();
+        if (mContentCaptureSession != null) return mContentCaptureSession;
 
         // Then the session explicitly set in an ancestor
         ContentCaptureSession session = null;
@@ -9159,21 +9227,6 @@
         return session;
     }
 
-    /**
-     * Optimized version of {@link #getContentCaptureSession()} that avoids a service lookup.
-     */
-    @Nullable
-    private ContentCaptureSession getContentCaptureSession(@NonNull ContentCaptureManager ccm) {
-        if (mContentCaptureSession != null) return mContentCaptureSession.get();
-
-        ContentCaptureSession session = null;
-        if (mParent instanceof View) {
-            session = ((View) mParent).getContentCaptureSession(ccm);
-        }
-
-        return session != null ? session : ccm.getMainContentCaptureSession();
-    }
-
     @Nullable
     private AutofillManager getAutofillManager() {
         return mContext.getSystemService(AutofillManager.class);
@@ -9346,6 +9399,62 @@
     }
 
     /**
+     * Dispatches the initial Content Capture events for a view structure.
+     *
+     * @hide
+     */
+    public void dispatchInitialProvideContentCaptureStructure(@NonNull ContentCaptureManager ccm) {
+        AttachInfo ai = mAttachInfo;
+        if (ai == null) {
+            Log.w(CONTENT_CAPTURE_LOG_TAG,
+                    "dispatchProvideContentCaptureStructure(): no AttachInfo for " + this);
+            return;
+        }
+
+        // We must set it before checkign if the view itself is important, because it might
+        // initially not be (for example, if it's empty), although that might change later (for
+        // example, if important views are added)
+        ai.mReadyForContentCaptureUpdates = true;
+
+        if (!isImportantForContentCapture()) {
+            if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) {
+                Log.d(CONTENT_CAPTURE_LOG_TAG,
+                        "dispatchProvideContentCaptureStructure(): decorView is not important");
+            }
+            return;
+        }
+
+        ai.mContentCaptureManager = ccm;
+
+        ContentCaptureSession session = getContentCaptureSession();
+        if (session == null) {
+            if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) {
+                Log.d(CONTENT_CAPTURE_LOG_TAG,
+                        "dispatchProvideContentCaptureStructure(): no session for " + this);
+            }
+            return;
+        }
+
+        session.internalNotifyViewHierarchyEvent(/* started= */ true);
+        try {
+            dispatchProvideContentCaptureStructure();
+        } finally {
+            session.internalNotifyViewHierarchyEvent(/* started= */ false);
+        }
+    }
+
+    /** @hide */
+    void dispatchProvideContentCaptureStructure() {
+        ContentCaptureSession session = getContentCaptureSession();
+        if (session != null) {
+            ViewStructure structure = session.newViewStructure(this);
+            onProvideContentCaptureStructure(structure, /* flags= */ 0);
+            setNotifiedContentCaptureAppeared();
+            session.notifyViewAppeared(structure);
+        }
+    }
+
+    /**
      * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
      *
      * Note: Called from the default {@link AccessibilityDelegate}.
@@ -17457,6 +17566,10 @@
             return;
         }
 
+        // Reset content capture caches
+        mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK;
+        mCachedContentCaptureSession = null;
+
         if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)
                 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID)
                 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED
@@ -27963,6 +28076,23 @@
         View mTooltipHost;
 
         /**
+         * The initial structure has been reported so the view is ready to report updates.
+         */
+        boolean mReadyForContentCaptureUpdates;
+
+        /**
+         * Map of ids (per session) that need to be notified after as gone the view hierchy is
+         * traversed.
+         */
+        // TODO(b/121197119): use SparseArray once session id becomes integer
+        ArrayMap<String, ArrayList<AutofillId>> mContentCaptureRemovedIds;
+
+        /**
+         * Cached reference to the {@link ContentCaptureManager}.
+         */
+        ContentCaptureManager mContentCaptureManager;
+
+        /**
          * Creates a new set of attachment information with the specified
          * events handler and thread.
          *
@@ -27980,6 +28110,31 @@
             mRootCallbacks = effectPlayer;
             mTreeObserver = new ViewTreeObserver(context);
         }
+
+        private void delayNotifyContentCaptureDisappeared(@NonNull ContentCaptureSession session,
+                @NonNull AutofillId id) {
+            if (mContentCaptureRemovedIds == null) {
+                // Most of the time there will be just one session, so intial capacity is 1
+                mContentCaptureRemovedIds = new ArrayMap<>(1);
+            }
+            String sessionId = session.getId();
+            // TODO: life would be much easier if we provided a MultiMap implementation somwhere...
+            ArrayList<AutofillId> ids = mContentCaptureRemovedIds.get(sessionId);
+            if (ids == null) {
+                ids = new ArrayList<>();
+                mContentCaptureRemovedIds.put(sessionId, ids);
+            }
+            ids.add(id);
+        }
+
+        @Nullable
+        private ContentCaptureManager getContentCaptureManager(@NonNull Context context) {
+            if (mContentCaptureManager != null) {
+                return mContentCaptureManager;
+            }
+            mContentCaptureManager = context.getSystemService(ContentCaptureManager.class);
+            return mContentCaptureManager;
+        }
     }
 
     /**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0986cfa..e0e7843 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3603,7 +3603,7 @@
             return;
         }
 
-        final ChildListForAutoFill children = getChildrenForAutofill(flags);
+        final ChildListForAutoFillOrContentCapture children = getChildrenForAutofill(flags);
         final int childrenCount = children.size();
         structure.setChildCount(childrenCount);
         for (int i = 0; i < childrenCount; i++) {
@@ -3614,13 +3614,31 @@
         children.recycle();
     }
 
+    /** @hide */
+    @Override
+    public void dispatchProvideContentCaptureStructure() {
+        super.dispatchProvideContentCaptureStructure();
+
+        if (!isLaidOut()) return;
+
+        final ChildListForAutoFillOrContentCapture children = getChildrenForContentCapture();
+        final int childrenCount = children.size();
+        for (int i = 0; i < childrenCount; i++) {
+            final View child = children.get(i);
+            child.dispatchProvideContentCaptureStructure();
+        }
+        children.recycle();
+    }
+
     /**
      * Gets the children for autofill. Children for autofill are the first
      * level descendants that are important for autofill. The returned
      * child list object is pooled and the caller must recycle it once done.
      * @hide */
-    private @NonNull ChildListForAutoFill getChildrenForAutofill(@AutofillFlags int flags) {
-        final ChildListForAutoFill children = ChildListForAutoFill.obtain();
+    private @NonNull ChildListForAutoFillOrContentCapture getChildrenForAutofill(
+            @AutofillFlags int flags) {
+        final ChildListForAutoFillOrContentCapture children = ChildListForAutoFillOrContentCapture
+                .obtain();
         populateChildrenForAutofill(children, flags);
         return children;
     }
@@ -3647,6 +3665,34 @@
         }
     }
 
+    private @NonNull ChildListForAutoFillOrContentCapture getChildrenForContentCapture() {
+        final ChildListForAutoFillOrContentCapture children = ChildListForAutoFillOrContentCapture
+                .obtain();
+        populateChildrenForContentCapture(children);
+        return children;
+    }
+
+    /** @hide */
+    private void populateChildrenForContentCapture(ArrayList<View> list) {
+        final int childrenCount = mChildrenCount;
+        if (childrenCount <= 0) {
+            return;
+        }
+        final ArrayList<View> preorderedList = buildOrderedChildList();
+        final boolean customOrder = preorderedList == null
+                && isChildrenDrawingOrderEnabled();
+        for (int i = 0; i < childrenCount; i++) {
+            final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+            final View child = (preorderedList == null)
+                    ? mChildren[childIndex] : preorderedList.get(childIndex);
+            if (child.isImportantForContentCapture()) {
+                list.add(child);
+            } else if (child instanceof ViewGroup) {
+                ((ViewGroup) child).populateChildrenForContentCapture(list);
+            }
+        }
+    }
+
     private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList, View[] children,
             int childIndex) {
         final View child;
@@ -8544,16 +8590,16 @@
     /**
      * Pooled class that to hold the children for autifill.
      */
-    static class ChildListForAutoFill extends ArrayList<View> {
+    private static class ChildListForAutoFillOrContentCapture extends ArrayList<View> {
         private static final int MAX_POOL_SIZE = 32;
 
-        private static final Pools.SimplePool<ChildListForAutoFill> sPool =
+        private static final Pools.SimplePool<ChildListForAutoFillOrContentCapture> sPool =
                 new Pools.SimplePool<>(MAX_POOL_SIZE);
 
-        public static ChildListForAutoFill obtain() {
-            ChildListForAutoFill list = sPool.acquire();
+        public static ChildListForAutoFillOrContentCapture obtain() {
+            ChildListForAutoFillOrContentCapture list = sPool.acquire();
             if (list == null) {
-                list = new ChildListForAutoFill();
+                list = new ChildListForAutoFillOrContentCapture();
             }
             return list;
         }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9a317db..47528a0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -103,7 +103,10 @@
 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.Interpolator;
+import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
+import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.MainContentCaptureSession;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Scroller;
 
@@ -154,6 +157,7 @@
     private static final boolean DEBUG_FPS = false;
     private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
     private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV;
+    private static final boolean DEBUG_CONTENT_CAPTURE = false || LOCAL_LOGV;
 
     /**
      * Set to false if we do not want to use the multi threaded renderer even though
@@ -180,7 +184,7 @@
      * @see #USE_NEW_INSETS_PROPERTY
      * @hide
      */
-    public static final int sNewInsetsMode =
+    public static int sNewInsetsMode =
             SystemProperties.getInt(USE_NEW_INSETS_PROPERTY, 0);
 
     /**
@@ -412,6 +416,7 @@
     boolean mApplyInsetsRequested;
     boolean mLayoutRequested;
     boolean mFirst;
+    boolean mPerformContentCapture;
     boolean mReportNextDraw;
     boolean mFullRedrawNeeded;
     boolean mNewSurfaceNeeded;
@@ -608,6 +613,7 @@
         mTransparentRegion = new Region();
         mPreviousTransparentRegion = new Region();
         mFirst = true; // true for the first time the view is added
+        mPerformContentCapture = true; // also true for the first time the view is added
         mAdded = false;
         mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
                 context);
@@ -2756,6 +2762,24 @@
             }
         }
 
+        if (mAttachInfo.mContentCaptureRemovedIds != null) {
+            MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
+                    .getMainContentCaptureSession();
+            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureViewsGone");
+            try {
+                for (int i = 0; i < mAttachInfo.mContentCaptureRemovedIds.size(); i++) {
+                    String sessionId = mAttachInfo.mContentCaptureRemovedIds
+                            .keyAt(i);
+                    ArrayList<AutofillId> ids = mAttachInfo.mContentCaptureRemovedIds
+                            .valueAt(i);
+                    mainSession.notifyViewsDisappeared(sessionId, ids);
+                }
+                mAttachInfo.mContentCaptureRemovedIds = null;
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+            }
+        }
+
         mIsInTraversal = false;
     }
 
@@ -3451,6 +3475,35 @@
                 pendingDrawFinished();
             }
         }
+        if (mPerformContentCapture) {
+            performContentCapture();
+        }
+    }
+
+    private void performContentCapture() {
+        mPerformContentCapture = false; // One-time offer!
+        final View rootView = mView;
+        if (DEBUG_CONTENT_CAPTURE) {
+            Log.v(mTag, "dispatchContentCapture() on " + rootView);
+        }
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchContentCapture() for "
+                    + getClass().getSimpleName());
+        }
+        try {
+            // First check if context supports it, so it saves a service lookup when it doesn't
+            if (!mContext.isContentCaptureSupported()) return;
+
+            // Then check if it's enabled in the contex itself.
+            final ContentCaptureManager ccm = mContext
+                    .getSystemService(ContentCaptureManager.class);
+            if (ccm == null || !ccm.isContentCaptureEnabled()) return;
+
+            // Content capture is a go!
+            rootView.dispatchInitialProvideContentCaptureStructure(ccm);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
     }
 
     private boolean draw(boolean fullRedrawNeeded) {
diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
index 63c21f3..acb81e0 100644
--- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
@@ -93,6 +93,11 @@
     }
 
     @Override
+    public void internalNotifyViewHierarchyEvent(boolean started) {
+        getMainCaptureSession().notifyInitialViewHierarchyEvent(mId, started);
+    }
+
+    @Override
     boolean isContentCaptureEnabled() {
         return getMainCaptureSession().isContentCaptureEnabled();
     }
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 5814759..6a9759d 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.TaskInfo;
 import android.content.ComponentName;
 import android.content.Context;
@@ -57,6 +58,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int FLAG_DISABLED_BY_APP = 0x1;
 
     /**
@@ -67,6 +69,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int FLAG_DISABLED_BY_FLAG_SECURE = 0x2;
 
     /** @hide */
@@ -136,6 +139,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     @Nullable
     public Bundle getExtras() {
         return mExtras;
@@ -147,6 +151,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     @Nullable
     public Uri getUri() {
         return mUri;
@@ -158,6 +163,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     @Nullable
     public String getAction() {
         return mAction;
@@ -169,6 +175,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public int getTaskId() {
         return mTaskId;
     }
@@ -179,6 +186,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public @Nullable ComponentName getActivityComponent() {
         return mComponentName;
     }
@@ -191,6 +199,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public @Nullable ContentCaptureSessionId getParentSessionId() {
         return mParentSessionId == null ?  null : new ContentCaptureSessionId(mParentSessionId);
     }
@@ -207,6 +216,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public int getDisplayId() {
         return mDisplayId;
     }
@@ -220,7 +230,8 @@
      * @hide
      */
     @SystemApi
-     public @ContextCreationFlags int getFlags() {
+    @TestApi
+    public @ContextCreationFlags int getFlags() {
         return mFlags;
     }
 
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index a6d4472..dfac35d 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
@@ -36,6 +37,7 @@
 
 /** @hide */
 @SystemApi
+@TestApi
 public final class ContentCaptureEvent implements Parcelable {
 
     private static final String TAG = ContentCaptureEvent.class.getSimpleName();
@@ -69,13 +71,33 @@
      */
     public static final int TYPE_VIEW_TEXT_CHANGED = 3;
 
-    // TODO(b/111276913): add event to indicate when FLAG_SECURE was changed?
+    /**
+     * Called before events (such as {@link #TYPE_VIEW_APPEARED}) representing the initial view
+     * hierarchy are sent.
+     *
+     * <p><b>NOTE</b>: there is no guarantee this event will be sent. For example, it's not sent
+     * if the initial view hierarchy doesn't initially have any view that's important for content
+     * capture.
+     */
+    public static final int TYPE_INITIAL_VIEW_TREE_APPEARING = 4;
+
+    /**
+     * Called after events (such as {@link #TYPE_VIEW_APPEARED}) representing the initial view
+     * hierarchy are sent.
+     *
+     * <p><b>NOTE</b>: there is no guarantee this event will be sent. For example, it's not sent
+     * if the initial view hierarchy doesn't initially have any view that's important for content
+     * capture.
+     */
+    public static final int TYPE_INITIAL_VIEW_TREE_APPEARED = 5;
 
     /** @hide */
     @IntDef(prefix = { "TYPE_" }, value = {
             TYPE_VIEW_APPEARED,
             TYPE_VIEW_DISAPPEARED,
-            TYPE_VIEW_TEXT_CHANGED
+            TYPE_VIEW_TEXT_CHANGED,
+            TYPE_INITIAL_VIEW_TREE_APPEARING,
+            TYPE_INITIAL_VIEW_TREE_APPEARED
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventType{}
@@ -108,8 +130,10 @@
         return this;
     }
 
-    private void setAutofillIds(@NonNull ArrayList<AutofillId> ids) {
+    /** @hide */
+    public ContentCaptureEvent setAutofillIds(@NonNull ArrayList<AutofillId> ids) {
         mIds = Preconditions.checkNotNull(ids);
+        return this;
     }
 
     /**
@@ -193,7 +217,8 @@
      * Gets the type of the event.
      *
      * @return one of {@link #TYPE_VIEW_APPEARED}, {@link #TYPE_VIEW_DISAPPEARED},
-     * or {@link #TYPE_VIEW_TEXT_CHANGED}.
+     * {@link #TYPE_VIEW_TEXT_CHANGED}, {@link #TYPE_INITIAL_VIEW_TREE_APPEARING}, or
+     * {@link #TYPE_INITIAL_VIEW_TREE_APPEARED}.
      */
     public @EventType int getType() {
         return mType;
@@ -372,6 +397,10 @@
                 return "VIEW_DISAPPEARED";
             case TYPE_VIEW_TEXT_CHANGED:
                 return "VIEW_TEXT_CHANGED";
+            case TYPE_INITIAL_VIEW_TREE_APPEARING:
+                return "INITIAL_VIEW_HIERARCHY_STARTED";
+            case TYPE_INITIAL_VIEW_TREE_APPEARED:
+                return "INITIAL_VIEW_HIERARCHY_FINISHED";
             default:
                 return "UKNOWN_TYPE: " + type;
         }
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index f31856c..2512b95 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.annotation.UiThread;
 import android.content.ComponentName;
 import android.content.Context;
@@ -46,7 +47,7 @@
  * of every method.
  */
 /**
- * TODO(b/111276913): add javadocs / implement
+ * TODO(b/123577059): add javadocs / implement
  */
 @SystemService(Context.CONTENT_CAPTURE_MANAGER_SERVICE)
 public final class ContentCaptureManager {
@@ -120,6 +121,7 @@
     }
 
     /** @hide */
+    @UiThread
     public void onActivityStarted(@NonNull IBinder applicationToken,
             @NonNull ComponentName activityComponent, int flags) {
         synchronized (mLock) {
@@ -129,6 +131,7 @@
     }
 
     /** @hide */
+    @UiThread
     public void onActivityStopped() {
         getMainContentCaptureSession().destroy();
     }
@@ -140,6 +143,7 @@
      *
      * @hide
      */
+    @UiThread
     public void flush(@FlushReason int reason) {
         getMainContentCaptureSession().flush(reason);
     }
@@ -217,6 +221,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public boolean isContentCaptureFeatureEnabled() {
         if (mService == null) return false;
 
@@ -249,6 +254,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public void setContentCaptureFeatureEnabled(boolean enabled) {
         if (DEBUG) Log.d(TAG, "setContentCaptureFeatureEnabled(): setting to " + enabled);
 
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 68a3e8a..e028961 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -204,6 +204,12 @@
         return mId.hashCode();
     }
 
+    /** @hide */
+    @NonNull
+    public String getId() {
+        return mId;
+    }
+
     /**
      * Creates a new {@link ContentCaptureSession}.
      *
@@ -362,6 +368,9 @@
     abstract void internalNotifyViewTextChanged(@NonNull AutofillId id,
             @Nullable CharSequence text);
 
+    /** @hide */
+    public abstract void internalNotifyViewHierarchyEvent(boolean started);
+
     /**
      * Creates a {@link ViewStructure} for a "standard" view.
      *
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 034c8fa..eb945b5 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -15,6 +15,8 @@
  */
 package android.view.contentcapture;
 
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_INITIAL_VIEW_TREE_APPEARED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_INITIAL_VIEW_TREE_APPEARING;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_FINISHED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED;
@@ -24,10 +26,9 @@
 import static android.view.contentcapture.ContentCaptureHelper.VERBOSE;
 import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString;
 
-import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UiThread;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
@@ -56,16 +57,14 @@
  * <p>This session is created when the activity starts and finished when it stops; clients can use
  * it to create children activities.
  *
- * <p><b>NOTE: all methods in this class should return right away, or do the real work in a handler
- * thread. Hence, the only field that must be thread-safe is {@code mEnabled}, which is called at
- * the beginning of every method.
- *
  * @hide
  */
 public final class MainContentCaptureSession extends ContentCaptureSession {
 
     private static final String TAG = MainContentCaptureSession.class.getSimpleName();
 
+    private static final boolean FORCE_FLUSH = true;
+
     /**
      * Handler message used to flush the buffer.
      */
@@ -164,46 +163,28 @@
      *
      * @hide
      */
-    void start(@NonNull IBinder applicationToken, @NonNull ComponentName activityComponent,
+    @UiThread
+    void start(@NonNull IBinder token, @NonNull ComponentName component,
             int flags) {
         if (!isContentCaptureEnabled()) return;
 
         if (VERBOSE) {
-            Log.v(TAG, "start(): token=" + applicationToken + ", comp="
-                    + ComponentName.flattenToShortString(activityComponent));
+            Log.v(TAG, "start(): token=" + token + ", comp="
+                    + ComponentName.flattenToShortString(component));
         }
 
-        mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleStartSession, this,
-                applicationToken, activityComponent, flags));
-    }
-
-    @Override
-    void flush(@FlushReason int reason) {
-        mHandler.sendMessage(
-                obtainMessage(MainContentCaptureSession::handleForceFlush, this, reason));
-    }
-
-    @Override
-    void onDestroy() {
-        mHandler.removeMessages(MSG_FLUSH);
-        mHandler.sendMessage(
-                obtainMessage(MainContentCaptureSession::handleDestroySession, this));
-    }
-
-    private void handleStartSession(@NonNull IBinder token, @NonNull ComponentName componentName,
-            int flags) {
-        if (handleHasStarted()) {
+        if (hasStarted()) {
             // 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 "
+                        + ComponentName.flattenToShortString(component) + " while on state "
                         + getStateAsString(mState));
             }
             return;
         }
         mState = STATE_WAITING_FOR_SERVER;
         mApplicationToken = token;
-        mComponentName = componentName;
+        mComponentName = component;
 
         if (VERBOSE) {
             Log.v(TAG, "handleStartSession(): token=" + token + ", act="
@@ -213,28 +194,36 @@
         try {
             if (mSystemServerInterface == null) return;
 
-            mSystemServerInterface.startSession(mApplicationToken, componentName, mId, flags,
+            mSystemServerInterface.startSession(mApplicationToken, component, mId, flags,
                     new IResultReceiver.Stub() {
                         @Override
                         public void send(int resultCode, Bundle resultData) {
-                            IBinder binder = null;
+                            final IBinder binder;
                             if (resultData != null) {
                                 binder = resultData.getBinder(EXTRA_BINDER);
                                 if (binder == null) {
                                     Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result");
-                                    handleResetSession(STATE_DISABLED | STATE_INTERNAL_ERROR);
+                                    mHandler.post(() -> resetSession(
+                                            STATE_DISABLED | STATE_INTERNAL_ERROR));
                                     return;
                                 }
+                            } else {
+                                binder = null;
                             }
-                            handleSessionStarted(resultCode, binder);
+                            mHandler.post(() -> onSessionStarted(resultCode, binder));
                         }
                     });
         } catch (RemoteException e) {
-            Log.w(TAG, "Error starting session for " + componentName.flattenToShortString() + ": "
-                    + e);
+            Log.w(TAG, "Error starting session for " + component.flattenToShortString() + ": " + e);
         }
     }
 
+    @Override
+    void onDestroy() {
+        mHandler.removeMessages(MSG_FLUSH);
+        mHandler.post(() -> destroySession());
+    }
+
     /**
      * Callback from {@code system_server} after call to
      * {@link IContentCaptureManager#startSession(IBinder, ComponentName, String, int,
@@ -243,7 +232,8 @@
      * @param resultCode session state
      * @param binder handle to {@code IContentCaptureDirectManager}
      */
-    private void handleSessionStarted(int resultCode, @Nullable IBinder binder) {
+    @UiThread
+    private void onSessionStarted(int resultCode, @Nullable IBinder binder) {
         if (binder != null) {
             mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder);
             mDirectServiceVulture = () -> {
@@ -258,7 +248,7 @@
         }
 
         if ((resultCode & STATE_DISABLED) != 0) {
-            handleResetSession(resultCode);
+            resetSession(resultCode);
         } else {
             mState = resultCode;
             mDisabled.set(false);
@@ -270,10 +260,16 @@
         }
     }
 
-    private void handleSendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
+    @UiThread
+    private void sendEvent(@NonNull ContentCaptureEvent event) {
+        sendEvent(event, /* forceFlush= */ false);
+    }
+
+    @UiThread
+    private void sendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
         final int eventType = event.getType();
         if (VERBOSE) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event);
-        if (!handleHasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED) {
+        if (!hasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED) {
             // TODO(b/120494182): comment when this could happen (dialogs?)
             Log.v(TAG, "handleSendEvent(" + getDebugState() + ", "
                     + ContentCaptureEvent.getTypeAsString(eventType)
@@ -334,7 +330,7 @@
         final boolean bufferEvent = numberEvents < MAX_BUFFER_SIZE;
 
         if (bufferEvent && !forceFlush) {
-            handleScheduleFlush(FLUSH_REASON_IDLE_TIMEOUT, /* checkExisting= */ true);
+            scheduleFlush(FLUSH_REASON_IDLE_TIMEOUT, /* checkExisting= */ true);
             return;
         }
 
@@ -348,7 +344,7 @@
                 Log.d(TAG, "Closing session for " + getDebugState()
                         + " after " + numberEvents + " delayed events");
             }
-            handleResetSession(STATE_DISABLED | STATE_NO_RESPONSE);
+            resetSession(STATE_DISABLED | STATE_NO_RESPONSE);
             // TODO(b/111276913): blacklist activity / use special flag to indicate that
             // when it's launched again
             return;
@@ -365,19 +361,21 @@
                 flushReason = FLUSH_REASON_FULL;
         }
 
-        handleForceFlush(flushReason);
+        flush(flushReason);
     }
 
-    private boolean handleHasStarted() {
+    @UiThread
+    private boolean hasStarted() {
         return mState != UNKNOWN_STATE;
     }
 
-    private void handleScheduleFlush(@FlushReason int reason, boolean checkExisting) {
+    @UiThread
+    private void scheduleFlush(@FlushReason int reason, boolean checkExisting) {
         if (VERBOSE) {
             Log.v(TAG, "handleScheduleFlush(" + getDebugState(reason)
                     + ", checkExisting=" + checkExisting);
         }
-        if (!handleHasStarted()) {
+        if (!hasStarted()) {
             if (VERBOSE) Log.v(TAG, "handleScheduleFlush(): session not started yet");
             return;
         }
@@ -398,20 +396,22 @@
             Log.v(TAG, "handleScheduleFlush(): scheduled to flush in "
                     + FLUSHING_FREQUENCY_MS + "ms: " + TimeUtils.logTimeOfDay(mNextFlush));
         }
-        mHandler.sendMessageDelayed(
-                obtainMessage(MainContentCaptureSession::handleFlushIfNeeded, this, reason)
-                .setWhat(MSG_FLUSH), FLUSHING_FREQUENCY_MS);
+        // Post using a Runnable directly to trim a few μs from PooledLambda.obtainMessage()
+        mHandler.postDelayed(() -> flushIfNeeded(reason), MSG_FLUSH, FLUSHING_FREQUENCY_MS);
     }
 
-    private void handleFlushIfNeeded(@FlushReason int reason) {
+    @UiThread
+    private void flushIfNeeded(@FlushReason int reason) {
         if (mEvents == null || mEvents.isEmpty()) {
             if (VERBOSE) Log.v(TAG, "Nothing to flush");
             return;
         }
-        handleForceFlush(reason);
+        flush(reason);
     }
 
-    private void handleForceFlush(@FlushReason int reason) {
+    @Override
+    @UiThread
+    void flush(@FlushReason int reason) {
         if (mEvents == null) return;
 
         if (mDisabled.get()) {
@@ -426,7 +426,7 @@
                         + "client not ready: " + mEvents);
             }
             if (!mHandler.hasMessages(MSG_FLUSH)) {
-                handleScheduleFlush(reason, /* checkExisting= */ false);
+                scheduleFlush(reason, /* checkExisting= */ false);
             }
             return;
         }
@@ -443,7 +443,7 @@
             mFlushHistory.log(logRecord);
             mHandler.removeMessages(MSG_FLUSH);
 
-            final ParceledListSlice<ContentCaptureEvent> events = handleClearEvents();
+            final ParceledListSlice<ContentCaptureEvent> events = clearEvents();
             mDirectServiceInterface.sendEvents(events);
         } catch (RemoteException e) {
             Log.w(TAG, "Error sending " + numberEvents + " for " + getDebugState()
@@ -455,7 +455,8 @@
      * Resets the buffer and return a {@link ParceledListSlice} with the previous events.
      */
     @NonNull
-    private ParceledListSlice<ContentCaptureEvent> handleClearEvents() {
+    @UiThread
+    private ParceledListSlice<ContentCaptureEvent> clearEvents() {
         // NOTE: we must save a reference to the current mEvents and then set it to to null,
         // otherwise clearing it would clear it in the receiving side if the service is also local.
         final List<ContentCaptureEvent> events = mEvents == null
@@ -465,7 +466,8 @@
         return new ParceledListSlice<>(events);
     }
 
-    private void handleDestroySession() {
+    @UiThread
+    private void destroySession() {
         if (DEBUG) {
             Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
                     + (mEvents == null ? 0 : mEvents.size()) + " event(s) for "
@@ -484,7 +486,8 @@
 
     // TODO(b/122454205): once we support multiple sessions, we might need to move some of these
     // clearings out.
-    private void handleResetSession(int newState) {
+    @UiThread
+    private void resetSession(int newState) {
         if (VERBOSE) {
             Log.v(TAG, "handleResetSession(" + getActivityName() + "): from "
                     + getStateAsString(mState) + " to " + getStateAsString(newState));
@@ -518,6 +521,11 @@
     }
 
     @Override
+    public void internalNotifyViewHierarchyEvent(boolean started) {
+        notifyInitialViewHierarchyEvent(mId, started);
+    }
+
+    @Override
     boolean isContentCaptureEnabled() {
         return super.isContentCaptureEnabled() && mManager.isContentCaptureEnabled();
     }
@@ -532,37 +540,52 @@
     // change should also get get rid of the "internalNotifyXXXX" methods above
     void notifyChildSessionStarted(@NonNull String parentSessionId,
             @NonNull String childSessionId, @NonNull ContentCaptureContext clientContext) {
-        mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this,
-                new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
-                        .setParentSessionId(parentSessionId)
-                        .setClientContext(clientContext),
-                        /* forceFlush= */ true));
+        sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
+                .setParentSessionId(parentSessionId).setClientContext(clientContext),
+                FORCE_FLUSH);
     }
 
     void notifyChildSessionFinished(@NonNull String parentSessionId,
             @NonNull String childSessionId) {
-        mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this,
-                new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
-                        .setParentSessionId(parentSessionId), /* forceFlush= */ true));
+        sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
+                .setParentSessionId(parentSessionId), FORCE_FLUSH);
     }
 
     void notifyViewAppeared(@NonNull String sessionId, @NonNull ViewStructureImpl node) {
-        mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this,
-                new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED)
-                        .setViewNode(node.mNode), /* forceFlush= */ false));
+        sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED)
+                .setViewNode(node.mNode));
     }
 
     void notifyViewDisappeared(@NonNull String sessionId, @NonNull AutofillId id) {
-        mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this,
-                new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED).setAutofillId(id),
-                        /* forceFlush= */ false));
+        sendEvent(
+                new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED).setAutofillId(id));
+    }
+
+    /** @hide */
+    public void notifyViewsDisappeared(@NonNull String sessionId,
+            @NonNull ArrayList<AutofillId> ids) {
+        final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED);
+        if (ids.size() == 1) {
+            event.setAutofillId(ids.get(0));
+        } else {
+            event.setAutofillIds(ids);
+        }
+        sendEvent(event);
     }
 
     void notifyViewTextChanged(@NonNull String sessionId, @NonNull AutofillId id,
             @Nullable CharSequence text) {
-        mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this,
-                new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED).setAutofillId(id)
-                        .setText(text), /* forceFlush= */ false));
+        sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED).setAutofillId(id)
+                .setText(text));
+    }
+
+    void notifyInitialViewHierarchyEvent(@NonNull String sessionId, boolean started) {
+        if (started) {
+            sendEvent(new ContentCaptureEvent(sessionId, TYPE_INITIAL_VIEW_TREE_APPEARING));
+        } else {
+            sendEvent(new ContentCaptureEvent(sessionId, TYPE_INITIAL_VIEW_TREE_APPEARED),
+                    FORCE_FLUSH);
+        }
     }
 
     @Override
diff --git a/core/java/android/view/contentcapture/ViewNode.java b/core/java/android/view/contentcapture/ViewNode.java
index 0cabafa..eef841d 100644
--- a/core/java/android/view/contentcapture/ViewNode.java
+++ b/core/java/android/view/contentcapture/ViewNode.java
@@ -18,6 +18,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.assist.AssistStructure;
 import android.graphics.Matrix;
 import android.graphics.Rect;
@@ -42,6 +43,7 @@
 // instead
 /** @hide */
 @SystemApi
+@TestApi
 public final class ViewNode extends AssistStructure.ViewNode {
 
     private static final String TAG = ViewNode.class.getSimpleName();
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 7fee3ef..18f757c 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -16,6 +16,7 @@
 
 package android.view.inputmethod;
 
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
 
 import android.annotation.DrawableRes;
@@ -26,6 +27,7 @@
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
+import android.annotation.UserIdInt;
 import android.app.ActivityThread;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -46,6 +48,7 @@
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.Trace;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.style.SuggestionSpan;
 import android.util.Log;
@@ -954,6 +957,13 @@
         return mIInputContext;
     }
 
+    /**
+     * Returns the list of installed input methods.
+     *
+     * <p>On multi user environment, this API returns a result for the calling process user.</p>
+     *
+     * @return {@link List} of {@link InputMethodInfo}.
+     */
     public List<InputMethodInfo> getInputMethodList() {
         try {
             return mService.getInputMethodList();
@@ -962,9 +972,35 @@
         }
     }
 
+    /**
+     * Returns the list of enabled input methods.
+     *
+     * <p>On multi user environment, this API returns a result for the calling process user.</p>
+     *
+     * @return {@link List} of {@link InputMethodInfo}.
+     */
     public List<InputMethodInfo> getEnabledInputMethodList() {
         try {
-            return mService.getEnabledInputMethodList();
+            // We intentionally do not use UserHandle.getCallingUserId() here because for system
+            // services InputMethodManagerInternal.getEnabledInputMethodListAsUser() should be used
+            // instead.
+            return mService.getEnabledInputMethodList(UserHandle.myUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the list of enabled input methods for the specified user.
+     *
+     * @param userId user ID to query
+     * @return {@link List} of {@link InputMethodInfo}.
+     * @hide
+     */
+    @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
+    public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
+        try {
+            return mService.getEnabledInputMethodList(userId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -972,6 +1008,9 @@
 
     /**
      * Returns a list of enabled input method subtypes for the specified input method info.
+     *
+     * <p>On multi user environment, this API returns a result for the calling process user.</p>
+     *
      * @param imi An input method info whose subtypes list will be returned.
      * @param allowsImplicitlySelectedSubtypes A boolean flag to allow to return the implicitly
      * selected subtypes. If an input method info doesn't have enabled subtypes, the framework
@@ -1887,6 +1926,36 @@
     }
 
     /**
+     * Call showSoftInput with currently focused view.
+     * @return {@code true} if IME can be shown.
+     * @hide
+     */
+    public boolean requestImeShow(ResultReceiver resultReceiver) {
+        synchronized (mH) {
+            if (mServedView == null) {
+                return false;
+            }
+            showSoftInput(mServedView, 0 /* flags */, resultReceiver);
+            return true;
+        }
+    }
+
+    /**
+     * Notify IME directly that it is no longer visible.
+     * @hide
+     */
+    public void notifyImeHidden() {
+        synchronized (mH) {
+            try {
+                if (mCurMethod != null) {
+                    mCurMethod.notifyImeHidden();
+                }
+            } catch (RemoteException re) {
+            }
+        }
+    }
+
+    /**
      * Report the current selection range.
      *
      * <p><strong>Editor authors</strong>, you need to call this method whenever
diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java
index de15f33..eb81628 100644
--- a/core/java/android/view/inputmethod/InputMethodSession.java
+++ b/core/java/android/view/inputmethod/InputMethodSession.java
@@ -184,4 +184,11 @@
      * insertion point and composition string.
      */
     public void updateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo);
+
+    /**
+     * Notifies {@link android.inputmethodservice.InputMethodService} that IME has been
+     * hidden from user.
+     * @hide
+     */
+    public void notifyImeHidden();
 }
diff --git a/core/java/android/view/inspector/GeneratedInspectionCompanionProvider.java b/core/java/android/view/inspector/GeneratedInspectionCompanionProvider.java
new file mode 100644
index 0000000..8faae1f
--- /dev/null
+++ b/core/java/android/view/inspector/GeneratedInspectionCompanionProvider.java
@@ -0,0 +1,47 @@
+/*
+ * 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.view.inspector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * An inspection companion provider that loads pre-generated inspection companions
+ *
+ * @see android.processor.view.inspector.PlatformInspectableProcessor
+ */
+public class GeneratedInspectionCompanionProvider implements InspectionCompanionProvider {
+    /**
+     * The suffix used for the generated class
+     */
+    private static final String COMPANION_SUFFIX = "$$InspectionCompanion";
+
+    @Override
+    @Nullable
+    @SuppressWarnings("unchecked")
+    public <T> InspectionCompanion<T> provide(@NonNull Class<T> cls) {
+        final String companionName = cls.getName() + COMPANION_SUFFIX;
+
+        try {
+            final Class<InspectionCompanion<T>> companionClass =
+                    (Class<InspectionCompanion<T>>) cls.getClassLoader().loadClass(companionName);
+            return companionClass.newInstance();
+        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+            return null;
+        }
+    }
+}
diff --git a/core/java/android/view/inspector/InspectionCompanionProvider.java b/core/java/android/view/inspector/InspectionCompanionProvider.java
new file mode 100644
index 0000000..c08f49c
--- /dev/null
+++ b/core/java/android/view/inspector/InspectionCompanionProvider.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 android.view.inspector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * An interface for services that can provide inspection companions for a class.
+ */
+public interface InspectionCompanionProvider {
+    /**
+     * Provide an {@link InspectionCompanion} for the supplied class.
+     *
+     * Implementing classes must not cache companion instances, and should instantiate a new one
+     * for each request.
+     *
+     * @param cls A {@link Class} representing the inspectable type
+     * @param <T> The type to find the companion for
+     * @return The inspection companion for the supplied type
+     */
+    @Nullable
+    <T> InspectionCompanion<T> provide(@NonNull Class<T> cls);
+}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 2dec4e8..8514b85 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -206,13 +206,13 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public ApplicationInfo mApplication;
 
     /**
      * The resource ID of the layout file. (Added to the parcel)
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private final int mLayoutId;
 
     /**
@@ -224,13 +224,13 @@
      * An array of actions to perform on the view tree once it has been
      * inflated
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private ArrayList<Action> mActions;
 
     /**
      * Maps bitmaps to unique indicies to avoid Bitmap duplication.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private BitmapCache mBitmapCache;
 
     /**
@@ -252,7 +252,7 @@
      * RemoteViews.
      */
     private RemoteViews mLandscape = null;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private RemoteViews mPortrait = null;
 
     @ApplyFlags
@@ -430,7 +430,7 @@
             // Do nothing
         }
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         public int mergeBehavior() {
             return MERGE_REPLACE;
         }
@@ -466,7 +466,7 @@
             // Nothing to visit by default
         }
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         int viewId;
     }
 
@@ -499,7 +499,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public void mergeRemoteViews(RemoteViews newRv) {
         if (newRv == null) return;
         // We first copy the new RemoteViews, as the process of merging modifies the way the actions
@@ -690,7 +690,7 @@
             return SET_PENDING_INTENT_TEMPLATE_TAG;
         }
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         PendingIntent pendingIntentTemplate;
     }
 
@@ -1138,7 +1138,7 @@
 
     private static class BitmapCache {
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         ArrayList<Bitmap> mBitmaps;
         int mBitmapMemory = -1;
 
@@ -1190,9 +1190,9 @@
 
     private class BitmapReflectionAction extends Action {
         int bitmapId;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         Bitmap bitmap;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         String methodName;
 
         BitmapReflectionAction(int viewId, String methodName, Bitmap bitmap) {
@@ -1258,10 +1258,10 @@
         static final int COLOR_STATE_LIST = 15;
         static final int ICON = 16;
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         String methodName;
         int type;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         Object value;
 
         ReflectionAction(int viewId, String methodName, int type, Object value) {
@@ -1554,7 +1554,7 @@
      * ViewGroup methods that are related to adding Views.
      */
     private class ViewGroupActionAdd extends Action {
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         private RemoteViews mNestedViews;
         private int mIndex;
 
@@ -2469,7 +2469,7 @@
      * Returns an estimate of the bitmap heap memory usage for this RemoteViews.
      */
     /** @hide */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int estimateMemoryUsage() {
         return mBitmapCache.getBitmapMemory();
     }
@@ -2517,7 +2517,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public void addView(int viewId, RemoteViews nestedView, int index) {
         addAction(new ViewGroupActionAdd(viewId, nestedView, index));
     }
@@ -2992,8 +2992,9 @@
      *      See {@link Adapter#getViewTypeCount()}.
      *
      * @hide
+     * @deprecated this appears to have no users outside of UnsupportedAppUsage?
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public void setRemoteAdapter(int viewId, ArrayList<RemoteViews> list, int viewTypeCount) {
         addAction(new SetRemoteViewsAdapterList(viewId, list, viewTypeCount));
     }
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index c256d57..eef40e1 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -341,10 +341,10 @@
     // the proper ordering of these system-wide.
     // =======================================================================================
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static INotificationManager sService;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     static private INotificationManager getService() {
         if (sService != null) {
             return sService;
diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
index cd80d53..429c618 100644
--- a/core/java/com/android/internal/policy/DecorContext.java
+++ b/core/java/com/android/internal/policy/DecorContext.java
@@ -22,6 +22,7 @@
 import android.view.ContextThemeWrapper;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
+import android.view.contentcapture.ContentCaptureManager;
 
 import java.lang.ref.WeakReference;
 
@@ -36,6 +37,7 @@
     private PhoneWindow mPhoneWindow;
     private WindowManager mWindowManager;
     private Resources mActivityResources;
+    private ContentCaptureManager mContentCaptureManager;
 
     private WeakReference<Context> mActivityContext;
 
@@ -60,6 +62,16 @@
             }
             return mWindowManager;
         }
+        if (Context.CONTENT_CAPTURE_MANAGER_SERVICE.equals(name)) {
+            if (mContentCaptureManager == null) {
+                Context activityContext = mActivityContext.get();
+                if (activityContext != null) {
+                    mContentCaptureManager = (ContentCaptureManager) activityContext
+                            .getSystemService(name);
+                }
+            }
+            return mContentCaptureManager;
+        }
         return super.getSystemService(name);
     }
 
@@ -79,4 +91,9 @@
     public AssetManager getAssets() {
         return mActivityResources.getAssets();
     }
+
+    @Override
+    public boolean isContentCaptureSupported() {
+        return true;
+    }
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 9df37ad..bfb5084 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -69,8 +69,9 @@
     void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded, in int notificationLocation);
     void onNotificationDirectReplied(String key);
     void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount, int smartActionCount,
-            boolean generatedByAsssistant);
-    void onNotificationSmartReplySent(in String key, in int replyIndex, in CharSequence reply, boolean generatedByAssistant, in int notificationLocation);
+            boolean generatedByAsssistant, boolean editBeforeSending);
+    void onNotificationSmartReplySent(in String key, in int replyIndex, in CharSequence reply,
+            in int notificationLocation, boolean modifiedBeforeSending);
     void onNotificationSettingsViewed(String key);
     void setSystemUiVisibility(int displayId, int vis, int mask, String cause);
 
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 226b8db..397df56 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -690,4 +690,17 @@
         }
         return result;
     }
+
+    /**
+     * Returns the first element from the array for which
+     * condition {@code predicate} is true, or null if there is no such element
+     */
+    public static @Nullable <T> T find(@Nullable T[] items,
+            @NonNull java.util.function.Predicate<T> predicate) {
+        if (isEmpty(items)) return null;
+        for (final T item : items) {
+            if (predicate.test(item)) return item;
+        }
+        return null;
+    }
 }
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index f91b837..78fdfe4 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -335,6 +335,13 @@
     }
 
     /**
+     * @return the first element if not empty/null, null otherwise
+     */
+    public static @Nullable <T> T firstOrNull(@Nullable Collection<T> cur) {
+        return isEmpty(cur) ? null : cur.iterator().next();
+    }
+
+    /**
      * @return list of single given element if it's not null, empty list otherwise
      */
     public static @NonNull <T> List<T> singletonOrEmpty(@Nullable T item) {
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 0752efe..98e854c 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -36,7 +36,7 @@
     // TODO: Use ParceledListSlice instead
     List<InputMethodInfo> getInputMethodList();
     // TODO: Use ParceledListSlice instead
-    List<InputMethodInfo> getEnabledInputMethodList();
+    List<InputMethodInfo> getEnabledInputMethodList(int userId);
     List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in String imiId,
             boolean allowsImplicitlySelectedSubtypes);
     InputMethodSubtype getLastInputMethodSubtype();
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
index 794238a..664643c 100644
--- a/core/java/com/android/internal/view/IInputMethodSession.aidl
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -48,4 +48,6 @@
     void finishSession();
 
     void updateCursorAnchorInfo(in CursorAnchorInfo cursorAnchorInfo);
+
+    void notifyImeHidden();
 }
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index 7609b67..498bc5a 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -39,6 +39,7 @@
     private View mActions;
     private View mHeader;
     private View mMainColumn;
+    private View mMediaContent;
     private int mImagePushIn;
 
     public MediaNotificationView(Context context) {
@@ -70,7 +71,7 @@
                     (MarginLayoutParams) mRightIcon.getLayoutParams();
             int imageEndMargin = layoutParams.getMarginEnd();
             size -= imageEndMargin;
-            int fullHeight = getMeasuredHeight();
+            int fullHeight = mMediaContent.getMeasuredHeight();
             if (size > fullHeight) {
                 size = fullHeight;
             } else if (size < fullHeight) {
@@ -154,5 +155,6 @@
         mActions = findViewById(com.android.internal.R.id.media_actions);
         mHeader = findViewById(com.android.internal.R.id.notification_header);
         mMainColumn = findViewById(com.android.internal.R.id.notification_main_column);
+        mMediaContent = findViewById(com.android.internal.R.id.notification_media_content);
     }
 }
diff --git a/core/java/com/android/server/backup/PermissionBackupHelper.java b/core/java/com/android/server/backup/PermissionBackupHelper.java
index ff0e63d..c0ba181 100644
--- a/core/java/com/android/server/backup/PermissionBackupHelper.java
+++ b/core/java/com/android/server/backup/PermissionBackupHelper.java
@@ -19,7 +19,6 @@
 import android.app.AppGlobals;
 import android.app.backup.BlobBackupHelper;
 import android.content.pm.IPackageManager;
-import android.os.UserHandle;
 import android.util.Slog;
 
 public class PermissionBackupHelper extends BlobBackupHelper {
@@ -32,8 +31,12 @@
     // key under which the permission-grant state blob is committed to backup
     private static final String KEY_PERMISSIONS = "permissions";
 
-    public PermissionBackupHelper() {
+    private final int mUserId;
+
+    public PermissionBackupHelper(int userId) {
         super(STATE_VERSION, KEY_PERMISSIONS);
+
+        mUserId = userId;
     }
 
     @Override
@@ -45,7 +48,7 @@
         try {
             switch (key) {
                 case KEY_PERMISSIONS:
-                    return pm.getPermissionGrantBackup(UserHandle.USER_SYSTEM);
+                    return pm.getPermissionGrantBackup(mUserId);
 
                 default:
                     Slog.w(TAG, "Unexpected backup key " + key);
@@ -65,7 +68,7 @@
         try {
             switch (key) {
                 case KEY_PERMISSIONS:
-                    pm.restorePermissionGrants(payload, UserHandle.USER_SYSTEM);
+                    pm.restorePermissionGrants(payload, mUserId);
                     break;
 
                 default:
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 47e7a0e7..8878421 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -19,7 +19,7 @@
 import android.app.IWallpaperManager;
 import android.app.backup.BackupAgentHelper;
 import android.app.backup.BackupDataInput;
-import android.app.backup.BackupDataOutput;
+import android.app.backup.BackupHelper;
 import android.app.backup.FullBackup;
 import android.app.backup.FullBackupDataOutput;
 import android.app.backup.WallpaperBackupHelper;
@@ -31,8 +31,11 @@
 import android.os.UserHandle;
 import android.util.Slog;
 
+import com.google.android.collect.Sets;
+
 import java.io.File;
 import java.io.IOException;
+import java.util.Set;
 
 /**
  * Backup agent for various system-managed data.  Wallpapers are now handled by a
@@ -77,20 +80,25 @@
     // Use old keys to keep legacy data compatibility and avoid writing two wallpapers
     private static final String WALLPAPER_IMAGE_KEY = WallpaperBackupHelper.WALLPAPER_IMAGE_KEY;
 
-    private WallpaperBackupHelper mWallpaperHelper = null;
+    private static final Set<String> sEligibleForMultiUser = Sets.newArraySet(
+            PERMISSION_HELPER);
+
+    private int mUserId = UserHandle.USER_SYSTEM;
 
     @Override
-    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
-            ParcelFileDescriptor newState) throws IOException {
+    public void onCreate(UserHandle user) {
+        super.onCreate(user);
+
+        mUserId = user.getIdentifier();
+
         addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
         addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
         addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
-        addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
+        addHelper(PERMISSION_HELPER, new PermissionBackupHelper(mUserId));
         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
         addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
         addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
         addHelper(SLICES_HELPER, new SliceBackupHelper(this));
-        super.onBackup(oldState, data, newState);
     }
 
     @Override
@@ -103,26 +111,25 @@
             throws IOException {
         // Slot in a restore helper for the older wallpaper backup schema to support restore
         // from devices still generating data in that format.
-        mWallpaperHelper = new WallpaperBackupHelper(this,
-                new String[] { WALLPAPER_IMAGE_KEY} );
-        addHelper(WALLPAPER_HELPER, mWallpaperHelper);
+        addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this,
+                new String[] { WALLPAPER_IMAGE_KEY}));
 
         // On restore, we also support a long-ago wallpaper data schema "system_files"
         addHelper("system_files", new WallpaperBackupHelper(this,
                 new String[] { WALLPAPER_IMAGE_KEY} ));
 
-        addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
-        addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
-        addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
-        addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
-        addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
-        addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
-        addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
-        addHelper(SLICES_HELPER, new SliceBackupHelper(this));
-
         super.onRestore(data, appVersionCode, newState);
     }
 
+    @Override
+    public void addHelper(String keyPrefix, BackupHelper helper) {
+        if (mUserId != UserHandle.USER_SYSTEM && !sEligibleForMultiUser.contains(keyPrefix)) {
+            return;
+        }
+
+        super.addHelper(keyPrefix, helper);
+    }
+
     /**
      * Support for 'adb restore' of legacy archives
      */
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index e7a1c49..345058b 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -276,6 +276,7 @@
         "libmediametrics",
         "libmeminfo",
         "libaudioclient",
+        "libaudiopolicy",
         "libjpeg",
         "libusbhost",
         "libharfbuzz_ng",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 49598bb..d69d416 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -230,6 +230,11 @@
 extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
 extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
 
+// Namespace for Android Runtime flags applied during boot time.
+static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
+// Feature flag name for Garbage Collector type.
+static const char* GCTYPE = "gctype";
+
 static AndroidRuntime* gCurRuntime = NULL;
 
 /*
@@ -776,7 +781,9 @@
     }
 
     std::string gc_type_override =
-            server_configurable_flags::GetServerConfigurableFlag("runtime_native", "gctype", "");
+            server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
+                                                                 GCTYPE,
+                                                                 /*default_value=*/ "");
     std::string gc_type_override_temp;
     if (gc_type_override.empty()) {
         parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:");
diff --git a/core/res/res/layout/notification_material_media_seekbar.xml b/core/res/res/layout/notification_material_media_seekbar.xml
new file mode 100644
index 0000000..1b691d6
--- /dev/null
+++ b/core/res/res/layout/notification_material_media_seekbar.xml
@@ -0,0 +1,64 @@
+<?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:id="@+id/notification_media_progress"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:layout_alignParentBottom="true"
+    >
+    <SeekBar android:id="@+id/notification_media_progress_bar"
+        style="@style/Widget.ProgressBar.Horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:maxHeight="3dp"
+        android:paddingTop="24dp"
+        android:paddingBottom="24dp"
+        android:layout_marginBottom="-24dp"
+        android:layout_marginTop="-12dp"
+        android:splitTrack="false"
+    />
+    <FrameLayout
+        android:id="@+id/notification_media_progress_time"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginBottom="11dp"
+        >
+
+        <!-- width is set to "match_parent" to avoid extra layout calls -->
+        <TextView android:id="@+id/notification_media_elapsed_time"
+            style="@style/Widget.DeviceDefault.Notification.Text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentLeft="true"
+            android:layout_marginStart="@dimen/notification_content_margin_start"
+            android:gravity="left"
+        />
+
+        <TextView android:id="@+id/notification_media_total_time"
+            style="@style/Widget.DeviceDefault.Notification.Text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentRight="true"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:gravity="right"
+        />
+    </FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index 56f7a59..3267f72 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -39,6 +39,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="vertical"
+        android:id="@+id/notification_media_content"
         >
         <LinearLayout
             android:id="@+id/notification_main_column"
@@ -84,5 +85,9 @@
                 android:id="@+id/media_seamless"
             />
         </LinearLayout>
+        <ViewStub android:id="@+id/notification_media_seekbar_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+        />
     </LinearLayout>
 </com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 01b0866..64d91ad 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -34,49 +34,61 @@
         android:layout_width="match_parent"
         android:layout_height="@dimen/media_notification_header_height" />
     <LinearLayout
-        android:id="@+id/notification_main_column"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:layout_marginStart="@dimen/notification_content_margin_start"
-        android:layout_marginTop="@dimen/notification_content_margin_top"
-        android:tag="media"
+        android:orientation="vertical"
+        android:id="@+id/notification_media_content"
         >
         <LinearLayout
-            android:id="@+id/notification_content_container"
+            android:id="@+id/notification_main_column"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_gravity="fill_vertical"
-            android:layout_weight="1"
-            android:minHeight="@dimen/notification_min_content_height"
-            android:paddingBottom="@dimen/notification_content_margin"
-            android:orientation="vertical"
-            >
-            <include layout="@layout/notification_template_part_line1"/>
-            <include layout="@layout/notification_template_text"/>
-        </LinearLayout>
-        <LinearLayout
-            android:id="@+id/media_actions"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="bottom|end"
-            android:layout_marginStart="10dp"
-            android:layout_marginBottom="@dimen/media_notification_actions_padding_bottom"
-            android:layoutDirection="ltr"
             android:orientation="horizontal"
+            android:layout_marginStart="@dimen/notification_content_margin_start"
+            android:layout_marginTop="@dimen/notification_content_margin_top"
+            android:layout_alignParentTop="true"
+            android:tag="media"
             >
-            <include
-                layout="@layout/notification_material_media_action"
-                android:id="@+id/action0"
-            />
-            <include
-                layout="@layout/notification_material_media_action"
-                android:id="@+id/action1"
-            />
-            <include
-                layout="@layout/notification_material_media_action"
-                android:id="@+id/action2"
-            />
+            <LinearLayout
+                android:id="@+id/notification_content_container"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="fill_vertical"
+                android:layout_weight="1"
+                android:minHeight="@dimen/notification_min_content_height"
+                android:paddingBottom="@dimen/notification_content_margin"
+                android:orientation="vertical"
+                >
+                <include layout="@layout/notification_template_part_line1"/>
+                <include layout="@layout/notification_template_text"/>
+            </LinearLayout>
+            <LinearLayout
+                android:id="@+id/media_actions"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="bottom|end"
+                android:layout_marginStart="10dp"
+                android:layoutDirection="ltr"
+                android:orientation="horizontal"
+                >
+                <include
+                    layout="@layout/notification_material_media_action"
+                    android:id="@+id/action0"
+                />
+                <include
+                    layout="@layout/notification_material_media_action"
+                    android:id="@+id/action1"
+                />
+                <include
+                    layout="@layout/notification_material_media_action"
+                    android:id="@+id/action2"
+                />
+            </LinearLayout>
         </LinearLayout>
+        <ViewStub android:id="@+id/notification_media_seekbar_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+        />
     </LinearLayout>
 </FrameLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ef59d13..d65ef03 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1937,6 +1937,7 @@
          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>
+        <item>android.app.role.DIALER: com.android.phone</item>
     </string-array>
 
     <!-- Enable/disable default bluetooth profiles:
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a06222c..ed15e18 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -195,6 +195,12 @@
   <java-symbol type="id" name="action3" />
   <java-symbol type="id" name="action4" />
   <java-symbol type="id" name="media_seamless" />
+  <java-symbol type="id" name="notification_media_seekbar_container" />
+  <java-symbol type="id" name="notification_media_content" />
+  <java-symbol type="id" name="notification_media_progress" />
+  <java-symbol type="id" name="notification_media_progress_bar" />
+  <java-symbol type="id" name="notification_media_elapsed_time" />
+  <java-symbol type="id" name="notification_media_total_time" />
   <java-symbol type="id" name="big_picture" />
   <java-symbol type="id" name="big_text" />
   <java-symbol type="id" name="chronometer" />
@@ -1572,6 +1578,7 @@
   <java-symbol type="layout" name="immersive_mode_cling" />
   <java-symbol type="layout" name="user_switching_dialog" />
   <java-symbol type="layout" name="common_tab_settings" />
+  <java-symbol type="layout" name="notification_material_media_seekbar" />
 
   <java-symbol type="anim" name="slide_in_child_bottom" />
   <java-symbol type="anim" name="slide_in_right" />
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 6a81050..40ebd44 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -36,12 +36,11 @@
     frameworks-core-util-lib \
     mockwebserver \
     guava \
-    androidx.test.runner \
-    androidx.test.ext.junit \
-    androidx.test.rules \
     androidx.test.espresso.core \
+    androidx.test.ext.junit \
+    androidx.test.runner \
+    androidx.test.rules \
     mockito-target-minus-junit4 \
-    espresso-core \
     ub-uiautomator \
     platform-test-annotations \
     truth-prebuilt \
diff --git a/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java b/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
index be1d44c..c71bc73 100644
--- a/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
@@ -16,22 +16,28 @@
 
 package android.animation;
 
-import android.test.ActivityInstrumentationTestCase2;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
 
 import com.android.frameworks.coretests.R;
 
+import org.junit.Rule;
+import org.junit.Test;
+
 import java.util.HashSet;
 import java.util.Set;
 
 @LargeTest
-public class AnimatorInflaterTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity>  {
-    Set<Integer> identityHashes = new HashSet<Integer>();
+public class AnimatorInflaterTest {
+    @Rule
+    public final ActivityTestRule<BasicAnimatorActivity> mActivityRule =
+            new ActivityTestRule<>(BasicAnimatorActivity.class);
 
-    public AnimatorInflaterTest() {
-        super(BasicAnimatorActivity.class);
-    }
+    private final Set<Integer> mIdentityHashes = new HashSet<>();
 
     private void assertUnique(Object object) {
         assertUnique(object, "");
@@ -39,15 +45,16 @@
 
     private void assertUnique(Object object, String msg) {
         final int code = System.identityHashCode(object);
-        assertTrue("object should be unique " + msg + ", obj:" + object, identityHashes.add(code));
-
+        assertTrue("object should be unique " + msg + ", obj:" + object, mIdentityHashes.add(code));
     }
 
+    @Test
     public void testLoadStateListAnimator() {
-        StateListAnimator sla1 = AnimatorInflater.loadStateListAnimator(getActivity(),
+        final BasicAnimatorActivity activity = mActivityRule.getActivity();
+        StateListAnimator sla1 = AnimatorInflater.loadStateListAnimator(activity,
                 R.anim.test_state_anim);
-        sla1.setTarget(getActivity().mAnimatingButton);
-        StateListAnimator sla2 = AnimatorInflater.loadStateListAnimator(getActivity(),
+        sla1.setTarget(activity.mAnimatingButton);
+        StateListAnimator sla2 = AnimatorInflater.loadStateListAnimator(activity,
                 R.anim.test_state_anim);
         assertNull(sla2.getTarget());
         for (StateListAnimator sla : new StateListAnimator[]{sla1, sla2}) {
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java b/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
index 55837ba..7a1de0c 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
@@ -16,27 +16,38 @@
 
 package android.animation;
 
-import android.test.ActivityInstrumentationTestCase2;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import android.view.View;
 
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
 
 import com.android.frameworks.coretests.R;
 
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
 import java.util.ArrayList;
 
-public class AnimatorSetActivityTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> {
+@SmallTest
+public class AnimatorSetActivityTest {
+
+    @Rule
+    public final ActivityTestRule<AnimatorSetActivity> mActivityRule =
+            new ActivityTestRule<>(AnimatorSetActivity.class);
 
     private static final long POLL_INTERVAL = 100; // ms
     private AnimatorSetActivity mActivity;
     private ObjectAnimator a1,a2,a3;
     private ValueAnimator a4,a5;
 
-    public AnimatorSetActivityTest() {
-        super(AnimatorSetActivity.class);
-    }
-
     static class MyListener implements Animator.AnimatorListener {
         boolean startIsCalled = false;
         boolean endIsCalled = false;
@@ -63,10 +74,9 @@
         }
     }
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
+        mActivity = mActivityRule.getActivity();
 
         View square1 = mActivity.findViewById(R.id.square1);
         View square2 = mActivity.findViewById(R.id.square2);
@@ -78,7 +88,7 @@
         a5 = ValueAnimator.ofFloat(10f, 5f).setDuration(850);
     }
 
-    @Override
+    @After
     public void tearDown() throws Exception {
         mActivity = null;
         a1 = null;
@@ -86,10 +96,9 @@
         a3 = null;
         a4 = null;
         a5 = null;
-        super.tearDown();
     }
 
-    @SmallTest
+    @Test
     public void testGetChildAnimations() {
         AnimatorSet s1 = new AnimatorSet();
         s1.playTogether(a1, a2, a3);
@@ -129,7 +138,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testTotalDuration() {
         ArrayList<Animator> list = getAnimatorList();
 
@@ -192,7 +201,7 @@
 
     }
 
-    @SmallTest
+    @Test
     public void testGetDuration() {
         AnimatorSet s = new AnimatorSet();
         assertTrue(s.getDuration() < 0);
@@ -205,8 +214,8 @@
 
     }
 
-    @SmallTest
     @UiThreadTest
+    @Test
     public void testSetDuration() {
         AnimatorSet s = getSequentialSet();
         assertTrue(s.getDuration() < 0);
@@ -224,7 +233,7 @@
         assertEquals(duration, a5.getDuration());
     }
 
-    @SmallTest
+    @Test
     public void testAddListener() throws InterruptedException {
         // Verify that the listener is added to the list of listeners in the AnimatorSet
         // and that newly added listener gets callback for lifecycle events of the animator
@@ -241,13 +250,10 @@
         assertFalse(listener.endIsCalled);
 
         try {
-            runTestOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    s.start();
-                    assertTrue(listener.startIsCalled);
-                    assertFalse(listener.endIsCalled);
-                }
+            mActivityRule.runOnUiThread(() -> {
+                s.start();
+                assertTrue(listener.startIsCalled);
+                assertFalse(listener.endIsCalled);
             });
         } catch (Throwable throwable) {
             throwable.printStackTrace();
@@ -258,18 +264,13 @@
         assertTrue(listener.endIsCalled);
     }
 
-    @SmallTest
+    @Test
     public void testRemoveListener() throws Throwable {
         final AnimatorSet s = new AnimatorSet();
         s.playTogether(a1, a2, a3, a4);
         MyListener listener = new MyListener();
         s.addListener(listener);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                s.start();
-            }
-        });
+        mActivityRule.runOnUiThread(s::start);
 
         Thread.sleep(s.getTotalDuration() + 100);
         assertTrue(listener.startIsCalled);
@@ -282,18 +283,13 @@
         listener.startIsCalled = false;
         listener.endIsCalled = false;
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                s.start();
-            }
-        });
+        mActivityRule.runOnUiThread(s::start);
         Thread.sleep(s.getTotalDuration() + 100);
         assertFalse(listener.startIsCalled);
         assertFalse(listener.endIsCalled);
     }
 
-    @SmallTest
+    @Test
     public void testEnd() throws Throwable {
         // End animator set
         final AnimatorSet s = new AnimatorSet();
@@ -301,37 +297,30 @@
         final MyListener listener = new MyListener();
         s.addListener(listener);
         assertFalse(listener.endIsCalled);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                s.start();
-                assertTrue(s.isStarted());
-                assertTrue(listener.startIsCalled);
-                assertFalse(listener.endIsCalled);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            s.start();
+            assertTrue(s.isStarted());
+            assertTrue(listener.startIsCalled);
+            assertFalse(listener.endIsCalled);
         });
 
         Thread.sleep(a2.getTotalDuration());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                s.end();
-                assertTrue(listener.startIsCalled);
-                assertTrue(listener.endIsCalled);
-                assertFalse(s.isRunning());
-                assertFalse(s.isStarted());
+        mActivityRule.runOnUiThread(() -> {
+            s.end();
+            assertTrue(listener.startIsCalled);
+            assertTrue(listener.endIsCalled);
+            assertFalse(s.isRunning());
+            assertFalse(s.isStarted());
 
-                assertFalse(a1.isStarted());
-                assertFalse(a2.isStarted());
-                assertFalse(a3.isStarted());
-                assertFalse(a4.isStarted());
-            }
+            assertFalse(a1.isStarted());
+            assertFalse(a2.isStarted());
+            assertFalse(a3.isStarted());
+            assertFalse(a4.isStarted());
         });
-
     }
 
-    @SmallTest
+    @Test
     public void testStart() throws Throwable {
         final AnimatorSet s = new AnimatorSet();
         ArrayList<Animator> animators = getAnimatorList();
@@ -355,12 +344,9 @@
             assertFalse(l.endIsCalled);
         }
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                s.start();
-                assertTrue(l.startIsCalled);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            s.start();
+            assertTrue(l.startIsCalled);
         });
 
         long timeout = s.getTotalDuration() * 2;
@@ -383,7 +369,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testCancel() throws Throwable {
         // Check whether cancel would trigger onAnimationCanceled and cancel all the unfinished
         // animations
@@ -411,42 +397,33 @@
             assertFalse(l.endIsCalled);
         }
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                s.start();
-            }
-        });
+        mActivityRule.runOnUiThread(s::start);
 
         Thread.sleep(a1.getTotalDuration());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertTrue(s.isStarted());
-                ArrayList<Integer> runningAnimIds = new ArrayList<Integer>();
-                for (int i = 0; i < animators.size(); i++) {
-                    if (animators.get(i).isStarted()) {
-                        runningAnimIds.add(i);
-                    }
-                }
-                s.cancel();
-                assertTrue(l.startIsCalled);
-                assertTrue(l.cancelIsCalled);
-                assertTrue(l.endIsCalled);
-
-                for (int i = 0; i < listeners.size(); i++) {
-                    assertTrue(listeners.get(i).startIsCalled);
-                    if (runningAnimIds.contains(i)) {
-                        assertTrue(listeners.get(i).cancelIsCalled);
-                    }
-                    assertTrue(listeners.get(i).endIsCalled);
+        mActivityRule.runOnUiThread(() -> {
+            assertTrue(s.isStarted());
+            ArrayList<Integer> runningAnimIds = new ArrayList<>();
+            for (int i = 0; i < animators.size(); i++) {
+                if (animators.get(i).isStarted()) {
+                    runningAnimIds.add(i);
                 }
             }
-        });
+            s.cancel();
+            assertTrue(l.startIsCalled);
+            assertTrue(l.cancelIsCalled);
+            assertTrue(l.endIsCalled);
 
+            for (int i = 0; i < listeners.size(); i++) {
+                assertTrue(listeners.get(i).startIsCalled);
+                if (runningAnimIds.contains(i)) {
+                    assertTrue(listeners.get(i).cancelIsCalled);
+                }
+                assertTrue(listeners.get(i).endIsCalled);
+            }
+        });
     }
 
-    @SmallTest
+    @Test
     public void testIsRunning() throws Throwable {
         final AnimatorSet s = new AnimatorSet();
         final long startDelay = 500;
@@ -455,12 +432,7 @@
         s.setStartDelay(startDelay);
         MyListener listener = new MyListener();
         s.addListener(listener);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                s.start();
-            }
-        });
+        mActivityRule.runOnUiThread(s::start);
 
         while (!listener.endIsCalled) {
             boolean passedStartDelay = a1.isStarted() || a2.isStarted() || a3.isStarted() ||
@@ -471,35 +443,29 @@
         assertFalse(s.isRunning());
     }
 
-    @SmallTest
+    @Test
     public void testPauseAndResume() throws Throwable {
         final AnimatorSet set = getSequentialSet();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // Calling pause before start should have no effect, per documentation
-                set.pause();
-                set.start();
-                assertFalse(set.isPaused());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            // Calling pause before start should have no effect, per documentation
+            set.pause();
+            set.start();
+            assertFalse(set.isPaused());
         });
 
         while (!a2.isStarted()) {
             Thread.sleep(50);
         }
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertFalse(set.isPaused());
-                set.pause();
-                assertTrue(set.isPaused());
-                set.resume();
-                assertFalse(set.isPaused());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            assertFalse(set.isPaused());
+            set.pause();
+            assertTrue(set.isPaused());
+            set.resume();
+            assertFalse(set.isPaused());
         });
     }
 
-    @SmallTest
+    @Test
     public void testClone() throws Throwable {
         // Set up an AnimatorSet and two clones, add one listener to each. When the clones animate,
         // listeners of both the clone and the animator being cloned should receive animation
@@ -535,14 +501,11 @@
 
         // Start the animation, and make the first clone during its run and the second clone once
         // it ends.
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertFalse(l1.startIsCalled);
-                assertFalse(l1.endIsCalled);
+        mActivityRule.runOnUiThread(() -> {
+            assertFalse(l1.startIsCalled);
+            assertFalse(l1.endIsCalled);
 
-                s1.start();
-            }
+            s1.start();
         });
 
         // Make the first clone, during the animation's run.
@@ -552,20 +515,12 @@
         s2.addListener(l2);
 
         Thread.sleep(POLL_INTERVAL);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                s1.end();
-            }
-        });
+        mActivityRule.runOnUiThread(s1::end);
 
         Thread.sleep(POLL_INTERVAL);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertTrue(l1.startIsCalled);
-                assertTrue(l1.endIsCalled);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            assertTrue(l1.startIsCalled);
+            assertTrue(l1.endIsCalled);
         });
         Thread.sleep(POLL_INTERVAL);
 
@@ -574,59 +529,49 @@
         final MyListener l3 = new MyListener();
         s3.addListener(l3);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // Checking the fields before animations start.
-                assertFalse(l2.startIsCalled);
-                assertFalse(l2.cancelIsCalled);
-                assertFalse(l2.endIsCalled);
-                assertFalse(l3.startIsCalled);
-                assertFalse(l3.cancelIsCalled);
-                assertFalse(l3.endIsCalled);
+        mActivityRule.runOnUiThread(() -> {
+            // Checking the fields before animations start.
+            assertFalse(l2.startIsCalled);
+            assertFalse(l2.cancelIsCalled);
+            assertFalse(l2.endIsCalled);
+            assertFalse(l3.startIsCalled);
+            assertFalse(l3.cancelIsCalled);
+            assertFalse(l3.endIsCalled);
 
-                s2.start();
-                s3.start();
-            }
+            s2.start();
+            s3.start();
         });
 
         Thread.sleep(POLL_INTERVAL);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // Make sure the listeners receive the callbacks
-                // At this time only onAnimationStart() should be called.
-                assertTrue(l2.startIsCalled);
-                assertTrue(l3.startIsCalled);
-                assertFalse(l2.endIsCalled);
-                assertFalse(l3.endIsCalled);
-                assertFalse(l2.cancelIsCalled);
-                assertFalse(l3.cancelIsCalled);
+        mActivityRule.runOnUiThread(() -> {
+            // Make sure the listeners receive the callbacks
+            // At this time only onAnimationStart() should be called.
+            assertTrue(l2.startIsCalled);
+            assertTrue(l3.startIsCalled);
+            assertFalse(l2.endIsCalled);
+            assertFalse(l3.endIsCalled);
+            assertFalse(l2.cancelIsCalled);
+            assertFalse(l3.cancelIsCalled);
 
-                s2.end();
-                s3.cancel();
-            }
+            s2.end();
+            s3.cancel();
         });
         Thread.sleep(POLL_INTERVAL);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // Check that the new listeners for the new animations gets called for the events.
-                assertTrue(l2.startIsCalled);
-                assertFalse(l2.cancelIsCalled);
-                assertTrue(l2.endIsCalled);
-                assertTrue(l3.startIsCalled);
-                assertTrue(l3.cancelIsCalled);
-                assertTrue(l3.endIsCalled);
+        mActivityRule.runOnUiThread(() -> {
+            // Check that the new listeners for the new animations gets called for the events.
+            assertTrue(l2.startIsCalled);
+            assertFalse(l2.cancelIsCalled);
+            assertTrue(l2.endIsCalled);
+            assertTrue(l3.startIsCalled);
+            assertTrue(l3.cancelIsCalled);
+            assertTrue(l3.endIsCalled);
 
-                // Check that the listener on the animation that was being clone receive the
-                // animation lifecycle events for the clones.
-                assertTrue(onlyContains(startedAnimators, s1, s2, s3));
-                assertTrue(onlyContains(canceledAnimators, s3));
-                assertTrue(onlyContains(endedAnimators, s1, s2, s3));
-            }
+            // Check that the listener on the animation that was being clone receive the
+            // animation lifecycle events for the clones.
+            assertTrue(onlyContains(startedAnimators, s1, s2, s3));
+            assertTrue(onlyContains(canceledAnimators, s3));
+            assertTrue(onlyContains(endedAnimators, s1, s2, s3));
         });
-
     }
 
     /**
@@ -663,5 +608,4 @@
         list.add(a5);
         return list;
     }
-
 }
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
index 4e90d1a..94c90aa 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
@@ -23,6 +23,8 @@
 
 import com.android.frameworks.coretests.R;
 
+import org.junit.Test;
+
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -36,7 +38,7 @@
 
     @Override
     public void setUp() throws Exception {
-        button = (Button) getActivity().findViewById(R.id.animatingButton);
+        button =  mActivityRule.getActivity().findViewById(R.id.animatingButton);
         mAnimator = new AnimatorSet();
         ((AnimatorSet)mAnimator).playSequentially(xAnim, yAnim);
         super.setUp();
@@ -53,23 +55,21 @@
      * its children
      */
     @MediumTest
-    public void testPlayingCancelDuringChildDelay() throws Exception {
+    @Test
+    public void testPlayingCancelDuringChildDelay() throws Throwable {
         yAnim.setStartDelay(500);
         final AnimatorSet animSet = new AnimatorSet();
         animSet.playSequentially(xAnim, yAnim);
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Handler handler = new Handler();
-                    animSet.addListener(mFutureListener);
-                    mRunning = true;
-                    animSet.start();
-                    handler.postDelayed(new Canceler(animSet, mFuture), ANIM_DURATION + 250);
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                Handler handler = new Handler();
+                animSet.addListener(mFutureListener);
+                mRunning = true;
+                animSet.start();
+                handler.postDelayed(new Canceler(animSet, mFuture), ANIM_DURATION + 250);
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
diff --git a/core/tests/coretests/src/android/animation/AutoCancelTest.java b/core/tests/coretests/src/android/animation/AutoCancelTest.java
index b3ec92c..7df7336 100644
--- a/core/tests/coretests/src/android/animation/AutoCancelTest.java
+++ b/core/tests/coretests/src/android/animation/AutoCancelTest.java
@@ -16,15 +16,24 @@
 
 package android.animation;
 
+import static org.junit.Assert.assertTrue;
+
 import android.os.Handler;
-import android.test.ActivityInstrumentationTestCase2;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Rule;
+import org.junit.Test;
 
 import java.util.HashMap;
 import java.util.concurrent.TimeUnit;
 
-public class AutoCancelTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
+public class AutoCancelTest {
+
+    @Rule
+    public final ActivityTestRule<BasicAnimatorActivity> mActivityRule =
+            new ActivityTestRule<>(BasicAnimatorActivity.class);
 
     boolean mAnimX1Canceled = false;
     boolean mAnimXY1Canceled = false;
@@ -37,10 +46,6 @@
 
     HashMap<Animator, Boolean> mCanceledMap = new HashMap<Animator, Boolean>();
 
-    public AutoCancelTest() {
-        super(BasicAnimatorActivity.class);
-    }
-
     ObjectAnimator setupAnimator(long startDelay, String... properties) {
         ObjectAnimator returnVal;
         if (properties.length == 1) {
@@ -58,8 +63,7 @@
         return returnVal;
     }
 
-    private void setupAnimators(long startDelay, boolean startLater, final FutureWaiter future)
-    throws Exception {
+    private void setupAnimators(long startDelay, boolean startLater, final FutureWaiter future) {
         // Animators to be auto-canceled
         final ObjectAnimator animX1 = setupAnimator(startDelay, "x");
         final ObjectAnimator animY1 = setupAnimator(startDelay, "y");
@@ -123,64 +127,56 @@
     }
 
     @SmallTest
-    public void testAutoCancel() throws Exception {
+    @Test
+    public void testAutoCancel() throws Throwable {
         final FutureWaiter future = new FutureWaiter();
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    setupAnimators(0, false, future);
-                } catch (Exception e) {
-                    future.setException(e);
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                setupAnimators(0, false, future);
+            } catch (Exception e) {
+                future.setException(e);
             }
         });
         assertTrue(future.get(FUTURE_TIMEOUT, TimeUnit.MILLISECONDS));
     }
 
     @SmallTest
-    public void testAutoCancelDelayed() throws Exception {
+    @Test
+    public void testAutoCancelDelayed() throws Throwable {
         final FutureWaiter future = new FutureWaiter();
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    setupAnimators(START_DELAY, false, future);
-                } catch (Exception e) {
-                    future.setException(e);
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                setupAnimators(START_DELAY, false, future);
+            } catch (Exception e) {
+                future.setException(e);
             }
         });
         assertTrue(future.get(FUTURE_TIMEOUT, TimeUnit.MILLISECONDS));
     }
 
     @SmallTest
-    public void testAutoCancelTestLater() throws Exception {
+    @Test
+    public void testAutoCancelTestLater() throws Throwable {
         final FutureWaiter future = new FutureWaiter();
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    setupAnimators(0, true, future);
-                } catch (Exception e) {
-                    future.setException(e);
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                setupAnimators(0, true, future);
+            } catch (Exception e) {
+                future.setException(e);
             }
         });
         assertTrue(future.get(FUTURE_TIMEOUT, TimeUnit.MILLISECONDS));
     }
 
     @SmallTest
-    public void testAutoCancelDelayedTestLater() throws Exception {
+    @Test
+    public void testAutoCancelDelayedTestLater() throws Throwable {
         final FutureWaiter future = new FutureWaiter();
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    setupAnimators(START_DELAY, true, future);
-                } catch (Exception e) {
-                    future.setException(e);
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                setupAnimators(START_DELAY, true, future);
+            } catch (Exception e) {
+                future.setException(e);
             }
         });
         assertTrue(future.get(FUTURE_TIMEOUT, TimeUnit.MILLISECONDS));
diff --git a/core/tests/coretests/src/android/animation/EventsTest.java b/core/tests/coretests/src/android/animation/EventsTest.java
index ba7413a..0c40a95 100644
--- a/core/tests/coretests/src/android/animation/EventsTest.java
+++ b/core/tests/coretests/src/android/animation/EventsTest.java
@@ -16,12 +16,20 @@
 
 package android.animation;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.CallSuper;
 import android.os.Handler;
-import android.test.ActivityInstrumentationTestCase2;
 
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
 
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -38,8 +46,11 @@
  * wait for some later event to occur before ending. These tests use a combination of an
  * AbstractFuture mechanism and a delayed action to release that Future later.
  */
-public abstract class EventsTest
-        extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
+public abstract class EventsTest {
+
+    @Rule
+    public final ActivityTestRule<BasicAnimatorActivity> mActivityRule =
+            new ActivityTestRule<>(BasicAnimatorActivity.class);
 
     protected static final int ANIM_DURATION = 400;
     protected static final int ANIM_DELAY = 100;
@@ -55,7 +66,6 @@
     private boolean mCanceled; // tracks whether we've canceled the animator
     protected Animator.AnimatorListener mFutureListener; // mechanism for delaying end of the test
     protected FutureWaiter mFuture; // Mechanism for waiting for the UI test to complete
-    private Animator.AnimatorListener mListener; // Listener that handles/tests the events
 
     protected Animator mAnimator; // The animator used in the tests. Must be set in subclass
                                   // setup() method prior to calling the superclass setup()
@@ -67,10 +77,12 @@
     protected static class Canceler implements Runnable {
         Animator mAnim;
         FutureWaiter mFuture;
+
         public Canceler(Animator anim, FutureWaiter future) {
             mAnim = anim;
             mFuture = future;
         }
+
         @Override
         public void run() {
             try {
@@ -79,7 +91,7 @@
                 mFuture.setException(new RuntimeException(e));
             }
         }
-    };
+    }
 
     /**
      * Timeout length, based on when the animation should reasonably be complete.
@@ -95,10 +107,12 @@
     static class Ender implements Runnable {
         Animator mAnim;
         FutureWaiter mFuture;
+
         public Ender(Animator anim, FutureWaiter future) {
             mAnim = anim;
             mFuture = future;
         }
+
         @Override
         public void run() {
             try {
@@ -107,7 +121,7 @@
                 mFuture.setException(new RuntimeException(e));
             }
         }
-    };
+    }
 
     /**
      * Pauses the given animator. Used to delay pausing until some later time (after the
@@ -116,10 +130,12 @@
     static class Pauser implements Runnable {
         Animator mAnim;
         FutureWaiter mFuture;
+
         public Pauser(Animator anim, FutureWaiter future) {
             mAnim = anim;
             mFuture = future;
         }
+
         @Override
         public void run() {
             try {
@@ -128,7 +144,7 @@
                 mFuture.setException(new RuntimeException(e));
             }
         }
-    };
+    }
 
     /**
      * Resumes the given animator. Used to delay resuming until some later time (after the
@@ -137,10 +153,12 @@
     static class Resumer implements Runnable {
         Animator mAnim;
         FutureWaiter mFuture;
+
         public Resumer(Animator anim, FutureWaiter future) {
             mAnim = anim;
             mFuture = future;
         }
+
         @Override
         public void run() {
             try {
@@ -149,7 +167,7 @@
                 mFuture.setException(new RuntimeException(e));
             }
         }
-    };
+    }
 
     /**
      * Releases the given Future object when the listener's end() event is called. Specifically,
@@ -171,28 +189,14 @@
         public FutureReleaseListener(FutureWaiter future, long timeout) {
             mFuture = future;
             Handler handler = new Handler();
-            handler.postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    mFuture.release();
-                }
-            }, timeout);
+            handler.postDelayed(mFuture::release, timeout);
         }
 
         @Override
         public void onAnimationEnd(Animator animation) {
             Handler handler = new Handler();
-            handler.postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    mFuture.release();
-                }
-            }, FUTURE_RELEASE_DELAY);
+            handler.postDelayed(mFuture::release, FUTURE_RELEASE_DELAY);
         }
-    };
-
-    public EventsTest() {
-        super(BasicAnimatorActivity.class);
     }
 
     /**
@@ -201,13 +205,12 @@
      * and then call super.setup(), where further properties are set on that animator.
      * @throws Exception
      */
-    @Override
+    @CallSuper
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
-
         // mListener is the main testing mechanism of this file. The asserts of each test
         // are embedded in the listener callbacks that it implements.
-        mListener = new AnimatorListenerAdapter() {
+        final Animator.AnimatorListener listener = new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
                 // This should only be called on an animation that has not yet been started
@@ -236,9 +239,8 @@
             }
         };
 
-        mAnimator.addListener(mListener);
+        mAnimator.addListener(listener);
         mAnimator.setDuration(ANIM_DURATION);
-
         mFuture = new FutureWaiter();
 
         mRunning = false;
@@ -251,6 +253,7 @@
      */
     @UiThreadTest
     @SmallTest
+    @Test
     public void testCancel() throws Exception {
         mAnimator.cancel();
     }
@@ -260,6 +263,7 @@
      */
     @UiThreadTest
     @SmallTest
+    @Test
     public void testEnd() throws Exception {
         mRunning = true; // end() implicitly starts an unstarted animator
         mAnimator.end();
@@ -270,19 +274,17 @@
      */
     @UiThreadTest
     @SmallTest
-    public void testStartCancel() throws Exception {
+    @Test
+    public void testStartCancel() throws Throwable {
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mRunning = true;
-                    mAnimator.start();
-                    mAnimator.cancel();
-                    mFuture.release();
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                mRunning = true;
+                mAnimator.start();
+                mAnimator.cancel();
+                mFuture.release();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
@@ -293,19 +295,17 @@
      */
     @UiThreadTest
     @SmallTest
-    public void testStartEnd() throws Exception {
+    @Test
+    public void testStartEnd() throws Throwable {
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mRunning = true;
-                    mAnimator.start();
-                    mAnimator.end();
-                    mFuture.release();
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                mRunning = true;
+                mAnimator.start();
+                mAnimator.end();
+                mFuture.release();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
@@ -315,20 +315,18 @@
      * Same as testStartCancel, but with a startDelayed animator
      */
     @SmallTest
-    public void testStartDelayedCancel() throws Exception {
+    @Test
+    public void testStartDelayedCancel() throws Throwable {
         mFutureListener = new FutureReleaseListener(mFuture);
         mAnimator.setStartDelay(ANIM_DELAY);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mRunning = true;
-                    mAnimator.start();
-                    mAnimator.cancel();
-                    mFuture.release();
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                mRunning = true;
+                mAnimator.start();
+                mAnimator.cancel();
+                mFuture.release();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
@@ -338,20 +336,18 @@
      * Same as testStartEnd, but with a startDelayed animator
      */
     @SmallTest
-    public void testStartDelayedEnd() throws Exception {
+    @Test
+    public void testStartDelayedEnd() throws Throwable {
         mFutureListener = new FutureReleaseListener(mFuture);
         mAnimator.setStartDelay(ANIM_DELAY);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mRunning = true;
-                    mAnimator.start();
-                    mAnimator.end();
-                    mFuture.release();
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                mRunning = true;
+                mAnimator.start();
+                mAnimator.end();
+                mFuture.release();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
@@ -361,20 +357,18 @@
      * Verify that canceling an animator that is playing does the right thing.
      */
     @MediumTest
-    public void testPlayingCancel() throws Exception {
+    @Test
+    public void testPlayingCancel() throws Throwable {
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Handler handler = new Handler();
-                    mAnimator.addListener(mFutureListener);
-                    mRunning = true;
-                    mAnimator.start();
-                    handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DURATION);
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                Handler handler = new Handler();
+                mAnimator.addListener(mFutureListener);
+                mRunning = true;
+                mAnimator.start();
+                handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DURATION);
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
@@ -384,20 +378,18 @@
      * Verify that ending an animator that is playing does the right thing.
      */
     @MediumTest
-    public void testPlayingEnd() throws Exception {
+    @Test
+    public void testPlayingEnd() throws Throwable {
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Handler handler = new Handler();
-                    mAnimator.addListener(mFutureListener);
-                    mRunning = true;
-                    mAnimator.start();
-                    handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DURATION);
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                Handler handler = new Handler();
+                mAnimator.addListener(mFutureListener);
+                mRunning = true;
+                mAnimator.start();
+                handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DURATION);
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
@@ -407,21 +399,19 @@
      * Same as testPlayingCancel, but with a startDelayed animator
      */
     @MediumTest
-    public void testPlayingDelayedCancel() throws Exception {
+    @Test
+    public void testPlayingDelayedCancel() throws Throwable {
         mAnimator.setStartDelay(ANIM_DELAY);
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Handler handler = new Handler();
-                    mAnimator.addListener(mFutureListener);
-                    mRunning = true;
-                    mAnimator.start();
-                    handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DURATION);
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                Handler handler = new Handler();
+                mAnimator.addListener(mFutureListener);
+                mRunning = true;
+                mAnimator.start();
+                handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DURATION);
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
@@ -431,21 +421,19 @@
      * Same as testPlayingEnd, but with a startDelayed animator
      */
     @MediumTest
-    public void testPlayingDelayedEnd() throws Exception {
+    @Test
+    public void testPlayingDelayedEnd() throws Throwable {
         mAnimator.setStartDelay(ANIM_DELAY);
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Handler handler = new Handler();
-                    mAnimator.addListener(mFutureListener);
-                    mRunning = true;
-                    mAnimator.start();
-                    handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DURATION);
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                Handler handler = new Handler();
+                mAnimator.addListener(mFutureListener);
+                mRunning = true;
+                mAnimator.start();
+                handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DURATION);
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
@@ -455,24 +443,21 @@
      * Same as testPlayingDelayedCancel, but cancel during the startDelay period
      */
     @MediumTest
-    public void testPlayingDelayedCancelMidDelay() throws Exception {
+    @Test
+    public void testPlayingDelayedCancelMidDelay() throws Throwable {
         mAnimator.setStartDelay(ANIM_DELAY);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    // Set the listener to automatically timeout after an uncanceled animation
-                    // would have finished. This tests to make sure that we're not calling
-                    // the listeners with cancel/end callbacks since they won't be called
-                    // with the start event.
-                    mFutureListener = new FutureReleaseListener(mFuture, getTimeout());
-                    Handler handler = new Handler();
-                    mRunning = true;
-                    mAnimator.start();
-                    handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DELAY);
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                // Set the listener to automatically timeout after an uncanceled animation would
+                // have finished. This tests to make sure that we're not calling the listeners with
+                // cancel/end callbacks since they won't be called with the start event.
+                mFutureListener = new FutureReleaseListener(mFuture, getTimeout());
+                Handler handler = new Handler();
+                mRunning = true;
+                mAnimator.start();
+                handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DELAY);
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout() + 100,  TimeUnit.MILLISECONDS);
@@ -482,24 +467,21 @@
      * Same as testPlayingDelayedEnd, but end during the startDelay period
      */
     @MediumTest
-    public void testPlayingDelayedEndMidDelay() throws Exception {
+    @Test
+    public void testPlayingDelayedEndMidDelay() throws Throwable {
         mAnimator.setStartDelay(ANIM_DELAY);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    // Set the listener to automatically timeout after an uncanceled animation
-                    // would have finished. This tests to make sure that we're not calling
-                    // the listeners with cancel/end callbacks since they won't be called
-                    // with the start event.
-                    mFutureListener = new FutureReleaseListener(mFuture, getTimeout());
-                    Handler handler = new Handler();
-                    mRunning = true;
-                    mAnimator.start();
-                    handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DELAY);
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                // Set the listener to automatically timeout after an uncanceled animation would
+                // have finished. This tests to make sure that we're not calling the listeners with
+                // cancel/end callbacks since they won't be called with the start event.
+                mFutureListener = new FutureReleaseListener(mFuture, getTimeout());
+                Handler handler = new Handler();
+                mRunning = true;
+                mAnimator.start();
+                handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DELAY);
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout() + 100,  TimeUnit.MILLISECONDS);
@@ -510,20 +492,18 @@
      * does nothing.
      */
     @MediumTest
-    public void testStartDoubleCancel() throws Exception {
+    @Test
+    public void testStartDoubleCancel() throws Throwable {
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mRunning = true;
-                    mAnimator.start();
-                    mAnimator.cancel();
-                    mAnimator.cancel();
-                    mFuture.release();
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                mRunning = true;
+                mAnimator.start();
+                mAnimator.cancel();
+                mAnimator.cancel();
+                mFuture.release();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
@@ -534,21 +514,19 @@
      * does nothing.
      */
     @MediumTest
-    public void testStartDoubleEnd() throws Exception {
+    @Test
+    public void testStartDoubleEnd() throws Throwable {
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mRunning = true;
-                    mAnimator.start();
-                    mAnimator.end();
-                    mRunning = true; // end() implicitly starts an unstarted animator
-                    mAnimator.end();
-                    mFuture.release();
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                mRunning = true;
+                mAnimator.start();
+                mAnimator.end();
+                mRunning = true; // end() implicitly starts an unstarted animator
+                mAnimator.end();
+                mFuture.release();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
@@ -558,21 +536,19 @@
      * Same as testStartDoubleCancel, but with a startDelayed animator
      */
     @MediumTest
-    public void testStartDelayedDoubleCancel() throws Exception {
+    @Test
+    public void testStartDelayedDoubleCancel() throws Throwable {
         mAnimator.setStartDelay(ANIM_DELAY);
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mRunning = true;
-                    mAnimator.start();
-                    mAnimator.cancel();
-                    mAnimator.cancel();
-                    mFuture.release();
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                mRunning = true;
+                mAnimator.start();
+                mAnimator.cancel();
+                mAnimator.cancel();
+                mFuture.release();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
@@ -582,22 +558,20 @@
      * Same as testStartDoubleEnd, but with a startDelayed animator
      */
     @MediumTest
-    public void testStartDelayedDoubleEnd() throws Exception {
+    @Test
+    public void testStartDelayedDoubleEnd() throws Throwable {
         mAnimator.setStartDelay(ANIM_DELAY);
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mRunning = true;
-                    mAnimator.start();
-                    mAnimator.end();
-                    mRunning = true; // end() implicitly starts an unstarted animator
-                    mAnimator.end();
-                    mFuture.release();
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                mRunning = true;
+                mAnimator.start();
+                mAnimator.end();
+                mRunning = true; // end() implicitly starts an unstarted animator
+                mAnimator.end();
+                mFuture.release();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
@@ -608,22 +582,20 @@
      * the appropriate timeout duration.
      */
     @MediumTest
-    public void testPauseResume() throws Exception {
+    @Test
+    public void testPauseResume() throws Throwable {
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Handler handler = new Handler();
-                    mAnimator.addListener(mFutureListener);
-                    mRunning = true;
-                    mAnimator.start();
-                    handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
-                    handler.postDelayed(new Resumer(mAnimator, mFuture),
-                            ANIM_PAUSE_DELAY + ANIM_PAUSE_DURATION);
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                Handler handler = new Handler();
+                mAnimator.addListener(mFutureListener);
+                mRunning = true;
+                mAnimator.start();
+                handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
+                handler.postDelayed(new Resumer(mAnimator, mFuture),
+                        ANIM_PAUSE_DELAY + ANIM_PAUSE_DURATION);
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout() + ANIM_PAUSE_DURATION, TimeUnit.MILLISECONDS);
@@ -634,23 +606,21 @@
      * the appropriate timeout duration.
      */
     @MediumTest
-    public void testPauseResumeDelayed() throws Exception {
+    @Test
+    public void testPauseResumeDelayed() throws Throwable {
         mAnimator.setStartDelay(ANIM_DELAY);
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Handler handler = new Handler();
-                    mAnimator.addListener(mFutureListener);
-                    mRunning = true;
-                    mAnimator.start();
-                    handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
-                    handler.postDelayed(new Resumer(mAnimator, mFuture),
-                            ANIM_PAUSE_DELAY + ANIM_PAUSE_DURATION);
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                Handler handler = new Handler();
+                mAnimator.addListener(mFutureListener);
+                mRunning = true;
+                mAnimator.start();
+                handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
+                handler.postDelayed(new Resumer(mAnimator, mFuture),
+                        ANIM_PAUSE_DELAY + ANIM_PAUSE_DURATION);
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout() + ANIM_PAUSE_DURATION + ANIM_FULL_DURATION_SLOP,
@@ -661,20 +631,18 @@
      * Verify that pausing an animator without resuming it causes a timeout.
      */
     @MediumTest
-    public void testPauseTimeout() throws Exception {
+    @Test
+    public void testPauseTimeout() throws Throwable {
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Handler handler = new Handler();
-                    mAnimator.addListener(mFutureListener);
-                    mRunning = true;
-                    mAnimator.start();
-                    handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                Handler handler = new Handler();
+                mAnimator.addListener(mFutureListener);
+                mRunning = true;
+                mAnimator.start();
+                handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         try {
@@ -689,21 +657,19 @@
      * Verify that pausing a startDelayed animator without resuming it causes a timeout.
      */
     @MediumTest
-    public void testPauseTimeoutDelayed() throws Exception {
+    @Test
+    public void testPauseTimeoutDelayed() throws Throwable {
         mAnimator.setStartDelay(ANIM_DELAY);
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Handler handler = new Handler();
-                    mAnimator.addListener(mFutureListener);
-                    mRunning = true;
-                    mAnimator.start();
-                    handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                Handler handler = new Handler();
+                mAnimator.addListener(mFutureListener);
+                mRunning = true;
+                mAnimator.start();
+                handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         try {
diff --git a/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java b/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
index 53f9472..63ad061 100644
--- a/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
+++ b/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
@@ -27,11 +27,10 @@
 
     @Override
     public void setUp() throws Exception {
-        final BasicAnimatorActivity activity = getActivity();
-        Button button = (Button) activity.findViewById(R.id.animatingButton);
+        final BasicAnimatorActivity activity = mActivityRule.getActivity();
+        Button button = activity.findViewById(R.id.animatingButton);
 
         mAnimator = ObjectAnimator.ofFloat(button, "translationX", 0, 100);
         super.setUp();
     }
-
 }
diff --git a/core/tests/coretests/src/android/animation/StateListAnimatorTest.java b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
index e755b89..12f1977 100644
--- a/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
+++ b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
@@ -16,41 +16,47 @@
 
 package android.animation;
 
-import android.test.ActivityInstrumentationTestCase2;
+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.util.StateSet;
 import android.view.View;
 import android.view.ViewGroup;
 
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
 
 import com.android.frameworks.coretests.R;
 
+import org.junit.Rule;
+import org.junit.Test;
+
 import java.util.concurrent.atomic.AtomicInteger;
 
 @LargeTest
-public class StateListAnimatorTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
+public class StateListAnimatorTest {
 
-    public StateListAnimatorTest() {
-        super(BasicAnimatorActivity.class);
-    }
+    @Rule
+    public final ActivityTestRule<BasicAnimatorActivity> mActivityRule =
+            new ActivityTestRule<>(BasicAnimatorActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
-
+    @Test
     public void testInflateFromAnimator() throws Exception {
         StateListAnimator stateListAnimator = AnimatorInflater
-                .loadStateListAnimator(getActivity(), R.anim.test_state_anim);
+                .loadStateListAnimator(mActivityRule.getActivity(), R.anim.test_state_anim);
         assertNotNull("A state list animator should be returned", stateListAnimator);
         assertEquals("State list animator should have three items", 3,
                 stateListAnimator.getTuples().size());
     }
 
     @UiThreadTest
+    @Test
     public void testAttachDetach() throws Exception {
-        View view = new View(getActivity());
+        final BasicAnimatorActivity activity = mActivityRule.getActivity();
+        View view = new View(activity);
         final AtomicInteger setStateCount = new AtomicInteger(0);
         StateListAnimator stateListAnimator = new StateListAnimator() {
             @Override
@@ -62,7 +68,7 @@
         view.setStateListAnimator(stateListAnimator);
         assertNotNull("State list animator should have a reference to view even if it is detached",
                 stateListAnimator.getTarget());
-        ViewGroup viewGroup = (ViewGroup) getActivity().findViewById(android.R.id.content);
+        ViewGroup viewGroup = activity.findViewById(android.R.id.content);
         int preSetStateCount = setStateCount.get();
         viewGroup.addView(view);
         assertTrue("When view is attached, state list drawable's setState should be called",
@@ -82,9 +88,10 @@
                 stateListAnimator2.getTarget());
     }
 
+    @Test
     public void testStateListLoading() throws InterruptedException {
         StateListAnimator stateListAnimator = AnimatorInflater
-                .loadStateListAnimator(getActivity(), R.anim.test_state_anim);
+                .loadStateListAnimator(mActivityRule.getActivity(), R.anim.test_state_anim);
         assertNotNull("A state list animator should be returned", stateListAnimator);
         assertEquals("Steate list animator should have two items", 3,
                 stateListAnimator.getTuples().size());
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java b/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
index f6d71b8..ba9aef8 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
@@ -26,5 +26,4 @@
         mAnimator = ValueAnimator.ofFloat(0, 1);
         super.setUp();
     }
-
 }
diff --git a/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java b/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
index 997af00..81cd4da 100644
--- a/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
+++ b/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
@@ -16,17 +16,24 @@
 
 package android.animation;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import android.os.Handler;
-import android.test.ActivityInstrumentationTestCase2;
 import android.view.ViewPropertyAnimator;
 import android.widget.Button;
 
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
 
 import com.android.frameworks.coretests.R;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -41,8 +48,11 @@
  * wait for some later event to occur before ending. These tests use a combination of an
  * AbstractFuture mechanism and a delayed action to release that Future later.
  */
-public abstract class ViewPropertyAnimatorTest
-        extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
+public class ViewPropertyAnimatorTest {
+
+    @Rule
+    public final ActivityTestRule<BasicAnimatorActivity> mActivityRule =
+            new ActivityTestRule<>(BasicAnimatorActivity.class);
 
     protected static final int ANIM_DURATION = 400;
     protected static final int ANIM_DELAY = 100;
@@ -79,7 +89,7 @@
                 mFuture.setException(new RuntimeException(e));
             }
         }
-    };
+    }
 
     /**
      * Timeout length, based on when the animation should reasonably be complete.
@@ -108,28 +118,14 @@
         public FutureReleaseListener(FutureWaiter future, long timeout) {
             mFuture = future;
             Handler handler = new Handler();
-            handler.postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    mFuture.release();
-                }
-            }, timeout);
+            handler.postDelayed(mFuture::release, timeout);
         }
 
         @Override
         public void onAnimationEnd(Animator animation) {
             Handler handler = new Handler();
-            handler.postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    mFuture.release();
-                }
-            }, FUTURE_RELEASE_DELAY);
+            handler.postDelayed(mFuture::release, FUTURE_RELEASE_DELAY);
         }
-    };
-
-    public ViewPropertyAnimatorTest() {
-        super(BasicAnimatorActivity.class);
     }
 
     /**
@@ -138,15 +134,13 @@
      * and then call super.setup(), where further properties are set on that animator.
      * @throws Exception
      */
-    @Override
+    @Before
     public void setUp() throws Exception {
-        final BasicAnimatorActivity activity = getActivity();
-        Button button = (Button) activity.findViewById(R.id.animatingButton);
+        final BasicAnimatorActivity activity = mActivityRule.getActivity();
+        Button button = activity.findViewById(R.id.animatingButton);
 
         mAnimator = button.animate().x(100).y(100);
 
-        super.setUp();
-
         // mListener is the main testing mechanism of this file. The asserts of each test
         // are embedded in the listener callbacks that it implements.
         mListener = new AnimatorListenerAdapter() {
@@ -195,6 +189,7 @@
      */
     @UiThreadTest
     @SmallTest
+    @Test
     public void testCancel() throws Exception {
         mAnimator.cancel();
     }
@@ -204,19 +199,17 @@
      */
     @UiThreadTest
     @SmallTest
-    public void testStartCancel() throws Exception {
+    @Test
+    public void testStartCancel() throws Throwable {
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mRunning = true;
-                    mAnimator.start();
-                    mAnimator.cancel();
-                    mFuture.release();
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                mRunning = true;
+                mAnimator.start();
+                mAnimator.cancel();
+                mFuture.release();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
@@ -226,20 +219,18 @@
      * Same as testStartCancel, but with a startDelayed animator
      */
     @SmallTest
-    public void testStartDelayedCancel() throws Exception {
+    @Test
+    public void testStartDelayedCancel() throws Throwable {
         mFutureListener = new FutureReleaseListener(mFuture);
         mAnimator.setStartDelay(ANIM_DELAY);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mRunning = true;
-                    mAnimator.start();
-                    mAnimator.cancel();
-                    mFuture.release();
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                mRunning = true;
+                mAnimator.start();
+                mAnimator.cancel();
+                mFuture.release();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
@@ -249,20 +240,18 @@
      * Verify that canceling an animator that is playing does the right thing.
      */
     @MediumTest
-    public void testPlayingCancel() throws Exception {
+    @Test
+    public void testPlayingCancel() throws Throwable {
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Handler handler = new Handler();
-                    mAnimator.setListener(mFutureListener);
-                    mRunning = true;
-                    mAnimator.start();
-                    handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DURATION);
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                Handler handler = new Handler();
+                mAnimator.setListener(mFutureListener);
+                mRunning = true;
+                mAnimator.start();
+                handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DURATION);
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
@@ -272,21 +261,19 @@
      * Same as testPlayingCancel, but with a startDelayed animator
      */
     @MediumTest
-    public void testPlayingDelayedCancel() throws Exception {
+    @Test
+    public void testPlayingDelayedCancel() throws Throwable {
         mAnimator.setStartDelay(ANIM_DELAY);
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Handler handler = new Handler();
-                    mAnimator.setListener(mFutureListener);
-                    mRunning = true;
-                    mAnimator.start();
-                    handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DURATION);
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                Handler handler = new Handler();
+                mAnimator.setListener(mFutureListener);
+                mRunning = true;
+                mAnimator.start();
+                handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DURATION);
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
@@ -296,24 +283,21 @@
      * Same as testPlayingDelayedCancel, but cancel during the startDelay period
      */
     @MediumTest
-    public void testPlayingDelayedCancelMidDelay() throws Exception {
+    @Test
+    public void testPlayingDelayedCancelMidDelay() throws Throwable {
         mAnimator.setStartDelay(ANIM_DELAY);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    // Set the listener to automatically timeout after an uncanceled animation
-                    // would have finished. This tests to make sure that we're not calling
-                    // the listeners with cancel/end callbacks since they won't be called
-                    // with the start event.
-                    mFutureListener = new FutureReleaseListener(mFuture, getTimeout());
-                    Handler handler = new Handler();
-                    mRunning = true;
-                    mAnimator.start();
-                    handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DELAY);
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                // Set the listener to automatically timeout after an uncanceled animation would
+                // have finished. This tests to make sure that we're not calling the listeners with
+                // cancel/end callbacks since they won't be called with the start event.
+                mFutureListener = new FutureReleaseListener(mFuture, getTimeout());
+                Handler handler = new Handler();
+                mRunning = true;
+                mAnimator.start();
+                handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DELAY);
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout() + 100,  TimeUnit.MILLISECONDS);
@@ -324,20 +308,18 @@
      * does nothing.
      */
     @MediumTest
-    public void testStartDoubleCancel() throws Exception {
+    @Test
+    public void testStartDoubleCancel() throws Throwable {
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mRunning = true;
-                    mAnimator.start();
-                    mAnimator.cancel();
-                    mAnimator.cancel();
-                    mFuture.release();
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                mRunning = true;
+                mAnimator.start();
+                mAnimator.cancel();
+                mAnimator.cancel();
+                mFuture.release();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
@@ -347,24 +329,21 @@
      * Same as testStartDoubleCancel, but with a startDelayed animator
      */
     @MediumTest
-    public void testStartDelayedDoubleCancel() throws Exception {
+    @Test
+    public void testStartDelayedDoubleCancel() throws Throwable {
         mAnimator.setStartDelay(ANIM_DELAY);
         mFutureListener = new FutureReleaseListener(mFuture);
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mRunning = true;
-                    mAnimator.start();
-                    mAnimator.cancel();
-                    mAnimator.cancel();
-                    mFuture.release();
-                } catch (junit.framework.AssertionFailedError e) {
-                    mFuture.setException(new RuntimeException(e));
-                }
+        mActivityRule.runOnUiThread(() -> {
+            try {
+                mRunning = true;
+                mAnimator.start();
+                mAnimator.cancel();
+                mAnimator.cancel();
+                mFuture.release();
+            } catch (junit.framework.AssertionFailedError e) {
+                mFuture.setException(new RuntimeException(e));
             }
         });
         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
      }
-
 }
diff --git a/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
index 16be0b0..d8799cb 100644
--- a/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
+++ b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
@@ -17,7 +17,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-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/view/AccessibilityInteractionControllerTest.java b/core/tests/coretests/src/android/view/AccessibilityInteractionControllerTest.java
index d0719cb..7855ef9 100644
--- a/core/tests/coretests/src/android/view/AccessibilityInteractionControllerTest.java
+++ b/core/tests/coretests/src/android/view/AccessibilityInteractionControllerTest.java
@@ -26,9 +26,6 @@
 import android.app.UiAutomation;
 import android.graphics.Rect;
 import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -36,6 +33,10 @@
 import android.view.accessibility.AccessibilityTestActivity;
 import android.view.accessibility.AccessibilityWindowInfo;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.rule.ActivityTestRule;
+
 import com.android.compatibility.common.util.TestUtils;
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index b07cb99..da81d17 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -24,6 +24,7 @@
 
 import android.content.Context;
 import android.graphics.Insets;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.platform.test.annotations.Presubmit;
@@ -80,7 +81,7 @@
 
     @Test
     public void testImeVisibility() {
-        final InsetsSourceControl ime = new InsetsSourceControl(TYPE_IME, mLeash);
+        final InsetsSourceControl ime = new InsetsSourceControl(TYPE_IME, mLeash, new Point());
         mController.onControlsChanged(new InsetsSourceControl[] { ime });
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 7cd3c44..71ce02d 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -19,13 +19,23 @@
 import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.TYPE_TOP_BAR;
 
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
+import static android.view.WindowInsets.Type.sideBars;
+import static android.view.WindowInsets.Type.systemBars;
+import static android.view.WindowInsets.Type.topBar;
 import static junit.framework.Assert.assertEquals;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.graphics.Insets;
 import android.graphics.Matrix;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.platform.test.annotations.Presubmit;
@@ -55,6 +65,7 @@
     private SurfaceSession mSession = new SurfaceSession();
     private SurfaceControl mTopLeash;
     private SurfaceControl mNavLeash;
+    private InsetsState mInsetsState;
 
     @Mock Transaction mMockTransaction;
     @Mock InsetsController mMockController;
@@ -63,6 +74,7 @@
 
     @Before
     public void setup() {
+        ViewRootImpl.sNewInsetsMode = NEW_INSETS_MODE_FULL;
         MockitoAnnotations.initMocks(this);
         mTopLeash = new SurfaceControl.Builder(mSession)
                 .setName("testSurface")
@@ -70,24 +82,25 @@
         mNavLeash = new SurfaceControl.Builder(mSession)
                 .setName("testSurface")
                 .build();
-        InsetsState state = new InsetsState();
-        state.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 500, 100));
-        state.getSource(TYPE_NAVIGATION_BAR).setFrame(new Rect(400, 0, 500, 500));
-        InsetsSourceConsumer topConsumer = new InsetsSourceConsumer(TYPE_TOP_BAR, state,
+        mInsetsState = new InsetsState();
+        mInsetsState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 500, 100));
+        mInsetsState.getSource(TYPE_NAVIGATION_BAR).setFrame(new Rect(400, 0, 500, 500));
+        InsetsSourceConsumer topConsumer = new InsetsSourceConsumer(TYPE_TOP_BAR, mInsetsState,
                 () -> mMockTransaction, mMockController);
-        topConsumer.setControl(new InsetsSourceControl(TYPE_TOP_BAR, mTopLeash));
+        topConsumer.setControl(new InsetsSourceControl(TYPE_TOP_BAR, mTopLeash, new Point(0, 0)));
 
-        InsetsSourceConsumer navConsumer = new InsetsSourceConsumer(TYPE_NAVIGATION_BAR, state,
-                () -> mMockTransaction, mMockController);
+        InsetsSourceConsumer navConsumer = new InsetsSourceConsumer(TYPE_NAVIGATION_BAR,
+                mInsetsState, () -> mMockTransaction, mMockController);
         navConsumer.hide();
-        navConsumer.setControl(new InsetsSourceControl(TYPE_NAVIGATION_BAR, mNavLeash));
+        navConsumer.setControl(new InsetsSourceControl(TYPE_NAVIGATION_BAR, mNavLeash,
+                new Point(400, 0)));
 
         SparseArray<InsetsSourceConsumer> consumers = new SparseArray<>();
         consumers.put(TYPE_TOP_BAR, topConsumer);
         consumers.put(TYPE_NAVIGATION_BAR, navConsumer);
         mController = new InsetsAnimationControlImpl(consumers,
-                new Rect(0, 0, 500, 500), state, mMockListener, WindowInsets.Type.systemBars(),
-                () -> mMockTransactionApplier, mock(InsetsController.class));
+                new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
+                () -> mMockTransactionApplier, mMockController);
     }
 
     @Test
@@ -95,7 +108,7 @@
         assertEquals(Insets.of(0, 100, 100, 0), mController.getShownStateInsets());
         assertEquals(Insets.of(0, 0, 0, 0), mController.getHiddenStateInsets());
         assertEquals(Insets.of(0, 100, 0, 0), mController.getCurrentInsets());
-        assertEquals(WindowInsets.Type.systemBars(), mController.getTypes());
+        assertEquals(systemBars(), mController.getTypes());
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 8f21096..6dad6a2 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -27,6 +27,7 @@
 
 import android.content.Context;
 import android.graphics.Insets;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.view.WindowInsets.Type;
@@ -74,11 +75,12 @@
                             Insets.of(10, 10, 10, 10), rect, rect, rect, rect),
                     rect, rect);
         });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
     }
 
     @Test
     public void testControlsChanged() {
-        InsetsSourceControl control = new InsetsSourceControl(TYPE_TOP_BAR, mLeash);
+        InsetsSourceControl control = new InsetsSourceControl(TYPE_TOP_BAR, mLeash, new Point());
         mController.onControlsChanged(new InsetsSourceControl[] { control });
         assertEquals(mLeash,
                 mController.getSourceConsumer(TYPE_TOP_BAR).getControl().getLeash());
@@ -86,7 +88,7 @@
 
     @Test
     public void testControlsRevoked() {
-        InsetsSourceControl control = new InsetsSourceControl(TYPE_TOP_BAR, mLeash);
+        InsetsSourceControl control = new InsetsSourceControl(TYPE_TOP_BAR, mLeash, new Point());
         mController.onControlsChanged(new InsetsSourceControl[] { control });
         mController.onControlsChanged(new InsetsSourceControl[0]);
         assertNull(mController.getSourceConsumer(TYPE_TOP_BAR).getControl());
@@ -94,22 +96,19 @@
 
     @Test
     public void testAnimationEndState() {
-        final InsetsSourceControl navBar = new InsetsSourceControl(TYPE_NAVIGATION_BAR, mLeash);
-        final InsetsSourceControl topBar = new InsetsSourceControl(TYPE_TOP_BAR, mLeash);
-        final InsetsSourceControl ime = new InsetsSourceControl(TYPE_IME, mLeash);
+        InsetsSourceControl[] controls = prepareControls();
+        InsetsSourceControl navBar = controls[0];
+        InsetsSourceControl topBar = controls[1];
+        InsetsSourceControl ime = controls[2];
 
-        InsetsSourceControl[] controls = new InsetsSourceControl[3];
-        controls[0] = navBar;
-        controls[1] = topBar;
-        controls[2] = ime;
-        mController.onControlsChanged(controls);
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             mController.show(Type.all());
             // quickly jump to final state by cancelling it.
             mController.cancelExistingAnimation();
             assertTrue(mController.getSourceConsumer(navBar.getType()).isVisible());
             assertTrue(mController.getSourceConsumer(topBar.getType()).isVisible());
-            assertTrue(mController.getSourceConsumer(ime.getType()).isVisible());
+            // no focused view, no IME.
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
 
             mController.hide(Type.all());
             mController.cancelExistingAnimation();
@@ -119,11 +118,175 @@
 
             mController.show(Type.ime());
             mController.cancelExistingAnimation();
-            assertTrue(mController.getSourceConsumer(ime.getType()).isVisible());
+            // no focused view, no IME.
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
 
-            mController.hide(Type.ime());
+    @Test
+    public void testApplyImeVisibility() {
+        final InsetsSourceControl ime = new InsetsSourceControl(TYPE_IME, mLeash, new Point());
+
+        InsetsSourceControl[] controls = new InsetsSourceControl[3];
+        controls[0] = ime;
+        mController.onControlsChanged(controls);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            mController.applyImeVisibility(true);
+            mController.cancelExistingAnimation();
+            assertTrue(mController.getSourceConsumer(ime.getType()).isVisible());
+            mController.applyImeVisibility(false);
             mController.cancelExistingAnimation();
             assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
         });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    @Test
+    public void testShowHideSelectively() {
+        InsetsSourceControl[] controls = prepareControls();
+        InsetsSourceControl navBar = controls[0];
+        InsetsSourceControl topBar = controls[1];
+        InsetsSourceControl ime = controls[2];
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            int types = Type.sideBars() | Type.systemBars();
+            // test show select types.
+            mController.show(types);
+            mController.cancelExistingAnimation();
+            assertTrue(mController.getSourceConsumer(navBar.getType()).isVisible());
+            assertTrue(mController.getSourceConsumer(topBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+
+            // test hide all
+            mController.hide(types);
+            mController.cancelExistingAnimation();
+            assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(topBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    @Test
+    public void testShowHideSingle() {
+        InsetsSourceControl[] controls = prepareControls();
+        InsetsSourceControl navBar = controls[0];
+        InsetsSourceControl topBar = controls[1];
+        InsetsSourceControl ime = controls[2];
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            int types = Type.sideBars() | Type.systemBars();
+            // test show select types.
+            mController.show(types);
+            mController.cancelExistingAnimation();
+            assertTrue(mController.getSourceConsumer(navBar.getType()).isVisible());
+            assertTrue(mController.getSourceConsumer(topBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+
+            // test hide all
+            mController.hide(Type.all());
+            mController.cancelExistingAnimation();
+            assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(topBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+
+            // test single show
+            mController.show(Type.sideBars());
+            mController.cancelExistingAnimation();
+            assertTrue(mController.getSourceConsumer(navBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(topBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+
+            // test single hide
+            mController.hide(Type.sideBars());
+            assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(topBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    @Test
+    public void testShowHideMultiple() {
+        InsetsSourceControl[] controls = prepareControls();
+        InsetsSourceControl navBar = controls[0];
+        InsetsSourceControl topBar = controls[1];
+        InsetsSourceControl ime = controls[2];
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            // start two animations and see if previous is cancelled and final state is reached.
+            mController.show(Type.sideBars());
+            mController.show(Type.systemBars());
+            mController.cancelExistingAnimation();
+            assertTrue(mController.getSourceConsumer(navBar.getType()).isVisible());
+            assertTrue(mController.getSourceConsumer(topBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+
+            mController.hide(Type.sideBars());
+            mController.hide(Type.systemBars());
+            mController.cancelExistingAnimation();
+            assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(topBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+
+            int types = Type.sideBars() | Type.systemBars();
+            // show two at a time and hide one by one.
+            mController.show(types);
+            mController.hide(Type.sideBars());
+            mController.cancelExistingAnimation();
+            assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
+            assertTrue(mController.getSourceConsumer(topBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+
+            mController.hide(Type.systemBars());
+            mController.cancelExistingAnimation();
+            assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(topBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    @Test
+    public void testShowMultipleHideOneByOne() {
+        InsetsSourceControl[] controls = prepareControls();
+        InsetsSourceControl navBar = controls[0];
+        InsetsSourceControl topBar = controls[1];
+        InsetsSourceControl ime = controls[2];
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            int types = Type.sideBars() | Type.systemBars();
+            // show two at a time and hide one by one.
+            mController.show(types);
+            mController.hide(Type.sideBars());
+            mController.cancelExistingAnimation();
+            assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
+            assertTrue(mController.getSourceConsumer(topBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+
+            mController.hide(Type.systemBars());
+            mController.cancelExistingAnimation();
+            assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(topBar.getType()).isVisible());
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    private InsetsSourceControl[] prepareControls() {
+        final InsetsSourceControl navBar = new InsetsSourceControl(TYPE_NAVIGATION_BAR, mLeash,
+                new Point());
+        final InsetsSourceControl topBar = new InsetsSourceControl(TYPE_TOP_BAR, mLeash,
+                new Point());
+        final InsetsSourceControl ime = new InsetsSourceControl(TYPE_IME, mLeash, new Point());
+
+        InsetsSourceControl[] controls = new InsetsSourceControl[3];
+        controls[0] = navBar;
+        controls[1] = topBar;
+        controls[2] = ime;
+        mController.onControlsChanged(controls);
+        return controls;
     }
 }
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 82cd213..66146c9 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 
+import android.graphics.Point;
 import android.platform.test.annotations.Presubmit;
 import android.view.SurfaceControl.Transaction;
 
@@ -56,7 +57,7 @@
                 .build();
         mConsumer = new InsetsSourceConsumer(TYPE_TOP_BAR, new InsetsState(),
                 () -> mMockTransaction, mMockController);
-        mConsumer.setControl(new InsetsSourceControl(TYPE_TOP_BAR, mLeash));
+        mConsumer.setControl(new InsetsSourceControl(TYPE_TOP_BAR, mLeash, new Point()));
     }
 
     @Test
@@ -78,7 +79,7 @@
         reset(mMockTransaction);
         mConsumer.hide();
         verifyZeroInteractions(mMockTransaction);
-        mConsumer.setControl(new InsetsSourceControl(TYPE_TOP_BAR, mLeash));
+        mConsumer.setControl(new InsetsSourceControl(TYPE_TOP_BAR, mLeash, new Point()));
         verify(mMockTransaction).hide(eq(mLeash));
     }
 }
diff --git a/core/tests/coretests/src/android/view/PinchZoomAction.java b/core/tests/coretests/src/android/view/PinchZoomAction.java
index bec9b55..cfdec4d 100644
--- a/core/tests/coretests/src/android/view/PinchZoomAction.java
+++ b/core/tests/coretests/src/android/view/PinchZoomAction.java
@@ -16,20 +16,21 @@
 
 package android.view;
 
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import static org.hamcrest.Matchers.allOf;
 
 import android.os.SystemClock;
-import android.support.test.espresso.InjectEventSecurityException;
-import android.support.test.espresso.PerformException;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.action.Swiper;
-import android.support.test.espresso.util.HumanReadables;
+
+import androidx.test.espresso.InjectEventSecurityException;
+import androidx.test.espresso.PerformException;
+import androidx.test.espresso.UiController;
+import androidx.test.espresso.ViewAction;
+import androidx.test.espresso.action.Swiper;
+import androidx.test.espresso.util.HumanReadables;
 
 import org.hamcrest.Matcher;
 
diff --git a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
index 1990135..f63a454 100644
--- a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
+++ b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
@@ -16,48 +16,43 @@
 
 package android.view;
 
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
-import android.test.ActivityInstrumentationTestCase2;
 import android.util.DisplayMetrics;
 import android.widget.TextView;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
 
 import com.android.frameworks.coretests.R;
 
-import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
 @LargeTest
-public class ScaleGestureDetectorTest extends ActivityInstrumentationTestCase2<ScaleGesture> {
-    private ScaleGesture mScaleGestureActivity;
+public class ScaleGestureDetectorTest {
 
-    public ScaleGestureDetectorTest() {
-        super("com.android.frameworks.coretests", ScaleGesture.class);
-    }
+    @Rule
+    public final ActivityTestRule<ScaleGesture> mActivityRule =
+            new ActivityTestRule<>(ScaleGesture.class);
+    private ScaleGesture mScaleGestureActivity;
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
-        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
-        mScaleGestureActivity = getActivity();
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        super.tearDown();
+        mScaleGestureActivity = mActivityRule.getActivity();
     }
 
     @Test
     public void testScaleGestureDetector() {
         // No scaling should have occurred prior to performing pinch zoom action.
         final float initialScaleFactor = 1.0f;
-        assertEquals(initialScaleFactor, mScaleGestureActivity.getScaleFactor());
+        assertEquals(initialScaleFactor, mScaleGestureActivity.getScaleFactor(), 0f);
 
         // Specify start and end coordinates, irrespective of device display size.
         final DisplayMetrics dm = new DisplayMetrics();
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index 71612e6..34fdebf 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -155,5 +155,10 @@
         void internalNotifyViewTextChanged(AutofillId id, CharSequence text) {
             throw new UnsupportedOperationException("should not have been called");
         }
+
+        @Override
+        public void internalNotifyViewHierarchyEvent(boolean started) {
+            throw new UnsupportedOperationException("should not have been called");
+        }
     }
 }
diff --git a/core/tests/coretests/src/android/widget/EditorCursorTest.java b/core/tests/coretests/src/android/widget/EditorCursorTest.java
index e4f55df..585c601 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorTest.java
@@ -16,11 +16,12 @@
 
 package android.widget;
 
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
 import static android.widget.espresso.TextViewAssertions.hasInsertionPointerOnLeft;
 import static android.widget.espresso.TextViewAssertions.hasInsertionPointerOnRight;
 
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+
 import static junit.framework.Assert.fail;
 
 import static org.hamcrest.MatcherAssert.assertThat;
diff --git a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
index 483270e..f6e02bc 100644
--- a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
+++ b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
@@ -16,15 +16,6 @@
 
 package android.widget;
 
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.Espresso.pressBack;
-import static android.support.test.espresso.action.ViewActions.clearText;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.action.ViewActions.replaceText;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
 import static android.widget.espresso.DragHandleUtils.onHandleView;
 import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem;
 import static android.widget.espresso.FloatingToolbarEspressoUtils.clickFloatingToolbarItem;
@@ -37,43 +28,55 @@
 import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
 import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
 
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.Espresso.pressBack;
+import static androidx.test.espresso.action.ViewActions.clearText;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.action.ViewActions.replaceText;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.RootMatchers.withDecorView;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 import android.content.res.TypedArray;
-import android.support.test.espresso.NoMatchingViewException;
-import android.support.test.espresso.ViewAssertion;
-import android.test.ActivityInstrumentationTestCase2;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.Spanned;
 import android.text.TextPaint;
 import android.text.style.SuggestionSpan;
 import android.text.style.TextAppearanceSpan;
-import android.view.View;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
 
 import com.android.frameworks.coretests.R;
 
+import org.junit.Rule;
+import org.junit.Test;
+
 /**
  * SuggestionsPopupWindowTest tests.
  *
  * TODO: Add tests for when there are no suggestions
  */
-public class SuggestionsPopupWindowTest extends ActivityInstrumentationTestCase2<TextViewActivity> {
+@SmallTest
+public class SuggestionsPopupWindowTest {
 
-    public SuggestionsPopupWindowTest() {
-        super(TextViewActivity.class);
-    }
+    @Rule
+    public final ActivityTestRule<TextViewActivity> mActivityRule =
+            new ActivityTestRule<>(TextViewActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        getActivity();
+    private TextViewActivity getActivity() {
+        return mActivityRule.getActivity();
     }
 
     private void setSuggestionSpan(SuggestionSpan span, int start, int end) {
-        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
+        final TextView textView = getActivity().findViewById(R.id.textview);
         textView.post(
                 () -> {
                     final Spannable text = (Spannable) textView.getText();
@@ -83,7 +86,7 @@
         getInstrumentation().waitForIdleSync();
     }
 
-    @SmallTest
+    @Test
     public void testOnTextContextMenuItem() {
         final String text = "abc def ghi";
 
@@ -94,14 +97,14 @@
                 new String[]{"DEF", "Def"}, SuggestionSpan.FLAG_AUTO_CORRECTION);
         setSuggestionSpan(suggestionSpan, text.indexOf('d'), text.indexOf('f') + 1);
 
-        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
+        final TextView textView = getActivity().findViewById(R.id.textview);
         textView.post(() -> textView.onTextContextMenuItem(TextView.ID_REPLACE));
         getInstrumentation().waitForIdleSync();
 
         assertSuggestionsPopupIsDisplayed();
     }
 
-    @SmallTest
+    @Test
     public void testSelectionActionMode() {
         final String text = "abc def ghi";
 
@@ -123,7 +126,7 @@
         assertSuggestionsPopupIsDisplayed();
     }
 
-    @SmallTest
+    @Test
     public void testInsertionActionMode() {
         final String text = "abc def ghi";
 
@@ -146,13 +149,13 @@
     }
 
     private void showSuggestionsPopup() {
-        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
+        final TextView textView = getActivity().findViewById(R.id.textview);
         textView.post(() -> textView.onTextContextMenuItem(TextView.ID_REPLACE));
         getInstrumentation().waitForIdleSync();
         assertSuggestionsPopupIsDisplayed();
     }
 
-    @SmallTest
+    @Test
     public void testSuggestionItems() {
         final String text = "abc def ghi";
 
@@ -190,7 +193,7 @@
         onView(withId(R.id.textview)).check(matches(withText("abc ghi")));
     }
 
-    @SmallTest
+    @Test
     public void testMisspelled() {
         final String text = "abc def ghi";
 
@@ -217,7 +220,7 @@
         // TODO: Check if add to dictionary dialog is displayed.
     }
 
-    @SmallTest
+    @Test
     public void testEasyCorrect() {
         final String text = "abc def ghi";
 
@@ -253,7 +256,7 @@
                 getActivity().getString(com.android.internal.R.string.delete));
     }
 
-    @SmallTest
+    @Test
     public void testTextAppearanceInSuggestionsPopup() {
         final String text = "abc def ghi";
 
@@ -302,53 +305,49 @@
             assertSuggestionsPopupContainsItem(
                     getActivity().getString(com.android.internal.R.string.delete));
 
-            onSuggestionsPopup().check(new ViewAssertion() {
-                @Override
-                public void check(View view, NoMatchingViewException e) {
-                    final ListView listView = (ListView) view.findViewById(
-                            com.android.internal.R.id.suggestionContainer);
-                    assertNotNull(listView);
-                    final int childNum = listView.getChildCount();
-                    assertEquals(singleWordCandidates.length + multiWordCandidates.length,
-                            childNum);
+            onSuggestionsPopup().check((view, e) -> {
+                final ListView listView = view.findViewById(
+                        com.android.internal.R.id.suggestionContainer);
+                assertNotNull(listView);
+                final int childNum = listView.getChildCount();
+                assertEquals(singleWordCandidates.length + multiWordCandidates.length, childNum);
 
-                    for (int j = 0; j < childNum; j++) {
-                        final TextView suggestion = (TextView) listView.getChildAt(j);
-                        assertNotNull(suggestion);
-                        final Spanned spanned = (Spanned) suggestion.getText();
-                        assertNotNull(spanned);
+                for (int j = 0; j < childNum; j++) {
+                    final TextView suggestion = (TextView) listView.getChildAt(j);
+                    assertNotNull(suggestion);
+                    final Spanned spanned = (Spanned) suggestion.getText();
+                    assertNotNull(spanned);
 
-                        // Check that the suggestion item order is kept.
-                        final String expectedText;
-                        if (j < singleWordCandidates.length) {
-                            expectedText = "abc " + singleWordCandidates[j] + " ghi";
-                        } else {
-                            expectedText = multiWordCandidates[j - singleWordCandidates.length];
-                        }
-                        assertEquals(expectedText, spanned.toString());
-
-                        // Check that the text is highlighted with correct color and text size.
-                        final TextAppearanceSpan[] taSpan = spanned.getSpans(
-                                text.indexOf('d'), text.indexOf('f') + 1, TextAppearanceSpan.class);
-                        assertEquals(1, taSpan.length);
-                        TextPaint tp = new TextPaint();
-                        taSpan[0].updateDrawState(tp);
-                        assertEquals(expectedHighlightTextColor, tp.getColor());
-                        assertEquals(expectedHighlightTextSize, tp.getTextSize());
-
-                        // Check the correct part of the text is highlighted.
-                        final int expectedStart;
-                        final int expectedEnd;
-                        if (j < singleWordCandidates.length) {
-                            expectedStart = text.indexOf('d');
-                            expectedEnd = text.indexOf('f') + 1;
-                        } else {
-                            expectedStart = 0;
-                            expectedEnd = text.length();
-                        }
-                        assertEquals(expectedStart, spanned.getSpanStart(taSpan[0]));
-                        assertEquals(expectedEnd, spanned.getSpanEnd(taSpan[0]));
+                    // Check that the suggestion item order is kept.
+                    final String expectedText;
+                    if (j < singleWordCandidates.length) {
+                        expectedText = "abc " + singleWordCandidates[j] + " ghi";
+                    } else {
+                        expectedText = multiWordCandidates[j - singleWordCandidates.length];
                     }
+                    assertEquals(expectedText, spanned.toString());
+
+                    // Check that the text is highlighted with correct color and text size.
+                    final TextAppearanceSpan[] taSpan = spanned.getSpans(
+                            text.indexOf('d'), text.indexOf('f') + 1, TextAppearanceSpan.class);
+                    assertEquals(1, taSpan.length);
+                    TextPaint tp = new TextPaint();
+                    taSpan[0].updateDrawState(tp);
+                    assertEquals(expectedHighlightTextColor, tp.getColor());
+                    assertEquals(expectedHighlightTextSize, tp.getTextSize(), 0f);
+
+                    // Check the correct part of the text is highlighted.
+                    final int expectedStart;
+                    final int expectedEnd;
+                    if (j < singleWordCandidates.length) {
+                        expectedStart = text.indexOf('d');
+                        expectedEnd = text.indexOf('f') + 1;
+                    } else {
+                        expectedStart = 0;
+                        expectedEnd = text.length();
+                    }
+                    assertEquals(expectedStart, spanned.getSpanStart(taSpan[0]));
+                    assertEquals(expectedEnd, spanned.getSpanEnd(taSpan[0]));
                 }
             });
             pressBack();
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
index 41fa08b..b411668 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
@@ -16,15 +16,6 @@
 
 package android.widget;
 
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.Espresso.pressBack;
-import static android.support.test.espresso.action.ViewActions.replaceText;
-import static android.support.test.espresso.action.ViewActions.typeText;
-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 android.widget.espresso.ContextMenuUtils.assertContextMenuContainsItemDisabled;
 import static android.widget.espresso.ContextMenuUtils.assertContextMenuContainsItemEnabled;
 import static android.widget.espresso.ContextMenuUtils.assertContextMenuIsNotDisplayed;
@@ -42,6 +33,15 @@
 import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
 import static android.widget.espresso.TextViewAssertions.hasSelection;
 
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.Espresso.pressBack;
+import static androidx.test.espresso.action.ViewActions.replaceText;
+import static androidx.test.espresso.action.ViewActions.typeText;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+
 import android.app.Activity;
 import android.view.MotionEvent;
 import android.view.textclassifier.TextClassificationManager;
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 9d93421..267a9c8 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -16,15 +16,6 @@
 
 package android.widget;
 
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.action.ViewActions.longClick;
-import static android.support.test.espresso.action.ViewActions.pressKey;
-import static android.support.test.espresso.action.ViewActions.replaceText;
-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 android.widget.espresso.CustomViewActions.longPressAtRelativeCoordinates;
 import static android.widget.espresso.DragHandleUtils.onHandleView;
 import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem;
@@ -44,6 +35,16 @@
 import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
 import static android.widget.espresso.TextViewAssertions.hasSelection;
 
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.action.ViewActions.longClick;
+import static androidx.test.espresso.action.ViewActions.pressKey;
+import static androidx.test.espresso.action.ViewActions.replaceText;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
@@ -60,7 +61,6 @@
 import android.app.Instrumentation;
 import android.content.ClipData;
 import android.content.ClipboardManager;
-import android.support.test.espresso.action.EspressoKey;
 import android.support.test.uiautomator.UiDevice;
 import android.text.InputType;
 import android.text.Selection;
@@ -79,6 +79,7 @@
 import android.widget.espresso.CustomViewActions.RelativeCoordinatesProvider;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.espresso.action.EspressoKey;
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.Suppress;
 import androidx.test.rule.ActivityTestRule;
diff --git a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
index 02ee9be..0f8faa8 100644
--- a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
@@ -16,28 +16,29 @@
 
 package android.widget.espresso;
 
-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.RootMatchers.withDecorView;
-import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
-import static android.support.test.espresso.matcher.ViewMatchers.hasFocus;
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
-import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.RootMatchers.withDecorView;
+import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
+import static androidx.test.espresso.matcher.ViewMatchers.hasFocus;
+import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
+import static androidx.test.espresso.matcher.ViewMatchers.isEnabled;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
 import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.not;
 
-import android.support.test.espresso.NoMatchingRootException;
-import android.support.test.espresso.NoMatchingViewException;
-import android.support.test.espresso.ViewInteraction;
-import android.support.test.espresso.matcher.ViewMatchers;
 import android.view.View;
 import android.widget.MenuPopupWindow.MenuDropDownListView;
 
+import androidx.test.espresso.NoMatchingRootException;
+import androidx.test.espresso.NoMatchingViewException;
+import androidx.test.espresso.ViewInteraction;
+import androidx.test.espresso.matcher.ViewMatchers;
+
 import com.android.internal.view.menu.ListMenuItemView;
 
 import org.hamcrest.Description;
diff --git a/core/tests/coretests/src/android/widget/espresso/CustomViewActions.java b/core/tests/coretests/src/android/widget/espresso/CustomViewActions.java
index daf9e78..217553e 100644
--- a/core/tests/coretests/src/android/widget/espresso/CustomViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/CustomViewActions.java
@@ -16,15 +16,15 @@
 
 package android.widget.espresso;
 
-import static android.support.test.espresso.action.ViewActions.actionWithAssertions;
+import static androidx.test.espresso.action.ViewActions.actionWithAssertions;
 
 import android.view.View;
 
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralClickAction;
-import android.support.test.espresso.action.Press;
-import android.support.test.espresso.action.Tap;
+import androidx.test.espresso.ViewAction;
+import androidx.test.espresso.action.CoordinatesProvider;
+import androidx.test.espresso.action.GeneralClickAction;
+import androidx.test.espresso.action.Press;
+import androidx.test.espresso.action.Tap;
 
 import com.android.internal.util.Preconditions;
 
diff --git a/core/tests/coretests/src/android/widget/espresso/DragAction.java b/core/tests/coretests/src/android/widget/espresso/DragAction.java
index b2c8e38..afdc4d3 100644
--- a/core/tests/coretests/src/android/widget/espresso/DragAction.java
+++ b/core/tests/coretests/src/android/widget/espresso/DragAction.java
@@ -16,27 +16,30 @@
 
 package android.widget.espresso;
 
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
+
 import static com.android.internal.util.Preconditions.checkNotNull;
+
 import static org.hamcrest.Matchers.allOf;
+
 import android.annotation.Nullable;
 import android.os.SystemClock;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.PerformException;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.MotionEvents;
-import android.support.test.espresso.action.PrecisionDescriber;
-import android.support.test.espresso.action.Swiper;
-import android.support.test.espresso.util.HumanReadables;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
 
-import org.hamcrest.Matcher;
+import androidx.test.espresso.PerformException;
+import androidx.test.espresso.UiController;
+import androidx.test.espresso.ViewAction;
+import androidx.test.espresso.action.CoordinatesProvider;
+import androidx.test.espresso.action.MotionEvents;
+import androidx.test.espresso.action.PrecisionDescriber;
+import androidx.test.espresso.action.Swiper;
+import androidx.test.espresso.util.HumanReadables;
 
+import org.hamcrest.Matcher;
 
 /**
  * Drags on a View using touch events.<br>
diff --git a/core/tests/coretests/src/android/widget/espresso/DragHandleUtils.java b/core/tests/coretests/src/android/widget/espresso/DragHandleUtils.java
index 1693e54..1b849b5 100644
--- a/core/tests/coretests/src/android/widget/espresso/DragHandleUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/DragHandleUtils.java
@@ -16,22 +16,23 @@
 
 package android.widget.espresso;
 
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.RootMatchers.isPlatformPopup;
-import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
-import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.RootMatchers.isPlatformPopup;
+import static androidx.test.espresso.matcher.RootMatchers.withDecorView;
+import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
+import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
 
 import static org.hamcrest.Matchers.allOf;
 
-import android.support.test.espresso.NoMatchingRootException;
-import android.support.test.espresso.NoMatchingViewException;
-import android.support.test.espresso.ViewInteraction;
 import android.widget.Editor;
 
+import androidx.test.espresso.NoMatchingRootException;
+import androidx.test.espresso.NoMatchingViewException;
+import androidx.test.espresso.ViewInteraction;
+
 public final class DragHandleUtils {
 
     private DragHandleUtils() {}
diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
index 0355f82..d45d4b0 100644
--- a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
@@ -16,30 +16,31 @@
 
 package android.widget.espresso;
 
-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.RootMatchers.isPlatformPopup;
-import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
-import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withTagValue;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.RootMatchers.isPlatformPopup;
+import static androidx.test.espresso.matcher.RootMatchers.withDecorView;
+import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withTagValue;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
 import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.is;
 
-import android.support.test.espresso.NoMatchingRootException;
-import android.support.test.espresso.NoMatchingViewException;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.ViewInteraction;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.test.espresso.NoMatchingRootException;
+import androidx.test.espresso.NoMatchingViewException;
+import androidx.test.espresso.UiController;
+import androidx.test.espresso.ViewAction;
+import androidx.test.espresso.ViewInteraction;
+
 import com.android.internal.widget.FloatingToolbar;
 
 import org.hamcrest.Description;
diff --git a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
index b50d6f4..f56af5a 100644
--- a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
+++ b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
@@ -16,18 +16,19 @@
 
 package android.widget.espresso;
 
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.MotionEvents;
-import android.support.test.espresso.action.MotionEvents.DownResultHolder;
-import android.support.test.espresso.action.Press;
-import android.support.test.espresso.action.Tapper;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
 
+import androidx.test.espresso.UiController;
+import androidx.test.espresso.ViewAction;
+import androidx.test.espresso.action.CoordinatesProvider;
+import androidx.test.espresso.action.MotionEvents;
+import androidx.test.espresso.action.MotionEvents.DownResultHolder;
+import androidx.test.espresso.action.Press;
+import androidx.test.espresso.action.Tapper;
+
 import org.hamcrest.Matcher;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/espresso/MouseUiController.java b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java
index 022be76..abee736 100644
--- a/core/tests/coretests/src/android/widget/espresso/MouseUiController.java
+++ b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java
@@ -18,16 +18,19 @@
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
 import android.annotation.IntDef;
-import android.support.test.espresso.InjectEventSecurityException;
-import android.support.test.espresso.UiController;
+import android.os.SystemClock;
 import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 
+import androidx.test.espresso.InjectEventSecurityException;
+import androidx.test.espresso.UiController;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Iterator;
+
 /**
  * Class to wrap an UiController to overwrite source of motion events to SOURCE_MOUSE.
  * Note that this doesn't change the tool type.
@@ -71,6 +74,32 @@
         return mUiController.injectMotionEvent(event);
     }
 
+    /**
+     * Copied from latest {@link androidx.test.espresso.UiController}, since current
+     * {@link androidx.test.espresso.UiController#injectMotionEventSequence(Iterable)} seems not a
+     * default method.
+     */
+    @Override
+    public boolean injectMotionEventSequence(Iterable<MotionEvent> events)
+            throws InjectEventSecurityException {
+        android.util.Log.w(
+                "UIC",
+                "Using default injectMotionEventSeq() - this may not inject a sequence properly. "
+                + "If wrapping UIController please override this method and delegate.");
+        Iterator<MotionEvent> mei = events.iterator();
+        boolean success = true;
+        while (mei.hasNext()) {
+            MotionEvent me = mei.next();
+            if (me.getEventTime() - SystemClock.uptimeMillis() > 10) {
+                // Because the loopMainThreadForAtLeast is overkill for waiting, intentially only
+                // call it with a smaller amount of milliseconds as best effort
+                loopMainThreadForAtLeast(10);
+            }
+            success &= injectMotionEvent(me);
+        }
+        return success;
+    }
+
     @Override
     public boolean injectString(String str) throws InjectEventSecurityException {
         return mUiController.injectString(str);
diff --git a/core/tests/coretests/src/android/widget/espresso/SuggestionsPopupwindowUtils.java b/core/tests/coretests/src/android/widget/espresso/SuggestionsPopupwindowUtils.java
index b5a96ae..32c02403 100644
--- a/core/tests/coretests/src/android/widget/espresso/SuggestionsPopupwindowUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/SuggestionsPopupwindowUtils.java
@@ -16,36 +16,40 @@
 
 package android.widget.espresso;
 
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
-import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
-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 androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.RootMatchers.withDecorView;
+import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.view.View;
+
+import androidx.test.espresso.NoMatchingRootException;
+import androidx.test.espresso.NoMatchingViewException;
+import androidx.test.espresso.UiController;
+import androidx.test.espresso.ViewAction;
+import androidx.test.espresso.ViewInteraction;
+import androidx.test.espresso.action.GeneralLocation;
+import androidx.test.espresso.action.Press;
+import androidx.test.espresso.action.Tap;
 
 import org.hamcrest.Matcher;
 
-import android.support.test.espresso.NoMatchingRootException;
-import android.support.test.espresso.NoMatchingViewException;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.ViewInteraction;
-import android.support.test.espresso.action.GeneralLocation;
-import android.support.test.espresso.action.Press;
-import android.support.test.espresso.action.Tap;
-import android.view.View;
-
 public final class SuggestionsPopupwindowUtils {
     private static final int id = com.android.internal.R.id.suggestionWindowContainer;
 
     private SuggestionsPopupwindowUtils() {};
 
     public static ViewInteraction onSuggestionsPopup() {
+        getInstrumentation().waitForIdleSync();
         return onView(withId(id)).inRoot(withDecorView(hasDescendant(withId(id))));
     }
 
     private static ViewInteraction onSuggestionsPopupItem(Matcher<View> matcher) {
+        getInstrumentation().waitForIdleSync();
         return onView(matcher).inRoot(withDecorView(hasDescendant(withId(id))));
     }
 
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index b4c547e..83ce67b 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -16,16 +16,9 @@
 
 package android.widget.espresso;
 
-import static android.support.test.espresso.action.ViewActions.actionWithAssertions;
+import static androidx.test.espresso.action.ViewActions.actionWithAssertions;
 
 import android.graphics.Rect;
-import android.support.test.espresso.PerformException;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralLocation;
-import android.support.test.espresso.action.Press;
-import android.support.test.espresso.action.Tap;
-import android.support.test.espresso.util.HumanReadables;
 import android.text.Layout;
 import android.view.MotionEvent;
 import android.view.View;
@@ -33,6 +26,14 @@
 import android.widget.Editor.HandleView;
 import android.widget.TextView;
 
+import androidx.test.espresso.PerformException;
+import androidx.test.espresso.ViewAction;
+import androidx.test.espresso.action.CoordinatesProvider;
+import androidx.test.espresso.action.GeneralLocation;
+import androidx.test.espresso.action.Press;
+import androidx.test.espresso.action.Tap;
+import androidx.test.espresso.util.HumanReadables;
+
 /**
  * A collection of actions on a {@link android.widget.TextView}.
  */
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
index 5ed69e0..d638da5 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
@@ -16,7 +16,7 @@
 
 package android.widget.espresso;
 
-import static android.support.test.espresso.matcher.ViewMatchers.assertThat;
+import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
@@ -26,14 +26,15 @@
 import android.annotation.IntDef;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.support.test.espresso.NoMatchingViewException;
-import android.support.test.espresso.ViewAssertion;
 import android.text.Spanned;
 import android.text.TextUtils;
 import android.view.View;
 import android.widget.EditText;
 import android.widget.TextView;
 
+import androidx.test.espresso.NoMatchingViewException;
+import androidx.test.espresso.ViewAssertion;
+
 import junit.framework.AssertionFailedError;
 
 import org.hamcrest.Matcher;
diff --git a/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java b/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java
index 8bce1b0..1e6447d 100644
--- a/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java
+++ b/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java
@@ -16,17 +16,18 @@
 
 package android.widget.espresso;
 
-import org.hamcrest.Matcher;
-
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralClickAction;
-import android.support.test.espresso.action.PrecisionDescriber;
-import android.support.test.espresso.action.Tapper;
 import android.view.View;
 import android.view.ViewConfiguration;
 
+import androidx.test.espresso.UiController;
+import androidx.test.espresso.ViewAction;
+import androidx.test.espresso.action.CoordinatesProvider;
+import androidx.test.espresso.action.GeneralClickAction;
+import androidx.test.espresso.action.PrecisionDescriber;
+import androidx.test.espresso.action.Tapper;
+
+import org.hamcrest.Matcher;
+
 public final class ViewClickAction implements ViewAction {
     private final GeneralClickAction mGeneralClickAction;
 
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 fe2fb85..7430c7a 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -16,12 +16,12 @@
 
 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 androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isEnabled;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
 import static com.android.internal.app.ResolverWrapperActivity.sOverrides;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
index 3ddd8aa..64b7c2c 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
@@ -22,8 +22,9 @@
 
 import android.os.Process;
 import android.os.SystemClock;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
 
 import com.android.internal.os.KernelCpuThreadReader.ProcessCpuUsage;
 import com.android.internal.os.KernelCpuThreadReader.ThreadCpuUsage;
diff --git a/core/tests/coretests/src/com/android/internal/statusbar/NotificationVisibilityTest.java b/core/tests/coretests/src/com/android/internal/statusbar/NotificationVisibilityTest.java
index b740ecc..22432a8 100644
--- a/core/tests/coretests/src/com/android/internal/statusbar/NotificationVisibilityTest.java
+++ b/core/tests/coretests/src/com/android/internal/statusbar/NotificationVisibilityTest.java
@@ -19,8 +19,8 @@
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertThat;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 035ee10..bb47658 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -58,6 +58,14 @@
 }
 
 prebuilt_etc {
+    name: "privapp_whitelist_com.android.dialer",
+    product_specific: true,
+    sub_dir: "permissions",
+    src: "com.android.dialer.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
     name: "privapp_whitelist_com.android.launcher3",
     product_specific: true,
     sub_dir: "permissions",
diff --git a/data/etc/com.android.dialer.xml b/data/etc/com.android.dialer.xml
new file mode 100644
index 0000000..ccdb21f
--- /dev/null
+++ b/data/etc/com.android.dialer.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
+  -->
+<permissions>
+    <privapp-permissions package="com.android.dialer">
+        <permission name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"/>
+        <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+        <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
+        <permission name="android.permission.MODIFY_PHONE_STATE"/>
+        <permission name="android.permission.STATUS_BAR"/>
+        <permission name="android.permission.STOP_APP_SWITCHES"/>
+        <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
+        <permission name="com.android.voicemail.permission.WRITE_VOICEMAIL"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 2e7b998..0f35918 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -49,17 +49,6 @@
         <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.dialer">
-        <permission name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"/>
-        <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
-        <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
-        <permission name="android.permission.MODIFY_PHONE_STATE"/>
-        <permission name="android.permission.STATUS_BAR"/>
-        <permission name="android.permission.STOP_APP_SWITCHES"/>
-        <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
-        <permission name="com.android.voicemail.permission.WRITE_VOICEMAIL"/>
-    </privapp-permissions>
-
     <privapp-permissions package="com.android.emergency">
         <!-- Required to place emergency calls from emergency info screen. -->
         <permission name="android.permission.CALL_PRIVILEGED"/>
@@ -301,6 +290,7 @@
         <permission name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/>
         <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
         <permission name="android.permission.MOVE_PACKAGE"/>
+        <permission name="android.permission.OBSERVE_APP_USAGE"/>
         <permission name="android.permission.PACKAGE_USAGE_STATS" />
         <permission name="android.permission.POWER_SAVER" />
         <permission name="android.permission.READ_FRAME_BUFFER"/>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 080c5d5..18f0cae 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -25,6 +25,7 @@
 import android.annotation.WorkerThread;
 import android.content.res.ResourcesImpl;
 import android.hardware.HardwareBuffer;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.StrictMode;
@@ -77,7 +78,7 @@
      */
     private boolean mRequestPremultiplied;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769491)
     private byte[] mNinePatchChunk; // may be null
     @UnsupportedAppUsage
     private NinePatch.InsetStruct mNinePatchInsets; // may be null
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index 2f8d381..fe2d41e 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -43,7 +43,9 @@
         , mImageInfo(image_info) {}
 
 VkFunctorDrawHandler::~VkFunctorDrawHandler() {
-    mFunctorHandle->postDrawVk();
+    if (mDrawn) {
+        mFunctorHandle->postDrawVk();
+    }
 }
 
 void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) {
@@ -77,6 +79,7 @@
     params.format = vulkan_info.fFormat;
 
     mFunctorHandle->drawVk(params);
+    mDrawn = true;
 
     vulkan_info.fDrawBounds->offset.x = mClip.fLeft;
     vulkan_info.fDrawBounds->offset.y = mClip.fTop;
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
index 1a53c8f..d3f9777 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
@@ -44,6 +44,8 @@
     const SkMatrix mMatrix;
     const SkIRect mClip;
     const SkImageInfo mImageInfo;
+
+    bool mDrawn = false;
 };
 
 /**
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index e795b81..e91012f 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -85,12 +85,13 @@
     boolean stopGnssBatch();
     boolean injectLocation(in Location location);
 
-    // --- deprecated ---
     List<String> getAllProviders();
     List<String> getProviders(in Criteria criteria, boolean enabledOnly);
     String getBestProvider(in Criteria criteria, boolean enabledOnly);
     ProviderProperties getProviderProperties(String provider);
     String getNetworkProviderPackage();
+    boolean isProviderPackage(String packageName);
+
     void setLocationControllerExtraPackage(String packageName);
     String getLocationControllerExtraPackage();
     void setLocationControllerExtraPackageEnabled(boolean enabled);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 63b57d1..5aba22f 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2425,6 +2425,22 @@
     }
 
     /**
+     * Returns true if the given package name matches a location provider package, and false
+     * otherwise.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isProviderPackage(String packageName) {
+        try {
+            return mService.isProviderPackage(packageName);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+            return false;
+        }
+    }
+
+    /**
      * Set the extra location controller package for location services on the device.
      *
      * @hide
diff --git a/location/java/com/android/internal/location/ILocationProviderManager.aidl b/location/java/com/android/internal/location/ILocationProviderManager.aidl
index b1b8f0c..79166ae 100644
--- a/location/java/com/android/internal/location/ILocationProviderManager.aidl
+++ b/location/java/com/android/internal/location/ILocationProviderManager.aidl
@@ -26,6 +26,8 @@
  */
 interface ILocationProviderManager {
 
+    void onSetAdditionalProviderPackages(in List<String> packageNames);
+
     void onSetEnabled(boolean enabled);
 
     void onSetProperties(in ProviderProperties properties);
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index c721218..67d6496 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -19,6 +19,7 @@
     method protected boolean onSendExtraCommand(@Nullable String, @Nullable android.os.Bundle);
     method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
     method public void reportLocation(android.location.Location);
+    method public void setAdditionalProviderPackages(java.util.List<java.lang.String>);
     method public void setEnabled(boolean);
     method public void setProperties(com.android.location.provider.ProviderPropertiesUnbundled);
     field public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index 5bcec92..7cd7207 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -36,6 +36,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Base class for location providers implemented as unbundled services.
@@ -88,6 +90,7 @@
     @Nullable private volatile ILocationProviderManager mManager;
     private volatile ProviderProperties mProperties;
     private volatile boolean mEnabled;
+    private final ArrayList<String> mAdditionalProviderPackages;
 
     public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) {
         mTag = tag;
@@ -99,6 +102,7 @@
         mManager = null;
         mProperties = properties.getProviderProperties();
         mEnabled = true;
+        mAdditionalProviderPackages = new ArrayList<>(0);
     }
 
     public IBinder getBinder() {
@@ -160,6 +164,29 @@
     }
 
     /**
+     * Sets a list of additional packages that should be considered as part of this location
+     * provider for the purposes of generating locations. This should generally only be used when
+     * another package may issue location requests on behalf of this package in the course of
+     * providing location. This will inform location services to treat the other packages as
+     * location providers as well.
+     */
+    public void setAdditionalProviderPackages(List<String> packageNames) {
+        synchronized (mBinder) {
+            mAdditionalProviderPackages.clear();
+            mAdditionalProviderPackages.addAll(packageNames);
+        }
+
+        ILocationProviderManager manager = mManager;
+        if (manager != null) {
+            try {
+                manager.onSetAdditionalProviderPackages(mAdditionalProviderPackages);
+            } catch (RemoteException | RuntimeException e) {
+                Log.w(mTag, e);
+            }
+        }
+    }
+
+    /**
      * Returns true if this provider has been set as enabled. This will be true unless explicitly
      * set otherwise.
      */
@@ -275,6 +302,9 @@
         public void setLocationProviderManager(ILocationProviderManager manager) {
             synchronized (mBinder) {
                 try {
+                    if (!mAdditionalProviderPackages.isEmpty()) {
+                        manager.onSetAdditionalProviderPackages(mAdditionalProviderPackages);
+                    }
                     manager.onSetProperties(mProperties);
                     manager.onSetEnabled(mEnabled);
                 } catch (RemoteException e) {
diff --git a/media/Android.bp b/media/Android.bp
index 1aefebe..141d415c 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -102,7 +102,8 @@
     "--hide MissingPermission --hide BroadcastBehavior " +
     "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
     "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " +
-    "--hide HiddenTypedefConstant "
+    "--hide HiddenTypedefConstant --show-annotation android.annotation.SystemApi " +
+    " --show-annotation android.annotation.TestApi "
 
 droidstubs {
     name: "updatable-media-stubs",
@@ -110,8 +111,7 @@
         ":updatable-media-srcs-without-aidls",
         ":framework-media-annotation-srcs",
     ],
-    args: metalava_updatable_media_args + " --show-annotation android.annotation.SystemApi " +
-        " --show-annotation android.annotation.TestApi ",
+    args: metalava_updatable_media_args,
     // Ideally, sdk_version here should be "current_system", but "current - 1" is used
     // to avoid dependency cycle with framework.
     sdk_version: "28",
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index 925ca0d..f7afa31 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -86,6 +86,12 @@
 /**
  * MediaPlayer2 class can be used to control playback of audio/video files and streams.
  *
+ * <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.
+ *
  * <p>Topics covered here are:
  * <ol>
  * <li><a href="#PlayerStates">Player states</a>
diff --git a/media/java/android/media/AudioRecordingConfiguration.java b/media/java/android/media/AudioRecordingConfiguration.java
index 1d763ce..0af47e8 100644
--- a/media/java/android/media/AudioRecordingConfiguration.java
+++ b/media/java/android/media/AudioRecordingConfiguration.java
@@ -402,7 +402,7 @@
                 && (mClientPortId == that.mClientPortId)
                 && (mClientSilenced == that.mClientSilenced)
                 && (mDeviceSource == that.mDeviceSource)
-                && (mClientEffects.equals(that.mClientEffects))
-                && (mDeviceEffects.equals(that.mDeviceEffects)));
+                && (Arrays.equals(mClientEffects, that.mClientEffects))
+                && (Arrays.equals(mDeviceEffects, that.mDeviceEffects)));
     }
 }
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index 4f74ec9..963b1d1 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -97,9 +97,33 @@
      */
     public static final int QUALITY_2160P = 8;
 
+    /**
+     * Quality level corresponding to the VGA (640 x 480) resolution.
+     * @hide
+     */
+    public static final int QUALITY_VGA = 9;
+
+    /**
+     * Quality level corresponding to 4k-DCI (4096 x 2160) resolution.
+     * @hide
+     */
+    public static final int QUALITY_4KDCI = 10;
+
+    /**
+     * Quality level corresponding to QHD (2560 x 1440) resolution
+     * @hide
+     */
+    public static final int QUALITY_QHD = 11;
+
+    /**
+     * Quality level corresponding to 2K (2048 x 1080) resolution
+     * @hide
+     */
+    public static final int QUALITY_2K = 12;
+
     // Start and end of quality list
     private static final int QUALITY_LIST_START = QUALITY_LOW;
-    private static final int QUALITY_LIST_END = QUALITY_2160P;
+    private static final int QUALITY_LIST_END = QUALITY_2K;
 
     /**
      * Time lapse quality level corresponding to the lowest available resolution.
@@ -146,9 +170,34 @@
      */
     public static final int QUALITY_TIME_LAPSE_2160P = 1008;
 
+    /**
+     * Time lapse quality level corresponding to the VGA (640 x 480) resolution.
+     * @hide
+     */
+    public static final int QUALITY_TIME_LAPSE_VGA = 1009;
+
+    /**
+     * Time lapse quality level corresponding to the 4k-DCI (4096 x 2160) resolution.
+     * @hide
+     */
+    public static final int QUALITY_TIME_LAPSE_4KDCI = 1010;
+
+    /**
+     * Time lapse quality level corresponding to the QHD (2560 x 1440) resolution.
+     * @hide
+     */
+    public static final int QUALITY_TIME_LAPSE_QHD = 1011;
+
+    /**
+     * Time lapse quality level corresponding to the 2K (2048 x 1080) resolution.
+     * @hide
+     */
+    public static final int QUALITY_TIME_LAPSE_2K = 1012;
+
+
     // Start and end of timelapse quality list
     private static final int QUALITY_TIME_LAPSE_LIST_START = QUALITY_TIME_LAPSE_LOW;
-    private static final int QUALITY_TIME_LAPSE_LIST_END = QUALITY_TIME_LAPSE_2160P;
+    private static final int QUALITY_TIME_LAPSE_LIST_END = QUALITY_TIME_LAPSE_2K;
 
     /**
      * High speed ( >= 100fps) quality level corresponding to the lowest available resolution.
@@ -204,9 +253,27 @@
      */
     public static final int QUALITY_HIGH_SPEED_2160P = 2005;
 
+    /**
+     * High speed ( >= 100fps) quality level corresponding to the CIF (352 x 288)
+     * @hide
+     */
+    public static final int QUALITY_HIGH_SPEED_CIF = 2006;
+
+    /**
+     * High speed ( >= 100fps) quality level corresponding to the VGA (640 x 480)
+     * @hide
+     */
+    public static final int QUALITY_HIGH_SPEED_VGA = 2007;
+
+    /**
+     * High speed ( >= 100fps) quality level corresponding to the 4K-DCI (4096 x 2160)
+     * @hide
+     */
+    public static final int QUALITY_HIGH_SPEED_4KDCI = 2008;
+
     // Start and end of high speed quality list
     private static final int QUALITY_HIGH_SPEED_LIST_START = QUALITY_HIGH_SPEED_LOW;
-    private static final int QUALITY_HIGH_SPEED_LIST_END = QUALITY_HIGH_SPEED_2160P;
+    private static final int QUALITY_HIGH_SPEED_LIST_END = QUALITY_HIGH_SPEED_4KDCI;
 
     /**
      * Default recording duration in seconds before the session is terminated.
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 0c3d625..c6c2fdd 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -3373,6 +3373,8 @@
     /**
      * Change a video encoder's target bitrate on the fly. The value is an
      * Integer object containing the new bitrate in bps.
+     *
+     * @see #setParameters(Bundle)
      */
     public static final String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
 
@@ -3384,12 +3386,43 @@
      * input-side of the encoder in that case.
      * The value is an Integer object containing the value 1 to suspend
      * or the value 0 to resume.
+     *
+     * @see #setParameters(Bundle)
      */
     public static final String PARAMETER_KEY_SUSPEND = "drop-input-frames";
 
     /**
+     * When {@link #PARAMETER_KEY_SUSPEND} is present, the client can also
+     * optionally use this key to specify the timestamp (in micro-second)
+     * at which the suspend/resume operation takes effect.
+     *
+     * Note that the specified timestamp must be greater than or equal to the
+     * timestamp of any previously queued suspend/resume operations.
+     *
+     * The value is a long int, indicating the timestamp to suspend/resume.
+     *
+     * @see #setParameters(Bundle)
+     */
+    public static final String PARAMETER_KEY_SUSPEND_TIME = "drop-start-time-us";
+
+    /**
+     * Specify an offset (in micro-second) to be added on top of the timestamps
+     * onward. A typical use case is to apply an adjust to the timestamps after
+     * a period of pause by the user.
+     *
+     * This parameter can only be used on an encoder in "surface-input" mode.
+     *
+     * The value is a long int, indicating the timestamp offset to be applied.
+     *
+     * @see #setParameters(Bundle)
+     */
+    public static final String PARAMETER_KEY_OFFSET_TIME = "time-offset-us";
+
+    /**
      * Request that the encoder produce a sync frame "soon".
      * Provide an Integer with the value 0.
+     *
+     * @see #setParameters(Bundle)
      */
     public static final String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
 
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index c82b5f6..4ca0216 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -463,6 +463,63 @@
         = "repeat-previous-frame-after";
 
     /**
+     * Instruct the video encoder in "surface-input" mode to drop excessive
+     * frames from the source, so that the input frame rate to the encoder
+     * does not exceed the specified fps.
+     *
+     * The associated value is a float, representing the max frame rate to
+     * feed the encoder at.
+     *
+     * @hide
+     */
+    public static final String KEY_MAX_FPS_TO_ENCODER
+        = "max-fps-to-encoder";
+
+    /**
+     * Instruct the video encoder in "surface-input" mode to limit the gap of
+     * timestamp between any two adjacent frames fed to the encoder to the
+     * specified amount (in micro-second).
+     *
+     * The associated value is a long int. When positive, it represents the max
+     * timestamp gap between two adjacent frames fed to the encoder. When negative,
+     * the absolute value represents a fixed timestamp gap between any two adjacent
+     * frames fed to the encoder. Note that this will also apply even when the
+     * original timestamp goes backward in time. Under normal conditions, such frames
+     * would be dropped and not sent to the encoder.
+     *
+     * The output timestamp will be restored to the original timestamp and will
+     * not be affected.
+     *
+     * This is used in some special scenarios where input frames arrive sparingly
+     * but it's undesirable to allocate more bits to any single frame, or when it's
+     * important to ensure all frames are captured (rather than captured in the
+     * correct order).
+     *
+     * @hide
+     */
+    public static final String KEY_MAX_PTS_GAP_TO_ENCODER
+        = "max-pts-gap-to-encoder";
+
+    /**
+     * If specified when configuring a video encoder that's in "surface-input"
+     * mode, it will instruct the encoder to put the surface source in suspended
+     * state when it's connected. No video frames will be accepted until a resume
+     * operation (see {@link MediaCodec#PARAMETER_KEY_SUSPEND}), optionally with
+     * timestamp specified via {@link MediaCodec#PARAMETER_KEY_SUSPEND_TIME}, is
+     * received.
+     *
+     * The value is an integer, with 1 indicating to create with the surface
+     * source suspended, or 0 otherwise. The default value is 0.
+     *
+     * If this key is not set or set to 0, the surface source will accept buffers
+     * as soon as it's connected to the encoder (although they may not be encoded
+     * immediately). This key can be used when the client wants to prepare the
+     * encoder session in advance, but do not want to accept buffers immediately.
+     */
+    public static final String KEY_CREATE_INPUT_SURFACE_SUSPENDED
+        = "create-input-buffers-suspended";
+
+    /**
      * If specified when configuring a video decoder rendering to a surface,
      * causes the decoder to output "blank", i.e. black frames to the surface
      * when stopped to clear out any previously displayed contents.
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 5f51320..e08dab4 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -26,7 +26,6 @@
 #include <media/AudioTrack.h>
 #include "SoundPool.h"
 #include "SoundPoolThread.h"
-#include <media/AudioPolicyHelper.h>
 #include <media/NdkMediaCodec.h>
 #include <media/NdkMediaExtractor.h>
 #include <media/NdkMediaFormat.h>
@@ -746,7 +745,8 @@
         // initialize track
         size_t afFrameCount;
         uint32_t afSampleRate;
-        audio_stream_type_t streamType = audio_attributes_to_stream_type(mSoundPool->attributes());
+        audio_stream_type_t streamType =
+                AudioSystem::attributesToStreamType(*mSoundPool->attributes());
         if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
             afFrameCount = kDefaultFrameCount;
         }
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index b7d8492..b6b229c 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -105,6 +105,7 @@
     protected AssistantSettings.Factory mSettingsFactory = AssistantSettings.FACTORY;
     @VisibleForTesting
     protected AssistantSettings mSettings;
+    private SmsHelper mSmsHelper;
 
     public Assistant() {
     }
@@ -122,6 +123,18 @@
         mAgingHelper = new AgingHelper(getContext(),
                 mNotificationCategorizer,
                 new AgingCallback());
+        mSmsHelper = new SmsHelper(this);
+        mSmsHelper.initialize();
+    }
+
+    @Override
+    public void onDestroy() {
+        // This null check is only for the unit tests as ServiceTestCase.tearDown calls onDestroy
+        // without having first called onCreate.
+        if (mSmsHelper != null) {
+            mSmsHelper.destroy();
+        }
+        super.onDestroy();
     }
 
     private void loadFile() {
@@ -215,7 +228,7 @@
             return null;
         }
         NotificationEntry entry =
-                new NotificationEntry(mPackageManager, sbn, channel, SmsHelper.getInstance(this));
+                new NotificationEntry(mPackageManager, sbn, channel, mSmsHelper);
         SmartActionsHelper.SmartSuggestions suggestions = mSmartActionsHelper.suggest(entry);
         return createEnqueuedNotificationAdjustment(
                 entry, suggestions.actions, suggestions.replies);
@@ -262,7 +275,7 @@
             Ranking ranking = getRanking(sbn.getKey(), rankingMap);
             if (ranking != null && ranking.getChannel() != null) {
                 NotificationEntry entry = new NotificationEntry(mPackageManager,
-                        sbn, ranking.getChannel(), SmsHelper.getInstance(this));
+                        sbn, ranking.getChannel(), mSmsHelper);
                 String key = getKey(
                         sbn.getPackageName(), sbn.getUserId(), ranking.getChannel().getId());
                 ChannelImpressions ci = mkeyToImpressions.getOrDefault(key,
@@ -398,7 +411,6 @@
     @Override
     public void onListenerConnected() {
         if (DEBUG) Log.i(TAG, "CONNECTED");
-        SmsHelper.getInstance(this).initialize();
         try {
             mFile = new AtomicFile(new File(new File(
                     Environment.getDataUserCePackageDirectory(
@@ -415,7 +427,6 @@
 
     @Override
     public void onListenerDisconnected() {
-        SmsHelper.getInstance(this).destroy();
         if (mAgingHelper != null) {
             mAgingHelper.onDestroy();
         }
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmsHelper.java
index b077138..07be0b8 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmsHelper.java
@@ -33,23 +33,11 @@
 public class SmsHelper {
     private static final String TAG = "SmsHelper";
 
-    private static SmsHelper sSmsHelper;
-    private static final Object sLock = new Object();
-
     private final Context mContext;
     private ComponentName mDefaultSmsApplication;
     private BroadcastReceiver mBroadcastReceiver;
 
-    static SmsHelper getInstance(Context context) {
-        synchronized (sLock) {
-            if (sSmsHelper == null) {
-                sSmsHelper = new SmsHelper(context);
-            }
-            return sSmsHelper;
-        }
-    }
-
-    private SmsHelper(Context context) {
+    SmsHelper(Context context) {
         mContext = context.getApplicationContext();
     }
 
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index c032683..e8c728d 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -166,6 +166,7 @@
 
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
     <uses-permission android:name="android.permission.SUSPEND_APPS" />
+    <uses-permission android:name="android.permission.OBSERVE_APP_USAGE" />
     <uses-permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND" />
     <!-- Permission needed to wipe the device for Test Harness Mode -->
     <uses-permission android:name="android.permission.ENABLE_TEST_HARNESS_MODE" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 815ae9a..866b46f 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -631,6 +631,14 @@
                   android:exported="true">
         </provider>
 
+        <!-- Provides list and realistic previews of clock faces for the picker app. -->
+        <provider
+            android:name="com.android.keyguard.clock.ClockOptionsProvider"
+            android:authorities="com.android.keyguard.clock"
+            android:exported="true"
+            android:grantUriPermissions="true">
+        </provider>
+
         <receiver
             android:name=".statusbar.KeyboardShortcutsReceiver">
             <intent-filter>
diff --git a/packages/SystemUI/docs/physics-animation-layout.md b/packages/SystemUI/docs/physics-animation-layout.md
index a67b5e8..300f63a 100644
--- a/packages/SystemUI/docs/physics-animation-layout.md
+++ b/packages/SystemUI/docs/physics-animation-layout.md
@@ -26,7 +26,7 @@
 
 ### Animation Control Methods
 ![Diagram of how calls to animateValueForChildAtIndex dispatch to DynamicAnimations.](physics-animation-layout-control-methods.png)
-Once the layout has used the controller’s configuration properties to build the animations, the controller can use them to actually run animations. This is done for two reasons - reacting to a view being added or removed, or responding to another class (such as a touch handler or broadcast receiver) requesting an animation. ```onChildAdded``` and ```onChildRemoved``` are called automatically by the layout, giving the controller the opportunity to animate the child in/out. Custom methods are called by anyone with access to the controller instance to do things like expand, collapse, or move the child views.
+Once the layout has used the controller’s configuration properties to build the animations, the controller can use them to actually run animations. This is done for two reasons - reacting to a view being added or removed, or responding to another class (such as a touch handler or broadcast receiver) requesting an animation. ```onChildAdded```, ```onChildRemoved```, and ```setChildVisibility``` are called automatically by the layout, giving the controller the opportunity to animate the child in/out/visible/gone. Custom methods are called by anyone with access to the controller instance to do things like expand, collapse, or move the child views.
 
 In either case, the controller has access to the layout’s protected ```animateValueForChildAtIndex(ViewProperty property, int index, float value)``` method. This method is used to actually run an animation.
 
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/bubble_preview.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/bubble_preview.png
new file mode 100644
index 0000000..67f072f
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/bubble_preview.png
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/bubble_thumbnail.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/bubble_thumbnail.png
new file mode 100644
index 0000000..8d0e6ed
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/bubble_thumbnail.png
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_preview.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_preview.png
new file mode 100644
index 0000000..035a4df
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_preview.png
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_thumbnail.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_thumbnail.png
new file mode 100644
index 0000000..1ac0113
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_thumbnail.png
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/stretch_preview.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/stretch_preview.png
new file mode 100644
index 0000000..63927bc
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/stretch_preview.png
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/stretch_thumbnail.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/stretch_thumbnail.png
new file mode 100644
index 0000000..83d714b
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/stretch_thumbnail.png
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/type_preview.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/type_preview.png
new file mode 100644
index 0000000..a538149
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/type_preview.png
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/type_thumbnail.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/type_thumbnail.png
new file mode 100644
index 0000000..2bfd655
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/type_thumbnail.png
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 41acf82..1f33307 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -485,4 +485,17 @@
         <item>Fifty\nNine</item>
     </string-array>
 
+    <!-- Title for default clock face that will appear in the picker app next to a preview image of
+         the clock face. [CHAR LIMIT=8] -->
+    <string name="clock_title_default" translatable="false">Default</string>
+    <!-- Title for Bubble clock face that will appear in the picker app next to a preview image of
+         the clock face. [CHAR LIMIT=8] -->
+    <string name="clock_title_bubble" translatable="false">Bubble</string>
+    <!-- Title for Stretch clock face that will appear in the picker app next to a preview image of
+         the clock face. [CHAR LIMIT=8] -->
+    <string name="clock_title_stretch" translatable="false">Stretch</string>
+    <!-- Title for Typographic clock face that will appear in the picker app next to a preview image of
+         the clock face. [CHAR LIMIT=8] -->
+    <string name="clock_title_type" translatable="false">Type</string>
+
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1060211..a5c8eaf 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -23,8 +23,9 @@
     <dimen name="navigation_bar_size">@*android:dimen/navigation_bar_height</dimen>
     <!-- Minimum swipe distance to catch the swipe gestures to invoke assist or switch tasks. -->
     <dimen name="navigation_bar_min_swipe_distance">48dp</dimen>
-    <!-- The distance from a side of device of the navigation bar to start an edge swipe -->
-    <dimen name="navigation_bar_edge_swipe_threshold">48dp</dimen>
+    <!-- The default distance from a side of the device to start an edge swipe from -->
+    <dimen name="navigation_bar_default_edge_width">48dp</dimen>
+    <dimen name="navigation_bar_default_edge_height">500dp</dimen>
 
     <!-- thickness (height) of the dead zone at the top of the navigation bar,
          reducing false presses on navbar buttons; approx 2mm -->
@@ -83,6 +84,9 @@
     <!-- Increased height of a small notification in the status bar -->
     <dimen name="notification_min_height_increased">146dp</dimen>
 
+    <!-- Increased height of a collapsed media notification in the status bar -->
+    <dimen name="notification_min_height_media">160dp</dimen>
+
     <!-- Height of a small notification in the status bar which was used before android N -->
     <dimen name="notification_min_height_legacy">64dp</dimen>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 56d9bf4c..5365dcf 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1829,6 +1829,9 @@
     <!-- SysUI Tuner: Button that leads to the navigation bar customization screen [CHAR LIMIT=60] -->
     <string name="nav_bar">Navigation bar</string>
 
+    <!-- Label for navigation edge panel for gestures [CHAR LIMIT=60] -->
+    <string name="nav_bar_edge_panel" translatable="false">Navigation bar Edge Panel</string>
+
     <!-- SysUI Tuner: Button that controls layout of navigation bar [CHAR LIMIT=60] -->
     <string name="nav_bar_layout">Layout</string>
 
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 2ce6965..d5bd2b2 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -21,12 +21,15 @@
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
+import android.os.Handler;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.settingslib.WirelessUtils;
@@ -206,6 +209,7 @@
     protected void updateCarrierText() {
         boolean allSimsMissing = true;
         boolean anySimReadyAndInService = false;
+        boolean missingSimsWithSubs = false;
         CharSequence displayText = null;
 
         List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
@@ -252,6 +256,7 @@
                 // described above.
                 displayText = makeCarrierStringOnEmergencyCapable(
                         getMissingSimMessage(), subs.get(0).getCarrierName());
+                missingSimsWithSubs = true;
             } else {
                 // We don't have a SubscriptionInfo to get the emergency calls only from.
                 // Grab it from the old sticky broadcast if possible instead. We can use it
@@ -288,12 +293,14 @@
             displayText = getAirplaneModeMessage();
         }
 
+        Handler handler = Dependency.get(Dependency.MAIN_HANDLER);
+        final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo(
+                displayText,
+                displayText.toString().split(mSeparator.toString()),
+                anySimReadyAndInService && !missingSimsWithSubs,
+                subsIds);
         if (mCarrierTextCallback != null) {
-            mCarrierTextCallback.updateCarrierInfo(new CarrierTextCallbackInfo(
-                    displayText,
-                    displayText.toString().split(mSeparator.toString()),
-                    anySimReadyAndInService,
-                    subsIds));
+            handler.post(() -> mCarrierTextCallback.updateCarrierInfo(info));
         }
 
     }
@@ -487,7 +494,8 @@
         public final boolean anySimReady;
         public final int[] subscriptionIds;
 
-        CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers,
+        @VisibleForTesting
+        public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers,
                 boolean anySimReady, int[] subscriptionIds) {
             this.carrierText = carrierText;
             this.listOfCarriers = listOfCarriers;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 64c5b17..261f391 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -264,7 +264,8 @@
      */
     private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm,
             final boolean shouldIncludeAuxiliarySubtypes) {
-        final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList();
+        final List<InputMethodInfo> enabledImis =
+                imm.getEnabledInputMethodListAsUser(KeyguardUpdateMonitor.getCurrentUser());
 
         // Number of the filtered IMEs
         int filteredImisCount = 0;
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockInfo.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockInfo.java
new file mode 100644
index 0000000..812f215
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockInfo.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.keyguard.clock;
+
+import android.graphics.Bitmap;
+
+import java.util.function.Supplier;
+
+/**
+ * Metadata about an available clock face.
+ */
+final class ClockInfo {
+
+    private final String mName;
+    private final String mTitle;
+    private final String mId;
+    private final Supplier<Bitmap> mThumbnail;
+    private final Supplier<Bitmap> mPreview;
+
+    private ClockInfo(String name, String title, String id,
+            Supplier<Bitmap> thumbnail, Supplier<Bitmap> preview) {
+        mName = name;
+        mTitle = title;
+        mId = id;
+        mThumbnail = thumbnail;
+        mPreview = preview;
+    }
+
+    /**
+     * Gets the non-internationalized name for the clock face.
+     */
+    String getName() {
+        return mName;
+    }
+
+    /**
+     * Gets the name (title) of the clock face to be shown in the picker app.
+     */
+    String getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * Gets the ID of the clock face, used by the picker to set the current selection.
+     */
+    String getId() {
+        return mId;
+    }
+
+    /**
+     * Gets a thumbnail image of the clock.
+     */
+    Bitmap getThumbnail() {
+        return mThumbnail.get();
+    }
+
+    /**
+     * Gets a potentially realistic preview image of the clock face.
+     */
+    Bitmap getPreview() {
+        return mPreview.get();
+    }
+
+    static Builder builder() {
+        return new Builder();
+    }
+
+    static class Builder {
+        private String mName;
+        private String mTitle;
+        private String mId;
+        private Supplier<Bitmap> mThumbnail;
+        private Supplier<Bitmap> mPreview;
+
+        public ClockInfo build() {
+            return new ClockInfo(mName, mTitle, mId, mThumbnail, mPreview);
+        }
+
+        public Builder setName(String name) {
+            mName = name;
+            return this;
+        }
+
+        public Builder setTitle(String title) {
+            mTitle = title;
+            return this;
+        }
+
+        public Builder setId(String id) {
+            mId = id;
+            return this;
+        }
+
+        public Builder setThumbnail(Supplier<Bitmap> thumbnail) {
+            mThumbnail = thumbnail;
+            return this;
+        }
+
+        public Builder setPreview(Supplier<Bitmap> preview) {
+            mPreview = preview;
+            return this;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 3217ca6..9598142 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -17,12 +17,15 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.graphics.BitmapFactory;
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.Settings;
 import android.view.LayoutInflater;
 
+import com.android.keyguard.R;
 import com.android.systemui.plugins.ClockPlugin;
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.ExtensionController.Extension;
@@ -45,6 +48,7 @@
     private final LayoutInflater mLayoutInflater;
     private final ContentResolver mContentResolver;
 
+    private final List<ClockInfo> mClockInfos = new ArrayList<>();
     /**
      * Observe settings changes to know when to switch the clock face.
      */
@@ -76,6 +80,36 @@
         mExtensionController = extensionController;
         mLayoutInflater = LayoutInflater.from(context);
         mContentResolver = context.getContentResolver();
+
+        Resources res = context.getResources();
+        mClockInfos.add(ClockInfo.builder()
+                .setName("default")
+                .setTitle(res.getString(R.string.clock_title_default))
+                .setId("default")
+                .setThumbnail(() -> BitmapFactory.decodeResource(res, R.drawable.default_thumbnail))
+                .setPreview(() -> BitmapFactory.decodeResource(res, R.drawable.default_preview))
+                .build());
+        mClockInfos.add(ClockInfo.builder()
+                .setName("bubble")
+                .setTitle(res.getString(R.string.clock_title_bubble))
+                .setId(BubbleClockController.class.getName())
+                .setThumbnail(() -> BitmapFactory.decodeResource(res, R.drawable.bubble_thumbnail))
+                .setPreview(() -> BitmapFactory.decodeResource(res, R.drawable.bubble_preview))
+                .build());
+        mClockInfos.add(ClockInfo.builder()
+                .setName("stretch")
+                .setTitle(res.getString(R.string.clock_title_stretch))
+                .setId(StretchAnalogClockController.class.getName())
+                .setThumbnail(() -> BitmapFactory.decodeResource(res, R.drawable.stretch_thumbnail))
+                .setPreview(() -> BitmapFactory.decodeResource(res, R.drawable.stretch_preview))
+                .build());
+        mClockInfos.add(ClockInfo.builder()
+                .setName("type")
+                .setTitle(res.getString(R.string.clock_title_type))
+                .setId(TypeClockController.class.getName())
+                .setThumbnail(() -> BitmapFactory.decodeResource(res, R.drawable.type_thumbnail))
+                .setPreview(() -> BitmapFactory.decodeResource(res, R.drawable.type_preview))
+                .build());
     }
 
     /**
@@ -101,6 +135,13 @@
         }
     }
 
+    /**
+     * Get information about available clock faces.
+     */
+    List<ClockInfo> getClockInfos() {
+        return mClockInfos;
+    }
+
     private void setClockPlugin(ClockPlugin plugin) {
         for (int i = 0; i < mListeners.size(); i++) {
             // It probably doesn't make sense to supply the same plugin instances to multiple
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java
new file mode 100644
index 0000000..5ef35be
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java
@@ -0,0 +1,185 @@
+/*
+ * 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.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
+
+import java.io.FileNotFoundException;
+import java.util.List;
+import java.util.function.Supplier;
+
+/**
+ * Exposes custom clock face options and provides realistic preview images.
+ *
+ * APIs:
+ *
+ *   /list_options: List the available clock faces, which has the following columns
+ *     name: name of the clock face
+ *     title: title of the clock face
+ *     id: value used to set the clock face
+ *     thumbnail: uri of the thumbnail image, should be /thumbnail/{name}
+ *     preview: uri of the preview image, should be /preview/{name}
+ *
+ *   /thumbnail/{id}: Opens a file stream for the thumbnail image for clock face {id}.
+ *
+ *   /preview/{id}: Opens a file stream for the preview image for clock face {id}.
+ */
+public final class ClockOptionsProvider extends ContentProvider {
+
+    private static final String TAG = "ClockOptionsProvider";
+    private static final String KEY_LIST_OPTIONS = "/list_options";
+    private static final String KEY_PREVIEW = "preview";
+    private static final String KEY_THUMBNAIL = "thumbnail";
+    private static final String COLUMN_NAME = "name";
+    private static final String COLUMN_TITLE = "title";
+    private static final String COLUMN_ID = "id";
+    private static final String COLUMN_THUMBNAIL = "thumbnail";
+    private static final String COLUMN_PREVIEW = "preview";
+    private static final String MIME_TYPE_PNG = "image/png";
+    private static final String CONTENT_SCHEME = "content";
+    private static final String AUTHORITY = "com.android.keyguard.clock";
+
+    private final Supplier<List<ClockInfo>> mClocksSupplier;
+
+    public ClockOptionsProvider() {
+        this(() -> Dependency.get(ClockManager.class).getClockInfos());
+    }
+
+    @VisibleForTesting
+    ClockOptionsProvider(Supplier<List<ClockInfo>> clocksSupplier) {
+        mClocksSupplier = clocksSupplier;
+    }
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        List<String> segments = uri.getPathSegments();
+        if (segments.size() > 0 && (KEY_PREVIEW.equals(segments.get(0))
+                || KEY_THUMBNAIL.equals(segments.get(0)))) {
+            return MIME_TYPE_PNG;
+        }
+        return "vnd.android.cursor.dir/clock_faces";
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection,
+            String[] selectionArgs, String sortOrder) {
+        if (!KEY_LIST_OPTIONS.equals(uri.getPath())) {
+            return null;
+        }
+        MatrixCursor cursor = new MatrixCursor(new String[] {
+                COLUMN_NAME, COLUMN_TITLE, COLUMN_ID, COLUMN_THUMBNAIL, COLUMN_PREVIEW});
+        List<ClockInfo> clocks = mClocksSupplier.get();
+        for (int i = 0; i < clocks.size(); i++) {
+            ClockInfo clock = clocks.get(i);
+            cursor.newRow()
+                    .add(COLUMN_NAME, clock.getName())
+                    .add(COLUMN_TITLE, clock.getTitle())
+                    .add(COLUMN_ID, clock.getId())
+                    .add(COLUMN_THUMBNAIL, createThumbnailUri(clock))
+                    .add(COLUMN_PREVIEW, createPreviewUri(clock));
+        }
+        return cursor;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues initialValues) {
+        return null;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+        List<String> segments = uri.getPathSegments();
+        if (segments.size() != 2 || !(KEY_PREVIEW.equals(segments.get(0))
+                || KEY_THUMBNAIL.equals(segments.get(0)))) {
+            throw new FileNotFoundException("Invalid preview url");
+        }
+        String id = segments.get(1);
+        if (TextUtils.isEmpty(id)) {
+            throw new FileNotFoundException("Invalid preview url, missing id");
+        }
+        ClockInfo clock = null;
+        List<ClockInfo> clocks = mClocksSupplier.get();
+        for (int i = 0; i < clocks.size(); i++) {
+            if (id.equals(clocks.get(i).getId())) {
+                clock = clocks.get(i);
+                break;
+            }
+        }
+        if (clock == null) {
+            throw new FileNotFoundException("Invalid preview url, id not found");
+        }
+        return openPipeHelper(uri, MIME_TYPE_PNG, null, KEY_PREVIEW.equals(segments.get(0))
+                ? clock.getPreview() : clock.getThumbnail(), new MyWriter());
+    }
+
+    private Uri createThumbnailUri(ClockInfo clock) {
+        return new Uri.Builder()
+                .scheme(CONTENT_SCHEME)
+                .authority(AUTHORITY)
+                .appendPath(KEY_THUMBNAIL)
+                .appendPath(clock.getId())
+                .build();
+    }
+
+    private Uri createPreviewUri(ClockInfo clock) {
+        return new Uri.Builder()
+                .scheme(CONTENT_SCHEME)
+                .authority(AUTHORITY)
+                .appendPath(KEY_PREVIEW)
+                .appendPath(clock.getId())
+                .build();
+    }
+
+    private static class MyWriter implements ContentProvider.PipeDataWriter<Bitmap> {
+        @Override
+        public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType,
+                Bundle opts, Bitmap bitmap) {
+            try (AutoCloseOutputStream os = new AutoCloseOutputStream(output)) {
+                bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
+            } catch (Exception e) {
+                Log.w(TAG, "fail to write to pipe", e);
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 404f2e5..9a9a52f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -186,7 +186,12 @@
      * Set a listener to be notified of bubble expand events.
      */
     public void setExpandListener(BubbleExpandListener listener) {
-        mExpandListener = listener;
+        mExpandListener = ((isExpanding, key) -> {
+            if (listener != null) {
+                listener.onBubbleExpandChanged(isExpanding, key);
+            }
+            mStatusBarWindowController.setBubbleExpanded(isExpanding);
+        });
         if (mStackView != null) {
             mStackView.setExpandListener(mExpandListener);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 4f870f6..1644064 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -38,6 +38,12 @@
         extends PhysicsAnimationLayout.PhysicsAnimationController {
 
     /**
+     * How much to translate the bubbles when they're animating in/out. This value is multiplied by
+     * the bubble size.
+     */
+    private static final int ANIMATE_TRANSLATION_FACTOR = 4;
+
+    /**
      * The stack position from which the bubbles were expanded. Saved in {@link #expandFromStack}
      * and used to return to stack form in {@link #collapseBackToStack}.
      */
@@ -125,7 +131,10 @@
     Set<DynamicAnimation.ViewProperty> getAnimatedProperties() {
         return Sets.newHashSet(
                 DynamicAnimation.TRANSLATION_X,
-                DynamicAnimation.TRANSLATION_Y);
+                DynamicAnimation.TRANSLATION_Y,
+                DynamicAnimation.SCALE_X,
+                DynamicAnimation.SCALE_Y,
+                DynamicAnimation.ALPHA);
     }
 
     @Override
@@ -147,13 +156,55 @@
 
     @Override
     void onChildAdded(View child, int index) {
-        // TODO: Animate the new bubble into the row, and push the other bubbles out of the way.
-        child.setTranslationY(getExpandedY());
+        // Pop in from the top.
+        // TODO: Reverse this when bubbles are at the bottom.
+        child.setTranslationX(getXForChildAtIndex(index));
+        child.setTranslationY(getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR);
+        mLayout.animateValueForChild(DynamicAnimation.TRANSLATION_Y, child, getExpandedY());
+
+        // Animate the remaining bubbles to the correct X position.
+        for (int i = index + 1; i < mLayout.getChildCount(); i++) {
+            mLayout.animateValueForChildAtIndex(
+                    DynamicAnimation.TRANSLATION_X, i, getXForChildAtIndex(i));
+        }
     }
 
     @Override
-    void onChildToBeRemoved(View child, int index, Runnable actuallyRemove) {
-        // TODO: Animate the bubble out, and pull the other bubbles into its position.
-        actuallyRemove.run();
+    void onChildRemoved(View child, int index, Runnable finishRemoval) {
+        // Bubble pops out to the top.
+        // TODO: Reverse this when bubbles are at the bottom.
+        mLayout.animateValueForChild(
+                DynamicAnimation.ALPHA, child, 0f, finishRemoval);
+        mLayout.animateValueForChild(
+                DynamicAnimation.TRANSLATION_Y,
+                child,
+                getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR);
+
+        // Animate the remaining bubbles to the correct X position.
+        for (int i = index; i < mLayout.getChildCount(); i++) {
+            mLayout.animateValueForChildAtIndex(
+                    DynamicAnimation.TRANSLATION_X, i, getXForChildAtIndex(i));
+        }
+    }
+
+    @Override
+    protected void setChildVisibility(View child, int index, int visibility) {
+        if (visibility == View.VISIBLE) {
+            // Set alpha to 0 but then become visible immediately so the animation is visible.
+            child.setAlpha(0f);
+            child.setVisibility(View.VISIBLE);
+        }
+
+        // Fade in.
+        mLayout.animateValueForChild(
+                DynamicAnimation.ALPHA,
+                child,
+                /* value */ visibility == View.GONE ? 0f : 1f,
+                () -> super.setChildVisibility(child, index, visibility));
+    }
+
+    /** Returns the appropriate X translation value for a bubble at the given index. */
+    private float getXForChildAtIndex(int index) {
+        return mBubblePaddingPx + (mBubbleSizePx + mBubblePaddingPx) * index;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
index e4e6bc9..a4ddbf7 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
@@ -92,14 +92,18 @@
         abstract void onChildAdded(View child, int index);
 
         /**
-         * Called when a child is to be removed from the layout. Controllers can use this
-         * opportunity to animate out the new view before calling the provided callback to actually
-         * remove it.
+         * Called with a child view that has been removed from the layout, from the given index. The
+         * passed view has been removed from the layout and added back as a transient view, which
+         * renders normally, but is not part of the normal view hierarchy and will not be considered
+         * by getChildAt() and getChildCount().
          *
-         * Controllers should be careful to ensure that actuallyRemove is called on all code paths
-         * or child views will never be removed.
+         * The controller can perform animations on the child (either manually, or by using
+         * {@link #animateValueForChild}), and then call finishRemoval when complete.
+         *
+         * finishRemoval must be called by implementations of this method, or transient views will
+         * never be removed.
          */
-        abstract void onChildToBeRemoved(View child, int index, Runnable actuallyRemove);
+        abstract void onChildRemoved(View child, int index, Runnable finishRemoval);
 
         protected PhysicsAnimationLayout mLayout;
 
@@ -112,6 +116,15 @@
         protected PhysicsAnimationLayout getLayout() {
             return mLayout;
         }
+
+        /**
+         * Sets the child's visibility when it moves beyond or within the limits set by a call to
+         * {@link PhysicsAnimationLayout#setMaxRenderedChildren}. This can be overridden to animate
+         * this transition.
+         */
+        protected void setChildVisibility(View child, int index, int visibility) {
+            child.setVisibility(visibility);
+        }
     }
 
     /**
@@ -236,7 +249,7 @@
 
             // Tell the controller to animate this view out, and call the callback when it's
             // finished.
-            mController.onChildToBeRemoved(view, index, () -> {
+            mController.onChildRemoved(view, index, () -> {
                 // Done animating, remove the transient view.
                 removeTransientView(view);
 
@@ -457,11 +470,16 @@
     /** Hides children beyond the max rendering count. */
     private void setChildrenVisibility() {
         for (int i = 0; i < getChildCount(); i++) {
-            getChildAt(i).setVisibility(
-                    // Ignore views that are animating out when calculating whether to hide the
-                    // view. That is, if we're supposed to render 5 views, but 4 are animating out
-                    // and will soon be removed, render up to 9 views temporarily.
-                    i < mMaxRenderedChildren ? View.VISIBLE : View.GONE);
+            final int targetVisibility = i < mMaxRenderedChildren ? View.VISIBLE : View.GONE;
+            final View targetView = getChildAt(i);
+
+            if (targetView.getVisibility() != targetVisibility) {
+                if (mController != null) {
+                    mController.setChildVisibility(targetView, i, targetVisibility);
+                } else {
+                    targetView.setVisibility(targetVisibility);
+                }
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index 23c6fd3..0c089a75 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -316,10 +316,10 @@
     }
 
     @Override
-    void onChildToBeRemoved(View child, int index, Runnable actuallyRemove) {
+    void onChildRemoved(View child, int index, Runnable finishRemoval) {
         // Animate the child out, actually removing it once its alpha is zero.
         mLayout.animateValueForChild(
-                DynamicAnimation.ALPHA, child, 0f, actuallyRemove);
+                DynamicAnimation.ALPHA, child, 0f, finishRemoval);
         mLayout.animateValueForChild(DynamicAnimation.SCALE_X, child, ANIMATE_IN_STARTING_SCALE);
         mLayout.animateValueForChild(DynamicAnimation.SCALE_Y, child, ANIMATE_IN_STARTING_SCALE);
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index c0ed4b9..b865ce8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -54,6 +54,7 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.drawable.UserIconDrawable;
 import com.android.settingslib.graph.SignalDrawable;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.R.dimen;
 import com.android.systemui.plugins.ActivityStarter;
@@ -134,6 +135,15 @@
         mDeviceProvisionedController = deviceProvisionedController;
     }
 
+    @VisibleForTesting
+    public QSFooterImpl(Context context, AttributeSet attrs) {
+        this(context, attrs,
+                Dependency.get(ActivityStarter.class),
+                Dependency.get(UserInfoController.class),
+                Dependency.get(NetworkController.class),
+                Dependency.get(DeviceProvisionedController.class));
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -476,32 +486,62 @@
                 mInfos[0].visible && mInfos[1].visible ? View.VISIBLE : View.GONE);
     }
 
+    @VisibleForTesting
+    protected int getSlotIndex(int subscriptionId) {
+        return SubscriptionManager.getSlotIndex(subscriptionId);
+    }
+
     @Override
     public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
         if (info.anySimReady) {
             boolean[] slotSeen = new boolean[SIM_SLOTS];
-            for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) {
-                int slot = SubscriptionManager.getSlotIndex(info.subscriptionIds[i]);
-                mInfos[slot].visible = true;
-                slotSeen[slot] = true;
-                mCarrierTexts[slot].setText(info.listOfCarriers[i].toString().trim());
-                mCarrierGroups[slot].setVisibility(View.VISIBLE);
-            }
-            for (int i = 0; i < SIM_SLOTS; i++) {
-                if (!slotSeen[i]) {
+            if (info.listOfCarriers.length == info.subscriptionIds.length) {
+                for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) {
+                    int slot = getSlotIndex(info.subscriptionIds[i]);
+                    if (slot >= SIM_SLOTS) {
+                        Log.w(TAG, "updateInfoCarrier - slot: " + slot);
+                        continue;
+                    }
+                    if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+                        Log.e(TAG,
+                                "Invalid SIM slot index for subscription: "
+                                        + info.subscriptionIds[i]);
+                        continue;
+                    }
+                    mInfos[slot].visible = true;
+                    slotSeen[slot] = true;
+                    mCarrierTexts[slot].setText(info.listOfCarriers[i].toString().trim());
+                    mCarrierGroups[slot].setVisibility(View.VISIBLE);
+                }
+                for (int i = 0; i < SIM_SLOTS; i++) {
+                    if (!slotSeen[i]) {
+                        mInfos[i].visible = false;
+                        mCarrierGroups[i].setVisibility(View.GONE);
+                    }
+                }
+            } else {
+                // If there are sims ready but there are not the same number of carrier names as
+                // subscription ids, just show the full text in the first slot
+                mInfos[0].visible = true;
+                mCarrierTexts[0].setText(info.carrierText);
+                mCarrierGroups[0].setVisibility(View.VISIBLE);
+                for (int i = 1; i < SIM_SLOTS; i++) {
                     mInfos[i].visible = false;
+                    mCarrierTexts[i].setText("");
                     mCarrierGroups[i].setVisibility(View.GONE);
                 }
             }
-            handleUpdateState();
         } else {
             mInfos[0].visible = false;
-            mInfos[1].visible = false;
             mCarrierTexts[0].setText(info.carrierText);
             mCarrierGroups[0].setVisibility(View.VISIBLE);
-            mCarrierGroups[1].setVisibility(View.GONE);
-            handleUpdateState();
+            for (int i = 1; i < SIM_SLOTS; i++) {
+                mInfos[i].visible = false;
+                mCarrierTexts[i].setText("");
+                mCarrierGroups[i].setVisibility(View.GONE);
+            }
         }
+        handleUpdateState();
     }
 
     @Override
@@ -510,9 +550,14 @@
             int qsType, boolean activityIn, boolean activityOut,
             String typeContentDescription,
             String description, boolean isWide, int subId, boolean roaming) {
-        int slotIndex = SubscriptionManager.getSlotIndex(subId);
+        int slotIndex = getSlotIndex(subId);
         if (slotIndex >= SIM_SLOTS) {
-            Log.e(TAG, "setMobileDataIndicators - slot: " + slotIndex);
+            Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
+            return;
+        }
+        if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+            Log.e(TAG, "Invalid SIM slot index for subscription: " + subId);
+            return;
         }
         mInfos[slotIndex].visible = statusIcon.visible;
         mInfos[slotIndex].mobileSignalIconId = statusIcon.icon;
@@ -539,7 +584,6 @@
         boolean roaming;
     }
 
-
     /**
      * TextView that changes its ellipsize value with its visibility.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 31d1621..491f310 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -54,6 +54,7 @@
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.ShadeController;
@@ -231,7 +232,8 @@
                 return false;
             }
 
-            return activateRemoteInput(view, inputs, input, pendingIntent);
+            return activateRemoteInput(view, inputs, input, pendingIntent,
+                    null /* editedSuggestionInfo */);
         }
     };
 
@@ -291,6 +293,19 @@
                 }
                 try {
                     mBarService.onNotificationDirectReplied(entry.notification.getKey());
+                    if (entry.editedSuggestionInfo != null) {
+                        boolean modifiedBeforeSending =
+                                !TextUtils.equals(entry.remoteInputText,
+                                        entry.editedSuggestionInfo.originalText);
+                        mBarService.onNotificationSmartReplySent(
+                                entry.notification.getKey(),
+                                entry.editedSuggestionInfo.index,
+                                entry.editedSuggestionInfo.originalText,
+                                NotificationLogger
+                                        .getNotificationLocation(entry)
+                                        .toMetricsEventEnum(),
+                                modifiedBeforeSending);
+                    }
                 } catch (RemoteException e) {
                     // Nothing to do, system going down
                 }
@@ -310,10 +325,12 @@
      * @param inputs The remote inputs that need to be sent to the app.
      * @param input The remote input that needs to be activated.
      * @param pendingIntent The pending intent to be sent to the app.
+     * @param editedSuggestionInfo The smart reply that should be inserted in the remote input, or
+     *         {@code null} if the user is not editing a smart reply.
      * @return Whether the {@link RemoteInput} was activated.
      */
     public boolean activateRemoteInput(View view, RemoteInput[] inputs, RemoteInput input,
-            PendingIntent pendingIntent) {
+            PendingIntent pendingIntent, @Nullable EditedSuggestionInfo editedSuggestionInfo) {
 
         ViewParent p = view.getParent();
         RemoteInputView riv = null;
@@ -386,7 +403,7 @@
 
         riv.setRevealParameters(cx, cy, r);
         riv.setPendingIntent(pendingIntent);
-        riv.setRemoteInput(inputs, input);
+        riv.setRemoteInput(inputs, input, editedSuggestionInfo);
         riv.focusAnimated();
 
         return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
index 5a8f71d..736b9eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
@@ -56,13 +56,12 @@
      * Notifies StatusBarService a smart reply is sent.
      */
     public void smartReplySent(NotificationEntry entry, int replyIndex, CharSequence reply,
-            boolean generatedByAssistant, int notificationLocation) {
+            int notificationLocation, boolean modifiedBeforeSending) {
         mCallback.onSmartReplySent(entry, reply);
         mSendingKeys.add(entry.key);
         try {
-            mBarService.onNotificationSmartReplySent(
-                    entry.notification.getKey(), replyIndex, reply, generatedByAssistant,
-                    notificationLocation);
+            mBarService.onNotificationSmartReplySent(entry.notification.getKey(), replyIndex, reply,
+                    notificationLocation, modifiedBeforeSending);
         } catch (RemoteException e) {
             // Nothing to do, system going down
         }
@@ -100,10 +99,10 @@
      * Smart Replies and Actions have been added to the UI.
      */
     public void smartSuggestionsAdded(final NotificationEntry entry, int replyCount,
-            int actionCount, boolean generatedByAssistant) {
+            int actionCount, boolean generatedByAssistant, boolean editBeforeSending) {
         try {
-            mBarService.onNotificationSmartSuggestionsAdded(
-                    entry.notification.getKey(), replyCount, actionCount, generatedByAssistant);
+            mBarService.onNotificationSmartSuggestionsAdded(entry.notification.getKey(), replyCount,
+                    actionCount, generatedByAssistant, editBeforeSending);
         } catch (RemoteException e) {
             // Nothing to do, system going down
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index db9fcc8..9f1693c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -105,6 +105,14 @@
     /** Smart replies provided by the NotificationAssistantService. */
     @NonNull
     public CharSequence[] systemGeneratedSmartReplies = new CharSequence[0];
+
+    /**
+     * If {@link android.app.RemoteInput#getEditChoicesBeforeSending} is enabled, and the user is
+     * currently editing a choice (smart reply), then this field contains the information about the
+     * suggestion being edited. Otherwise <code>null</code>.
+     */
+    public EditedSuggestionInfo editedSuggestionInfo;
+
     @VisibleForTesting
     public int suppressedVisualEffects;
     public boolean suspended;
@@ -746,4 +754,23 @@
     private static boolean isCategory(String category, Notification n) {
         return Objects.equals(n.category, category);
     }
+
+    /** Information about a suggestion that is being edited. */
+    public static class EditedSuggestionInfo {
+
+        /**
+         * The value of the suggestion (before any user edits).
+         */
+        public final CharSequence originalText;
+
+        /**
+         * The index of the suggestion that is being edited.
+         */
+        public final int index;
+
+        public EditedSuggestionInfo(CharSequence originalText, int index) {
+            this.originalText = originalText;
+            this.index = index;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index bed2426..b8e33a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -90,6 +90,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.logging.NotificationCounters;
 import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
+import com.android.systemui.statusbar.notification.row.wrapper.NotificationMediaTemplateViewWrapper;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
@@ -144,6 +145,7 @@
     private int mNotificationMinHeightBeforeP;
     private int mNotificationMinHeight;
     private int mNotificationMinHeightLarge;
+    private int mNotificationMinHeightMedia;
     private int mNotificationMaxHeight;
     private int mIncreasedPaddingBetweenElements;
     private int mNotificationLaunchHeight;
@@ -652,8 +654,15 @@
         boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
         boolean beforeP = mEntry.targetSdk < Build.VERSION_CODES.P;
         int minHeight;
+
+        View expandedView = layout.getExpandedChild();
+        boolean isMediaLayout = expandedView != null
+                && expandedView.findViewById(com.android.internal.R.id.media_actions) != null;
+
         if (customView && beforeP && !mIsSummaryWithChildren) {
             minHeight = beforeN ? mNotificationMinHeightBeforeN : mNotificationMinHeightBeforeP;
+        } else if (isMediaLayout && !NotificationMediaTemplateViewWrapper.HIDE_COMPACT_SCRUBBER) {
+            minHeight = mNotificationMinHeightMedia;
         } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
             minHeight = mNotificationMinHeightLarge;
         } else {
@@ -1642,6 +1651,8 @@
                 R.dimen.notification_min_height);
         mNotificationMinHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
                 R.dimen.notification_min_height_increased);
+        mNotificationMinHeightMedia = NotificationUtils.getFontScaledHeight(mContext,
+                R.dimen.notification_min_height_media);
         mNotificationMaxHeight = NotificationUtils.getFontScaledHeight(mContext,
                 R.dimen.notification_max_height);
         mMaxHeadsUpHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 878d533..8095615 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1509,8 +1509,13 @@
                     boolean fromAssistant = smartRepliesAndActions.smartReplies == null
                             ? smartRepliesAndActions.smartActions.fromAssistant
                             : smartRepliesAndActions.smartReplies.fromAssistant;
+                    boolean editBeforeSending = smartRepliesAndActions.smartReplies != null
+                            && mSmartReplyConstants.getEffectiveEditChoicesBeforeSending(
+                                    smartRepliesAndActions.smartReplies.remoteInput
+                                            .getEditChoicesBeforeSending());
+
                     mSmartReplyController.smartSuggestionsAdded(entry, numSmartReplies,
-                            numSmartActions, fromAssistant);
+                            numSmartActions, fromAssistant, editBeforeSending);
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index 5a9a568..ddda3e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -16,26 +16,222 @@
 
 package com.android.systemui.statusbar.notification.row.wrapper;
 
-import android.content.Context;
-import android.view.View;
+import static com.android.systemui.Dependency.MAIN_HANDLER;
 
+import android.app.Notification;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
+import android.os.Handler;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewStub;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import com.android.internal.R;
+import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.TransformableView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
+import java.util.Timer;
+import java.util.TimerTask;
+
 /**
  * Wraps a notification containing a media template
  */
 public class NotificationMediaTemplateViewWrapper extends NotificationTemplateViewWrapper {
 
+    private static final String TAG = "NotificationMediaTVW";
+    private static final long PROGRESS_UPDATE_INTERVAL = 1000; // 1s
+    private static final String COMPACT_MEDIA_TAG = "media";
+    private final Handler mHandler = Dependency.get(MAIN_HANDLER);
+    private Timer mSeekBarTimer;
+    private View mActions;
+    private SeekBar mSeekBar;
+    private TextView mSeekBarElapsedTime;
+    private TextView mSeekBarTotalTime;
+    private long mDuration = 0;
+    private MediaController mMediaController;
+    private View mSeekBarView;
+    private Context mContext;
+
+    // TODO: implement as phenotype flag
+    public static final boolean HIDE_COMPACT_SCRUBBER = true;
+
+    private SeekBar.OnSeekBarChangeListener mSeekListener = new SeekBar.OnSeekBarChangeListener() {
+        @Override
+        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+        }
+
+        @Override
+        public void onStartTrackingTouch(SeekBar seekBar) {
+        }
+
+        @Override
+        public void onStopTrackingTouch(SeekBar seekBar) {
+            if (mMediaController != null && canSeekMedia()) {
+                mMediaController.getTransportControls().seekTo(mSeekBar.getProgress());
+            }
+        }
+    };
+
+    private MediaController.Callback mMediaCallback = new MediaController.Callback() {
+        @Override
+        public void onSessionDestroyed() {
+            clearTimer();
+            mMediaController.unregisterCallback(this);
+        }
+
+        @Override
+        public void onPlaybackStateChanged(PlaybackState state) {
+            if (state.getState() != PlaybackState.STATE_PLAYING) {
+                clearTimer();
+            } else if (mSeekBarTimer == null) {
+                startTimer();
+            }
+        }
+    };
+
     protected NotificationMediaTemplateViewWrapper(Context ctx, View view,
             ExpandableNotificationRow row) {
         super(ctx, view, row);
+        mContext = ctx;
     }
 
-    View mActions;
-
     private void resolveViews() {
         mActions = mView.findViewById(com.android.internal.R.id.media_actions);
+
+        final MediaSession.Token token = mRow.getEntry().notification.getNotification().extras
+                .getParcelable(Notification.EXTRA_MEDIA_SESSION);
+
+        if (token == null || (COMPACT_MEDIA_TAG.equals(mView.getTag()) && HIDE_COMPACT_SCRUBBER)) {
+            if (mSeekBarView != null) {
+                mSeekBarView.setVisibility(View.GONE);
+            }
+            return;
+        }
+
+        // Check for existing media controller and clean up / create as necessary
+        if (mMediaController == null || !mMediaController.getSessionToken().equals(token)) {
+            if (mMediaController != null) {
+                mMediaController.unregisterCallback(mMediaCallback);
+            }
+            mMediaController = new MediaController(mContext, token);
+        }
+
+        if (mMediaController.getMetadata() != null) {
+            long duration = mMediaController.getMetadata().getLong(
+                    MediaMetadata.METADATA_KEY_DURATION);
+            if (duration <= 0) {
+                // Don't include the seekbar if this is a livestream
+                Log.d(TAG, "removing seekbar");
+                if (mSeekBarView != null) {
+                    mSeekBarView.setVisibility(View.GONE);
+                }
+                return;
+            } else {
+                // Otherwise, make sure the seekbar is visible
+                if (mSeekBarView != null) {
+                    mSeekBarView.setVisibility(View.VISIBLE);
+                }
+            }
+        }
+
+        // Inflate the seekbar template
+        ViewStub stub = mView.findViewById(R.id.notification_media_seekbar_container);
+        if (stub instanceof ViewStub) {
+            LayoutInflater layoutInflater = LayoutInflater.from(stub.getContext());
+            stub.setLayoutInflater(layoutInflater);
+            stub.setLayoutResource(R.layout.notification_material_media_seekbar);
+            mSeekBarView = stub.inflate();
+
+            mSeekBar = mSeekBarView.findViewById(R.id.notification_media_progress_bar);
+            mSeekBar.setOnSeekBarChangeListener(mSeekListener);
+
+            mSeekBarElapsedTime = mSeekBarView.findViewById(R.id.notification_media_elapsed_time);
+            mSeekBarTotalTime = mSeekBarView.findViewById(R.id.notification_media_total_time);
+
+            if (mSeekBarTimer == null) {
+                // Disable seeking if it is not supported for this media session
+                if (!canSeekMedia()) {
+                    mSeekBar.getThumb().setAlpha(0);
+                    mSeekBar.setEnabled(false);
+                } else {
+                    mSeekBar.getThumb().setAlpha(255);
+                    mSeekBar.setEnabled(true);
+                }
+
+                startTimer();
+
+                mMediaController.registerCallback(mMediaCallback);
+            }
+        }
+        updateSeekBarTint(mSeekBarView);
+    }
+
+    private void startTimer() {
+        clearTimer();
+        mSeekBarTimer = new Timer(true /* isDaemon */);
+        mSeekBarTimer.schedule(new TimerTask() {
+            @Override
+            public void run() {
+                mHandler.post(mUpdatePlaybackUi);
+            }
+        }, 0, PROGRESS_UPDATE_INTERVAL);
+    }
+
+    private void clearTimer() {
+        if (mSeekBarTimer != null) {
+            // TODO: also trigger this when the notification panel is collapsed
+            mSeekBarTimer.cancel();
+            mSeekBarTimer.purge();
+            mSeekBarTimer = null;
+        }
+    }
+
+    private boolean canSeekMedia() {
+        if (mMediaController == null || mMediaController.getPlaybackState() == null) {
+            return false;
+        }
+
+        long actions = mMediaController.getPlaybackState().getActions();
+        return (actions == 0 || (actions & PlaybackState.ACTION_SEEK_TO) != 0);
+    }
+
+    protected final Runnable mUpdatePlaybackUi = new Runnable() {
+        @Override
+        public void run() {
+            if (mMediaController != null && mMediaController.getMetadata() != null
+                    && mSeekBar != null) {
+                long position = mMediaController.getPlaybackState().getPosition();
+                long duration = mMediaController.getMetadata().getLong(
+                        MediaMetadata.METADATA_KEY_DURATION);
+
+                if (mDuration != duration) {
+                    mDuration = duration;
+                    mSeekBar.setMax((int) mDuration);
+                    mSeekBarTotalTime.setText(millisecondsToTimeString(duration));
+                }
+                mSeekBar.setProgress((int) position);
+
+                mSeekBarElapsedTime.setText(millisecondsToTimeString(position));
+            } else {
+                // We no longer have a media session / notification
+                clearTimer();
+            }
+        }
+    };
+
+    private String millisecondsToTimeString(long milliseconds) {
+        long seconds = milliseconds / 1000;
+        String text = DateUtils.formatElapsedTime(seconds);
+        return text;
     }
 
     @Override
@@ -46,6 +242,27 @@
         super.onContentUpdated(row);
     }
 
+    private void updateSeekBarTint(View seekBarContainer) {
+        if (seekBarContainer == null) {
+            return;
+        }
+
+        if (this.getNotificationHeader() == null) {
+            return;
+        }
+
+        int tintColor = getNotificationHeader().getOriginalIconColor();
+        mSeekBarElapsedTime.setTextColor(tintColor);
+        mSeekBarTotalTime.setTextColor(tintColor);
+
+        ColorStateList tintList = ColorStateList.valueOf(tintColor);
+        mSeekBar.setThumbTintList(tintList);
+        tintList = tintList.withAlpha(192); // 75%
+        mSeekBar.setProgressTintList(tintList);
+        tintList = tintList.withAlpha(128); // 50%
+        mSeekBar.setProgressBackgroundTintList(tintList);
+    }
+
     @Override
     protected void updateTransformedTypes() {
         // This also clears the existing types
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
new file mode 100644
index 0000000..dae4da7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+public class NavigationBarEdgePanel extends View {
+    private static final String TAG = "NavigationBarEdgePanel";
+
+    public static NavigationBarEdgePanel create(@NonNull Context context, int width, int height,
+            int gravity) {
+        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
+                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+                PixelFormat.TRANSLUCENT);
+        lp.gravity = gravity;
+        lp.setTitle(TAG + context.getDisplayId());
+        lp.accessibilityTitle = context.getString(R.string.nav_bar_edge_panel);
+        lp.windowAnimations = 0;
+        NavigationBarEdgePanel panel = new NavigationBarEdgePanel(context);
+        panel.setLayoutParams(lp);
+        return panel;
+    }
+
+    private NavigationBarEdgePanel(Context context) {
+        super(context);
+    }
+
+    public void setWindowFlag(int flags, boolean enable) {
+        WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
+        if (lp == null || enable == ((lp.flags & flags) != 0)) {
+            return;
+        }
+        if (enable) {
+            lp.flags |= flags;
+        } else {
+            lp.flags &= ~flags;
+        }
+        updateLayout(lp);
+    }
+
+    public void setDimensions(int width, int height) {
+        final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
+        if (lp.width != width || lp.height != height) {
+            lp.width = width;
+            lp.height = height;
+            updateLayout(lp);
+        }
+    }
+
+    private void updateLayout(WindowManager.LayoutParams lp) {
+        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
+        wm.updateViewLayout(this, lp);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 02683c1..651670c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -18,6 +18,8 @@
 
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
 
 import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_QUICK_SCRUB;
 import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
@@ -35,6 +37,8 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.annotation.DrawableRes;
+import android.annotation.IntDef;
+import android.annotation.SuppressLint;
 import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -51,6 +55,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
+import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
@@ -87,12 +92,21 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.function.Consumer;
 
 public class NavigationBarView extends FrameLayout implements PluginListener<NavGesture> {
     final static boolean DEBUG = false;
     final static String TAG = "StatusBar/NavBarView";
 
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({WINDOW_TARGET_BOTTOM, WINDOW_TARGET_LEFT, WINDOW_TARGET_RIGHT})
+    public @interface WindowTarget{}
+    public static final int WINDOW_TARGET_BOTTOM = 0;
+    public static final int WINDOW_TARGET_LEFT = 1;
+    public static final int WINDOW_TARGET_RIGHT = 2;
+
     // slippery nav bar when everything is disabled, e.g. during setup
     final static boolean SLIPPERY_WHEN_DISABLED = true;
 
@@ -109,6 +123,7 @@
     int mNavigationIconHints = 0;
 
     private @NavigationBarCompat.HitTarget int mDownHitTarget = HIT_TARGET_NONE;
+    private @WindowTarget int mWindowHitTarget = WINDOW_TARGET_BOTTOM;
     private Rect mHomeButtonBounds = new Rect();
     private Rect mBackButtonBounds = new Rect();
     private Rect mRecentsButtonBounds = new Rect();
@@ -160,6 +175,9 @@
     private NavigationAssistantAction mAssistantAction;
     private NavigationNotificationPanelAction mNotificationPanelAction;
 
+    private NavigationBarEdgePanel mLeftEdgePanel;
+    private NavigationBarEdgePanel mRightEdgePanel;
+
     /**
      * Helper that is responsible for showing the right toast when a disallowed activity operation
      * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
@@ -222,6 +240,18 @@
         }
     };
 
+    private final OnTouchListener mEdgePanelTouchListener = new OnTouchListener() {
+        @SuppressLint("ClickableViewAccessibility")
+        @Override
+        public boolean onTouch(View v, MotionEvent event) {
+            if (event.getActionMasked() == ACTION_DOWN) {
+                mWindowHitTarget = v == mLeftEdgePanel ? WINDOW_TARGET_LEFT : WINDOW_TARGET_RIGHT;
+                mDownHitTarget = HIT_TARGET_NONE;
+            }
+            return mGestureHelper.onTouchEvent(event);
+        }
+    };
+
     private class H extends Handler {
         public void handleMessage(Message m) {
             switch (m.what) {
@@ -297,6 +327,16 @@
                 mColorAdaptionController.end();
             }
         }
+
+        @Override
+        public void onEdgeSensitivityChanged(int width, int height) {
+            if (mLeftEdgePanel != null) {
+                mLeftEdgePanel.setDimensions(width, height);
+            }
+            if (mRightEdgePanel != null) {
+                mRightEdgePanel.setDimensions(width, height);
+            }
+        }
     };
 
     public NavigationBarView(Context context, AttributeSet attrs) {
@@ -433,6 +473,7 @@
                 int x = (int) event.getX();
                 int y = (int) event.getY();
                 mDownHitTarget = HIT_TARGET_NONE;
+                mWindowHitTarget = WINDOW_TARGET_BOTTOM;
                 if (deadZoneConsumed) {
                     mDownHitTarget = HIT_TARGET_DEAD_ZONE;
                 } else if (getBackButton().isVisible() && mBackButtonBounds.contains(x, y)) {
@@ -483,6 +524,10 @@
         return mDownHitTarget;
     }
 
+    public @WindowTarget int getWindowTarget() {
+        return mWindowHitTarget;
+    }
+
     public void abortCurrentGesture() {
         getHomeButton().abortCurrentGesture();
     }
@@ -837,24 +882,32 @@
     }
 
     private void setSlippery(boolean slippery) {
-        boolean changed = false;
+        setWindowFlag(WindowManager.LayoutParams.FLAG_SLIPPERY, slippery);
+    }
+
+    public void setWindowTouchable(boolean flag) {
+        setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
+        if (mLeftEdgePanel != null) {
+            mLeftEdgePanel.setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
+        }
+        if (mRightEdgePanel != null) {
+            mRightEdgePanel.setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !flag);
+        }
+    }
+
+    private void setWindowFlag(int flags, boolean enable) {
         final ViewGroup navbarView = ((ViewGroup) getParent());
-        final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) navbarView
-                .getLayoutParams();
-        if (lp == null) {
+        WindowManager.LayoutParams lp = (WindowManager.LayoutParams) navbarView.getLayoutParams();
+        if (lp == null || enable == ((lp.flags & flags) != 0)) {
             return;
         }
-        if (slippery && (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) == 0) {
-            lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
-            changed = true;
-        } else if (!slippery && (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) != 0) {
-            lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY;
-            changed = true;
+        if (enable) {
+            lp.flags |= flags;
+        } else {
+            lp.flags &= ~flags;
         }
-        if (changed) {
-            WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
-            wm.updateViewLayout(navbarView, lp);
-        }
+        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
+        wm.updateViewLayout(navbarView, lp);
     }
 
     public void setMenuVisibility(final boolean show) {
@@ -1016,6 +1069,17 @@
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to get nav bar position.", e);
         }
+
+        // For landscape, hide the panel that would interfere with navigation bar layout
+        if (mLeftEdgePanel != null && mRightEdgePanel != null) {
+            mLeftEdgePanel.setVisibility(VISIBLE);
+            mRightEdgePanel.setVisibility(VISIBLE);
+            if (navBarPos == NAV_BAR_LEFT) {
+                mLeftEdgePanel.setVisibility(GONE);
+            } else if (navBarPos == NAV_BAR_RIGHT) {
+                mRightEdgePanel.setVisibility(GONE);
+            }
+        }
         mGestureHelper.setBarState(isRtl, navBarPos);
     }
 
@@ -1142,6 +1206,21 @@
                 NavGesture.class, false /* Only one */);
         setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
         mColorAdaptionController.start();
+
+        if (mPrototypeController.isEnabled()) {
+            WindowManager wm = (WindowManager) getContext()
+                    .getSystemService(Context.WINDOW_SERVICE);
+            int width = mPrototypeController.getEdgeSensitivityWidth();
+            int height = mPrototypeController.getEdgeSensitivityHeight();
+            mLeftEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height,
+                    Gravity.START | Gravity.BOTTOM);
+            mRightEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height,
+                    Gravity.END | Gravity.BOTTOM);
+            mLeftEdgePanel.setOnTouchListener(mEdgePanelTouchListener);
+            mRightEdgePanel.setOnTouchListener(mEdgePanelTouchListener);
+            wm.addView(mLeftEdgePanel, mLeftEdgePanel.getLayoutParams());
+            wm.addView(mRightEdgePanel, mRightEdgePanel.getLayoutParams());
+        }
     }
 
     @Override
@@ -1157,6 +1236,17 @@
         for (int i = 0; i < mButtonDispatchers.size(); ++i) {
             mButtonDispatchers.valueAt(i).onDestroy();
         }
+
+        if (mPrototypeController.isEnabled()) {
+            WindowManager wm = (WindowManager) getContext()
+                    .getSystemService(Context.WINDOW_SERVICE);
+            if (mLeftEdgePanel != null) {
+                wm.removeView(mLeftEdgePanel);
+            }
+            if (mRightEdgePanel != null) {
+                wm.removeView(mRightEdgePanel);
+            }
+        }
     }
 
     private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index b4feb25..8421e23 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.content.Context;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
@@ -34,7 +35,12 @@
 public class NavigationPrototypeController extends ContentObserver {
     private static final String HIDE_BACK_BUTTON_SETTING = "quickstepcontroller_hideback";
     private static final String HIDE_HOME_BUTTON_SETTING = "quickstepcontroller_hidehome";
+    private static final String PROTOTYPE_ENABLED = "prototype_enabled";
 
+    private static final String EDGE_SENSITIVITY_HEIGHT_SETTING =
+            "quickstepcontroller_edge_height_sensitivity";
+    public static final String EDGE_SENSITIVITY_WIDTH_SETTING =
+            "quickstepcontroller_edge_width_sensitivity";
     private final String GESTURE_MATCH_SETTING = "quickstepcontroller_gesture_match_map";
     public static final String NAV_COLOR_ADAPT_ENABLE_SETTING = "navbar_color_adapt_enable";
 
@@ -79,6 +85,8 @@
         registerObserver(HIDE_HOME_BUTTON_SETTING);
         registerObserver(GESTURE_MATCH_SETTING);
         registerObserver(NAV_COLOR_ADAPT_ENABLE_SETTING);
+        registerObserver(EDGE_SENSITIVITY_WIDTH_SETTING);
+        registerObserver(EDGE_SENSITIVITY_HEIGHT_SETTING);
     }
 
     /**
@@ -106,10 +114,26 @@
             } else if (path.endsWith(NAV_COLOR_ADAPT_ENABLE_SETTING)) {
                 mListener.onColorAdaptChanged(
                         NavBarTintController.isEnabled(mContext));
+            } else if (path.endsWith(EDGE_SENSITIVITY_WIDTH_SETTING)
+                    || path.endsWith(EDGE_SENSITIVITY_HEIGHT_SETTING)) {
+                mListener.onEdgeSensitivityChanged(getEdgeSensitivityWidth(),
+                        getEdgeSensitivityHeight());
             }
         }
     }
 
+    public int getEdgeSensitivityWidth() {
+        return convertDpToPixel(getGlobalInt(EDGE_SENSITIVITY_WIDTH_SETTING, 0));
+    }
+
+    public int getEdgeSensitivityHeight() {
+        return convertDpToPixel(getGlobalInt(EDGE_SENSITIVITY_HEIGHT_SETTING, 0));
+    }
+
+    public boolean isEnabled() {
+        return getGlobalBool(PROTOTYPE_ENABLED, false);
+    }
+
     /**
      * Retrieve the action map to apply to the quick step controller
      * @return an action map
@@ -144,15 +168,24 @@
         return Settings.Global.getInt(mContext.getContentResolver(), name, defaultVal ? 1 : 0) == 1;
     }
 
+    private int getGlobalInt(String name, int defaultVal) {
+        return Settings.Global.getInt(mContext.getContentResolver(), name, defaultVal);
+    }
+
     private void registerObserver(String name) {
         mContext.getContentResolver()
                 .registerContentObserver(Settings.Global.getUriFor(name), false, this);
     }
 
+    private static int convertDpToPixel(float dp) {
+        return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
+    }
+
     public interface OnPrototypeChangedListener {
         void onGestureRemap(@GestureAction int[] actions);
         void onBackButtonVisibilityChanged(boolean visible);
         void onHomeButtonVisibilityChanged(boolean visible);
         void onColorAdaptChanged(boolean enabled);
+        void onEdgeSensitivityChanged(int width, int height);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index d5d283c..84f1cef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -28,9 +28,12 @@
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
+import static com.android.systemui.statusbar.phone.NavigationBarView.WINDOW_TARGET_BOTTOM;
+import static com.android.systemui.statusbar.phone.NavigationPrototypeController.EDGE_SENSITIVITY_WIDTH_SETTING;
 
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Rect;
@@ -42,12 +45,9 @@
 import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
+import android.view.ViewConfiguration;
 import android.view.ViewPropertyAnimator;
 
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -72,6 +72,7 @@
     /** Experiment to swipe home button left to execute a back key press */
     private static final String HIDE_BACK_BUTTON_PROP = "quickstepcontroller_hideback";
     private static final String ENABLE_CLICK_THROUGH_NAV_PROP = "quickstepcontroller_clickthrough";
+    private static final String GESTURE_REGION_THRESHOLD_SETTING = "gesture_region_threshold";
     private static final long BACK_BUTTON_FADE_IN_ALPHA = 150;
     private static final long CLICK_THROUGH_TAP_DELAY = 70;
     private static final long CLICK_THROUGH_TAP_RESET_DELAY = 100;
@@ -109,10 +110,10 @@
     private float mMaxDragLimit;
     private float mMinDragLimit;
     private float mDragDampeningFactor;
-    private float mEdgeSwipeThreshold;
     private boolean mClickThroughPressed;
     private float mClickThroughPressX;
     private float mClickThroughPressY;
+    private int mGestureRegionThreshold;
 
     private NavigationGestureAction mCurrentAction;
     private NavigationGestureAction[] mGestureActions = new NavigationGestureAction[MAX_GESTURES];
@@ -139,7 +140,7 @@
     };
 
     private final Runnable mClickThroughResetTap = () -> {
-        setWindowTouchable(true);
+        mNavigationBarView.setWindowTouchable(true);
         mClickThroughPressed = false;
     };
 
@@ -210,7 +211,8 @@
 
         // The same down event was just sent on intercept and therefore can be ignored here
         final boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
-                && mOverviewEventSender.getProxy() != null;
+                && mOverviewEventSender.getProxy() != null
+                && mNavigationBarView.getWindowTarget() == WINDOW_TARGET_BOTTOM;
         return ignoreProxyDownEvent || handleTouchEvent(event);
     }
 
@@ -268,12 +270,15 @@
                 mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
                 mAllowGestureDetection = true;
                 mNotificationsVisibleOnDown = !mNavigationBarView.isNotificationsFullyCollapsed();
-                mEdgeSwipeThreshold = mContext.getResources()
-                        .getDimensionPixelSize(R.dimen.navigation_bar_edge_swipe_threshold);
+                final int defaultRegionThreshold = mContext.getResources()
+                        .getDimensionPixelOffset(R.dimen.navigation_bar_default_edge_width);
+                mGestureRegionThreshold = convertDpToPixel(getIntGlobalSetting(mContext,
+                        EDGE_SENSITIVITY_WIDTH_SETTING, defaultRegionThreshold));
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
-                if (!mAllowGestureDetection) {
+                if (!mAllowGestureDetection
+                        || mNavigationBarView.getWindowTarget() != WINDOW_TARGET_BOTTOM) {
                     break;
                 }
                 int x = (int) event.getX();
@@ -330,18 +335,12 @@
                     } else if (exceededSwipeHorizontalTouchSlop) {
                         if (mDragHPositive ? (posH < touchDownH) : (posH > touchDownH)) {
                             // Swiping left (rtl) gesture
-                            int index = mGestureActions[ACTION_SWIPE_LEFT_FROM_EDGE_INDEX] != null
-                                        && isEdgeSwipeAlongNavBar(touchDownH, !mDragHPositive)
-                                    ? ACTION_SWIPE_LEFT_FROM_EDGE_INDEX : ACTION_SWIPE_LEFT_INDEX;
-                            tryToStartGesture(mGestureActions[index], true /* alignedWithNavBar */,
-                                    event);
+                            tryToStartGesture(mGestureActions[ACTION_SWIPE_LEFT_INDEX],
+                                    true /* alignedWithNavBar */, event);
                         } else {
                             // Swiping right (ltr) gesture
-                            int index = mGestureActions[ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX] != null
-                                        && isEdgeSwipeAlongNavBar(touchDownH, mDragHPositive)
-                                    ? ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX : ACTION_SWIPE_RIGHT_INDEX;
-                            tryToStartGesture(mGestureActions[index], true /* alignedWithNavBar */,
-                                    event);
+                            tryToStartGesture(mGestureActions[ACTION_SWIPE_RIGHT_INDEX],
+                                    true /* alignedWithNavBar */, event);
                         }
                     }
                 }
@@ -354,24 +353,34 @@
             case MotionEvent.ACTION_UP:
                 if (mCurrentAction != null) {
                     mCurrentAction.endGesture();
-                } else if (action == MotionEvent.ACTION_UP
-                        && getBoolGlobalSetting(mContext, ENABLE_CLICK_THROUGH_NAV_PROP)
-                        && !mClickThroughPressed) {
-                    // Enable click through functionality where no gesture has been detected and not
-                    // passed the drag slop so inject a touch event at the same location
-                    // after making the navigation bar window untouchable. After a some time, the
-                    // navigation bar will be able to take input events again
-                    float diffX = Math.abs(event.getX() - mTouchDownX);
-                    float diffY = Math.abs(event.getY() - mTouchDownY);
+                } else if (action == MotionEvent.ACTION_UP) {
+                    if (canTriggerEdgeSwipe(event)) {
+                        int index = mNavigationBarView.getWindowTarget() == NAV_BAR_LEFT
+                                ? ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX
+                                : ACTION_SWIPE_LEFT_FROM_EDGE_INDEX;
+                        tryToStartGesture(mGestureActions[index], false /* alignedWithNavBar */,
+                                event);
+                        if (mCurrentAction != null) {
+                            mCurrentAction.endGesture();
+                        }
+                    } else if (getBoolGlobalSetting(mContext, ENABLE_CLICK_THROUGH_NAV_PROP)
+                            && !mClickThroughPressed) {
+                        // Enable click through functionality where no gesture has been detected and
+                        // not passed the drag slop so inject a touch event at the same location
+                        // after making the navigation bar window untouchable. After a some time,
+                        // the navigation bar will be able to take input events again
+                        float diffX = Math.abs(event.getX() - mTouchDownX);
+                        float diffY = Math.abs(event.getY() - mTouchDownY);
 
-                    if ((diffX <= NavigationBarCompat.getQuickStepDragSlopPx()
-                            && diffY <= NavigationBarCompat.getQuickStepDragSlopPx())) {
-                        setWindowTouchable(false);
-                        mClickThroughPressX = event.getRawX();
-                        mClickThroughPressY = event.getRawY();
-                        mClickThroughPressed = true;
-                        mNavigationBarView.postDelayed(mClickThroughSendTap,
-                                CLICK_THROUGH_TAP_DELAY);
+                        if ((diffX <= NavigationBarCompat.getQuickStepDragSlopPx()
+                                && diffY <= NavigationBarCompat.getQuickStepDragSlopPx())) {
+                            mNavigationBarView.setWindowTouchable(false);
+                            mClickThroughPressX = event.getRawX();
+                            mClickThroughPressY = event.getRawY();
+                            mClickThroughPressed = true;
+                            mNavigationBarView.postDelayed(mClickThroughSendTap,
+                                    CLICK_THROUGH_TAP_DELAY);
+                        }
                     }
                 }
 
@@ -403,30 +412,6 @@
         return mCurrentAction != null || deadZoneConsumed;
     }
 
-    private void setWindowTouchable(boolean flag) {
-        final WindowManager.LayoutParams lp = (WindowManager.LayoutParams)
-                ((ViewGroup) mNavigationBarView.getParent()).getLayoutParams();
-        if (flag) {
-            lp.flags &= ~LayoutParams.FLAG_NOT_TOUCHABLE;
-        } else {
-            lp.flags |= LayoutParams.FLAG_NOT_TOUCHABLE;
-        }
-        final WindowManager wm = (WindowManager) mNavigationBarView.getContext()
-                .getSystemService(Context.WINDOW_SERVICE);
-        wm.updateViewLayout((View) mNavigationBarView.getParent(), lp);
-    }
-
-    private boolean isEdgeSwipeAlongNavBar(int touchDown, boolean dragPositiveDirection) {
-        // Detect edge swipe from side of 0 -> threshold
-        if (dragPositiveDirection) {
-            return touchDown < mEdgeSwipeThreshold;
-        }
-        // Detect edge swipe from side of size -> (size - threshold)
-        final int largeSide = isNavBarVertical()
-                ? mNavigationBarView.getHeight() : mNavigationBarView.getWidth();
-        return touchDown > largeSide - mEdgeSwipeThreshold;
-    }
-
     private void handleDragHitTarget(int position, int touchDown) {
         // Drag the hit target if gesture action requires it
         if (mHitTarget != null && (mGestureVerticalDragsButton || mGestureHorizontalDragsButton)) {
@@ -448,6 +433,10 @@
     }
 
     private boolean shouldProxyEvents(int action) {
+        // Do not send events for side navigation bar panels
+        if (mNavigationBarView.getWindowTarget() != WINDOW_TARGET_BOTTOM) {
+            return false;
+        }
         final boolean actionValid = (mCurrentAction == null
                 || !mCurrentAction.disableProxyEvents());
         if (actionValid && !mIsInScreenPinning) {
@@ -619,6 +608,32 @@
         }
     }
 
+    /**
+     * To trigger an edge swipe, the user must start from the left or right edges of certain height
+     * from the bottom then past the drag slope towards the center of the screen, followed by either
+     * a timed trigger for fast swipes or distance if held on the screen longer.
+     * For time, user must swipe up quickly before the Tap Timeout (typically 100ms) and for
+     * distance, the user can drag back to cancel if the touch up has not past the threshold.
+     * @param event Touch up event
+     * @return whether or not edge swipe gesture occurs
+     */
+    private boolean canTriggerEdgeSwipe(MotionEvent event) {
+        if (mNavigationBarView.getWindowTarget() == WINDOW_TARGET_BOTTOM) {
+            return false;
+        }
+        int x = (int) event.getX();
+        int y = (int) event.getY();
+        int xDiff = Math.abs(x - mTouchDownX);
+        int yDiff = Math.abs(y - mTouchDownY);
+        final boolean exceededSwipeTouchSlop = xDiff > NavigationBarCompat.getQuickStepDragSlopPx()
+                && xDiff > yDiff;
+        if (exceededSwipeTouchSlop) {
+            long timeDiff = event.getEventTime() - event.getDownTime();
+            return xDiff > mGestureRegionThreshold || timeDiff < ViewConfiguration.getTapTimeout();
+        }
+        return false;
+    }
+
     private boolean canPerformAnyAction() {
         for (NavigationGestureAction action: mGestureActions) {
             if (action != null && action.isEnabled()) {
@@ -684,10 +699,18 @@
         return mNavBarPosition == NAV_BAR_LEFT || mNavBarPosition == NAV_BAR_RIGHT;
     }
 
+    private static int convertDpToPixel(float dp) {
+        return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
+    }
+
     static boolean getBoolGlobalSetting(Context context, String key) {
         return Settings.Global.getInt(context.getContentResolver(), key, 0) != 0;
     }
 
+    static int getIntGlobalSetting(Context context, String key, int defaultValue) {
+        return Settings.Global.getInt(context.getContentResolver(), key, defaultValue);
+    }
+
     public static boolean shouldhideBackButton(Context context) {
         return getBoolGlobalSetting(context, HIDE_BACK_BUTTON_PROP);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSwitchAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSwitchAction.java
index 40f2392..974de4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSwitchAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSwitchAction.java
@@ -22,7 +22,6 @@
 import android.annotation.NonNull;
 import android.graphics.Rect;
 import android.os.RemoteException;
-import android.provider.Settings;
 import android.util.Log;
 import android.view.MotionEvent;
 
@@ -34,7 +33,6 @@
  */
 public class QuickSwitchAction extends NavigationGestureAction {
     private static final String TAG = "QuickSwitchAction";
-    private static final String QUICKSWITCH_ENABLED_SETTING = "QUICK_SWITCH";
 
     protected final Rect mDragOverRect = new Rect();
 
@@ -71,10 +69,6 @@
 
     @Override
     protected void onGestureStart(MotionEvent event) {
-        // Temporarily enable launcher to allow quick switch instead of quick scrub
-        Settings.Global.putInt(mNavigationBarView.getContext().getContentResolver(),
-                QUICKSWITCH_ENABLED_SETTING, 1 /* enabled */);
-
         startQuickGesture(event);
     }
 
@@ -105,10 +99,6 @@
     @Override
     protected void onGestureEnd() {
         endQuickGesture(true /* animate */);
-
-        // Disable launcher to use quick switch instead of quick scrub
-        Settings.Global.putInt(mNavigationBarView.getContext().getContentResolver(),
-                QUICKSWITCH_ENABLED_SETTING, 0 /* disabled */);
     }
 
     protected void startQuickGesture(MotionEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index ffaa236..86e17f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -202,7 +202,8 @@
     private void applyFocusableFlag(State state) {
         boolean panelFocusable = state.statusBarFocusable && state.panelExpanded;
         if (state.bouncerShowing && (state.keyguardOccluded || state.keyguardNeedsInput)
-                || ENABLE_REMOTE_INPUT && state.remoteInputActive) {
+                || ENABLE_REMOTE_INPUT && state.remoteInputActive
+                || state.bubbleExpanded) {
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
@@ -486,6 +487,21 @@
         return mCurrentState.bubblesShowing;
     }
 
+    /**
+     * Sets if there is a bubble being expanded on the screen.
+     */
+    public void setBubbleExpanded(boolean bubbleExpanded) {
+        mCurrentState.bubbleExpanded = bubbleExpanded;
+        apply(mCurrentState);
+    }
+
+    /**
+     * The bubble is shown in expanded state for the status bar.
+     */
+    public boolean getBubbleExpanded() {
+        return mCurrentState.bubbleExpanded;
+    }
+
     public void setStateListener(OtherwisedCollapsedListener listener) {
         mListener = listener;
     }
@@ -539,6 +555,7 @@
         boolean wallpaperSupportsAmbientMode;
         boolean notTouchable;
         boolean bubblesShowing;
+        boolean bubbleExpanded;
 
         /**
          * The {@link StatusBar} state from the status bar.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 7881df9..1e09063 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -18,6 +18,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.Notification;
 import android.app.PendingIntent;
@@ -59,6 +60,7 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
@@ -269,10 +271,24 @@
         mPendingIntent = pendingIntent;
     }
 
-    public void setRemoteInput(RemoteInput[] remoteInputs, RemoteInput remoteInput) {
+    /**
+     * Sets the remote input for this view.
+     *
+     * @param remoteInputs The remote inputs that need to be sent to the app.
+     * @param remoteInput The remote input that needs to be activated.
+     * @param editedSuggestionInfo The smart reply that should be inserted in the remote input, or
+     *         {@code null} if the user is not editing a smart reply.
+     */
+    public void setRemoteInput(RemoteInput[] remoteInputs, RemoteInput remoteInput,
+            @Nullable EditedSuggestionInfo editedSuggestionInfo) {
         mRemoteInputs = remoteInputs;
         mRemoteInput = remoteInput;
         mEditText.setHint(mRemoteInput.getLabel());
+
+        mEntry.editedSuggestionInfo = editedSuggestionInfo;
+        if (editedSuggestionInfo != null) {
+            mEntry.remoteInputText = editedSuggestionInfo.originalText;
+        }
     }
 
     public void focusAnimated() {
@@ -389,7 +405,7 @@
     public void stealFocusFrom(RemoteInputView other) {
         other.close();
         setPendingIntent(other.mPendingIntent);
-        setRemoteInput(other.mRemoteInputs, other.mRemoteInput);
+        setRemoteInput(other.mRemoteInputs, other.mRemoteInput, mEntry.editedSuggestionInfo);
         setRevealParameters(other.mRevealCx, other.mRevealCy, other.mRevealR);
         focus();
     }
@@ -429,7 +445,7 @@
                 continue;
             }
             setPendingIntent(a.actionIntent);
-            setRemoteInput(inputs, input);
+            setRemoteInput(inputs, input, null /* editedSuggestionInfo*/);
             return true;
         }
         return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 1d2d6f7..45d215e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -38,6 +38,7 @@
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 
@@ -252,16 +253,17 @@
         OnDismissAction action = () -> {
             if (mConstants.getEffectiveEditChoicesBeforeSending(
                     smartReplies.remoteInput.getEditChoicesBeforeSending())) {
-                entry.remoteInputText = choice;
+                EditedSuggestionInfo editedSuggestionInfo =
+                        new EditedSuggestionInfo(choice, replyIndex);
                 mRemoteInputManager.activateRemoteInput(b,
                         new RemoteInput[] { smartReplies.remoteInput }, smartReplies.remoteInput,
-                        smartReplies.pendingIntent);
+                        smartReplies.pendingIntent, editedSuggestionInfo);
                 return false;
             }
 
             smartReplyController.smartReplySent(entry, replyIndex, b.getText(),
-                    smartReplies.fromAssistant,
-                    NotificationLogger.getNotificationLocation(entry).toMetricsEventEnum());
+                    NotificationLogger.getNotificationLocation(entry).toMetricsEventEnum(),
+                    false /* modifiedBeforeSending */);
             Bundle results = new Bundle();
             results.putString(smartReplies.remoteInput.getResultKey(), choice.toString());
             Intent intent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockInfoTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockInfoTest.java
new file mode 100644
index 0000000..d2b2654
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockInfoTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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 static org.mockito.Mockito.verify;
+
+import android.graphics.Bitmap;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.Supplier;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public final class ClockInfoTest extends SysuiTestCase {
+
+    @Mock
+    private Supplier<Bitmap> mMockSupplier;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testGetName() {
+        final String name = "name";
+        ClockInfo info = ClockInfo.builder().setName(name).build();
+        assertThat(info.getName()).isEqualTo(name);
+    }
+
+    @Test
+    public void testGetTitle() {
+        final String title = "title";
+        ClockInfo info = ClockInfo.builder().setTitle(title).build();
+        assertThat(info.getTitle()).isEqualTo(title);
+    }
+
+    @Test
+    public void testGetId() {
+        final String id = "id";
+        ClockInfo info = ClockInfo.builder().setId(id).build();
+        assertThat(info.getId()).isEqualTo(id);
+    }
+
+    @Test
+    public void testGetThumbnail() {
+        ClockInfo info = ClockInfo.builder().setThumbnail(mMockSupplier).build();
+        info.getThumbnail();
+        verify(mMockSupplier).get();
+    }
+
+    @Test
+    public void testGetPreview() {
+        ClockInfo info = ClockInfo.builder().setPreview(mMockSupplier).build();
+        info.getPreview();
+        verify(mMockSupplier).get();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockOptionsProviderTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockOptionsProviderTest.java
new file mode 100644
index 0000000..0cd6f9a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockOptionsProviderTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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 static org.mockito.Mockito.verify;
+
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Supplier;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public final class ClockOptionsProviderTest extends SysuiTestCase {
+
+    private static final String CONTENT_SCHEME = "content";
+    private static final String AUTHORITY = "com.android.keyguard.clock";
+    private static final String LIST_OPTIONS = "list_options";
+    private static final String PREVIEW = "preview";
+    private static final String THUMBNAIL = "thumbnail";
+    private static final String MIME_TYPE_LIST_OPTIONS = "vnd.android.cursor.dir/clock_faces";
+    private static final String MIME_TYPE_PNG = "image/png";
+    private static final String NAME_COLUMN = "name";
+    private static final String TITLE_COLUMN = "title";
+    private static final String ID_COLUMN = "id";
+    private static final String PREVIEW_COLUMN = "preview";
+    private static final String THUMBNAIL_COLUMN = "thumbnail";
+
+    private ClockOptionsProvider mProvider;
+    private Supplier<List<ClockInfo>> mMockSupplier;
+    private List<ClockInfo> mClocks;
+    private Uri mListOptionsUri;
+    @Mock
+    private Supplier<Bitmap> mMockBitmapSupplier;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mClocks = new ArrayList<>();
+        mProvider = new ClockOptionsProvider(() -> mClocks);
+        mListOptionsUri = new Uri.Builder()
+                .scheme(CONTENT_SCHEME)
+                .authority(AUTHORITY)
+                .appendPath(LIST_OPTIONS)
+                .build();
+    }
+
+    @Test
+    public void testGetType_listOptions() {
+        Uri uri = new Uri.Builder()
+                .scheme(CONTENT_SCHEME)
+                .authority(AUTHORITY)
+                .appendPath(LIST_OPTIONS)
+                .build();
+        assertThat(mProvider.getType(uri)).isEqualTo(MIME_TYPE_LIST_OPTIONS);
+    }
+
+    @Test
+    public void testGetType_preview() {
+        Uri uri = new Uri.Builder()
+                .scheme(CONTENT_SCHEME)
+                .authority(AUTHORITY)
+                .appendPath(PREVIEW)
+                .appendPath("id")
+                .build();
+        assertThat(mProvider.getType(uri)).isEqualTo(MIME_TYPE_PNG);
+    }
+
+    @Test
+    public void testGetType_thumbnail() {
+        Uri uri = new Uri.Builder()
+                .scheme(CONTENT_SCHEME)
+                .authority(AUTHORITY)
+                .appendPath(THUMBNAIL)
+                .appendPath("id")
+                .build();
+        assertThat(mProvider.getType(uri)).isEqualTo(MIME_TYPE_PNG);
+    }
+
+    @Test
+    public void testQuery_noClocks() {
+        Cursor cursor = mProvider.query(mListOptionsUri, null, null, null);
+        assertThat(cursor.getCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void testQuery_listOptions() {
+        mClocks.add(ClockInfo.builder()
+                .setName("name_a")
+                .setTitle("title_a")
+                .setId("id_a")
+                .build());
+        mClocks.add(ClockInfo.builder()
+                .setName("name_b")
+                .setTitle("title_b")
+                .setId("id_b")
+                .build());
+        Cursor cursor = mProvider.query(mListOptionsUri, null, null, null);
+        assertThat(cursor.getCount()).isEqualTo(2);
+        cursor.moveToFirst();
+        assertThat(cursor.getString(
+                cursor.getColumnIndex(NAME_COLUMN))).isEqualTo("name_a");
+        assertThat(cursor.getString(
+                cursor.getColumnIndex(TITLE_COLUMN))).isEqualTo("title_a");
+        assertThat(cursor.getString(
+                cursor.getColumnIndex(ID_COLUMN))).isEqualTo("id_a");
+        assertThat(cursor.getString(
+                cursor.getColumnIndex(PREVIEW_COLUMN)))
+                .isEqualTo("content://com.android.keyguard.clock/preview/id_a");
+        assertThat(cursor.getString(
+                cursor.getColumnIndex(THUMBNAIL_COLUMN)))
+                .isEqualTo("content://com.android.keyguard.clock/thumbnail/id_a");
+        cursor.moveToNext();
+        assertThat(cursor.getString(
+                cursor.getColumnIndex(NAME_COLUMN))).isEqualTo("name_b");
+        assertThat(cursor.getString(
+                cursor.getColumnIndex(TITLE_COLUMN))).isEqualTo("title_b");
+        assertThat(cursor.getString(
+                cursor.getColumnIndex(ID_COLUMN))).isEqualTo("id_b");
+        assertThat(cursor.getString(
+                cursor.getColumnIndex(PREVIEW_COLUMN)))
+                .isEqualTo("content://com.android.keyguard.clock/preview/id_b");
+        assertThat(cursor.getString(
+                cursor.getColumnIndex(THUMBNAIL_COLUMN)))
+                .isEqualTo("content://com.android.keyguard.clock/thumbnail/id_b");
+    }
+
+    @Test
+    public void testOpenFile_preview() throws Exception {
+        mClocks.add(ClockInfo.builder()
+                .setId("id")
+                .setPreview(mMockBitmapSupplier)
+                .build());
+        Uri uri = new Uri.Builder()
+                .scheme(CONTENT_SCHEME)
+                .authority(AUTHORITY)
+                .appendPath(PREVIEW)
+                .appendPath("id")
+                .build();
+        mProvider.openFile(uri, "r").close();
+        verify(mMockBitmapSupplier).get();
+    }
+
+    @Test
+    public void testOpenFile_thumbnail() throws Exception {
+        mClocks.add(ClockInfo.builder()
+                .setId("id")
+                .setThumbnail(mMockBitmapSupplier)
+                .build());
+        Uri uri = new Uri.Builder()
+                .scheme(CONTENT_SCHEME)
+                .authority(AUTHORITY)
+                .appendPath(THUMBNAIL)
+                .appendPath("id")
+                .build();
+        mProvider.openFile(uri, "r").close();
+        verify(mMockBitmapSupplier).get();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index e32d48d..49b4641 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -168,12 +168,14 @@
         // We should have bubbles & their notifs should show in the shade
         assertTrue(mBubbleController.hasBubbles());
         assertTrue(mRow.getEntry().showInShadeWhenBubble());
+        assertFalse(mStatusBarWindowController.getBubbleExpanded());
 
         // Expand the stack
         BubbleStackView stackView = mBubbleController.getStackView();
         stackView.expandStack();
         assertTrue(mBubbleController.isStackExpanded());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key);
+        assertTrue(mStatusBarWindowController.getBubbleExpanded());
 
         // Make sure it's no longer in the shade
         assertFalse(mRow.getEntry().showInShadeWhenBubble());
@@ -182,6 +184,7 @@
         stackView.collapseStack();
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key);
         assertFalse(mBubbleController.isStackExpanded());
+        assertFalse(mStatusBarWindowController.getBubbleExpanded());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
index 1bb7ef4..c0aac7e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
@@ -55,11 +55,12 @@
         mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
         mBubblePadding = res.getDimensionPixelSize(R.dimen.bubble_padding);
         mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
+
+        mExpansionPoint = new PointF(100, 100);
     }
 
     @Test
     public void testExpansionAndCollapse() throws InterruptedException {
-        mExpansionPoint = new PointF(100, 100);
         Runnable afterExpand = Mockito.mock(Runnable.class);
         mExpandedController.expandFromStack(mExpansionPoint, afterExpand);
 
@@ -77,27 +78,48 @@
         Mockito.verify(afterExpand).run();
     }
 
+    @Test
+    public void testOnChildRemoved() throws InterruptedException {
+        Runnable afterExpand = Mockito.mock(Runnable.class);
+        mExpandedController.expandFromStack(mExpansionPoint, afterExpand);
+        waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
+        testExpanded();
+
+        // Remove some views and see if the remaining child views still pass the expansion test.
+        mLayout.removeView(mViews.get(0));
+        mLayout.removeView(mViews.get(3));
+        waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
+        testExpanded();
+    }
+
     /** Check that children are in the correct positions for being stacked. */
     private void testStackedAtPosition(float x, float y, int offsetMultiplier) {
         // Make sure the rest of the stack moved again, including the first bubble not moving, and
         // is stacked to the right now that we're on the right side of the screen.
         for (int i = 0; i < mLayout.getChildCount(); i++) {
             assertEquals(x + i * offsetMultiplier * mStackOffset,
-                    mViews.get(i).getTranslationX(), 2f);
-            assertEquals(y, mViews.get(i).getTranslationY(), 2f);
+                    mLayout.getChildAt(i).getTranslationX(), 2f);
+            assertEquals(y, mLayout.getChildAt(i).getTranslationY(), 2f);
+
+            if (i < mMaxRenderedBubbles) {
+                assertEquals(1f, mLayout.getChildAt(i).getAlpha(), .01f);
+            }
         }
     }
 
     /** Check that children are in the correct positions for being expanded. */
     private void testExpanded() {
-        // Make sure the rest of the stack moved again, including the first bubble not moving, and
-        // is stacked to the right now that we're on the right side of the screen.
-        for (int i = 0; i < mLayout.getChildCount(); i++) {
+        // Check all the visible bubbles to see if they're in the right place.
+        for (int i = 0; i < Math.min(mLayout.getChildCount(), mMaxRenderedBubbles); i++) {
             assertEquals(mBubblePadding + (i * (mBubbleSize + mBubblePadding)),
-                    mViews.get(i).getTranslationX(),
+                    mLayout.getChildAt(i).getTranslationX(),
                     2f);
             assertEquals(mBubblePadding + mCutoutInsetSize,
-                    mViews.get(i).getTranslationY(), 2f);
+                    mLayout.getChildAt(i).getTranslationY(), 2f);
+
+            if (i < mMaxRenderedBubbles) {
+                assertEquals(1f, mLayout.getChildAt(i).getAlpha(), .01f);
+            }
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
index 5be991f..c3214040 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
@@ -25,6 +25,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
 
 import android.os.SystemClock;
 import android.support.test.filters.SmallTest;
@@ -100,9 +101,9 @@
         mTestableController.setRemoveImmediately(true);
         mLayout.removeView(mViews.get(1));
         mLayout.removeView(mViews.get(2));
-        Mockito.verify(mTestableController).onChildToBeRemoved(
+        Mockito.verify(mTestableController).onChildRemoved(
                 eq(mViews.get(1)), eq(1), any());
-        Mockito.verify(mTestableController).onChildToBeRemoved(
+        Mockito.verify(mTestableController).onChildRemoved(
                 eq(mViews.get(2)), eq(1), any());
 
         // Make sure we still get view added notifications after doing some removals.
@@ -345,6 +346,24 @@
         assertTrue(mViews.get(0).getTranslationY() < 1000);
     }
 
+    @Test
+    public void testSetChildVisibility() throws InterruptedException {
+        mLayout.setController(mTestableController);
+        addOneMoreThanRenderLimitBubbles();
+
+        // The last view should have been set to GONE by the controller, since we added one more
+        // than the limit and it got pushed off. None of the first children should have been set
+        // VISIBLE, since they would have been animated in by onChildAdded.
+        Mockito.verify(mTestableController).setChildVisibility(
+                mViews.get(mViews.size() - 1), 5, View.GONE);
+        Mockito.verify(mTestableController, never()).setChildVisibility(
+                any(View.class), anyInt(), eq(View.VISIBLE));
+
+        // Remove the first view, which should cause the last view to become visible again.
+        mLayout.removeView(mViews.get(0));
+        Mockito.verify(mTestableController).setChildVisibility(
+                mViews.get(mViews.size() - 1), 4, View.VISIBLE);
+    }
 
     /** Standard test of chained translation animations. */
     private void testChainedTranslationAnimations() throws InterruptedException {
@@ -440,10 +459,15 @@
         void onChildAdded(View child, int index) {}
 
         @Override
-        void onChildToBeRemoved(View child, int index, Runnable actuallyRemove) {
+        void onChildRemoved(View child, int index, Runnable finishRemoval) {
             if (mRemoveImmediately) {
-                actuallyRemove.run();
+                finishRemoval.run();
             }
         }
+
+        @Override
+        protected void setChildVisibility(View child, int index, int visibility) {
+            super.setChildVisibility(child, index, visibility);
+        }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
index 8503962..374a73c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
@@ -16,27 +16,35 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.support.test.filters.SmallTest;
+import android.telephony.SubscriptionManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.LayoutInflater;
 import android.view.View;
 
+import com.android.keyguard.CarrierTextController.CarrierTextCallbackInfo;
 import com.android.systemui.R;
 import com.android.systemui.R.id;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
@@ -68,4 +76,117 @@
         // Verify Settings wasn't launched.
         verify(mActivityStarter, never()).startActivity(any(), anyBoolean());
     }
+
+    @Test // throws no Exception
+    public void testUpdateCarrierText_sameLengts() {
+        QSFooterImpl spiedFooter = Mockito.spy(mFooter);
+        when(spiedFooter.getSlotIndex(anyInt())).thenAnswer(
+                new Answer<Integer>() {
+                    @Override
+                    public Integer answer(InvocationOnMock invocationOnMock) throws Throwable {
+                        return invocationOnMock.getArgument(0);
+                    }
+                });
+
+        // listOfCarriers length 1, subscriptionIds length 1, anySims false
+        CarrierTextCallbackInfo c1 = new CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{""},
+                false,
+                new int[]{0});
+        spiedFooter.updateCarrierInfo(c1);
+
+        // listOfCarriers length 1, subscriptionIds length 1, anySims true
+        CarrierTextCallbackInfo c2 = new CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{""},
+                true,
+                new int[]{0});
+        spiedFooter.updateCarrierInfo(c2);
+
+        // listOfCarriers length 2, subscriptionIds length 2, anySims false
+        CarrierTextCallbackInfo c3 = new CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{"", ""},
+                false,
+                new int[]{0, 1});
+        spiedFooter.updateCarrierInfo(c3);
+
+        // listOfCarriers length 2, subscriptionIds length 2, anySims true
+        CarrierTextCallbackInfo c4 = new CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{"", ""},
+                true,
+                new int[]{0, 1});
+        spiedFooter.updateCarrierInfo(c4);
+    }
+
+    @Test // throws no Exception
+    public void testUpdateCarrierText_differentLength() {
+        QSFooterImpl spiedFooter = Mockito.spy(mFooter);
+        when(spiedFooter.getSlotIndex(anyInt())).thenAnswer(
+                new Answer<Integer>() {
+                    @Override
+                    public Integer answer(InvocationOnMock invocationOnMock) throws Throwable {
+                        return invocationOnMock.getArgument(0);
+                    }
+                });
+
+        // listOfCarriers length 2, subscriptionIds length 1, anySims false
+        CarrierTextCallbackInfo c1 = new CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{"", ""},
+                false,
+                new int[]{0});
+        spiedFooter.updateCarrierInfo(c1);
+
+        // listOfCarriers length 2, subscriptionIds length 1, anySims true
+        CarrierTextCallbackInfo c2 = new CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{"", ""},
+                true,
+                new int[]{0});
+        spiedFooter.updateCarrierInfo(c2);
+
+        // listOfCarriers length 1, subscriptionIds length 2, anySims false
+        CarrierTextCallbackInfo c3 = new CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{""},
+                false,
+                new int[]{0, 1});
+        spiedFooter.updateCarrierInfo(c3);
+
+        // listOfCarriers length 1, subscriptionIds length 2, anySims true
+        CarrierTextCallbackInfo c4 = new CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{""},
+                true,
+                new int[]{0, 1});
+        spiedFooter.updateCarrierInfo(c4);
+    }
+
+    @Test // throws no Exception
+    public void testUpdateCarrierText_invalidSim() {
+        QSFooterImpl spiedFooter = Mockito.spy(mFooter);
+        when(spiedFooter.getSlotIndex(anyInt())).thenReturn(
+                SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+        CarrierTextCallbackInfo c4 = new CarrierTextCallbackInfo(
+                "",
+                new CharSequence[]{"", ""},
+                true,
+                new int[]{0, 1});
+        spiedFooter.updateCarrierInfo(c4);
+    }
+
+    @Test // throws no Exception
+    public void testSetMobileDataIndicators_invalidSim() {
+        QSFooterImpl spiedFooter = Mockito.spy(mFooter);
+        when(spiedFooter.getSlotIndex(anyInt())).thenReturn(
+                SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+        spiedFooter.setMobileDataIndicators(
+                mock(NetworkController.IconState.class),
+                mock(NetworkController.IconState.class),
+                0, 0, true, true, "", "", true, 0, true);
+    }
+
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index f34e1a6..31cd280 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -98,8 +98,8 @@
 
     @Test
     public void testSendSmartReply_updatesRemoteInput() {
-        mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, false,
-                MetricsEvent.LOCATION_UNKNOWN);
+        mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT,
+                MetricsEvent.LOCATION_UNKNOWN, false /* modifiedBeforeSending */);
 
         // Sending smart reply should make calls to NotificationEntryManager
         // to update the notification with reply and spinner.
@@ -109,48 +109,49 @@
 
     @Test
     public void testSendSmartReply_logsToStatusBar() throws RemoteException {
-        mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, false,
-                MetricsEvent.LOCATION_UNKNOWN);
+        mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT,
+                MetricsEvent.LOCATION_UNKNOWN, false /* modifiedBeforeSending */);
 
         // Check we log the result to the status bar service.
         verify(mIStatusBarService).onNotificationSmartReplySent(mSbn.getKey(),
-                TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, false, MetricsEvent.LOCATION_UNKNOWN);
+                TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, MetricsEvent.LOCATION_UNKNOWN, false);
     }
 
 
     @Test
-    public void testSendSmartReply_logsToStatusBar_generatedByAssistant() throws RemoteException {
-        mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, true,
-                MetricsEvent.LOCATION_UNKNOWN);
+    public void testSendSmartReply_logsToStatusBar_modifiedBeforeSending() throws RemoteException {
+        mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT,
+                MetricsEvent.LOCATION_UNKNOWN, true /* modifiedBeforeSending */);
 
         // Check we log the result to the status bar service.
         verify(mIStatusBarService).onNotificationSmartReplySent(mSbn.getKey(),
-                TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, true, MetricsEvent.LOCATION_UNKNOWN);
+                TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, MetricsEvent.LOCATION_UNKNOWN, true);
     }
 
     @Test
     public void testShowSmartSuggestions_logsToStatusBar() throws RemoteException {
         final boolean generatedByAsssistant = true;
+        final boolean editBeforeSending = true;
         mSmartReplyController.smartSuggestionsAdded(mEntry, TEST_CHOICE_COUNT, TEST_ACTION_COUNT,
-                generatedByAsssistant);
+                generatedByAsssistant, editBeforeSending);
 
         // Check we log the result to the status bar service.
         verify(mIStatusBarService).onNotificationSmartSuggestionsAdded(mSbn.getKey(),
-                TEST_CHOICE_COUNT, TEST_ACTION_COUNT, generatedByAsssistant);
+                TEST_CHOICE_COUNT, TEST_ACTION_COUNT, generatedByAsssistant, editBeforeSending);
     }
 
     @Test
     public void testSendSmartReply_reportsSending() {
-        mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, false,
-                MetricsEvent.LOCATION_UNKNOWN);
+        mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT,
+                MetricsEvent.LOCATION_UNKNOWN, false /* modifiedBeforeSending */);
 
         assertTrue(mSmartReplyController.isSendingSmartReply(mSbn.getKey()));
     }
 
     @Test
     public void testSendingSmartReply_afterRemove_shouldReturnFalse() {
-        mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT, false,
-                MetricsEvent.LOCATION_UNKNOWN);
+        mSmartReplyController.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT,
+                MetricsEvent.LOCATION_UNKNOWN, false /* modifiedBeforeSending */);
         mSmartReplyController.stopSending(mEntry);
 
         assertFalse(mSmartReplyController.isSendingSmartReply(mSbn.getKey()));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
index 382dde9..dbf00a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
@@ -23,6 +23,7 @@
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_DEAD_ZONE;
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
+import static com.android.systemui.statusbar.phone.NavigationBarView.WINDOW_TARGET_BOTTOM;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -63,7 +64,6 @@
 public class QuickStepControllerTest extends SysuiTestCase {
     private static final int NAVBAR_WIDTH = 1000;
     private static final int NAVBAR_HEIGHT = 300;
-    private static final int EDGE_THRESHOLD = 100;
 
     private QuickStepController mController;
     private NavigationBarView mNavigationBarView;
@@ -77,8 +77,6 @@
         MockitoAnnotations.initMocks(this);
         final ButtonDispatcher backButton = mock(ButtonDispatcher.class);
         mResources = mock(Resources.class);
-        doReturn(EDGE_THRESHOLD).when(mResources)
-                .getDimensionPixelSize(R.dimen.navigation_bar_edge_swipe_threshold);
 
         mProxyService = mock(OverviewProxyService.class);
         mProxy = mock(IOverviewProxy.Stub.class);
@@ -95,6 +93,7 @@
         doReturn(true).when(mNavigationBarView).isNotificationsFullyCollapsed();
         doReturn(true).when(mNavigationBarView).isQuickScrubEnabled();
         doReturn(HIT_TARGET_NONE).when(mNavigationBarView).getDownHitTarget();
+        doReturn(WINDOW_TARGET_BOTTOM).when(mNavigationBarView).getWindowTarget();
         doReturn(backButton).when(mNavigationBarView).getBackButton();
         doReturn(mResources).when(mNavigationBarView).getResources();
         doReturn(mContext).when(mNavigationBarView).getContext();
@@ -196,10 +195,8 @@
         NavigationGestureAction swipeDown = mockAction(true);
         NavigationGestureAction swipeLeft = mockAction(true);
         NavigationGestureAction swipeRight = mockAction(true);
-        NavigationGestureAction swipeLeftFromEdge = mockAction(true);
-        NavigationGestureAction swipeRightFromEdge = mockAction(true);
-        mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
-                swipeRightFromEdge);
+        mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+                null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
 
         // Swipe Up
         assertGestureTriggersAction(swipeUp, 1, 100, 5, 1);
@@ -209,10 +206,6 @@
         assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH / 2, 1, 5, 1);
         // Swipe Right
         assertGestureTriggersAction(swipeRight, NAVBAR_WIDTH / 2, 1, NAVBAR_WIDTH, 5);
-        // Swipe Left from Edge
-        assertGestureTriggersAction(swipeLeftFromEdge, NAVBAR_WIDTH, 1, 5, 1);
-        // Swipe Right from Edge
-        assertGestureTriggersAction(swipeRightFromEdge, 0, 1, NAVBAR_WIDTH, 5);
     }
 
     @Test
@@ -224,10 +217,8 @@
         NavigationGestureAction swipeDown = mockAction(true);
         NavigationGestureAction swipeLeft = mockAction(true);
         NavigationGestureAction swipeRight = mockAction(true);
-        NavigationGestureAction swipeLeftFromEdge = mockAction(true);
-        NavigationGestureAction swipeRightFromEdge = mockAction(true);
-        mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
-                swipeRightFromEdge);
+        mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+                null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
 
         // In landscape
         mController.setBarState(false /* isRTL */, NAV_BAR_RIGHT);
@@ -240,10 +231,6 @@
         assertGestureTriggersAction(swipeUp, 100, 1, 5, 1);
         // Swipe Right
         assertGestureTriggersAction(swipeDown, 1, 1, 100, 5);
-        // Swipe Up from Edge
-        assertGestureTriggersAction(swipeRightFromEdge, 1, NAVBAR_WIDTH, 5, 0);
-        // Swipe Down from Edge
-        assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, 0, NAVBAR_WIDTH);
     }
 
     @Test
@@ -256,10 +243,8 @@
         NavigationGestureAction swipeDown = mockAction(true);
         NavigationGestureAction swipeLeft = mockAction(true);
         NavigationGestureAction swipeRight = mockAction(true);
-        NavigationGestureAction swipeLeftFromEdge = mockAction(true);
-        NavigationGestureAction swipeRightFromEdge = mockAction(true);
-        mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
-                swipeRightFromEdge);
+        mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+                null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
 
         // Swipe Up
         assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, 1);
@@ -269,10 +254,6 @@
         assertGestureTriggersAction(swipeDown, 100, 1, 5, 1);
         // Swipe Right
         assertGestureTriggersAction(swipeUp, 1, 1, 100, 5);
-        // Swipe Up from Edge
-        assertGestureTriggersAction(swipeLeftFromEdge, 1, NAVBAR_WIDTH, 5, 0);
-        // Swipe Down from Edge
-        assertGestureTriggersAction(swipeRightFromEdge, 0, 1, 0, NAVBAR_WIDTH);
     }
 
     @Test
@@ -286,10 +267,8 @@
         NavigationGestureAction swipeDown = mockAction(true);
         NavigationGestureAction swipeLeft = mockAction(true);
         NavigationGestureAction swipeRight = mockAction(true);
-        NavigationGestureAction swipeLeftFromEdge = mockAction(true);
-        NavigationGestureAction swipeRightFromEdge = mockAction(true);
-        mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
-                swipeRightFromEdge);
+        mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+                null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
 
         // Swipe Up in RTL
         assertGestureTriggersAction(swipeUp, 1, 100, 5, 1);
@@ -299,10 +278,6 @@
         assertGestureTriggersAction(swipeRight, NAVBAR_WIDTH / 2, 1, 5, 1);
         // Swipe Right in RTL
         assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH / 2, 1, NAVBAR_WIDTH, 0);
-        // Swipe Left from Edge
-        assertGestureTriggersAction(swipeRightFromEdge, NAVBAR_WIDTH, 1, 5, 1);
-        // Swipe Right from Edge
-        assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, NAVBAR_WIDTH, 5);
     }
 
     @Test
@@ -316,10 +291,8 @@
         NavigationGestureAction swipeDown = mockAction(true);
         NavigationGestureAction swipeLeft = mockAction(true);
         NavigationGestureAction swipeRight = mockAction(true);
-        NavigationGestureAction swipeLeftFromEdge = mockAction(true);
-        NavigationGestureAction swipeRightFromEdge = mockAction(true);
-        mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
-                swipeRightFromEdge);
+        mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+                null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
 
         // Swipe Up
         assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, 1);
@@ -329,10 +302,6 @@
         assertGestureTriggersAction(swipeUp, 100, 1, 5, 1);
         // Swipe Right
         assertGestureTriggersAction(swipeDown, 1, 1, 100, 5);
-        // Swipe Up from Edge
-        assertGestureTriggersAction(swipeLeftFromEdge, 1, NAVBAR_WIDTH, 5, 0);
-        // Swipe Down from Edge
-        assertGestureTriggersAction(swipeRightFromEdge, 0, 1, 0, NAVBAR_WIDTH);
     }
 
     @Test
@@ -346,10 +315,8 @@
         NavigationGestureAction swipeDown = mockAction(true);
         NavigationGestureAction swipeLeft = mockAction(true);
         NavigationGestureAction swipeRight = mockAction(true);
-        NavigationGestureAction swipeLeftFromEdge = mockAction(true);
-        NavigationGestureAction swipeRightFromEdge = mockAction(true);
-        mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
-                swipeRightFromEdge);
+        mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
+                null /* leftEdgeSwipe */, null /* rightEdgeSwipe */);
 
         // Swipe Up
         assertGestureTriggersAction(swipeRight, 1, NAVBAR_WIDTH / 2, 5, 1);
@@ -359,10 +326,6 @@
         assertGestureTriggersAction(swipeDown, 100, 1, 5, 1);
         // Swipe Right
         assertGestureTriggersAction(swipeUp, 1, 1, 100, 5);
-        // Swipe Up from Edge
-        assertGestureTriggersAction(swipeRightFromEdge, 1, NAVBAR_WIDTH, 5, 0);
-        // Swipe Down from Edge
-        assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, 0, NAVBAR_WIDTH);
     }
 
     @Test
@@ -602,25 +565,6 @@
         assertGestureDragsHitTargetAllDirections(buttonView, true /* isRTL */, NAV_BAR_LEFT);
     }
 
-    @Test
-    public void testNoEdgeActionsTriggerNormalActions() {
-        doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
-        doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
-
-        NavigationGestureAction swipeUp = mockAction(true);
-        NavigationGestureAction swipeDown = mockAction(true);
-        NavigationGestureAction swipeLeft = mockAction(true);
-        NavigationGestureAction swipeRight = mockAction(true);
-        mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight,
-                null /* swipeLeftFromEdgeAction */,
-                null /* swipeLeftFromEdgeAction */);
-
-        // Swipe Left from Edge
-        assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH, 1, 5, 1);
-        // Swipe Right from Edge
-        assertGestureTriggersAction(swipeRight, 0, 1, NAVBAR_WIDTH, 5);
-    }
-
     private void assertGestureDragsHitTargetAllDirections(View buttonView, boolean isRTL,
             int navPos) {
         mController.setBarState(isRTL, navPos);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index ed98c62..568ff55f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -96,7 +96,7 @@
         RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).build();
 
         view.setPendingIntent(pendingIntent);
-        view.setRemoteInput(new RemoteInput[]{input}, input);
+        view.setRemoteInput(new RemoteInput[]{input}, input, null /* editedSuggestionInfo */);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 5570122..6793eca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -191,15 +191,7 @@
         setSmartReplies(TEST_CHOICES);
         mView.getChildAt(2).performClick();
         verify(mLogger).smartReplySent(mEntry, 2, TEST_CHOICES[2],
-                false /* generatedByAsssitant */, MetricsEvent.LOCATION_UNKNOWN);
-    }
-
-    @Test
-    public void testSendSmartReply_controllerCalled_generatedByAssistant() {
-        setSmartReplies(TEST_CHOICES, true);
-        mView.getChildAt(2).performClick();
-        verify(mLogger).smartReplySent(mEntry, 2, TEST_CHOICES[2],
-                true /* generatedByAsssitant */, MetricsEvent.LOCATION_UNKNOWN);
+                MetricsEvent.LOCATION_UNKNOWN, false /* modifiedBeforeSending */);
     }
 
     @Test
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/Android.mk b/packages/overlays/IconPackCircularSettingsOverlay/Android.mk
new file mode 100644
index 0000000..ad7324d
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/Android.mk
@@ -0,0 +1,31 @@
+#
+#  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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := IconPackCircularSettings
+LOCAL_CERTIFICATE := platform
+LOCAL_PRODUCT_MODULE := true
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := IconPackCircularSettingsOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/AndroidManifest.xml b/packages/overlays/IconPackCircularSettingsOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..c1a5698
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/AndroidManifest.xml
@@ -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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.theme.icon_pack.circular.settings"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <overlay android:targetPackage="com.android.settings" android:category="android.theme.customization.icon_pack.settings" android:priority="1"/>
+    <application android:label="Circular" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_apps.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_apps.xml
new file mode 100644
index 0000000..dbac48d
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_apps.xml
@@ -0,0 +1,54 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M6,4A2,2,0,0,0,6,8H7.5A0.5 0.5 ,0,0,0,8,7.5V6A2,2,0,0,0,6,4Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,8h1.5a0.5 0.5 ,0,0,0,0.5-0.5V6a2,2,0,1,0-2,2Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M20,6a2,2,0,1,0-2,2h1.5a0.5 0.5 ,0,0,0,0.5-0.5Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M6,14H7.5a0.5 0.5 ,0,0,0,0.5-0.5V12a2,2,0,1,0-2,2Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,14h1.5a0.5 0.5 ,0,0,0,0.5-0.5V12a2,2,0,1,0-2,2Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M20,12a2,2,0,1,0-2,2h1.5a0.5 0.5 ,0,0,0,0.5-0.5Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M6,20H7.5a0.5 0.5 ,0,0,0,0.5-0.5V18a2,2,0,1,0-2,2Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,20h1.5a0.5 0.5 ,0,0,0,0.5-0.5V18a2,2,0,1,0-2,2Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M20,18a2,2,0,1,0-2,2h1.5a0.5 0.5 ,0,0,0,0.5-0.5Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_devices_other.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_devices_other.xml
new file mode 100644
index 0000000..a407bd6
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_devices_other.xml
@@ -0,0 +1,36 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M2,16.5A2.5,2.5,0,0,0,4.5,19h2a0.5 0.5 ,0,0,0,0-1h-2A1.5,1.5,0,0,1,3,16.5v-9A1.5,1.5,0,0,1,4.5,6h17a0.5 0.5 ,0,0,0,0-1H4.5A2.5,2.5,0,0,0,2,7.5Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M14,16a3,3,0,1,0-3,3A3,3,0,0,0,14,16ZM9,16a2,2,0,1,1,2,2A2,2,0,0,1,9,16Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M22,17V10a2,2,0,0,0-2-2H17a2,2,0,0,0-2,2v7a2,2,0,0,0,2,2h3A2,2,0,0,0,22,17Zm-6,0V10a1,1,0,0,1,1-1h3a1,1,0,0,1,1,1v7a1,1,0,0,1-1,1H17A1,1,0,0,1,16,17Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_help.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_help.xml
new file mode 100644
index 0000000..c906847
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_help.xml
@@ -0,0 +1,36 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,22h0A10,10,0,0,0,22,12v0A10,10,0,1,0,12,22ZM12,3a9,9,0,1,1-9,9A9,9,0,0,1,12,3Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M8.62,9.65a0.5 0.5 ,0,0,0,0.61-0.37,2.94,2.94,0,0,1,5-1.41A2.64,2.64,0,0,1,15,10a2.27,2.27,0,0,1-1,1.69l-0.44 0.26 a3.21,3.21,0,0,0-1.91,2.47A0.49 0.49 ,0,0,0,12,15h0.08a0.5 0.5 ,0,0,0,0.49-0.42A2.25,2.25,0,0,1,14,12.81l0.5-0.29A3.27,3.27,0,0,0,16,10.09,3.62,3.62,0,0,0,14.9,7.16a4,4,0,0,0-5.6,0A4.06,4.06,0,0,0,8.25,9.05 0.5 0.5,0,0,0,8.62,9.65Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 16.25 C 12.4142135624 16.25 12.75 16.5857864376 12.75 17 C 12.75 17.4142135624 12.4142135624 17.75 12 17.75 C 11.5857864376 17.75 11.25 17.4142135624 11.25 17 C 11.25 16.5857864376 11.5857864376 16.25 12 16.25 Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_phone_info.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_phone_info.xml
new file mode 100644
index 0000000..f3419d4
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_phone_info.xml
@@ -0,0 +1,36 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M15,22a3,3,0,0,0,3-3V5a3,3,0,0,0-3-3H9A3,3,0,0,0,6,5V19a3,3,0,0,0,3,3ZM7,6H17V18H7ZM9,3h6a2,2,0,0,1,2,2H7A2,2,0,0,1,9,3ZM7,19H17a2,2,0,0,1-2,2H9A2,2,0,0,1,7,19Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,10.5a0.5 0.5 ,0,0,0-0.5 0.5 v4.5a0.5 0.5 ,0,0,0,1,0V11A0.5 0.5 ,0,0,0,12,10.5Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 8 C 12.4142135624 8 12.75 8.33578643763 12.75 8.75 C 12.75 9.16421356237 12.4142135624 9.5 12 9.5 C 11.5857864376 9.5 11.25 9.16421356237 11.25 8.75 C 11.25 8.33578643763 11.5857864376 8 12 8 Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_accessibility.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_accessibility.xml
new file mode 100644
index 0000000..8a8ddec
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_accessibility.xml
@@ -0,0 +1,42 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M21,5.35A0.51 0.51 ,0,0,0,20.37,5,37.25,37.25,0,0,1,3.63,5,0.51 0.51 ,0,0,0,3,5.35 0.51 0.51,0,0,0,3.37,6,32.05,32.05,0,0,0,9,6.87V20a0.5 0.5 ,0,0,0,1,0V13.5h4V20a0.5 0.5 ,0,0,0,1,0V6.87A32.05,32.05,0,0,0,20.63,6,0.51 0.51 ,0,0,0,21,5.35Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 22 C 12.5522847498 22 13 22.4477152502 13 23 C 13 23.5522847498 12.5522847498 24 12 24 C 11.4477152502 24 11 23.5522847498 11 23 C 11 22.4477152502 11.4477152502 22 12 22 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 16 22 C 16.5522847498 22 17 22.4477152502 17 23 C 17 23.5522847498 16.5522847498 24 16 24 C 15.4477152502 24 15 23.5522847498 15 23 C 15 22.4477152502 15.4477152502 22 16 22 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 8 22 C 8.55228474983 22 9 22.4477152502 9 23 C 9 23.5522847498 8.55228474983 24 8 24 C 7.44771525017 24 7 23.5522847498 7 23 C 7 22.4477152502 7.44771525017 22 8 22 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 1 C 13.1045694997 1 14 1.89543050034 14 3 C 14 4.10456949966 13.1045694997 5 12 5 C 10.8954305003 5 10 4.10456949966 10 3 C 10 1.89543050034 10.8954305003 1 12 1 Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_accounts.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_accounts.xml
new file mode 100644
index 0000000..01fc4b9
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_accounts.xml
@@ -0,0 +1,33 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,22A10,10,0,1,0,2,12,10,10,0,0,0,12,22Zm0-1a9,9,0,0,1-7-3.31,10.37,10.37,0,0,1,13.94,0A9,9,0,0,1,12,21ZM3,12a9,9,0,0,1,18,0,8.88,8.88,0,0,1-1.45,4.88,11.35,11.35,0,0,0-15.1,0A8.83,8.83,0,0,1,3,12Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M15.5,9.5A3.5,3.5,0,1,0,12,13,3.5,3.5,0,0,0,15.5,9.5Zm-6,0A2.5,2.5,0,1,1,12,12,2.5,2.5,0,0,1,9.5,9.5Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_battery_white.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_battery_white.xml
new file mode 100644
index 0000000..b43923f
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_battery_white.xml
@@ -0,0 +1,30 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M14,4a1,1,0,0,0-1-1H11a1,1,0,0,0-1,1H9A2,2,0,0,0,7,6V19a2,2,0,0,0,2,2h6a2,2,0,0,0,2-2V6a2,2,0,0,0-2-2Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_display_white.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_display_white.xml
new file mode 100644
index 0000000..580271b
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_display_white.xml
@@ -0,0 +1,33 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M3.41,14.72A2,2,0,0,1,4,16.14V18a2,2,0,0,0,2,2H7.86a2,2,0,0,1,1.42 0.59 l1.31,1.31a2,2,0,0,0,2.82,0l1.31-1.31A2,2,0,0,1,16.14,20H18a2,2,0,0,0,2-2V16.14a2,2,0,0,1,0.59-1.42l1.31-1.31a2,2,0,0,0,0-2.82L20.59,9.28A2,2,0,0,1,20,7.86V6a2,2,0,0,0-2-2H16.14a2,2,0,0,1-1.42-0.59L13.41,2.1a2,2,0,0,0-2.82,0L9.28,3.41A2,2,0,0,1,7.86,4H6A2,2,0,0,0,4,6V7.86a2,2,0,0,1-0.59,1.42L2.1,10.59a2,2,0,0,0,0,2.82Zm-0.6-3.43L4.12,10A3,3,0,0,0,5,7.86V6A1,1,0,0,1,6,5H7.86A3,3,0,0,0,10,4.12l1.31-1.31a1,1,0,0,1,1.42,0L14,4.12A3,3,0,0,0,16.14,5H18a1,1,0,0,1,1,1V7.86A3,3,0,0,0,19.88,10l1.31,1.31a1,1,0,0,1,0,1.42L19.88,14A3,3,0,0,0,19,16.14V18a1,1,0,0,1-1,1H16.14a3,3,0,0,0-2.12 0.88 l-1.31,1.31a1,1,0,0,1-1.42,0L10,19.88A3,3,0,0,0,7.86,19H6a1,1,0,0,1-1-1V16.14A3,3,0,0,0,4.12,14L2.81,12.71a1,1,0,0,1,0-1.42Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M17,12a5,5,0,0,0-5-5V17A5,5,0,0,0,17,12Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_location.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_location.xml
new file mode 100644
index 0000000..37d5576
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_location.xml
@@ -0,0 +1,33 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,21.5s7-5.34,7-11.25A7.13,7.13,0,0,0,12,3a7.13,7.13,0,0,0-7,7.25C5,16.16,12,21.5,12,21.5ZM12,4a6.13,6.13,0,0,1,6,6.25c0,4.37-4.37,8.54-6,10-1.63-1.4-6-5.57-6-9.95A6.13,6.13,0,0,1,12,4Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M15,10a3,3,0,1,0-3,3A3,3,0,0,0,15,10Zm-5,0a2,2,0,1,1,2,2A2,2,0,0,1,10,10Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_privacy.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_privacy.xml
new file mode 100644
index 0000000..32f9e53
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_privacy.xml
@@ -0,0 +1,36 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,17a9.48,9.48,0,0,1-8.92-5.5A9.48,9.48,0,0,1,12,6a9.5,9.5,0,0,1,8.65,5h1.13A10.5,10.5,0,0,0,12,5,10.47,10.47,0,0,0,2,11.5,10.47,10.47,0,0,0,12,18a11.48,11.48,0,0,0,4-0.7V16.22A10.48,10.48,0,0,1,12,17Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,8a3.5,3.5,0,1,0,3.5,3.5A3.5,3.5,0,0,0,12,8Zm0,6a2.5,2.5,0,1,1,2.5-2.5A2.5,2.5,0,0,1,12,14Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M22,15V14a2,2,0,0,0-4,0v1a1,1,0,0,0-1,1v3a1,1,0,0,0,1,1h4a1,1,0,0,0,1-1V16A1,1,0,0,0,22,15Zm-3,0V14a1,1,0,0,1,2,0v1Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_security_white.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_security_white.xml
new file mode 100644
index 0000000..71d427a
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_security_white.xml
@@ -0,0 +1,33 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,12a1.5,1.5,0,0,0-0.5,2.91V16.5a0.5 0.5 ,0,0,0,1,0V14.91A1.5,1.5,0,0,0,12,12Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M23,5a4,4,0,0,0-8,0V8H6A1,1,0,0,0,5,9v9a3,3,0,0,0,3,3h8a3,3,0,0,0,3-3V9a1,1,0,0,0-1-1H16V5a3,3,0,0,1,6,0,0.5 0.5 ,0,0,0,1,0ZM18,9v9a2,2,0,0,1-2,2H8a2,2,0,0,1-2-2V9H18Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_system_dashboard_white.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_system_dashboard_white.xml
new file mode 100644
index 0000000..f4b29ae
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_system_dashboard_white.xml
@@ -0,0 +1,36 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,22A10,10,0,1,0,2,12,10,10,0,0,0,12,22ZM12,3a9,9,0,1,1-9,9A9,9,0,0,1,12,3Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,11a0.5 0.5 ,0,0,0-0.5 0.5 v5a0.5 0.5 ,0,0,0,1,0v-5A0.5 0.5 ,0,0,0,12,11Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 7 C 12.4142135624 7 12.75 7.33578643763 12.75 7.75 C 12.75 8.16421356237 12.4142135624 8.5 12 8.5 C 11.5857864376 8.5 11.25 8.16421356237 11.25 7.75 C 11.25 7.33578643763 11.5857864376 7 12 7 Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_wireless_white.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_wireless_white.xml
new file mode 100644
index 0000000..85abfff
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_wireless_white.xml
@@ -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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 11.99 16.5 C 12.8184271247 16.5 13.49 17.1715728753 13.49 18 C 13.49 18.8284271247 12.8184271247 19.5 11.99 19.5 C 11.1615728753 19.5 10.49 18.8284271247 10.49 18 C 10.49 17.1715728753 11.1615728753 16.5 11.99 16.5 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M18.76,11.8a0.54 0.54 ,0,0,0,0.36-0.14 0.51 0.51,0,0,0,0-0.71A10.08,10.08,0,0,0,4.87,11a0.5 0.5 ,0,0,0,0,0.71 0.51 0.51,0,0,0,0.71,0,9.07,9.07,0,0,1,12.83,0A0.54 0.54 ,0,0,0,18.76,11.8Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M2.15,8.15a0.49 0.49 ,0,0,0,0.7 0.7 ,12.8,12.8,0,0,1,18.3,0,0.48 0.48 ,0,0,0,0.7,0,0.48 0.48 ,0,0,0,0-0.7A13.77,13.77,0,0,0,2.15,8.15Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M15.93,14.64a0.49 0.49 ,0,0,0,0.35-0.15 0.5 0.5,0,0,0,0-0.71,6.08,6.08,0,0,0-8.58,0,0.51 0.51 ,0,0,0,0,0.71 0.5 0.5,0,0,0,0.71,0,5.07,5.07,0,0,1,7.16,0A0.51 0.51 ,0,0,0,15.93,14.64Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_storage_white.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_storage_white.xml
new file mode 100644
index 0000000..ea7a97f
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_storage_white.xml
@@ -0,0 +1,45 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M3,5V7A1,1,0,0,0,4,8H20a1,1,0,0,0,1-1V5a2,2,0,0,0-2-2H5A2,2,0,0,0,3,5ZM20,5V7H4V5A1,1,0,0,1,5,4H19A1,1,0,0,1,20,5Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M3,19a1,1,0,0,0,1,1H20a1,1,0,0,0,1-1V17a2,2,0,0,0-2-2H5a2,2,0,0,0-2,2Zm1-2a1,1,0,0,1,1-1H19a1,1,0,0,1,1,1v2H4Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M3,13a1,1,0,0,0,1,1H20a1,1,0,0,0,1-1V11a2,2,0,0,0-2-2H5a2,2,0,0,0-2,2Zm1-2a1,1,0,0,1,1-1H19a1,1,0,0,1,1,1v2H4Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 6.01 4.75 C 6.42421356237 4.75 6.76 5.08578643763 6.76 5.5 C 6.76 5.91421356237 6.42421356237 6.25 6.01 6.25 C 5.59578643763 6.25 5.26 5.91421356237 5.26 5.5 C 5.26 5.08578643763 5.59578643763 4.75 6.01 4.75 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 6.01 10.75 C 6.42421356237 10.75 6.76 11.0857864376 6.76 11.5 C 6.76 11.9142135624 6.42421356237 12.25 6.01 12.25 C 5.59578643763 12.25 5.26 11.9142135624 5.26 11.5 C 5.26 11.0857864376 5.59578643763 10.75 6.01 10.75 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 6.01 16.75 C 6.42421356237 16.75 6.76 17.0857864376 6.76 17.5 C 6.76 17.9142135624 6.42421356237 18.25 6.01 18.25 C 5.59578643763 18.25 5.26 17.9142135624 5.26 17.5 C 5.26 17.0857864376 5.59578643763 16.75 6.01 16.75 Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_volume_up_24dp.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_volume_up_24dp.xml
new file mode 100644
index 0000000..7ed248d
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_volume_up_24dp.xml
@@ -0,0 +1,36 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M13.79,13.79a0.5 0.5 ,0,0,0,0.21,1,0.54 0.54 ,0,0,0,0.21-0.05,2.92,2.92,0,0,0,0-5.39 0.49 0.49,0,0,0-0.66 0.24 0.5 0.5 ,0,0,0,0.24 0.67 ,1.93,1.93,0,0,1,0,3.58Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M13.89,17.67a0.5 0.5 ,0,0,0,0.11,1l0.11,0a6.78,6.78,0,0,0,0-13.28 0.5 0.5,0,1,0-0.22,1,5.79,5.79,0,0,1,0,11.34Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M5,15H7l4.15,4.15a0.47 0.47 ,0,0,0,0.35 0.14 0.5 0.5 ,0,0,0,0.5-0.5V5.21a0.5 0.5 ,0,0,0-0.5-0.5 0.47 0.47,0,0,0-0.35 0.14 L7,9H5a2,2,0,0,0-2,2v2A2,2,0,0,0,5,15ZM4,11a1,1,0,0,1,1-1H7.41l0.3-0.29L11,6.41V17.59l-3.29-3.3L7.41,14H5a1,1,0,0,1-1-1Z" />
+</vector>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_wifi_tethering.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_wifi_tethering.xml
new file mode 100644
index 0000000..10c1592
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_wifi_tethering.xml
@@ -0,0 +1,36 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 11 C 12.8284271247 11 13.5 11.6715728753 13.5 12.5 C 13.5 13.3284271247 12.8284271247 14 12 14 C 11.1715728753 14 10.5 13.3284271247 10.5 12.5 C 10.5 11.6715728753 11.1715728753 11 12 11 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M15.18,16.39a0.51 0.51 ,0,0,0,0.71,0,5.5,5.5,0,0,0,0-7.78,5.52,5.52,0,0,0-7.78,0,5.5,5.5,0,0,0,0,7.78 0.5 0.5,0,0,0,0.35 0.15 0.51 0.51 ,0,0,0,0.36-0.15 0.51 0.51,0,0,0,0-0.71,4.5,4.5,0,1,1,6.36,0A0.51 0.51 ,0,0,0,15.18,16.39Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M18,19.22a0.49 0.49 ,0,0,0,0.35 0.14 0.5 0.5 ,0,0,0,0.36-0.14,9.5,9.5,0,1,0-13.44,0,0.51 0.51 ,0,0,0,0.71,0,0.5 0.5 ,0,0,0,0-0.71,8.5,8.5,0,0,1,12-12,8.5,8.5,0,0,1,0,12A0.5 0.5 ,0,0,0,18,19.22Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/Android.mk b/packages/overlays/IconPackFilledSettingsOverlay/Android.mk
new file mode 100644
index 0000000..0443560
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/Android.mk
@@ -0,0 +1,31 @@
+#
+#  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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := IconPackFilledSettings
+LOCAL_CERTIFICATE := platform
+LOCAL_PRODUCT_MODULE := true
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := IconPackFilledSettingsOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/AndroidManifest.xml b/packages/overlays/IconPackFilledSettingsOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..de81e21
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/AndroidManifest.xml
@@ -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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.theme.icon_pack.filled.settings"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <overlay android:targetPackage="com.android.settings" android:category="android.theme.customization.icon_pack.settings" android:priority="1"/>
+    <application android:label="Filled" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_apps.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_apps.xml
new file mode 100644
index 0000000..015e73e
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_apps.xml
@@ -0,0 +1,52 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 4.5 4 L 7.5 4 Q 8 4 8 4.5 L 8 7.5 Q 8 8 7.5 8 L 4.5 8 Q 4 8 4 7.5 L 4 4.5 Q 4 4 4.5 4 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 10.5 4 L 13.5 4 Q 14 4 14 4.5 L 14 7.5 Q 14 8 13.5 8 L 10.5 8 Q 10 8 10 7.5 L 10 4.5 Q 10 4 10.5 4 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 16.5 4 L 19.5 4 Q 20 4 20 4.5 L 20 7.5 Q 20 8 19.5 8 L 16.5 8 Q 16 8 16 7.5 L 16 4.5 Q 16 4 16.5 4 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 4.5 10 L 7.5 10 Q 8 10 8 10.5 L 8 13.5 Q 8 14 7.5 14 L 4.5 14 Q 4 14 4 13.5 L 4 10.5 Q 4 10 4.5 10 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 10.5 10 L 13.5 10 Q 14 10 14 10.5 L 14 13.5 Q 14 14 13.5 14 L 10.5 14 Q 10 14 10 13.5 L 10 10.5 Q 10 10 10.5 10 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 16.5 10 L 19.5 10 Q 20 10 20 10.5 L 20 13.5 Q 20 14 19.5 14 L 16.5 14 Q 16 14 16 13.5 L 16 10.5 Q 16 10 16.5 10 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 4.5 16 L 7.5 16 Q 8 16 8 16.5 L 8 19.5 Q 8 20 7.5 20 L 4.5 20 Q 4 20 4 19.5 L 4 16.5 Q 4 16 4.5 16 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 10.5 16 L 13.5 16 Q 14 16 14 16.5 L 14 19.5 Q 14 20 13.5 20 L 10.5 20 Q 10 20 10 19.5 L 10 16.5 Q 10 16 10.5 16 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 16.5 16 L 19.5 16 Q 20 16 20 16.5 L 20 19.5 Q 20 20 19.5 20 L 16.5 20 Q 16 20 16 19.5 L 16 16.5 Q 16 16 16.5 16 Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_devices_other.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_devices_other.xml
new file mode 100644
index 0000000..0b12655
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_devices_other.xml
@@ -0,0 +1,34 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M3,20H6a1,1,0,0,0,0-2H3V6H20a1,1,0,0,0,0-2H3A2,2,0,0,0,1,6V18A2,2,0,0,0,3,20Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M23,19V9a1.08,1.08,0,0,0-1-1H16a1.08,1.08,0,0,0-1,1V19a1.08,1.08,0,0,0,1,1h6A1.08,1.08,0,0,0,23,19Zm-2-1H17V10h4Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M9,12v1.78a3,3,0,0,0,0,4.44V20h4V18.22a3,3,0,0,0,0-4.44V12Zm2,5.5A1.5,1.5,0,1,1,12.5,16,1.5,1.5,0,0,1,11,17.5Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_help.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_help.xml
new file mode 100644
index 0000000..097894d
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_help.xml
@@ -0,0 +1,28 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,2A10,10,0,1,0,22,12,10,10,0,0,0,12,2Zm0,16.81a1.3,1.3,0,1,1,1.3-1.3A1.3,1.3,0,0,1,12,18.81Zm1.07-4.62a1,1,0,0,1-1.13 0.79 ,1,1,0,0,1-0.83-1.23c0.52-2.61,2.66-2.84,2.87-4.5a2,2,0,0,0-1.34-2.17,2,2,0,0,0-2.55,1.37,1,1,0,1,1-1.93-0.53A4,4,0,0,1,16,9.13C15.92,11.57,13.5,11.74,13.07,14.19Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_phone_info.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_phone_info.xml
new file mode 100644
index 0000000..80f3d1e7
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_phone_info.xml
@@ -0,0 +1,34 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M7,1A2,2,0,0,0,5,3V21a2,2,0,0,0,2,2H17a2,2,0,0,0,2-2V3a2,2,0,0,0-2-2ZM17,19H7V5H17Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,11.62a1,1,0,0,0-1,0.9v3.59a1,1,0,0,0,2,0V12.52A1,1,0,0,0,12,11.62Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 7.06 C 12.6903559373 7.06 13.25 7.61964406271 13.25 8.31 C 13.25 9.00035593729 12.6903559373 9.56 12 9.56 C 11.3096440627 9.56 10.75 9.00035593729 10.75 8.31 C 10.75 7.61964406271 11.3096440627 7.06 12 7.06 Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_accessibility.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_accessibility.xml
new file mode 100644
index 0000000..9c8287b
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_accessibility.xml
@@ -0,0 +1,40 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M20.76,5l0-0.06a1,1,0,0,0-1.2-0.72A35.66,35.66,0,0,1,12,5a35.66,35.66,0,0,1-7.54-0.76A1,1,0,0,0,3.26,5l0,0.06A1,1,0,0,0,4,6.24,37,37,0,0,0,9,7V19a1,1,0,0,0,2,0V14h2v5a1,1,0,0,0,2,0V7a37,37,0,0,0,5-0.76A1,1,0,0,0,20.76,5Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 0 C 13.1045694997 0 14 0.895430500338 14 2 C 14 3.10456949966 13.1045694997 4 12 4 C 10.8954305003 4 10 3.10456949966 10 2 C 10 0.895430500338 10.8954305003 0 12 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 22 C 12.5522847498 22 13 22.4477152502 13 23 C 13 23.5522847498 12.5522847498 24 12 24 C 11.4477152502 24 11 23.5522847498 11 23 C 11 22.4477152502 11.4477152502 22 12 22 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 16 22 C 16.5522847498 22 17 22.4477152502 17 23 C 17 23.5522847498 16.5522847498 24 16 24 C 15.4477152502 24 15 23.5522847498 15 23 C 15 22.4477152502 15.4477152502 22 16 22 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 8 22 C 8.55228474983 22 9 22.4477152502 9 23 C 9 23.5522847498 8.55228474983 24 8 24 C 7.44771525017 24 7 23.5522847498 7 23 C 7 22.4477152502 7.44771525017 22 8 22 Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_accounts.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_accounts.xml
new file mode 100644
index 0000000..ea418a8
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_accounts.xml
@@ -0,0 +1,31 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,22A10,10,0,1,0,2,12,10,10,0,0,0,12,22ZM12,4a8,8,0,0,1,6.36,12.83c-1.43-1.74-4.9-2.33-6.36-2.33s-4.93 0.59 -6.36,2.33A8,8,0,0,1,12,4Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 6 C 13.9329966244 6 15.5 7.56700337559 15.5 9.5 C 15.5 11.4329966244 13.9329966244 13 12 13 C 10.0670033756 13 8.5 11.4329966244 8.5 9.5 C 8.5 7.56700337559 10.0670033756 6 12 6 Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_battery_white.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_battery_white.xml
new file mode 100644
index 0000000..1c5df00
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_battery_white.xml
@@ -0,0 +1,28 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M10,2V4H8.33A1.34,1.34,0,0,0,7,5.33V20.66A1.34,1.34,0,0,0,8.33,22h7.33A1.34,1.34,0,0,0,17,20.67V5.33A1.34,1.34,0,0,0,15.67,4H14V2Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_display_white.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_display_white.xml
new file mode 100644
index 0000000..02e15d2
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_display_white.xml
@@ -0,0 +1,28 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M4,15.3V19a1,1,0,0,0,1,1H8.69l2.6,2.6a1,1,0,0,0,1.41,0L15.3,20H19a1,1,0,0,0,1-1V15.31l2.6-2.6a1,1,0,0,0,0-1.41L20,8.69V5a1,1,0,0,0-1-1H15.31l-2.6-2.6a1,1,0,0,0-1.41,0L8.69,4H5A1,1,0,0,0,4,5V8.69l-2.6,2.6a1,1,0,0,0,0,1.41ZM12,6a6,6,0,0,1,0,12Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_location.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_location.xml
new file mode 100644
index 0000000..818236b
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_location.xml
@@ -0,0 +1,28 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,2A7,7,0,0,0,5,9c0,4.17,4.42,9.92,6.24,12.11a1,1,0,0,0,1.53,0C14.58,18.92,19,13.17,19,9A7,7,0,0,0,12,2Zm0,9.5A2.5,2.5,0,1,1,14.5,9,2.5,2.5,0,0,1,12,11.5Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_privacy.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_privacy.xml
new file mode 100644
index 0000000..b080882
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_privacy.xml
@@ -0,0 +1,34 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,19a12,12,0,0,0,2-0.17v-2A10.13,10.13,0,0,1,12,17a9.77,9.77,0,0,1-8.82-5.5,9.82,9.82,0,0,1,17.64,0H23a11.82,11.82,0,0,0-22,0A11.83,11.83,0,0,0,12,19Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M16.5,11.5a4.55,4.55,0,1,0-2.38,3.95,5,5,0,0,1,2.31-3.22A4.4,4.4,0,0,0,16.5,11.5ZM12,14.2a2.7,2.7,0,1,1,2.7-2.7A2.7,2.7,0,0,1,12,14.2Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M23,21V17a1.08,1.08,0,0,0-1-1v-0.5a2.5,2.5,0,0,0-5,0V16a1.08,1.08,0,0,0-1,1v4a1.08,1.08,0,0,0,1,1h5A1.08,1.08,0,0,0,23,21Zm-2.5-5h-2v-0.5a1,1,0,0,1,2,0Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_security_white.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_security_white.xml
new file mode 100644
index 0000000..39ac0d7
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_security_white.xml
@@ -0,0 +1,28 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M23,6a1,1,0,0,0,0.92-1.2A5,5,0,0,0,18.57,1a5.15,5.15,0,0,0-4.51,5.19V8H6a2,2,0,0,0-2,2V20a2,2,0,0,0,2,2H18a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2H16V6.12A3.18,3.18,0,0,1,18.44,3a3.1,3.1,0,0,1,3.62,2.27A1,1,0,0,0,23,6ZM12,17a2,2,0,1,1,2-2A2,2,0,0,1,12,17Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_system_dashboard_white.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_system_dashboard_white.xml
new file mode 100644
index 0000000..3c29998
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_system_dashboard_white.xml
@@ -0,0 +1,28 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M2,12A10,10,0,1,0,12,2,10,10,0,0,0,2,12Zm11,5.42a1,1,0,0,1-2,0V10.68a1,1,0,0,1,2,0ZM12,5.58a1.35,1.35,0,1,1-1.35,1.35A1.34,1.34,0,0,1,12,5.58Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_wireless_white.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_wireless_white.xml
new file mode 100644
index 0000000..8fa846e
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_wireless_white.xml
@@ -0,0 +1,34 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M11.29,19.29a1,1,0,0,0,1.42,0L14,18a1,1,0,0,0-0.22-1.58A3.92,3.92,0,0,0,12,16a4,4,0,0,0-1.77 0.41 A1,1,0,0,0,10,18Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M17.6,14.39l0.71-0.71a1,1,0,0,0-0.08-1.49,10,10,0,0,0-12.44,0,1,1,0,0,0-0.08,1.49l0.7 0.72 a1,1,0,0,0,1.32 0.08 A6.91,6.91,0,0,1,12,13a7,7,0,0,1,4.29,1.47A1,1,0,0,0,17.6,14.39Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M21.83,10.16l0.71-0.71A1,1,0,0,0,22.48,8a15.79,15.79,0,0,0-20.92,0,1,1,0,0,0-0.07,1.47l0.71 0.71 a1,1,0,0,0,1.35 0.07 ,12.79,12.79,0,0,1,16.94,0A1,1,0,0,0,21.83,10.16Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_storage_white.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_storage_white.xml
new file mode 100644
index 0000000..82733b6
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_storage_white.xml
@@ -0,0 +1,34 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M4,14H20a2,2,0,0,0,0-4H4a2,2,0,0,0,0,4Zm1-3.1A1.1,1.1,0,1,1,3.9,12,1.1,1.1,0,0,1,5,10.9Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M4,8H20a2,2,0,0,0,0-4H4A2,2,0,0,0,4,8ZM5,4.9A1.1,1.1,0,1,1,3.9,6,1.1,1.1,0,0,1,5,4.9Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M4,20H20a2,2,0,0,0,0-4H4a2,2,0,0,0,0,4Zm1-3.1A1.1,1.1,0,1,1,3.9,18,1.1,1.1,0,0,1,5,16.9Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_volume_up_24dp.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_volume_up_24dp.xml
new file mode 100644
index 0000000..9587e54
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_volume_up_24dp.xml
@@ -0,0 +1,34 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M10.29,5.7,7,9H4a1,1,0,0,0-1,1v4a1,1,0,0,0,1,1H7l3.29,3.29A1,1,0,0,0,12,17.58V6.41A1,1,0,0,0,10.29,5.7Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M16.5,12A4.5,4.5,0,0,0,14,8V16A4.47,4.47,0,0,0,16.5,12Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M14,19.54a0.91 0.91 ,0,0,0,1.22 0.86 ,9,9,0,0,0,0-16.8A0.91 0.91 ,0,0,0,14,4.46v0.19a0.92 0.92 ,0,0,0,0.61 0.85 ,7,7,0,0,1,0,13,0.92 0.92 ,0,0,0-0.61 0.85 Z" />
+</vector>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_wifi_tethering.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_wifi_tethering.xml
new file mode 100644
index 0000000..84c347b
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_wifi_tethering.xml
@@ -0,0 +1,34 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M15.46,16.46h0A1,1,0,0,0,17,16.35,5.9,5.9,0,0,0,18,13,6,6,0,1,0,7,16.35a1,1,0,0,0,1.51 0.11 h0a1,1,0,0,0,0.11-1.29A3.9,3.9,0,0,1,8,12.44a4,4,0,1,1,7.32,2.73A1,1,0,0,0,15.46,16.46Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M10.86,3.06A10,10,0,0,0,4.19,19.25a1,1,0,0,0,1.49 0.07 A1,1,0,0,0,5.75,18a8.05,8.05,0,0,1-1.59-6.61A8,8,0,0,1,20,13a7.89,7.89,0,0,1-1.77,5,1,1,0,0,0,0.08,1.31h0a1,1,0,0,0,1.49-0.07A9.9,9.9,0,0,0,22,13,10,10,0,0,0,10.86,3.06Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M10,13a2,2,0,1,0,2-2A2,2,0,0,0,10,13Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/Android.mk b/packages/overlays/IconPackRoundedSettingsOverlay/Android.mk
new file mode 100644
index 0000000..44ac6dd
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/Android.mk
@@ -0,0 +1,31 @@
+#
+#  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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := IconPackRoundedSettings
+LOCAL_CERTIFICATE := platform
+LOCAL_PRODUCT_MODULE := true
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := IconPackRoundedSettingsOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/AndroidManifest.xml b/packages/overlays/IconPackRoundedSettingsOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..df71e15
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/AndroidManifest.xml
@@ -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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.theme.icon_pack.rounded.settings"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <overlay android:targetPackage="com.android.settings" android:category="android.theme.customization.icon_pack.settings" android:priority="1"/>
+    <application android:label="Rounded" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_apps.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_apps.xml
new file mode 100644
index 0000000..62acfc6
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_apps.xml
@@ -0,0 +1,52 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 5.5 4 L 6.5 4 Q 8 4 8 5.5 L 8 6.5 Q 8 8 6.5 8 L 5.5 8 Q 4 8 4 6.5 L 4 5.5 Q 4 4 5.5 4 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 11.5 4 L 12.5 4 Q 14 4 14 5.5 L 14 6.5 Q 14 8 12.5 8 L 11.5 8 Q 10 8 10 6.5 L 10 5.5 Q 10 4 11.5 4 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 17.5 4 L 18.5 4 Q 20 4 20 5.5 L 20 6.5 Q 20 8 18.5 8 L 17.5 8 Q 16 8 16 6.5 L 16 5.5 Q 16 4 17.5 4 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 5.5 10 L 6.5 10 Q 8 10 8 11.5 L 8 12.5 Q 8 14 6.5 14 L 5.5 14 Q 4 14 4 12.5 L 4 11.5 Q 4 10 5.5 10 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 11.5 10 L 12.5 10 Q 14 10 14 11.5 L 14 12.5 Q 14 14 12.5 14 L 11.5 14 Q 10 14 10 12.5 L 10 11.5 Q 10 10 11.5 10 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 17.5 10 L 18.5 10 Q 20 10 20 11.5 L 20 12.5 Q 20 14 18.5 14 L 17.5 14 Q 16 14 16 12.5 L 16 11.5 Q 16 10 17.5 10 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 5.5 16 L 6.5 16 Q 8 16 8 17.5 L 8 18.5 Q 8 20 6.5 20 L 5.5 20 Q 4 20 4 18.5 L 4 17.5 Q 4 16 5.5 16 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 11.5 16 L 12.5 16 Q 14 16 14 17.5 L 14 18.5 Q 14 20 12.5 20 L 11.5 20 Q 10 20 10 18.5 L 10 17.5 Q 10 16 11.5 16 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 17.5 16 L 18.5 16 Q 20 16 20 17.5 L 20 18.5 Q 20 20 18.5 20 L 17.5 20 Q 16 20 16 18.5 L 16 17.5 Q 16 16 17.5 16 Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_devices_other.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_devices_other.xml
new file mode 100644
index 0000000..be7f297
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_devices_other.xml
@@ -0,0 +1,34 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M22,18V10a1.5,1.5,0,0,0-1.5-1.5h-4A1.5,1.5,0,0,0,15,10v8a1.5,1.5,0,0,0,1.5,1.5h4A1.5,1.5,0,0,0,22,18Zm-5.5-8h4v8h-4Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M13,17a2.5,2.5,0,1,0-2.5,2.5A2.5,2.5,0,0,0,13,17ZM9.5,17a1,1,0,1,1,1,1A1,1,0,0,1,9.5,17Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M21.25,4H3.5A1.5,1.5,0,0,0,2,5.5V18a1.5,1.5,0,0,0,1.5,1.5H5.25a0.75 0.75 ,0,0,0,0-1.5H3.5V5.5H21.25a0.75 0.75 ,0,0,0,0-1.5Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_help.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_help.xml
new file mode 100644
index 0000000..e8c3e47
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_help.xml
@@ -0,0 +1,34 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,22h0A10,10,0,0,0,22,12v0A10,10,0,1,0,12,22ZM12,3.5A8.51,8.51,0,0,1,20.5,12h0.75l-0.75,0A8.49,8.49,0,0,1,12,20.5h0a8.5,8.5,0,0,1,0-17Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M8.67,10a0.77 0.77 ,0,0,0,0.91-0.56,2.48,2.48,0,0,1,0.65-1.19,2.57,2.57,0,0,1,3.54,0A2.2,2.2,0,0,1,14.43,10a1.81,1.81,0,0,1-0.84,1.37c-0.13 0.09 -0.26 0.16 -0.4 0.24 a3.3,3.3,0,0,0-1.93,2.51 0.76 0.76,0,0,0,0.62 0.87 H12a0.75 0.75 ,0,0,0,0.74-0.62,1.84,1.84,0,0,1,1.19-1.46l0.49-0.29a3.32,3.32,0,0,0,1.5-2.48,3.71,3.71,0,0,0-1.09-3,4.1,4.1,0,0,0-5.66,0,4,4,0,0,0-1.05,1.9A0.75 0.75 ,0,0,0,8.67,10Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 16 C 12.5522847498 16 13 16.4477152502 13 17 C 13 17.5522847498 12.5522847498 18 12 18 C 11.4477152502 18 11 17.5522847498 11 17 C 11 16.4477152502 11.4477152502 16 12 16 Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_phone_info.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_phone_info.xml
new file mode 100644
index 0000000..e5e57d4
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_phone_info.xml
@@ -0,0 +1,34 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M8,1A3,3,0,0,0,5,4V20a3,3,0,0,0,3,3h8a3,3,0,0,0,3-3V4a3,3,0,0,0-3-3Zm8,20.5H8A1.5,1.5,0,0,1,6.5,20h11A1.5,1.5,0,0,1,16,21.5Zm1.5-3H6.5V5.5h11ZM17.5,4H6.5A1.5,1.5,0,0,1,8,2.5h8A1.5,1.5,0,0,1,17.5,4Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,11.25a0.76 0.76 ,0,0,0-0.75 0.75 v4a0.75 0.75 ,0,0,0,1.5,0V12A0.76 0.76 ,0,0,0,12,11.25Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 7 C 12.5522847498 7 13 7.44771525017 13 8 C 13 8.55228474983 12.5522847498 9 12 9 C 11.4477152502 9 11 8.55228474983 11 8 C 11 7.44771525017 11.4477152502 7 12 7 Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_accessibility.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_accessibility.xml
new file mode 100644
index 0000000..1ac58b5
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_accessibility.xml
@@ -0,0 +1,40 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M14.25,2.5A2.25,2.25,0,1,0,12,4.75,2.25,2.25,0,0,0,14.25,2.5Zm-3,0a0.75 0.75 ,0,1,1,0.75 0.75 A0.76 0.76 ,0,0,1,11.25,2.5Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M20.72,5.28a0.77 0.77 ,0,0,0-0.94-0.5,29.53,29.53,0,0,1-7.78,1,29.72,29.72,0,0,1-7.78-1,0.75 0.75 ,0,0,0-0.44,1.44A28.14,28.14,0,0,0,9,7.12V19a0.75 0.75 ,0,0,0,1.5,0V14h3v5A0.75 0.75 ,0,0,0,15,19V7.12a28.14,28.14,0,0,0,5.22-0.9A0.76 0.76 ,0,0,0,20.72,5.28Zm-7.22,2V12.5h-3V7.25Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 8 22 C 8.55228474983 22 9 22.4477152502 9 23 C 9 23.5522847498 8.55228474983 24 8 24 C 7.44771525017 24 7 23.5522847498 7 23 C 7 22.4477152502 7.44771525017 22 8 22 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 22 C 12.5522847498 22 13 22.4477152502 13 23 C 13 23.5522847498 12.5522847498 24 12 24 C 11.4477152502 24 11 23.5522847498 11 23 C 11 22.4477152502 11.4477152502 22 12 22 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 16 22 C 16.5522847498 22 17 22.4477152502 17 23 C 17 23.5522847498 16.5522847498 24 16 24 C 15.4477152502 24 15 23.5522847498 15 23 C 15 22.4477152502 15.4477152502 22 16 22 Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_accounts.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_accounts.xml
new file mode 100644
index 0000000..90da97f
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_accounts.xml
@@ -0,0 +1,31 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M6.21,20.14l0.08 0.06 A10,10,0,0,0,12,22h0a10,10,0,0,0,5.76-1.84h0A10,10,0,0,0,22,12v0A10,10,0,1,0,6.21,20.14Zm5.8 0.36 h0a8.45,8.45,0,0,1-4.5-1.3V15.75A0.76 0.76 ,0,0,1,8.25,15h7.5a0.76 0.76 ,0,0,1,0.75 0.75 V19.2A8.39,8.39,0,0,1,12,20.5Zm0-17A8.51,8.51,0,0,1,20.5,12h0.75l-0.75,0A8.47,8.47,0,0,1,18,18V15.75a2.25,2.25,0,0,0-2.25-2.25H8.25A2.25,2.25,0,0,0,6,15.75V18A8.49,8.49,0,0,1,12,3.5Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,12h0A3,3,0,1,0,9,9H9A3,3,0,0,0,12,12ZM10.5,9A1.5,1.5,0,1,1,12,10.5h0A1.5,1.5,0,0,1,10.5,9Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_battery_white.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_battery_white.xml
new file mode 100644
index 0000000..3f3b95a
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_battery_white.xml
@@ -0,0 +1,28 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M13,2.49H11a1,1,0,0,0-1,1V4H7A1,1,0,0,0,6,5V21a1,1,0,0,0,1,1H17a1,1,0,0,0,1-1V5a1,1,0,0,0-1-1H14V3.49A1,1,0,0,0,13,2.49Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_display_white.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_display_white.xml
new file mode 100644
index 0000000..54993e2
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_display_white.xml
@@ -0,0 +1,52 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M19.5,12h0A7.5,7.5,0,1,0,12,19.5h0A7.49,7.49,0,0,0,19.5,12ZM12,18h0a6,6,0,1,1,6-6h0a6,6,0,0,1-6,6Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 1.5 C 12.4142135624 1.5 12.75 1.83578643763 12.75 2.25 C 12.75 2.66421356237 12.4142135624 3 12 3 C 11.5857864376 3 11.25 2.66421356237 11.25 2.25 C 11.25 1.83578643763 11.5857864376 1.5 12 1.5 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 5.1 4.35 C 5.51421356237 4.35 5.85 4.68578643763 5.85 5.1 C 5.85 5.51421356237 5.51421356237 5.85 5.1 5.85 C 4.68578643763 5.85 4.35 5.51421356237 4.35 5.1 C 4.35 4.68578643763 4.68578643763 4.35 5.1 4.35 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 2.25 11.25 C 2.66421356237 11.25 3 11.5857864376 3 12 C 3 12.4142135624 2.66421356237 12.75 2.25 12.75 C 1.83578643763 12.75 1.5 12.4142135624 1.5 12 C 1.5 11.5857864376 1.83578643763 11.25 2.25 11.25 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 5.1 18.15 C 5.51421356237 18.15 5.85 18.4857864376 5.85 18.9 C 5.85 19.3142135624 5.51421356237 19.65 5.1 19.65 C 4.68578643763 19.65 4.35 19.3142135624 4.35 18.9 C 4.35 18.4857864376 4.68578643763 18.15 5.1 18.15 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 21 C 12.4142135624 21 12.75 21.3357864376 12.75 21.75 C 12.75 22.1642135624 12.4142135624 22.5 12 22.5 C 11.5857864376 22.5 11.25 22.1642135624 11.25 21.75 C 11.25 21.3357864376 11.5857864376 21 12 21 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 18.9 18.15 C 19.3142135624 18.15 19.65 18.4857864376 19.65 18.9 C 19.65 19.3142135624 19.3142135624 19.65 18.9 19.65 C 18.4857864376 19.65 18.15 19.3142135624 18.15 18.9 C 18.15 18.4857864376 18.4857864376 18.15 18.9 18.15 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 21.75 11.25 C 22.1642135624 11.25 22.5 11.5857864376 22.5 12 C 22.5 12.4142135624 22.1642135624 12.75 21.75 12.75 C 21.3357864376 12.75 21 12.4142135624 21 12 C 21 11.5857864376 21.3357864376 11.25 21.75 11.25 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 18.9 4.35 C 19.3142135624 4.35 19.65 4.68578643763 19.65 5.1 C 19.65 5.51421356237 19.3142135624 5.85 18.9 5.85 C 18.4857864376 5.85 18.15 5.51421356237 18.15 5.1 C 18.15 4.68578643763 18.4857864376 4.35 18.9 4.35 Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_location.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_location.xml
new file mode 100644
index 0000000..26aa308
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_location.xml
@@ -0,0 +1,31 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M15,10a3,3,0,1,0-3,3A3,3,0,0,0,15,10Zm-4.5,0A1.5,1.5,0,1,1,12,11.5,1.5,1.5,0,0,1,10.5,10Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M11.37,21.76A1,1,0,0,0,12,22a1,1,0,0,0,0.62-0.22C14.5,20.26,20,15.5,20,10a8,8,0,0,0-8-8,7.89,7.89,0,0,0-8,8C4,15.5,9.48,20.25,11.37,21.76ZM12,3.51A6.5,6.5,0,0,1,18.5,10c0,4.4-4.31,8.53-6.5,10.34C9.82,18.54,5.5,14.4,5.5,10A6.43,6.43,0,0,1,12,3.51Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_privacy.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_privacy.xml
new file mode 100644
index 0000000..a6619bd
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_privacy.xml
@@ -0,0 +1,34 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,8a4,4,0,0,0,0,8,3.94,3.94,0,0,0,2.23-0.68,5.06,5.06,0,0,1,1.67-2.47A4,4,0,0,0,16,12,4,4,0,0,0,12,8Zm0,6.5A2.5,2.5,0,1,1,14.5,12,2.5,2.5,0,0,1,12,14.5Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M1.55,12.27C1.67,12.58,4.58,20,12,20a10.57,10.57,0,0,0,2-0.21V18.27a8.44,8.44,0,0,1-2,0.23c-5.72,0-8.37-5.22-8.94-6.5C3.63,10.75,6.33,5.5,12,5.5s8.38,5.22,9,6.5l-0.06 0.12 a4.84,4.84,0,0,1,1.28 0.8 c0.17-0.36 0.27 -0.6 0.29 -0.65a0.72 0.72 ,0,0,0,0-0.54C22.34,11.42,19.43,4,12,4S1.67,11.42,1.55,11.73A0.72 0.72 ,0,0,0,1.55,12.27Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M21.25,16.5v-0.66a2.26,2.26,0,0,0-4.5,0v0.66H16V22h6V16.5Zm-3,0v-0.66c0-0.29 0.38 -0.59 0.75 -0.59s0.75 0.3 0.75 0.59 v0.66Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_security_white.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_security_white.xml
new file mode 100644
index 0000000..d769f4f
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_security_white.xml
@@ -0,0 +1,31 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 13.5 C 12.8284271247 13.5 13.5 14.1715728753 13.5 15 C 13.5 15.8284271247 12.8284271247 16.5 12 16.5 C 11.1715728753 16.5 10.5 15.8284271247 10.5 15 C 10.5 14.1715728753 11.1715728753 13.5 12 13.5 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M18.51,3A2.32,2.32,0,0,1,21,5.15a0.79 0.79 ,0,0,0,0.76 0.74 0.75 0.75 ,0,0,0,0.74-0.77,3.8,3.8,0,0,0-4-3.66,3.83,3.83,0,0,0-4,3.68V8.5h-9A1.5,1.5,0,0,0,4,10V20a1.5,1.5,0,0,0,1.5,1.5h13A1.5,1.5,0,0,0,20,20V10a1.5,1.5,0,0,0-1.5-1.5H16V5.15A2.35,2.35,0,0,1,18.51,3Zm0,17H5.5V10h13Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_system_dashboard_white.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_system_dashboard_white.xml
new file mode 100644
index 0000000..ee990f9
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_system_dashboard_white.xml
@@ -0,0 +1,34 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M19.07,4.93A10,10,0,1,0,22,12,10,10,0,0,0,19.07,4.93ZM18,18a8.5,8.5,0,1,1,2.5-6A8.53,8.53,0,0,1,18,18Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,10a0.76 0.76 ,0,0,0-0.75 0.75 v5.5a0.75 0.75 ,0,0,0,1.5,0v-5.5A0.76 0.76 ,0,0,0,12,10Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 7 C 12.5522847498 7 13 7.44771525017 13 8 C 13 8.55228474983 12.5522847498 9 12 9 C 11.4477152502 9 11 8.55228474983 11 8 C 11 7.44771525017 11.4477152502 7 12 7 Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_wireless_white.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_wireless_white.xml
new file mode 100644
index 0000000..ffd2c64
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_wireless_white.xml
@@ -0,0 +1,37 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M15.78,14.82a0.57 0.57 ,0,0,0,0.16 0.15 0.75 0.75 ,0,0,0,1-0.2 0.76 0.76,0,0,0-0.2-1,6.77,6.77,0,0,0-9.55,0,0.76 0.76 ,0,0,0,0,1,0.75 0.75 ,0,0,0,1.06,0h0a5.24,5.24,0,0,1,7.42,0A0.08 0.08 ,0,0,0,15.78,14.82Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 17 C 12.8284271247 17 13.5 17.6715728753 13.5 18.5 C 13.5 19.3284271247 12.8284271247 20 12 20 C 11.1715728753 20 10.5 19.3284271247 10.5 18.5 C 10.5 17.6715728753 11.1715728753 17 12 17 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M20,11.79a0.77 0.77 ,0,0,0,0-1.07h0a11.59,11.59,0,0,0-8-3.5,11.63,11.63,0,0,0-8,3.5 0.77 0.77,0,0,0,0,1.07 0.76 0.76,0,0,0,1.07,0,10.12,10.12,0,0,1,7-3,10.12,10.12,0,0,1,7,3A0.75 0.75 ,0,0,0,20,11.79Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,2.75A14.76,14.76,0,0,0,1.22,7.2a0.77 0.77 ,0,0,0,0,1,0.75 0.75 ,0,0,0,1.06,0,13.25,13.25,0,0,1,9.7-4,13.27,13.27,0,0,1,9.72,4,0.73 0.73 ,0,0,0,1,0,0.75 0.75 ,0,0,0,0.05-1.06A14.76,14.76,0,0,0,12,2.75Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_storage_white.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_storage_white.xml
new file mode 100644
index 0000000..e6125db
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_storage_white.xml
@@ -0,0 +1,43 @@
+<!--
+/**
+ * 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:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M21,2.75A0.76 0.76 ,0,0,0,20.25,2H3.75A0.76 0.76 ,0,0,0,3,2.75v4.5A0.76 0.76 ,0,0,0,3.75,8h16.5A0.76 0.76 ,0,0,0,21,7.25ZM19.5,6.5H4.5v-3h15Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 5.25 4.25 H 6.75 V 5.75 H 5.25 V 4.25 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M21,9.75A0.76 0.76 ,0,0,0,20.25,9H3.75A0.76 0.76 ,0,0,0,3,9.75v4.5a0.76 0.76 ,0,0,0,0.75 0.75 h16.5a0.76 0.76 ,0,0,0,0.75-0.75ZM19.5,13.5H4.5v-3h15Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 5.25 11.25 H 6.75 V 12.75 H 5.25 V 11.25 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M21,21.25v-4.5a0.76 0.76 ,0,0,0-0.75-0.75H3.75a0.76 0.76 ,0,0,0-0.75 0.75 v4.5a0.76 0.76 ,0,0,0,0.75 0.75 h16.5A0.76 0.76 ,0,0,0,21,21.25Zm-1.5-0.75H4.5v-3h15Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 5.25 18.25 H 6.75 V 19.75 H 5.25 V 18.25 Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_volume_up_24dp.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_volume_up_24dp.xml
new file mode 100644
index 0000000..76d3e5f
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_volume_up_24dp.xml
@@ -0,0 +1,34 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M5.69,16l5,5a0.77 0.77 ,0,0,0,0.53 0.22 0.75 0.75 ,0,0,0,0.29-0.06A0.74 0.74 ,0,0,0,12,20.5V3.5A0.75 0.75 ,0,0,0,10.72,3l-5,5H3.49A1.52,1.52,0,0,0,2,9.5v5A1.5,1.5,0,0,0,3.5,16ZM3.5,9.5H6a0.75 0.75 ,0,0,0,0.53-0.22l4-4V18.69l-4-4A0.75 0.75 ,0,0,0,6,14.5H3.5Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M13.52,20.64a0.77 0.77 ,0,0,0,0.73 0.56 0.63 0.63 ,0,0,0,0.19,0,9.48,9.48,0,0,0,0-18.34 0.75 0.75,0,0,0-0.92 0.53 0.76 0.76 ,0,0,0,0.54 0.92 ,8,8,0,0,1,0,15.44A0.76 0.76 ,0,0,0,13.52,20.64Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M13.85,15a0.76 0.76 ,0,0,0-0.24,1,0.78 0.78 ,0,0,0,0.64 0.35 0.83 0.83 ,0,0,0,0.4-0.11,5,5,0,0,0,1.6-6.88,5.2,5.2,0,0,0-1.6-1.6A0.75 0.75 ,0,1,0,13.85,9,3.33,3.33,0,0,1,15,10.16,3.47,3.47,0,0,1,13.85,15Z" />
+</vector>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_wifi_tethering.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_wifi_tethering.xml
new file mode 100644
index 0000000..eadd300
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_wifi_tethering.xml
@@ -0,0 +1,34 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 12 11 C 12.8284271247 11 13.5 11.6715728753 13.5 12.5 C 13.5 13.3284271247 12.8284271247 14 12 14 C 11.1715728753 14 10.5 13.3284271247 10.5 12.5 C 10.5 11.6715728753 11.1715728753 11 12 11 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M15,16.57a0.75 0.75 ,0,0,0,1.06,0,5.75,5.75,0,1,0-8.14,0,0.79 0.79 ,0,0,0,0.53 0.22 A0.75 0.75 ,0,0,0,9,16.57a0.74 0.74 ,0,0,0,0-1.06,4.25,4.25,0,1,1,6,0A0.75 0.75 ,0,0,0,15,16.57Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M18.36,19.61a0.71 0.71 ,0,0,0,0.53-0.22A9.74,9.74,0,0,0,5.11,5.61a9.73,9.73,0,0,0,0,13.78 0.74 0.74,0,0,0,1.06,0,0.75 0.75 ,0,0,0,0-1.06A8.24,8.24,0,0,1,17.83,6.67a8.23,8.23,0,0,1,0,11.66 0.75 0.75,0,0,0,0,1.06A0.74 0.74 ,0,0,0,18.36,19.61Z" />
+</vector>
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 76bb24d..eb8710d 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6936,6 +6936,19 @@
     // OS: Q
     ACTION_SET_NEW_PARENT_PROFILE_PASSWORD = 1646;
 
+    // Tagged data for SMART_REPLY_VISIBLE and SMART_REPLY_ACTION.
+    // Whether the smart reply was / is to be sent via direct reply because
+    // getEditChoicesBeforeSending was enabled.
+    // OS: Q
+    NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING = 1647;
+
+    // Tagged data for SMART_REPLY_ACTION.
+    // Whether the smart reply was modified by the user via the direct reply field (implies that
+    // getEditChoicesBeforeSending was enabled).
+    // actions/replies.
+    // OS: Q
+    NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING = 1648;
+
     // ---- 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/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
index 7ee3047..593bb2c 100644
--- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
@@ -20,6 +20,7 @@
 import static com.android.server.backup.BackupManagerService.TAG;
 import static com.android.server.backup.UserBackupManagerService.PACKAGE_MANAGER_SENTINEL;
 import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import android.annotation.Nullable;
 import android.app.AppGlobals;
@@ -40,11 +41,18 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.server.backup.transport.TransportClient;
 
+import com.google.android.collect.Sets;
+
+import java.util.Set;
+
 /**
  * Utility methods wrapping operations on ApplicationInfo and PackageInfo.
  */
 public class AppBackupUtils {
     private static final boolean DEBUG = false;
+    // Whitelist of system packages that are eligible for backup in non-system users.
+    private static final Set<String> systemPackagesWhitelistedForAllUsers =
+            Sets.newArraySet(PACKAGE_MANAGER_SENTINEL, PLATFORM_PACKAGE_NAME);
 
     /**
      * Returns whether app is eligible for backup.
@@ -72,9 +80,9 @@
 
         // 2. they run as a system-level uid
         if (UserHandle.isCore(app.uid)) {
-            // and the backup is happening for non-system user
-            if (userId != UserHandle.USER_SYSTEM && !app.packageName.equals(
-                    PACKAGE_MANAGER_SENTINEL)) {
+            // and the backup is happening for non-system user on a non-whitelisted package.
+            if (userId != UserHandle.USER_SYSTEM
+                    && !systemPackagesWhitelistedForAllUsers.contains(app.packageName)) {
                 return false;
             }
 
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index c8a27f1..7102b82 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -416,36 +416,5 @@
             // 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/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index a36c7c0..1165b09 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -114,6 +114,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -669,7 +670,7 @@
         // create a passive location provider, which is always enabled
         LocationProvider passiveProviderManager = new LocationProvider(PASSIVE_PROVIDER);
         addProviderLocked(passiveProviderManager);
-        mPassiveProvider = new PassiveProvider(passiveProviderManager);
+        mPassiveProvider = new PassiveProvider(mContext, passiveProviderManager);
         passiveProviderManager.attachLocked(mPassiveProvider);
 
         if (GnssLocationProvider.isSupported()) {
@@ -805,7 +806,7 @@
                     Integer.parseInt(fragments[9]) /* accuracy */);
             LocationProvider testProviderManager = new LocationProvider(name);
             addProviderLocked(testProviderManager);
-            new MockProvider(testProviderManager, properties);
+            new MockProvider(mContext, testProviderManager, properties);
         }
     }
 
@@ -895,15 +896,12 @@
         }
 
         @GuardedBy("mLock")
-        @Nullable
-        public String getPackageLocked() {
+        public List<String> getPackagesLocked() {
             if (mProvider == null) {
-                return null;
-            } else if (mProvider instanceof LocationProviderProxy) {
-                // safe to not clear binder context since this doesn't call into the actual provider
-                return ((LocationProviderProxy) mProvider).getConnectedPackageName();
+                return Collections.emptyList();
             } else {
-                return mContext.getPackageName();
+                // safe to not clear binder context since this doesn't call into the real provider
+                return mProvider.getProviderPackages();
             }
         }
 
@@ -2172,10 +2170,8 @@
             return true;
         }
 
-        for (LocationProvider provider : mProviders) {
-            if (callerIdentity.mPackageName.equals(provider.getPackageLocked())) {
-                return true;
-            }
+        if (isProviderPackage(callerIdentity.mPackageName)) {
+            return true;
         }
 
         return false;
@@ -2192,10 +2188,8 @@
             return true;
         }
 
-        for (LocationProvider provider : mProviders) {
-            if (record.mReceiver.mCallerIdentity.mPackageName.equals(provider.getPackageLocked())) {
-                return true;
-            }
+        if (isProviderPackage(record.mReceiver.mCallerIdentity.mPackageName)) {
+            return true;
         }
 
         return false;
@@ -2571,8 +2565,8 @@
                 if (provider == null) return null;
 
                 // only the current user or location providers may get location this way
-                if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isLocationProviderLocked(
-                        uid)) {
+                if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isProviderPackage(
+                        packageName)) {
                     return null;
                 }
 
@@ -2894,7 +2888,25 @@
             if (provider == null) {
                 return null;
             }
-            return provider.getPackageLocked();
+            List<String> packages = provider.getPackagesLocked();
+            if (packages.isEmpty()) {
+                return null;
+            } else {
+                return packages.get(0);
+            }
+        }
+    }
+
+    @Override
+    public boolean isProviderPackage(String packageName) {
+        synchronized (mLock) {
+            for (LocationProvider provider : mProviders) {
+                if (provider.getPackagesLocked().contains(packageName)) {
+                    return true;
+                }
+            }
+
+            return false;
         }
     }
 
@@ -2976,28 +2988,6 @@
     }
 
     @GuardedBy("mLock")
-    private boolean isLocationProviderLocked(int uid) {
-        if (uid == Process.SYSTEM_UID) {
-            return true;
-        }
-
-        String[] packageNames = mPackageManager.getPackagesForUid(uid);
-        if (packageNames == null) {
-            return false;
-        }
-        for (LocationProvider provider : mProviders) {
-            String packageName = provider.getPackageLocked();
-            if (packageName == null) {
-                continue;
-            }
-            if (ArrayUtils.contains(packageNames, packageName)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @GuardedBy("mLock")
     private static boolean shouldBroadcastSafeLocked(
             Location loc, Location lastLoc, UpdateRecord record, long now) {
         // Always broadcast the first update
@@ -3099,7 +3089,7 @@
 
             int receiverUserId = UserHandle.getUserId(receiver.mCallerIdentity.mUid);
             if (!isCurrentProfileLocked(receiverUserId)
-                    && !isLocationProviderLocked(receiver.mCallerIdentity.mUid)) {
+                    && !isProviderPackage(receiver.mCallerIdentity.mPackageName)) {
                 if (D) {
                     Log.d(TAG, "skipping loc update for background user " + receiverUserId +
                             " (current user: " + mCurrentUserId + ", app: " +
@@ -3288,7 +3278,8 @@
 
                 MockLocationProvider mockProviderManager = new MockLocationProvider(name);
                 addProviderLocked(mockProviderManager);
-                mockProviderManager.attachLocked(new MockProvider(mockProviderManager, properties));
+                mockProviderManager.attachLocked(
+                        new MockProvider(mContext, mockProviderManager, properties));
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -3428,7 +3419,7 @@
                 if (provider.mProvider instanceof LocationProviderProxy) {
                     pw.println("    " + provider.getName() + ": "
                             + ((LocationProviderProxy) provider.mProvider)
-                            .getConnectedPackageName());
+                            .getProviderPackages());
                 }
             }
             pw.println("  Historical Records by Provider:");
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index e731f34..ddbb421 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -80,6 +80,7 @@
         DeviceConfig.ActivityManagerNativeBoot.NAMESPACE,
         DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
         DeviceConfig.NAMESPACE_NETD_NATIVE,
+        DeviceConfig.RuntimeNativeBoot.NAMESPACE,
         DeviceConfig.RuntimeNative.NAMESPACE,
     };
 
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index deaa931..a3bae52 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -15,6 +15,9 @@
  */
 package com.android.server.audio;
 
+import static com.android.server.audio.AudioService.CONNECTION_STATE_CONNECTED;
+import static com.android.server.audio.AudioService.CONNECTION_STATE_DISCONNECTED;
+
 import android.annotation.NonNull;
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothDevice;
@@ -43,7 +46,7 @@
 /** @hide */
 /*package*/ final class AudioDeviceBroker {
 
-    private static final String TAG = "AudioDeviceBroker";
+    private static final String TAG = "AS.AudioDeviceBroker";
 
     private static final long BROKER_WAKELOCK_TIMEOUT_MS = 5000; //5s
 
@@ -62,27 +65,27 @@
     private int mForcedUseForCommExt;
 
     // Manages all connected devices, only ever accessed on the message loop
-    //### or make it synchronized
     private final AudioDeviceInventory mDeviceInventory;
     // Manages notifications to BT service
     private final BtHelper mBtHelper;
 
 
     //-------------------------------------------------------------------
+    // we use a different lock than mDeviceStateLock so as not to create
+    // lock contention between enqueueing a message and handling them
     private static final Object sLastDeviceConnectionMsgTimeLock = new Object();
+    @GuardedBy("sLastDeviceConnectionMsgTimeLock")
     private static long sLastDeviceConnectMsgTime = 0;
 
-    private final Object mBluetoothA2dpEnabledLock = new Object();
+    // General lock to be taken whenever the state of the audio devices is to be checked or changed
+    private final Object mDeviceStateLock = new Object();
+
     // Request to override default use of A2DP for media.
-    @GuardedBy("mBluetoothA2dpEnabledLock")
+    @GuardedBy("mDeviceStateLock")
     private boolean mBluetoothA2dpEnabled;
 
-    // lock always taken synchronized on mConnectedDevices
-    /*package*/  final Object mA2dpAvrcpLock = new Object();
-    // lock always taken synchronized on mConnectedDevices
-    /*package*/  final Object mHearingAidLock = new Object();
-
     // lock always taken when accessing AudioService.mSetModeDeathHandlers
+    // TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055
     /*package*/ final Object mSetModeLock = new Object();
 
     //-------------------------------------------------------------------
@@ -109,13 +112,17 @@
     // All post* methods are asynchronous
 
     /*package*/ void onSystemReady() {
-        mBtHelper.onSystemReady();
+        synchronized (mDeviceStateLock) {
+            mBtHelper.onSystemReady();
+        }
     }
 
     /*package*/ void onAudioServerDied() {
         // Restore forced usage for communications and record
-        onSetForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, "onAudioServerDied");
-        onSetForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm, "onAudioServerDied");
+        synchronized (mDeviceStateLock) {
+            onSetForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, "onAudioServerDied");
+            onSetForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm, "onAudioServerDied");
+        }
         // restore devices
         sendMsgNoDelay(MSG_RESTORE_DEVICES, SENDMSG_REPLACE);
     }
@@ -130,7 +137,9 @@
     }
 
     /*package*/ void disconnectAllBluetoothProfiles() {
-        mBtHelper.disconnectAllBluetoothProfiles();
+        synchronized (mDeviceStateLock) {
+            mBtHelper.disconnectAllBluetoothProfiles();
+        }
     }
 
     /**
@@ -140,11 +149,13 @@
      * @param intent
      */
     /*package*/ void receiveBtEvent(@NonNull Intent intent) {
-        mBtHelper.receiveBtEvent(intent);
+        synchronized (mDeviceStateLock) {
+            mBtHelper.receiveBtEvent(intent);
+        }
     }
 
     /*package*/ void setBluetoothA2dpOn_Async(boolean on, String source) {
-        synchronized (mBluetoothA2dpEnabledLock) {
+        synchronized (mDeviceStateLock) {
             if (mBluetoothA2dpEnabled == on) {
                 return;
             }
@@ -158,28 +169,34 @@
     }
 
     /*package*/ void setSpeakerphoneOn(boolean on, String eventSource) {
-        if (on) {
-            if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
-                setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
+        synchronized (mDeviceStateLock) {
+            if (on) {
+                if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
+                    setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
+                }
+                mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
+            } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
+                mForcedUseForComm = AudioSystem.FORCE_NONE;
             }
-            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
-        } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
-            mForcedUseForComm = AudioSystem.FORCE_NONE;
-        }
 
-        mForcedUseForCommExt = mForcedUseForComm;
-        setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
+            mForcedUseForCommExt = mForcedUseForComm;
+            setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
+        }
     }
 
     /*package*/ boolean isSpeakerphoneOn() {
-        return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
+        synchronized (mDeviceStateLock) {
+            return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
+        }
     }
 
     /*package*/ void setWiredDeviceConnectionState(int type,
             @AudioService.ConnectionState int state, String address, String name,
             String caller) {
         //TODO move logging here just like in setBluetooth* methods
-        mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller);
+        synchronized (mDeviceStateLock) {
+            mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller);
+        }
     }
 
     /*package*/ int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
@@ -192,22 +209,27 @@
                         + " addr=" + device.getAddress()
                         + " prof=" + profile + " supprNoisy=" + suppressNoisyIntent
                         + " vol=" + a2dpVolume)).printLog(TAG));
-        if (mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE,
-                new BtHelper.BluetoothA2dpDeviceInfo(device))) {
-            AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
-                    "A2DP connection state ignored"));
-            return 0;
+        synchronized (mDeviceStateLock) {
+            if (mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE,
+                    new BtHelper.BluetoothA2dpDeviceInfo(device))) {
+                AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+                        "A2DP connection state ignored"));
+                return 0;
+            }
+            return mDeviceInventory.setBluetoothA2dpDeviceConnectionState(
+                    device, state, profile, suppressNoisyIntent,
+                    AudioSystem.DEVICE_NONE, a2dpVolume);
         }
-        return mDeviceInventory.setBluetoothA2dpDeviceConnectionState(
-                device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE, a2dpVolume);
     }
 
     /*package*/ int handleBluetoothA2dpActiveDeviceChange(
             @NonNull BluetoothDevice device,
             @AudioService.BtProfileConnectionState int state, int profile,
             boolean suppressNoisyIntent, int a2dpVolume) {
-        return mDeviceInventory.handleBluetoothA2dpActiveDeviceChange(device, state, profile,
-                suppressNoisyIntent, a2dpVolume);
+        synchronized (mDeviceStateLock) {
+            return mDeviceInventory.handleBluetoothA2dpActiveDeviceChange(device, state, profile,
+                    suppressNoisyIntent, a2dpVolume);
+        }
     }
 
     /*package*/ int setBluetoothHearingAidDeviceConnectionState(
@@ -218,57 +240,69 @@
                         + " addr=" + device.getAddress()
                         + " supprNoisy=" + suppressNoisyIntent
                         + " src=" + eventSource)).printLog(TAG));
-        return mDeviceInventory.setBluetoothHearingAidDeviceConnectionState(
-                device, state, suppressNoisyIntent, musicDevice);
+        synchronized (mDeviceStateLock) {
+            return mDeviceInventory.setBluetoothHearingAidDeviceConnectionState(
+                    device, state, suppressNoisyIntent, musicDevice);
+        }
     }
 
     // never called by system components
     /*package*/ void setBluetoothScoOnByApp(boolean on) {
-        mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
+        synchronized (mDeviceStateLock) {
+            mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
+        }
     }
 
     /*package*/ boolean isBluetoothScoOnForApp() {
-        return mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO;
+        synchronized (mDeviceStateLock) {
+            return mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO;
+        }
     }
 
     /*package*/ void setBluetoothScoOn(boolean on, String eventSource) {
         //Log.i(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource);
-        if (on) {
-            // do not accept SCO ON if SCO audio is not connected
-            if (!mBtHelper.isBluetoothScoOn()) {
-                mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
-                return;
+        synchronized (mDeviceStateLock) {
+            if (on) {
+                // do not accept SCO ON if SCO audio is not connected
+                if (!mBtHelper.isBluetoothScoOn()) {
+                    mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
+                    return;
+                }
+                mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
+            } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
+                mForcedUseForComm = AudioSystem.FORCE_NONE;
             }
-            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
-        } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
-            mForcedUseForComm = AudioSystem.FORCE_NONE;
+            mForcedUseForCommExt = mForcedUseForComm;
+            AudioSystem.setParameters("BT_SCO=" + (on ? "on" : "off"));
+            sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
+                    AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
+            sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
+                    AudioSystem.FOR_RECORD, mForcedUseForComm, eventSource);
+            // Un-mute ringtone stream volume
+            mAudioService.setUpdateRingerModeServiceInt();
         }
-        mForcedUseForCommExt = mForcedUseForComm;
-        AudioSystem.setParameters("BT_SCO=" + (on ? "on" : "off"));
-        sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
-                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
-        sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
-                AudioSystem.FOR_RECORD, mForcedUseForComm, eventSource);
-        // Un-mute ringtone stream volume
-        mAudioService.setUpdateRingerModeServiceInt();
     }
 
     /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
-        return mDeviceInventory.startWatchingRoutes(observer);
+        synchronized (mDeviceStateLock) {
+            return mDeviceInventory.startWatchingRoutes(observer);
+        }
     }
 
     /*package*/ AudioRoutesInfo getCurAudioRoutes() {
-        return mDeviceInventory.getCurAudioRoutes();
+        synchronized (mDeviceStateLock) {
+            return mDeviceInventory.getCurAudioRoutes();
+        }
     }
 
     /*package*/ boolean isAvrcpAbsoluteVolumeSupported() {
-        synchronized (mA2dpAvrcpLock) {
+        synchronized (mDeviceStateLock) {
             return mBtHelper.isAvrcpAbsoluteVolumeSupported();
         }
     }
 
     /*package*/ boolean isBluetoothA2dpOn() {
-        synchronized (mBluetoothA2dpEnabledLock) {
+        synchronized (mDeviceStateLock) {
             return mBluetoothA2dpEnabled;
         }
     }
@@ -355,14 +389,12 @@
         sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE);
     }
 
-    //###TODO unify with handleSetA2dpSinkConnectionState
     /*package*/ void postA2dpSinkConnection(int state,
             @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
         sendILMsg(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE, SENDMSG_QUEUE,
                 state, btDeviceInfo, delay);
     }
 
-    //###TODO unify with handleSetA2dpSourceConnectionState
     /*package*/ void postA2dpSourceConnection(int state,
             @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
         sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE,
@@ -395,7 +427,7 @@
                 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
                 .append(Binder.getCallingPid()).append(" src:").append(source).toString();
 
-        synchronized (mBluetoothA2dpEnabledLock) {
+        synchronized (mDeviceStateLock) {
             mBluetoothA2dpEnabled = on;
             mBrokerHandler.removeMessages(MSG_IIL_SET_FORCE_BT_A2DP_USE);
             onSetForceUse(
@@ -407,25 +439,38 @@
 
     /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address,
                                                        String deviceName) {
-        return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName);
+        synchronized (mDeviceStateLock) {
+            return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName);
+        }
     }
 
     /*package*/ void handleDisconnectA2dp() {
-        mDeviceInventory.disconnectA2dp();
+        synchronized (mDeviceStateLock) {
+            mDeviceInventory.disconnectA2dp();
+        }
     }
     /*package*/ void handleDisconnectA2dpSink() {
-        mDeviceInventory.disconnectA2dpSink();
+        synchronized (mDeviceStateLock) {
+            mDeviceInventory.disconnectA2dpSink();
+        }
+    }
+
+    /*package*/ void handleDisconnectHearingAid() {
+        synchronized (mDeviceStateLock) {
+            mDeviceInventory.disconnectHearingAid();
+        }
     }
 
     /*package*/ void handleSetA2dpSinkConnectionState(@BluetoothProfile.BtProfileState int state,
                 @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
-        final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
-        //### DOESN'T HONOR SYNC ON DEVICES -> make a synchronized version?
-        // might be ok here because called on BT thread? + sync happening in
-        //  checkSendBecomingNoisyIntent
-        final int delay = mDeviceInventory.checkSendBecomingNoisyIntent(
-                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState,
-                AudioSystem.DEVICE_NONE);
+        final int intState = (state == BluetoothA2dp.STATE_CONNECTED)
+                ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED;
+        final int delay;
+        synchronized (mDeviceStateLock) {
+            delay = mDeviceInventory.checkSendBecomingNoisyIntent(
+                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState,
+                    AudioSystem.DEVICE_NONE);
+        }
         final String addr = btDeviceInfo == null ? "null" : btDeviceInfo.getBtDevice().getAddress();
 
         if (AudioService.DEBUG_DEVICES) {
@@ -437,10 +482,6 @@
                 state, btDeviceInfo, delay);
     }
 
-    /*package*/ void handleDisconnectHearingAid() {
-        mDeviceInventory.disconnectHearingAid();
-    }
-
     /*package*/ void handleSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state,
             @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
         final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
@@ -468,8 +509,6 @@
         sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, SENDMSG_QUEUE, btDeviceInfo);
     }
 
-    //###
-    // must be called synchronized on mConnectedDevices
     /*package*/ boolean hasScheduledA2dpDockTimeout() {
         return mBrokerHandler.hasMessages(MSG_IL_BTA2DP_DOCK_TIMEOUT);
     }
@@ -486,19 +525,19 @@
     }
 
     /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) {
-        synchronized (mA2dpAvrcpLock) {
+        synchronized (mDeviceStateLock) {
             mBtHelper.setAvrcpAbsoluteVolumeSupported(supported);
         }
     }
 
     /*package*/ boolean getBluetoothA2dpEnabled() {
-        synchronized (mBluetoothA2dpEnabledLock) {
+        synchronized (mDeviceStateLock) {
             return mBluetoothA2dpEnabled;
         }
     }
 
     /*package*/ int getA2dpCodec(@NonNull BluetoothDevice device) {
-        synchronized (mA2dpAvrcpLock) {
+        synchronized (mDeviceStateLock) {
             return mBtHelper.getA2dpCodec(device);
         }
     }
@@ -579,71 +618,97 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_RESTORE_DEVICES:
-                    mDeviceInventory.onRestoreDevices();
-                    synchronized (mBluetoothA2dpEnabledLock) {
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.onRestoreDevices();
                         mBtHelper.onAudioServerDiedRestoreA2dp();
                     }
                     break;
                 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
-                    mDeviceInventory.onSetWiredDeviceConnectionState(
-                            (AudioDeviceInventory.WiredDeviceConnectionState) msg.obj);
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.onSetWiredDeviceConnectionState(
+                                (AudioDeviceInventory.WiredDeviceConnectionState) msg.obj);
+                    }
                     break;
                 case MSG_I_BROADCAST_BT_CONNECTION_STATE:
-                    mBtHelper.onBroadcastScoConnectionState(msg.arg1);
+                    synchronized (mDeviceStateLock) {
+                        mBtHelper.onBroadcastScoConnectionState(msg.arg1);
+                    }
                     break;
-                case MSG_IIL_SET_FORCE_USE: // intented fall-through
+                case MSG_IIL_SET_FORCE_USE: // intended fall-through
                 case MSG_IIL_SET_FORCE_BT_A2DP_USE:
                     onSetForceUse(msg.arg1, msg.arg2, (String) msg.obj);
                     break;
                 case MSG_REPORT_NEW_ROUTES:
-                    mDeviceInventory.onReportNewRoutes();
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.onReportNewRoutes();
+                    }
                     break;
                 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE:
-                    mDeviceInventory.onSetA2dpSinkConnectionState(
-                            (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.onSetA2dpSinkConnectionState(
+                                (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
+                    }
                     break;
                 case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
-                    mDeviceInventory.onSetA2dpSourceConnectionState(
-                            (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.onSetA2dpSourceConnectionState(
+                                (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
+                    }
                     break;
                 case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
-                    mDeviceInventory.onSetHearingAidConnectionState(
-                            (BluetoothDevice) msg.obj, msg.arg1);
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.onSetHearingAidConnectionState(
+                                (BluetoothDevice) msg.obj, msg.arg1);
+                    }
                     break;
                 case MSG_BT_HEADSET_CNCT_FAILED:
-                    mBtHelper.resetBluetoothSco();
+                    synchronized (mDeviceStateLock) {
+                        mBtHelper.resetBluetoothSco();
+                    }
                     break;
                 case MSG_IL_BTA2DP_DOCK_TIMEOUT:
                     // msg.obj  == address of BTA2DP device
-                    mDeviceInventory.onMakeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1);
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.onMakeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1);
+                    }
                     break;
                 case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
                     final int a2dpCodec;
                     final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
-                    synchronized (mA2dpAvrcpLock) {
+                    synchronized (mDeviceStateLock) {
                         a2dpCodec = mBtHelper.getA2dpCodec(btDevice);
+                        mDeviceInventory.onBluetoothA2dpDeviceConfigChange(
+                                new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec));
                     }
-                    mDeviceInventory.onBluetoothA2dpDeviceConfigChange(
-                            new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec));
                     break;
                 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
                     onSendBecomingNoisyIntent();
                     break;
                 case MSG_II_SET_HEARING_AID_VOLUME:
-                    mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2);
+                    synchronized (mDeviceStateLock) {
+                        mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2);
+                    }
                     break;
                 case MSG_I_SET_AVRCP_ABSOLUTE_VOLUME:
-                    mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
+                    synchronized (mDeviceStateLock) {
+                        mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
+                    }
                     break;
                 case MSG_I_DISCONNECT_BT_SCO:
-                    mBtHelper.disconnectBluetoothSco(msg.arg1);
+                    synchronized (mDeviceStateLock) {
+                        mBtHelper.disconnectBluetoothSco(msg.arg1);
+                    }
                     break;
                 case MSG_TOGGLE_HDMI:
-                    mDeviceInventory.onToggleHdmi();
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.onToggleHdmi();
+                    }
                     break;
                 case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
-                    mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
-                            (BtHelper.BluetoothA2dpDeviceInfo) msg.obj);
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
+                                (BtHelper.BluetoothA2dpDeviceInfo) msg.obj);
+                    }
                     break;
                 default:
                     Log.wtf(TAG, "Invalid message " + msg.what);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 97649a7..11fdc8f 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -162,10 +162,7 @@
                 "A2DP sink connected: device addr=" + address + " state=" + state
                         + " vol=" + a2dpVolume));
 
-        final int a2dpCodec;
-        synchronized (mDeviceBroker.mA2dpAvrcpLock) {
-            a2dpCodec = btInfo.getCodec();
-        }
+        final int a2dpCodec = btInfo.getCodec();
 
         synchronized (mConnectedDevices) {
             final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
@@ -508,22 +505,20 @@
 
     /*package*/ void disconnectA2dp() {
         synchronized (mConnectedDevices) {
-            synchronized (mDeviceBroker.mA2dpAvrcpLock) {
-                final ArraySet<String> toRemove = new ArraySet<>();
-                // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
-                mConnectedDevices.values().forEach(deviceInfo -> {
-                    if (deviceInfo.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
-                        toRemove.add(deviceInfo.mDeviceAddress);
-                    }
-                });
-                if (toRemove.size() > 0) {
-                    final int delay = checkSendBecomingNoisyIntentInt(
-                            AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                            0, AudioSystem.DEVICE_NONE);
-                    toRemove.stream().forEach(deviceAddress ->
-                            makeA2dpDeviceUnavailableLater(deviceAddress, delay)
-                    );
+            final ArraySet<String> toRemove = new ArraySet<>();
+            // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
+            mConnectedDevices.values().forEach(deviceInfo -> {
+                if (deviceInfo.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
+                    toRemove.add(deviceInfo.mDeviceAddress);
                 }
+            });
+            if (toRemove.size() > 0) {
+                final int delay = checkSendBecomingNoisyIntentInt(
+                        AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                        AudioService.CONNECTION_STATE_DISCONNECTED, AudioSystem.DEVICE_NONE);
+                toRemove.stream().forEach(deviceAddress ->
+                        makeA2dpDeviceUnavailableLater(deviceAddress, delay)
+                );
             }
         }
     }
@@ -543,22 +538,20 @@
 
     /*package*/ void disconnectHearingAid() {
         synchronized (mConnectedDevices) {
-            synchronized (mDeviceBroker.mHearingAidLock) {
-                final ArraySet<String> toRemove = new ArraySet<>();
-                // Disconnect ALL DEVICE_OUT_HEARING_AID devices
-                mConnectedDevices.values().forEach(deviceInfo -> {
-                    if (deviceInfo.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) {
-                        toRemove.add(deviceInfo.mDeviceAddress);
-                    }
-                });
-                if (toRemove.size() > 0) {
-                    final int delay = checkSendBecomingNoisyIntentInt(
-                            AudioSystem.DEVICE_OUT_HEARING_AID, 0, AudioSystem.DEVICE_NONE);
-                    toRemove.stream().forEach(deviceAddress ->
-                            // TODO delay not used?
-                            makeHearingAidDeviceUnavailable(deviceAddress /*, delay*/)
-                    );
+            final ArraySet<String> toRemove = new ArraySet<>();
+            // Disconnect ALL DEVICE_OUT_HEARING_AID devices
+            mConnectedDevices.values().forEach(deviceInfo -> {
+                if (deviceInfo.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) {
+                    toRemove.add(deviceInfo.mDeviceAddress);
                 }
+            });
+            if (toRemove.size() > 0) {
+                final int delay = checkSendBecomingNoisyIntentInt(
+                        AudioSystem.DEVICE_OUT_HEARING_AID, 0, AudioSystem.DEVICE_NONE);
+                toRemove.stream().forEach(deviceAddress ->
+                        // TODO delay not used?
+                        makeHearingAidDeviceUnavailable(deviceAddress /*, delay*/)
+                );
             }
         }
     }
@@ -566,7 +559,8 @@
     // must be called before removing the device from mConnectedDevices
     // musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
     // from AudioSystem
-    /*package*/ int checkSendBecomingNoisyIntent(int device, int state, int musicDevice) {
+    /*package*/ int checkSendBecomingNoisyIntent(int device,
+            @AudioService.ConnectionState int state, int musicDevice) {
         synchronized (mConnectedDevices) {
             return checkSendBecomingNoisyIntentInt(device, state, musicDevice);
         }
@@ -840,8 +834,9 @@
     // musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
     // from AudioSystem
     @GuardedBy("mConnectedDevices")
-    private int checkSendBecomingNoisyIntentInt(int device, int state, int musicDevice) {
-        if (state != 0) {
+    private int checkSendBecomingNoisyIntentInt(int device,
+            @AudioService.ConnectionState int state, int musicDevice) {
+        if (state != AudioService.CONNECTION_STATE_DISCONNECTED) {
             return 0;
         }
         if ((device & mBecomingNoisyIntentDevices) == 0) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 9457fe3..de63d0e 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -786,7 +786,6 @@
                 mPrescaleAbsoluteVolume[i] = preScale[i];
             }
         }
-
     }
 
     public void systemReady() {
@@ -1711,7 +1710,7 @@
                     Log.d(TAG, "adjustSreamVolume: postSetAvrcpAbsoluteVolumeIndex index="
                             + newIndex + "stream=" + streamType);
                 }
-                mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(newIndex);
+                mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(newIndex / 10);
             }
 
             // Check if volume update should be send to Hearing Aid
@@ -3821,7 +3820,6 @@
 
     private static void sendMsg(Handler handler, int msg,
             int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
-
         if (existingMsgPolicy == SENDMSG_REPLACE) {
             handler.removeMessages(msg);
         } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index bf32501..b63af8a 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -16,6 +16,7 @@
 package com.android.server.audio;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
@@ -35,8 +36,6 @@
 import android.provider.Settings;
 import android.util.Log;
 
-import com.android.internal.annotations.GuardedBy;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.NoSuchElementException;
@@ -57,21 +56,40 @@
     }
 
     // List of clients having issued a SCO start request
-    private final ArrayList<ScoClient> mScoClients = new ArrayList<ScoClient>();
+    private final @NonNull ArrayList<ScoClient> mScoClients = new ArrayList<ScoClient>();
 
     // BluetoothHeadset API to control SCO connection
-    private BluetoothHeadset mBluetoothHeadset;
+    private @Nullable BluetoothHeadset mBluetoothHeadset;
 
     // Bluetooth headset device
-    private BluetoothDevice mBluetoothHeadsetDevice;
+    private @Nullable BluetoothDevice mBluetoothHeadsetDevice;
+
+    private @Nullable BluetoothHearingAid mHearingAid;
+
+    // Reference to BluetoothA2dp to query for AbsoluteVolume.
+    private @Nullable BluetoothA2dp mA2dp;
+
+    // If absolute volume is supported in AVRCP device
+    private boolean mAvrcpAbsVolSupported = false;
+
+    // Current connection state indicated by bluetooth headset
+    private int mScoConnectionState;
 
     // Indicate if SCO audio connection is currently active and if the initiator is
     // audio service (internal) or bluetooth headset (external)
     private int mScoAudioState;
+
+    // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
+    // originated from an app targeting an API version before JB MR2 and raw audio after that.
+    private int mScoAudioMode;
+
     // SCO audio state is not active
     private static final int SCO_STATE_INACTIVE = 0;
     // SCO audio activation request waiting for headset service to connect
     private static final int SCO_STATE_ACTIVATE_REQ = 1;
+    // SCO audio state is active due to an action in BT handsfree (either voice recognition or
+    // in call audio)
+    private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
     // SCO audio state is active or starting due to a request from AudioManager API
     private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
     // SCO audio deactivation request waiting for headset service to connect
@@ -79,39 +97,19 @@
     // SCO audio deactivation in progress, waiting for Bluetooth audio intent
     private static final int SCO_STATE_DEACTIVATING = 5;
 
-    // SCO audio state is active due to an action in BT handsfree (either voice recognition or
-    // in call audio)
-    private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
-
-    // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
-    // originated from an app targeting an API version before JB MR2 and raw audio after that.
-    private int mScoAudioMode;
     // SCO audio mode is undefined
-    /*package*/   static final int SCO_MODE_UNDEFINED = -1;
+    /*package*/  static final int SCO_MODE_UNDEFINED = -1;
     // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
     /*package*/  static final int SCO_MODE_VIRTUAL_CALL = 0;
     // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
     private  static final int SCO_MODE_RAW = 1;
     // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
     private  static final int SCO_MODE_VR = 2;
-
+    // max valid SCO audio mode values
     private static final int SCO_MODE_MAX = 2;
 
-    // Current connection state indicated by bluetooth headset
-    private int mScoConnectionState;
-
     private static final int BT_HEARING_AID_GAIN_MIN = -128;
 
-    @GuardedBy("mDeviceBroker.mHearingAidLock")
-    private BluetoothHearingAid mHearingAid;
-
-    // Reference to BluetoothA2dp to query for AbsoluteVolume.
-    @GuardedBy("mDeviceBroker.mA2dpAvrcpLock")
-    private BluetoothA2dp mA2dp;
-    // If absolute volume is supported in AVRCP device
-    @GuardedBy("mDeviceBroker.mA2dpAvrcpLock")
-    private boolean mAvrcpAbsVolSupported = false;
-
     //----------------------------------------------------------------------
     /*package*/ static class BluetoothA2dpDeviceInfo {
         private final @NonNull BluetoothDevice mBtDevice;
@@ -144,7 +142,7 @@
     //----------------------------------------------------------------------
     // Interface for AudioDeviceBroker
 
-    /*package*/ void onSystemReady() {
+    /*package*/ synchronized void onSystemReady() {
         mScoConnectionState = android.media.AudioManager.SCO_AUDIO_STATE_ERROR;
         resetBluetoothSco();
         getBluetoothHeadset();
@@ -165,45 +163,39 @@
         }
     }
 
-    @GuardedBy("mBluetoothA2dpEnabledLock")
-    /*package*/ void onAudioServerDiedRestoreA2dp() {
+    /*package*/ synchronized void onAudioServerDiedRestoreA2dp() {
         final int forMed = mDeviceBroker.getBluetoothA2dpEnabled()
                 ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP;
         mDeviceBroker.setForceUse_Async(AudioSystem.FOR_MEDIA, forMed, "onAudioServerDied()");
     }
 
-    @GuardedBy("mA2dpAvrcpLock")
-    /*package*/ boolean isAvrcpAbsoluteVolumeSupported() {
+    /*package*/ synchronized boolean isAvrcpAbsoluteVolumeSupported() {
         return (mA2dp != null && mAvrcpAbsVolSupported);
     }
 
-    @GuardedBy("mA2dpAvrcpLock")
-    /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) {
+    /*package*/ synchronized void setAvrcpAbsoluteVolumeSupported(boolean supported) {
         mAvrcpAbsVolSupported = supported;
     }
 
-    /*package*/ void setAvrcpAbsoluteVolumeIndex(int index) {
-        synchronized (mDeviceBroker.mA2dpAvrcpLock) {
-            if (mA2dp == null) {
-                if (AudioService.DEBUG_VOL) {
-                    Log.d(TAG, "setAvrcpAbsoluteVolumeIndex: bailing due to null mA2dp");
-                    return;
-                }
-            }
-            if (!mAvrcpAbsVolSupported) {
+    /*package*/ synchronized void setAvrcpAbsoluteVolumeIndex(int index) {
+        if (mA2dp == null) {
+            if (AudioService.DEBUG_VOL) {
+                Log.d(TAG, "setAvrcpAbsoluteVolumeIndex: bailing due to null mA2dp");
                 return;
             }
-            if (AudioService.DEBUG_VOL) {
-                Log.i(TAG, "setAvrcpAbsoluteVolumeIndex index=" + index);
-            }
-            AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent(
-                    AudioServiceEvents.VolumeEvent.VOL_SET_AVRCP_VOL, index / 10));
-            mA2dp.setAvrcpAbsoluteVolume(index / 10);
         }
+        if (!mAvrcpAbsVolSupported) {
+            return;
+        }
+        if (AudioService.DEBUG_VOL) {
+            Log.i(TAG, "setAvrcpAbsoluteVolumeIndex index=" + index);
+        }
+        AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent(
+                AudioServiceEvents.VolumeEvent.VOL_SET_AVRCP_VOL, index));
+        mA2dp.setAvrcpAbsoluteVolume(index);
     }
 
-    @GuardedBy("mA2dpAvrcpLock")
-    /*package*/ int getA2dpCodec(@NonNull BluetoothDevice device) {
+    /*package*/ synchronized int getA2dpCodec(@NonNull BluetoothDevice device) {
         if (mA2dp == null) {
             return AudioSystem.AUDIO_FORMAT_DEFAULT;
         }
@@ -218,7 +210,7 @@
         return mapBluetoothCodecToAudioFormat(btCodecConfig.getCodecType());
     }
 
-    /*package*/ void receiveBtEvent(Intent intent) {
+    /*package*/ synchronized void receiveBtEvent(Intent intent) {
         final String action = intent.getAction();
         if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) {
             BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
@@ -226,53 +218,51 @@
         } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
             boolean broadcast = false;
             int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
-            synchronized (mScoClients) {
-                int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
-                // broadcast intent if the connection was initated by AudioService
-                if (!mScoClients.isEmpty()
-                        && (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL
-                                || mScoAudioState == SCO_STATE_ACTIVATE_REQ
-                                || mScoAudioState == SCO_STATE_DEACTIVATE_REQ
-                                || mScoAudioState == SCO_STATE_DEACTIVATING)) {
-                    broadcast = true;
-                }
-                switch (btState) {
-                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
-                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
-                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
-                                && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
-                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+            int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
+            // broadcast intent if the connection was initated by AudioService
+            if (!mScoClients.isEmpty()
+                    && (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL
+                    || mScoAudioState == SCO_STATE_ACTIVATE_REQ
+                    || mScoAudioState == SCO_STATE_DEACTIVATE_REQ
+                    || mScoAudioState == SCO_STATE_DEACTIVATING)) {
+                broadcast = true;
+            }
+            switch (btState) {
+                case BluetoothHeadset.STATE_AUDIO_CONNECTED:
+                    scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
+                    if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
+                            && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
+                        mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+                    }
+                    mDeviceBroker.setBluetoothScoOn(true, "BtHelper.receiveBtEvent");
+                    break;
+                case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
+                    mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent");
+                    scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
+                    // startBluetoothSco called after stopBluetoothSco
+                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) {
+                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
+                                && connectBluetoothScoAudioHelper(mBluetoothHeadset,
+                                mBluetoothHeadsetDevice, mScoAudioMode)) {
+                            mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+                            broadcast = false;
+                            break;
                         }
-                        mDeviceBroker.setBluetoothScoOn(true, "BtHelper.receiveBtEvent");
-                        break;
-                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
-                        mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent");
-                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
-                        // startBluetoothSco called after stopBluetoothSco
-                        if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) {
-                            if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
-                                    && connectBluetoothScoAudioHelper(mBluetoothHeadset,
-                                            mBluetoothHeadsetDevice, mScoAudioMode)) {
-                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                                broadcast = false;
-                                break;
-                            }
-                        }
-                        // Tear down SCO if disconnected from external
-                        clearAllScoClients(0, mScoAudioState == SCO_STATE_ACTIVE_INTERNAL);
-                        mScoAudioState = SCO_STATE_INACTIVE;
-                        break;
-                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
-                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
-                                && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
-                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
-                        }
-                        break;
-                    default:
-                        // do not broadcast CONNECTING or invalid state
-                        broadcast = false;
-                        break;
-                }
+                    }
+                    // Tear down SCO if disconnected from external
+                    clearAllScoClients(0, mScoAudioState == SCO_STATE_ACTIVE_INTERNAL);
+                    mScoAudioState = SCO_STATE_INACTIVE;
+                    break;
+                case BluetoothHeadset.STATE_AUDIO_CONNECTING:
+                    if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
+                            && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
+                        mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+                    }
+                    break;
+                default:
+                    // do not broadcast CONNECTING or invalid state
+                    broadcast = false;
+                    break;
             }
             if (broadcast) {
                 broadcastScoConnectionState(scoAudioState);
@@ -289,15 +279,13 @@
      *
      * @return false if SCO isn't connected
      */
-    /*package*/ boolean isBluetoothScoOn() {
-        synchronized (mScoClients) {
-            if ((mBluetoothHeadset != null)
-                    && (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
-                            != BluetoothHeadset.STATE_AUDIO_CONNECTED)) {
-                Log.w(TAG, "isBluetoothScoOn(true) returning false because "
-                        + mBluetoothHeadsetDevice + " is not in audio connected mode");
-                return false;
-            }
+    /*package*/ synchronized boolean isBluetoothScoOn() {
+        if ((mBluetoothHeadset != null)
+                && (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+                != BluetoothHeadset.STATE_AUDIO_CONNECTED)) {
+            Log.w(TAG, "isBluetoothScoOn(true) returning false because "
+                    + mBluetoothHeadsetDevice + " is not in audio connected mode");
+            return false;
         }
         return true;
     }
@@ -308,17 +296,15 @@
      *
      * @param exceptPid pid whose SCO connections through {@link AudioManager} should be kept
      */
-    /*package*/ void disconnectBluetoothSco(int exceptPid) {
-        synchronized (mScoClients) {
-            checkScoAudioState();
-            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL) {
-                return;
-            }
-            clearAllScoClients(exceptPid, true);
+    /*package*/ synchronized void disconnectBluetoothSco(int exceptPid) {
+        checkScoAudioState();
+        if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL) {
+            return;
         }
+        clearAllScoClients(exceptPid, true);
     }
 
-    /*package*/ void startBluetoothScoForClient(IBinder cb, int scoAudioMode,
+    /*package*/ synchronized void startBluetoothScoForClient(IBinder cb, int scoAudioMode,
                 @NonNull String eventSource) {
         ScoClient client = getScoClient(cb, true);
         // The calling identity must be cleared before calling ScoClient.incCount().
@@ -337,7 +323,8 @@
         Binder.restoreCallingIdentity(ident);
     }
 
-    /*package*/ void stopBluetoothScoForClient(IBinder cb, @NonNull String eventSource) {
+    /*package*/ synchronized void stopBluetoothScoForClient(IBinder cb,
+            @NonNull String eventSource) {
         ScoClient client = getScoClient(cb, false);
         // The calling identity must be cleared before calling ScoClient.decCount().
         // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
@@ -352,36 +339,29 @@
     }
 
 
-    /*package*/ void setHearingAidVolume(int index, int streamType) {
-        synchronized (mDeviceBroker.mHearingAidLock) {
-            if (mHearingAid == null) {
-                if (AudioService.DEBUG_VOL) {
-                    Log.i(TAG, "setHearingAidVolume: null mHearingAid");
-                }
-                return;
-            }
-            //hearing aid expect volume value in range -128dB to 0dB
-            int gainDB = (int) AudioSystem.getStreamVolumeDB(streamType, index / 10,
-                    AudioSystem.DEVICE_OUT_HEARING_AID);
-            if (gainDB < BT_HEARING_AID_GAIN_MIN) {
-                gainDB = BT_HEARING_AID_GAIN_MIN;
-            }
+    /*package*/ synchronized void setHearingAidVolume(int index, int streamType) {
+        if (mHearingAid == null) {
             if (AudioService.DEBUG_VOL) {
-                Log.i(TAG, "setHearingAidVolume: calling mHearingAid.setVolume idx="
-                        + index + " gain=" + gainDB);
+                Log.i(TAG, "setHearingAidVolume: null mHearingAid");
             }
-            AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent(
-                    AudioServiceEvents.VolumeEvent.VOL_SET_HEARING_AID_VOL, index, gainDB));
-            mHearingAid.setVolume(gainDB);
+            return;
         }
+        //hearing aid expect volume value in range -128dB to 0dB
+        int gainDB = (int) AudioSystem.getStreamVolumeDB(streamType, index / 10,
+                AudioSystem.DEVICE_OUT_HEARING_AID);
+        if (gainDB < BT_HEARING_AID_GAIN_MIN) {
+            gainDB = BT_HEARING_AID_GAIN_MIN;
+        }
+        if (AudioService.DEBUG_VOL) {
+            Log.i(TAG, "setHearingAidVolume: calling mHearingAid.setVolume idx="
+                    + index + " gain=" + gainDB);
+        }
+        AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent(
+                AudioServiceEvents.VolumeEvent.VOL_SET_HEARING_AID_VOL, index, gainDB));
+        mHearingAid.setVolume(gainDB);
     }
 
-    //----------------------------------------------------------------------
-    private void broadcastScoConnectionState(int state) {
-        mDeviceBroker.broadcastScoConnectionState(state);
-    }
-
-    /*package*/ void onBroadcastScoConnectionState(int state) {
+    /*package*/ synchronized void onBroadcastScoConnectionState(int state) {
         if (state == mScoConnectionState) {
             return;
         }
@@ -393,6 +373,26 @@
         mScoConnectionState = state;
     }
 
+    /*package*/ synchronized void disconnectAllBluetoothProfiles() {
+        mDeviceBroker.handleDisconnectA2dp();
+        mDeviceBroker.handleDisconnectA2dpSink();
+        disconnectHeadset();
+        mDeviceBroker.handleDisconnectHearingAid();
+    }
+
+    /*package*/ synchronized void resetBluetoothSco() {
+        clearAllScoClients(0, false);
+        mScoAudioState = SCO_STATE_INACTIVE;
+        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+        AudioSystem.setParameters("A2dpSuspended=false");
+        mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
+    }
+
+    //----------------------------------------------------------------------
+    private void broadcastScoConnectionState(int state) {
+        mDeviceBroker.broadcastScoConnectionState(state);
+    }
+
     private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
         if (btDevice == null) {
             return true;
@@ -437,25 +437,23 @@
     }
 
     private void setBtScoActiveDevice(BluetoothDevice btDevice) {
-        synchronized (mScoClients) {
-            Log.i(TAG, "setBtScoActiveDevice: " + mBluetoothHeadsetDevice + " -> " + btDevice);
-            final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
-            if (Objects.equals(btDevice, previousActiveDevice)) {
-                return;
-            }
-            if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
-                Log.w(TAG, "setBtScoActiveDevice() failed to remove previous device "
-                        + previousActiveDevice);
-            }
-            if (!handleBtScoActiveDeviceChange(btDevice, true)) {
-                Log.e(TAG, "setBtScoActiveDevice() failed to add new device " + btDevice);
-                // set mBluetoothHeadsetDevice to null when failing to add new device
-                btDevice = null;
-            }
-            mBluetoothHeadsetDevice = btDevice;
-            if (mBluetoothHeadsetDevice == null) {
-                resetBluetoothSco();
-            }
+        Log.i(TAG, "setBtScoActiveDevice: " + mBluetoothHeadsetDevice + " -> " + btDevice);
+        final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
+        if (Objects.equals(btDevice, previousActiveDevice)) {
+            return;
+        }
+        if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
+            Log.w(TAG, "setBtScoActiveDevice() failed to remove previous device "
+                    + previousActiveDevice);
+        }
+        if (!handleBtScoActiveDeviceChange(btDevice, true)) {
+            Log.e(TAG, "setBtScoActiveDevice() failed to add new device " + btDevice);
+            // set mBluetoothHeadsetDevice to null when failing to add new device
+            btDevice = null;
+        }
+        mBluetoothHeadsetDevice = btDevice;
+        if (mBluetoothHeadsetDevice == null) {
+            resetBluetoothSco();
         }
     }
 
@@ -466,7 +464,7 @@
                     List<BluetoothDevice> deviceList;
                     switch(profile) {
                         case BluetoothProfile.A2DP:
-                            synchronized (mDeviceBroker.mA2dpAvrcpLock) {
+                            synchronized (BtHelper.this) {
                                 mA2dp = (BluetoothA2dp) proxy;
                                 deviceList = mA2dp.getConnectedDevices();
                                 if (deviceList.size() > 0) {
@@ -495,7 +493,7 @@
                             break;
 
                         case BluetoothProfile.HEADSET:
-                            synchronized (mScoClients) {
+                            synchronized (BtHelper.this) {
                                 // Discard timeout message
                                 mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
                                 mBluetoothHeadset = (BluetoothHeadset) proxy;
@@ -536,17 +534,19 @@
                             break;
 
                         case BluetoothProfile.HEARING_AID:
-                            mHearingAid = (BluetoothHearingAid) proxy;
-                            deviceList = mHearingAid.getConnectedDevices();
-                            if (deviceList.size() > 0) {
-                                btDevice = deviceList.get(0);
-                                final @BluetoothProfile.BtProfileState int state =
-                                        mHearingAid.getConnectionState(btDevice);
-                                mDeviceBroker.setBluetoothHearingAidDeviceConnectionState(
-                                        btDevice, state,
-                                        /*suppressNoisyIntent*/ false,
-                                        /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE,
-                                        /*eventSource*/ "mBluetoothProfileServiceListener");
+                            synchronized (BtHelper.this) {
+                                mHearingAid = (BluetoothHearingAid) proxy;
+                                deviceList = mHearingAid.getConnectedDevices();
+                                if (deviceList.size() > 0) {
+                                    btDevice = deviceList.get(0);
+                                    final @BluetoothProfile.BtProfileState int state =
+                                            mHearingAid.getConnectionState(btDevice);
+                                    mDeviceBroker.setBluetoothHearingAidDeviceConnectionState(
+                                            btDevice, state,
+                                            /*suppressNoisyIntent*/ false,
+                                            /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE,
+                                            /*eventSource*/ "mBluetoothProfileServiceListener");
+                                }
                             }
                             break;
 
@@ -579,18 +579,9 @@
                 }
             };
 
-    void disconnectAllBluetoothProfiles() {
-        mDeviceBroker.handleDisconnectA2dp();
-        mDeviceBroker.handleDisconnectA2dpSink();
-        disconnectHeadset();
-        mDeviceBroker.handleDisconnectHearingAid();
-    }
-
     private void disconnectHeadset() {
-        synchronized (mScoClients) {
-            setBtScoActiveDevice(null);
-            mBluetoothHeadset = null;
-        }
+        setBtScoActiveDevice(null);
+        mBluetoothHeadset = null;
     }
 
     //----------------------------------------------------------------------
@@ -605,8 +596,12 @@
             mStartcount = 0;
         }
 
+        @Override
         public void binderDied() {
-            synchronized (mScoClients) {
+            // this is the only place the implementation of ScoClient needs to be synchronized
+            // on the instance, as all other methods are directly or indirectly called from
+            // package-private methods, which are synchronized
+            synchronized (BtHelper.this) {
                 Log.w(TAG, "SCO client died");
                 int index = mScoClients.indexOf(this);
                 if (index < 0) {
@@ -618,77 +613,69 @@
             }
         }
 
-        public void incCount(int scoAudioMode) {
-            synchronized (mScoClients) {
-                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
-                if (mStartcount == 0) {
-                    try {
-                        mCb.linkToDeath(this, 0);
-                    } catch (RemoteException e) {
-                        // client has already died!
-                        Log.w(TAG, "ScoClient  incCount() could not link to "
-                                + mCb + " binder death");
-                    }
-                }
-                mStartcount++;
-            }
-        }
-
-        public void decCount() {
-            synchronized (mScoClients) {
-                if (mStartcount == 0) {
-                    Log.w(TAG, "ScoClient.decCount() already 0");
-                } else {
-                    mStartcount--;
-                    if (mStartcount == 0) {
-                        try {
-                            mCb.unlinkToDeath(this, 0);
-                        } catch (NoSuchElementException e) {
-                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
-                        }
-                    }
-                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
+        void incCount(int scoAudioMode) {
+            requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
+            if (mStartcount == 0) {
+                try {
+                    mCb.linkToDeath(this, 0);
+                } catch (RemoteException e) {
+                    // client has already died!
+                    Log.w(TAG, "ScoClient  incCount() could not link to "
+                            + mCb + " binder death");
                 }
             }
+            mStartcount++;
         }
 
-        public void clearCount(boolean stopSco) {
-            synchronized (mScoClients) {
-                if (mStartcount != 0) {
+        void decCount() {
+            if (mStartcount == 0) {
+                Log.w(TAG, "ScoClient.decCount() already 0");
+            } else {
+                mStartcount--;
+                if (mStartcount == 0) {
                     try {
                         mCb.unlinkToDeath(this, 0);
                     } catch (NoSuchElementException e) {
-                        Log.w(TAG, "clearCount() mStartcount: "
-                                + mStartcount + " != 0 but not registered to binder");
+                        Log.w(TAG, "decCount() going to 0 but not registered to binder");
                     }
                 }
-                mStartcount = 0;
-                if (stopSco) {
-                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
-                }
+                requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
             }
         }
 
-        public int getCount() {
+        void clearCount(boolean stopSco) {
+            if (mStartcount != 0) {
+                try {
+                    mCb.unlinkToDeath(this, 0);
+                } catch (NoSuchElementException e) {
+                    Log.w(TAG, "clearCount() mStartcount: "
+                            + mStartcount + " != 0 but not registered to binder");
+                }
+            }
+            mStartcount = 0;
+            if (stopSco) {
+                requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
+            }
+        }
+
+        int getCount() {
             return mStartcount;
         }
 
-        public IBinder getBinder() {
+        IBinder getBinder() {
             return mCb;
         }
 
-        public int getPid() {
+        int getPid() {
             return mCreatorPid;
         }
 
-        public int totalCount() {
-            synchronized (mScoClients) {
-                int count = 0;
-                for (ScoClient mScoClient : mScoClients) {
-                    count += mScoClient.getCount();
-                }
-                return count;
+        private int totalCount() {
+            int count = 0;
+            for (ScoClient mScoClient : mScoClients) {
+                count += mScoClient.getCount();
             }
+            return count;
         }
 
         private void requestScoState(int state, int scoAudioMode) {
@@ -705,6 +692,7 @@
                 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
                 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
                 // currently controlled by the same client process.
+                // TODO do not sync that way, see b/123769055
                 synchronized (mDeviceBroker.mSetModeLock) {
                     int modeOwnerPid =  mDeviceBroker.getSetModeDeathHandlers().isEmpty()
                             ? 0 : mDeviceBroker.getSetModeDeathHandlers().get(0).getPid();
@@ -857,60 +845,43 @@
         }
     }
 
-    /*package*/ void resetBluetoothSco() {
-        synchronized (mScoClients) {
-            clearAllScoClients(0, false);
-            mScoAudioState = SCO_STATE_INACTIVE;
-            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-        }
-        AudioSystem.setParameters("A2dpSuspended=false");
-        mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
-    }
-
-
     private void checkScoAudioState() {
-        synchronized (mScoClients) {
-            if (mBluetoothHeadset != null
-                    && mBluetoothHeadsetDevice != null
-                    && mScoAudioState == SCO_STATE_INACTIVE
-                    && mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
-                            != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
-                mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
-            }
+        if (mBluetoothHeadset != null
+                && mBluetoothHeadsetDevice != null
+                && mScoAudioState == SCO_STATE_INACTIVE
+                && mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
+            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
         }
     }
 
 
     private ScoClient getScoClient(IBinder cb, boolean create) {
-        synchronized (mScoClients) {
-            for (ScoClient existingClient : mScoClients) {
-                if (existingClient.getBinder() == cb) {
-                    return existingClient;
-                }
+        for (ScoClient existingClient : mScoClients) {
+            if (existingClient.getBinder() == cb) {
+                return existingClient;
             }
-            if (create) {
-                ScoClient newClient = new ScoClient(cb);
-                mScoClients.add(newClient);
-                return newClient;
-            }
-            return null;
         }
+        if (create) {
+            ScoClient newClient = new ScoClient(cb);
+            mScoClients.add(newClient);
+            return newClient;
+        }
+        return null;
     }
 
     private void clearAllScoClients(int exceptPid, boolean stopSco) {
-        synchronized (mScoClients) {
-            ScoClient savedClient = null;
-            for (ScoClient cl : mScoClients) {
-                if (cl.getPid() != exceptPid) {
-                    cl.clearCount(stopSco);
-                } else {
-                    savedClient = cl;
-                }
+        ScoClient savedClient = null;
+        for (ScoClient cl : mScoClients) {
+            if (cl.getPid() != exceptPid) {
+                cl.clearCount(stopSco);
+            } else {
+                savedClient = cl;
             }
-            mScoClients.clear();
-            if (savedClient != null) {
-                mScoClients.add(savedClient);
-            }
+        }
+        mScoClients.clear();
+        if (savedClient != null) {
+            mScoClients.add(savedClient);
         }
     }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 3f90dfe..6710986 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -781,7 +781,7 @@
         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,
+        HdmiLogger.debug("Reporting volume %d (%d-%d) as CEC volume %d", volume,
                 minVolume, maxVolume, scaledVolume);
 
         mService.sendCecCommand(
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d20508a..f0dce78 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1645,10 +1645,12 @@
     }
 
     @Override
-    public List<InputMethodInfo> getEnabledInputMethodList() {
-        final int callingUserId = UserHandle.getCallingUserId();
+    public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
+        if (UserHandle.getCallingUserId() != userId) {
+            mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+        }
         synchronized (mMethodMap) {
-            final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
+            final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
                     mSettings.getCurrentUserId(), null);
             if (resolvedUserIds.length != 1) {
                 return Collections.emptyList();
@@ -4697,7 +4699,7 @@
                     mSettings.getCurrentUserId(),
                     mContext.getBasePackageName());
             nextIme = mSettings.getSelectedInputMethod();
-            nextEnabledImes = getEnabledInputMethodList();
+            nextEnabledImes = mSettings.getEnabledInputMethodListLocked();
             final PrintWriter pr = shellCommand.getOutPrintWriter();
             pr.println("Reset current and enabled IMEs");
             pr.println("Newly selected IME:");
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 3222143..109024d 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.inputmethod;
 
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -1195,6 +1196,7 @@
      * Takes care of IPCs exposed to the IME client.
      */
     private static final class ApiCallbacks extends IInputMethodManager.Stub {
+        private final Context mContext;
         private final UserDataMap mUserDataMap;
         private final UserToInputMethodInfoMap mInputMethodInfoMap;
         private final AppOpsManager mAppOpsManager;
@@ -1202,6 +1204,7 @@
 
         ApiCallbacks(Context context, UserDataMap userDataMap,
                 UserToInputMethodInfoMap inputMethodInfoMap) {
+            mContext = context;
             mUserDataMap = userDataMap;
             mInputMethodInfoMap = inputMethodInfoMap;
             mAppOpsManager = context.getSystemService(AppOpsManager.class);
@@ -1239,8 +1242,11 @@
 
         @BinderThread
         @Override
-        public List<InputMethodInfo> getEnabledInputMethodList() {
-            return mInputMethodInfoMap.getAsList(UserHandle.getUserId(Binder.getCallingUid()));
+        public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
+            if (UserHandle.getCallingUserId() != userId) {
+                mContext.enforceCallingPermission(INTERACT_ACROSS_USERS_FULL, null);
+            }
+            return mInputMethodInfoMap.getAsList(userId);
         }
 
         @BinderThread
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index cefe583..19d10ec 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -509,7 +509,7 @@
         private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
         private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
         private static final boolean DEFAULT_USE_HEARTBEATS = false;
-        private static final boolean DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+        private static final boolean DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
         private static final long DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS =
                 10 * 60 * 1000L; // 10 minutes
         private static final long DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS =
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
index b3f1018..0edd17b 100644
--- a/services/core/java/com/android/server/location/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -16,6 +16,7 @@
 
 package com.android.server.location;
 
+import android.content.Context;
 import android.location.Location;
 import android.location.LocationProvider;
 import android.os.Bundle;
@@ -26,6 +27,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -65,9 +67,12 @@
         void onReportLocation(List<Location> locations);
     }
 
+    protected final Context mContext;
     private final LocationProviderManager mLocationProviderManager;
 
-    protected AbstractLocationProvider(LocationProviderManager locationProviderManager) {
+    protected AbstractLocationProvider(
+            Context context, LocationProviderManager locationProviderManager) {
+        mContext = context;
         mLocationProviderManager = locationProviderManager;
     }
 
@@ -101,6 +106,11 @@
         mLocationProviderManager.onSetProperties(properties);
     }
 
+    /** Returns list of packages currently associated with this provider. */
+    public List<String> getProviderPackages() {
+        return Collections.singletonList(mContext.getPackageName());
+    }
+
     /**
      * Called when the location service delivers a new request for fulfillment to the provider.
      * Replaces any previous requests completely.
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index ab9f711..b18110e 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -368,7 +368,6 @@
     private int mC2KServerPort;
     private boolean mSuplEsEnabled = false;
 
-    private final Context mContext;
     private final Looper mLooper;
     private final LocationExtras mLocationExtras = new LocationExtras();
     private final GnssStatusListenerHelper mGnssStatusListenerHelper;
@@ -562,9 +561,8 @@
 
     public GnssLocationProvider(Context context, LocationProviderManager locationProviderManager,
             Looper looper) {
-        super(locationProviderManager);
+        super(context, locationProviderManager);
 
-        mContext = context;
         mLooper = looper;
 
         // Create a wake lock
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 776beb5..34c8786 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -16,8 +16,11 @@
 
 package com.android.server.location;
 
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.location.Location;
 import android.location.LocationProvider;
 import android.os.Bundle;
@@ -39,6 +42,10 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * Proxy for ILocationProvider implementations.
@@ -48,14 +55,21 @@
     private static final String TAG = "LocationProviderProxy";
     private static final boolean D = LocationManagerService.D;
 
+    // used to ensure that updates to mProviderPackages are atomic
+    private final Object mProviderPackagesLock = new Object();
+
     // used to ensure that updates to mRequest and mWorkSource are atomic
     private final Object mRequestLock = new Object();
 
-    private final ServiceWatcher mServiceWatcher;
-
     private final ILocationProviderManager.Stub mManager = new ILocationProviderManager.Stub() {
         // executed on binder thread
         @Override
+        public void onSetAdditionalProviderPackages(List<String> packageNames) {
+            LocationProviderProxy.this.onSetAdditionalProviderPackages(packageNames);
+        }
+
+        // executed on binder thread
+        @Override
         public void onSetEnabled(boolean enabled) {
             LocationProviderProxy.this.setEnabled(enabled);
         }
@@ -73,6 +87,11 @@
         }
     };
 
+    private final ServiceWatcher mServiceWatcher;
+
+    @GuardedBy("mProviderPackagesLock")
+    private final CopyOnWriteArrayList<String> mProviderPackages = new CopyOnWriteArrayList<>();
+
     @GuardedBy("mRequestLock")
     @Nullable
     private ProviderRequest mRequest;
@@ -101,7 +120,7 @@
     private LocationProviderProxy(Context context, LocationProviderManager locationProviderManager,
             String action, int overlaySwitchResId, int defaultServicePackageNameResId,
             int initialPackageNamesResId) {
-        super(locationProviderManager);
+        super(context, locationProviderManager);
 
         mServiceWatcher = new ServiceWatcher(context, TAG, action, overlaySwitchResId,
                 defaultServicePackageNameResId, initialPackageNamesResId,
@@ -114,6 +133,7 @@
 
             @Override
             protected void onUnbind() {
+                resetProviderPackages(Collections.emptyList());
                 setEnabled(false);
                 setProperties(null);
             }
@@ -131,6 +151,8 @@
         ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
         if (D) Log.d(TAG, "applying state to connected service " + mServiceWatcher);
 
+        resetProviderPackages(Collections.emptyList());
+
         service.setLocationProviderManager(mManager);
 
         synchronized (mRequestLock) {
@@ -140,9 +162,11 @@
         }
     }
 
-    @Nullable
-    public String getConnectedPackageName() {
-        return mServiceWatcher.getCurrentPackageName();
+    @Override
+    public List<String> getProviderPackages() {
+        synchronized (mProviderPackagesLock) {
+            return mProviderPackages;
+        }
     }
 
     @Override
@@ -193,4 +217,30 @@
             service.sendExtraCommand(command, extras);
         });
     }
+
+    private void onSetAdditionalProviderPackages(List<String> packageNames) {
+        resetProviderPackages(packageNames);
+    }
+
+    private void resetProviderPackages(List<String> additionalPackageNames) {
+        ArrayList<String> permittedPackages = new ArrayList<>(additionalPackageNames.size());
+        for (String packageName : additionalPackageNames) {
+            try {
+                mContext.getPackageManager().getPackageInfo(packageName, MATCH_SYSTEM_ONLY);
+                permittedPackages.add(packageName);
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.w(TAG, mServiceWatcher + " specified unknown additional provider package: "
+                        + packageName);
+            }
+        }
+
+        synchronized (mProviderPackagesLock) {
+            mProviderPackages.clear();
+            String myPackage = mServiceWatcher.getCurrentPackageName();
+            if (myPackage != null) {
+                mProviderPackages.add(myPackage);
+                mProviderPackages.addAll(permittedPackages);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index fe91c63..6accad8 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -17,6 +17,7 @@
 package com.android.server.location;
 
 import android.annotation.Nullable;
+import android.content.Context;
 import android.location.Location;
 import android.location.LocationProvider;
 import android.os.Bundle;
@@ -41,9 +42,9 @@
     private long mStatusUpdateTime;
     private Bundle mExtras;
 
-    public MockProvider(
+    public MockProvider(Context context,
             LocationProviderManager locationProviderManager, ProviderProperties properties) {
-        super(locationProviderManager);
+        super(context, locationProviderManager);
 
         mEnabled = true;
         mLocation = null;
diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java
index 30260b2..3a841c9 100644
--- a/services/core/java/com/android/server/location/PassiveProvider.java
+++ b/services/core/java/com/android/server/location/PassiveProvider.java
@@ -16,6 +16,7 @@
 
 package com.android.server.location;
 
+import android.content.Context;
 import android.location.Criteria;
 import android.location.Location;
 import android.os.Bundle;
@@ -42,8 +43,8 @@
 
     private boolean mReportLocation;
 
-    public PassiveProvider(LocationProviderManager locationProviderManager) {
-        super(locationProviderManager);
+    public PassiveProvider(Context context, LocationProviderManager locationProviderManager) {
+        super(context, locationProviderManager);
 
         mReportLocation = false;
 
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index be15fda..b85abd9 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -51,7 +51,7 @@
      * Notifies that smart replies and actions have been added to the UI.
      */
     void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount, int smartActionCount,
-            boolean generatedByAssistant);
+            boolean generatedByAssistant, boolean editBeforeSending);
 
     /**
      * Notifies a smart reply is sent.
@@ -59,9 +59,9 @@
      * @param key the notification key
      * @param clickedIndex the index of clicked reply
      * @param reply the reply that is sent
-     * @param generatedByAssistant specifies is the reply generated by NAS
      * @param notificationLocation the location of the notification containing the smart reply
+     * @param modifiedBeforeSending whether the user changed the smart reply before sending
      */
     void onNotificationSmartReplySent(String key, int clickedIndex, CharSequence reply,
-            boolean generatedByAssistant, int notificationLocation);
+            int notificationLocation, boolean modifiedBeforeSending);
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ba187c0..34a6663c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -917,20 +917,21 @@
 
         @Override
         public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount,
-                int smartActionCount, boolean generatedByAssistant) {
+                int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) {
             synchronized (mNotificationLock) {
                 NotificationRecord r = mNotificationsByKey.get(key);
                 if (r != null) {
                     r.setNumSmartRepliesAdded(smartReplyCount);
                     r.setNumSmartActionsAdded(smartActionCount);
                     r.setSuggestionsGeneratedByAssistant(generatedByAssistant);
+                    r.setEditChoicesBeforeSending(editBeforeSending);
                 }
             }
         }
 
         @Override
         public void onNotificationSmartReplySent(String key, int replyIndex, CharSequence reply,
-                boolean generatedByAssistant, int notificationLocation) {
+                int notificationLocation, boolean modifiedBeforeSending) {
 
             synchronized (mNotificationLock) {
                 NotificationRecord r = mNotificationsByKey.get(key);
@@ -940,14 +941,20 @@
                             .setSubtype(replyIndex)
                             .addTaggedData(
                                     MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
-                                    generatedByAssistant ? 1 : 0)
+                                    r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
                             .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION,
-                                    notificationLocation);
+                                    notificationLocation)
+                            .addTaggedData(
+                                    MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
+                                    r.getEditChoicesBeforeSending() ? 1 : 0)
+                            .addTaggedData(
+                                    MetricsEvent.NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING,
+                                    modifiedBeforeSending ? 1 : 0);
                     mMetricsLogger.write(logMaker);
                     // Treat clicking on a smart reply as a user interaction.
                     reportUserInteraction(r);
                     mAssistants.notifyAssistantSuggestedReplySent(
-                            r.sbn, reply, generatedByAssistant);
+                            r.sbn, reply, r.getSuggestionsGeneratedByAssistant());
                 }
             }
         }
@@ -981,7 +988,10 @@
                             r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
                     // The fields in the NotificationVisibility.NotificationLocation enum map
                     // directly to the fields in the MetricsEvent.NotificationLocation enum.
-                    .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, notificationLocation);
+                    .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, notificationLocation)
+                    .addTaggedData(
+                            MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
+                            r.getEditChoicesBeforeSending() ? 1 : 0);
             mMetricsLogger.write(logMaker);
         }
     }
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index ab49ebb..b3394b4 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -178,6 +178,7 @@
     private int mNumberOfSmartRepliesAdded;
     private int mNumberOfSmartActionsAdded;
     private boolean mSuggestionsGeneratedByAssistant;
+    private boolean mEditChoicesBeforeSending;
     private boolean mHasSeenSmartReplies;
     /**
      * Whether this notification (and its channels) should be considered user locked. Used in
@@ -1136,6 +1137,14 @@
         return mSuggestionsGeneratedByAssistant;
     }
 
+    public boolean getEditChoicesBeforeSending() {
+        return mEditChoicesBeforeSending;
+    }
+
+    public void setEditChoicesBeforeSending(boolean editChoicesBeforeSending) {
+        mEditChoicesBeforeSending = editChoicesBeforeSending;
+    }
+
     public boolean hasSeenSmartReplies() {
         return mHasSeenSmartReplies;
     }
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index f736056..1dada92 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -17,8 +17,10 @@
 package com.android.server.os;
 
 import android.annotation.RequiresPermission;
+import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.content.Context;
+import android.content.pm.UserInfo;
 import android.os.Binder;
 import android.os.BugreportParams;
 import android.os.IDumpstate;
@@ -28,26 +30,29 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UserManager;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
 import java.io.FileDescriptor;
 
 // TODO(b/111441001):
-// 1. Handle the case where another bugreport is in progress
-// 2. Make everything threadsafe
-// 3. Pass validation & other errors on listener
+// Intercept onFinished() & implement death recipient here and shutdown
+// bugreportd service.
 
 /**
  * Implementation of the service that provides a privileged API to capture and consume bugreports.
  *
- * <p>Delegates the actualy generation to a native implementation of {@code Dumpstate}.
+ * <p>Delegates the actualy generation to a native implementation of {@code IDumpstate}.
  */
 class BugreportManagerServiceImpl extends IDumpstate.Stub {
     private static final String TAG = "BugreportManagerService";
     private static final String BUGREPORT_SERVICE = "bugreportd";
     private static final long DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS = 30 * 1000;
 
-    private IDumpstate mDs = null;
+    private final Object mLock = new Object();
     private final Context mContext;
     private final AppOpsManager mAppOps;
 
@@ -59,43 +64,44 @@
     @Override
     @RequiresPermission(android.Manifest.permission.DUMP)
     public IDumpstateToken setListener(String name, IDumpstateListener listener,
-            boolean getSectionDetails) throws RemoteException {
-        // TODO(b/111441001): Figure out if lazy setting of listener should be allowed
-        // and if so how to handle it.
+            boolean getSectionDetails) {
         throw new UnsupportedOperationException("setListener is not allowed on this service");
     }
 
-    // TODO(b/111441001): Intercept onFinished here in system server and shutdown
-    // the bugreportd service.
     @Override
     @RequiresPermission(android.Manifest.permission.DUMP)
     public void startBugreport(int callingUidUnused, String callingPackage,
             FileDescriptor bugreportFd, FileDescriptor screenshotFd,
-            int bugreportMode, IDumpstateListener listener) throws RemoteException {
-        int callingUid = Binder.getCallingUid();
-        // TODO(b/111441001): validate all arguments & ensure primary user
-        validate(bugreportMode);
+            int bugreportMode, IDumpstateListener listener) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "startBugreport");
+        Preconditions.checkNotNull(callingPackage);
+        Preconditions.checkNotNull(bugreportFd);
+        Preconditions.checkNotNull(listener);
+        validateBugreportMode(bugreportMode);
+        ensureIsPrimaryUser();
 
+        int callingUid = Binder.getCallingUid();
         mAppOps.checkPackage(callingUid, callingPackage);
-        mDs = getDumpstateService();
-        if (mDs == null) {
-            Slog.w(TAG, "Unable to get bugreport service");
-            // TODO(b/111441001): pass error on listener
-            return;
+
+        synchronized (mLock) {
+            startBugreportLocked(callingUid, callingPackage, bugreportFd, screenshotFd,
+                    bugreportMode, listener);
         }
-        mDs.startBugreport(callingUid, callingPackage,
-                bugreportFd, screenshotFd, bugreportMode, listener);
     }
 
     @Override
     @RequiresPermission(android.Manifest.permission.DUMP)
-    public void cancelBugreport() throws RemoteException {
-        // This tells init to cancel bugreportd service.
-        SystemProperties.set("ctl.stop", BUGREPORT_SERVICE);
-        mDs = null;
+    public void cancelBugreport() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "startBugreport");
+        // This tells init to cancel bugreportd service. Note that this is achieved through setting
+        // a system property which is not thread-safe. So the lock here offers thread-safety only
+        // among callers of the API.
+        synchronized (mLock) {
+            SystemProperties.set("ctl.stop", BUGREPORT_SERVICE);
+        }
     }
 
-    private boolean validate(@BugreportParams.BugreportMode int mode) {
+    private void validateBugreportMode(@BugreportParams.BugreportMode int mode) {
         if (mode != BugreportParams.BUGREPORT_MODE_FULL
                 && mode != BugreportParams.BUGREPORT_MODE_INTERACTIVE
                 && mode != BugreportParams.BUGREPORT_MODE_REMOTE
@@ -103,9 +109,66 @@
                 && mode != BugreportParams.BUGREPORT_MODE_TELEPHONY
                 && mode != BugreportParams.BUGREPORT_MODE_WIFI) {
             Slog.w(TAG, "Unknown bugreport mode: " + mode);
-            return false;
+            throw new IllegalArgumentException("Unknown bugreport mode: " + mode);
         }
-        return true;
+    }
+
+    /**
+     * Validates that the current user is the primary user.
+     *
+     * @throws IllegalArgumentException if the current user is not the primary user
+     */
+    private void ensureIsPrimaryUser() {
+        UserInfo currentUser = null;
+        try {
+            currentUser = ActivityManager.getService().getCurrentUser();
+        } catch (RemoteException e) {
+            // Impossible to get RemoteException for an in-process call.
+        }
+
+        UserInfo primaryUser = UserManager.get(mContext).getPrimaryUser();
+        if (currentUser == null) {
+            logAndThrow("No current user. Only primary user is allowed to take bugreports.");
+        }
+        if (primaryUser == null) {
+            logAndThrow("No primary user. Only primary user is allowed to take bugreports.");
+        }
+        if (primaryUser.id != currentUser.id) {
+            logAndThrow("Current user not primary user. Only primary user"
+                    + " is allowed to take bugreports.");
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void startBugreportLocked(int callingUid, String callingPackage,
+            FileDescriptor bugreportFd, FileDescriptor screenshotFd,
+            int bugreportMode, IDumpstateListener listener) {
+        if (isDumpstateBinderServiceRunningLocked()) {
+            Slog.w(TAG, "'dumpstate' is already running. Cannot start a new bugreport"
+                    + " while another one is currently in progress.");
+            // TODO(b/111441001): Use a new error code; add this to the documentation of the API.
+            reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
+            return;
+        }
+
+        IDumpstate ds = startAndGetDumpstateBinderServiceLocked();
+        if (ds == null) {
+            Slog.w(TAG, "Unable to get bugreport service");
+            reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
+            return;
+        }
+        try {
+            ds.startBugreport(callingUid, callingPackage,
+                    bugreportFd, screenshotFd, bugreportMode, listener);
+        } catch (RemoteException e) {
+            reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private boolean isDumpstateBinderServiceRunningLocked() {
+        IDumpstate ds = IDumpstate.Stub.asInterface(ServiceManager.getService("dumpstate"));
+        return ds != null;
     }
 
     /*
@@ -115,8 +178,12 @@
      * <p>Generating bugreports requires root privileges. To limit the footprint
      * of the root access, the actual generation in Dumpstate binary is accessed as a
      * oneshot service 'bugreport'.
+     *
+     * <p>Note that starting the service is achieved through setting a system property, which is
+     * not thread-safe. So the lock here offers thread-safety only among callers of the API.
      */
-    private IDumpstate getDumpstateService() {
+    @GuardedBy("mLock")
+    private IDumpstate startAndGetDumpstateBinderServiceLocked() {
         // Start bugreport service.
         SystemProperties.set("ctl.start", BUGREPORT_SERVICE);
 
@@ -145,4 +212,18 @@
         }
         return ds;
     }
+
+    private void reportError(IDumpstateListener listener, int errorCode) {
+        try {
+            listener.onError(errorCode);
+        } catch (RemoteException e) {
+            // Something went wrong in binder or app process. There's nothing to do here.
+            Slog.w(TAG, "onError() transaction threw RemoteException: " + e.getMessage());
+        }
+    }
+
+    private void logAndThrow(String message) {
+        Slog.w(TAG, message);
+        throw new IllegalArgumentException(message);
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6500805..e18da7f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -131,8 +131,6 @@
 import android.app.admin.IDevicePolicyManager;
 import android.app.admin.SecurityLog;
 import android.app.backup.IBackupManager;
-import android.app.role.RoleManager;
-import android.app.role.RoleManagerCallback;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -290,7 +288,6 @@
 import com.android.internal.os.Zygote;
 import com.android.internal.telephony.CarrierAppUtils;
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.ConcurrentUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
@@ -372,10 +369,8 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
@@ -989,6 +984,9 @@
     @GuardedBy("mPackages")
     private CheckPermissionDelegate mCheckPermissionDelegate;
 
+    @GuardedBy("mPackages")
+    private PackageManagerInternal.DefaultBrowserProvider mDefaultBrowserProvider;
+
     private class IntentVerifierProxy implements IntentFilterVerifier<ActivityIntentInfo> {
         private Context mContext;
         private ComponentName mIntentFilterVerifierComponent;
@@ -3943,13 +3941,13 @@
                 if (apex != null) {
                     try {
                         final ApexInfo activePkg = apex.getActivePackage(packageName);
-                        if (activePkg != null) {
+                        if (activePkg != null && !TextUtils.isEmpty(activePkg.packagePath)) {
                             try {
                                 return PackageParser.generatePackageInfoFromApex(
                                         new File(activePkg.packagePath), true /* collect certs */);
                             } catch (PackageParserException pe) {
-                                throw new IllegalStateException("Unable to parse: " + activePkg,
-                                        pe);
+                                Log.e(TAG, "Unable to parse package at "
+                                        + activePkg.packagePath, pe);
                             }
                         }
                     } catch (RemoteException e) {
@@ -13428,6 +13426,10 @@
             return false;
         }
 
+        if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) {
+            return false;
+        }
+
         boolean ensureVerifyAppsEnabled = isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS);
 
         // Check if installing from ADB
@@ -13581,31 +13583,25 @@
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
         }
-
         if (userId == UserHandle.USER_ALL) {
             return false;
         }
-        RoleManager roleManager = mContext.getSystemService(RoleManager.class);
-        UserHandle user = UserHandle.of(userId);
-        RoleManagerCallback.Future future = new RoleManagerCallback.Future();
-        if (packageName != null) {
-            Binder.withCleanCallingIdentity(() -> roleManager.addRoleHolderAsUser(
-                    RoleManager.ROLE_BROWSER, packageName, user, AsyncTask.THREAD_POOL_EXECUTOR,
-                    future));
-        } else {
-            Binder.withCleanCallingIdentity(() -> roleManager.clearRoleHoldersAsUser(
-                    RoleManager.ROLE_BROWSER, user, AsyncTask.THREAD_POOL_EXECUTOR, future));
+        PackageManagerInternal.DefaultBrowserProvider provider;
+        synchronized (mPackages) {
+            provider = mDefaultBrowserProvider;
         }
-        try {
-            future.get(5, TimeUnit.SECONDS);
-        } catch (InterruptedException | ExecutionException | TimeoutException e) {
-            Slog.e(TAG, "Exception while setting default browser package name: " + packageName, e);
+        if (provider == null) {
+            Slog.e(TAG, "mDefaultBrowserProvider is null");
             return false;
         }
-        synchronized (mPackages) {
-            if (packageName != null) {
-                mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowser(
-                        packageName, userId);
+        boolean successful = provider.setDefaultBrowser(packageName, userId);
+        if (!successful) {
+            return false;
+        }
+        if (packageName != null) {
+            synchronized (mPackages) {
+                mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
+                        userId);
             }
         }
         return true;
@@ -13620,10 +13616,15 @@
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return null;
         }
-        RoleManager roleManager = mContext.getSystemService(RoleManager.class);
-        List<String> packageNames = Binder.withCleanCallingIdentity(() ->
-                roleManager.getRoleHoldersAsUser(RoleManager.ROLE_BROWSER, UserHandle.of(userId)));
-        return CollectionUtils.firstOrNull(packageNames);
+        PackageManagerInternal.DefaultBrowserProvider provider;
+        synchronized (mPackages) {
+            provider = mDefaultBrowserProvider;
+        }
+        if (provider == null) {
+            Slog.e(TAG, "mDefaultBrowserProvider is null");
+            return null;
+        }
+        return provider.getDefaultBrowser(userId);
     }
 
     /**
@@ -23922,6 +23923,13 @@
                 return mSettings.removeDefaultBrowserPackageNameLPw(userId);
             }
         }
+
+        @Override
+        public void setDefaultBrowserProvider(@NonNull DefaultBrowserProvider provider) {
+            synchronized (mPackages) {
+                mDefaultBrowserProvider = provider;
+            }
+        }
     }
 
     @GuardedBy("mPackages")
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 0371663..55eb7ea 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -21,6 +21,7 @@
 import android.apex.ApexInfoList;
 import android.apex.ApexSessionInfo;
 import android.apex.IApexService;
+import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
 import android.content.Intent;
@@ -33,6 +34,7 @@
 import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.Signature;
+import android.content.rollback.IRollbackManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -186,6 +188,7 @@
     private void preRebootVerification(@NonNull PackageInstallerSession session) {
         boolean success = true;
 
+        // STOPSHIP: TODO(b/123753157): Verify APKs through Package Verifier.
         if (!sessionContainsApex(session)) {
             // TODO: Decide whether we want to fail fast by detecting signature mismatches for APKs,
             // right away.
@@ -238,6 +241,23 @@
             }
         }
 
+        if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
+            // If rollback is enabled for this session, we call through to the RollbackManager
+            // with the list of sessions it must enable rollback for. Note that notifyStagedSession
+            // is a synchronous operation.
+            final IRollbackManager rm = IRollbackManager.Stub.asInterface(
+                    ServiceManager.getService(Context.ROLLBACK_SERVICE));
+            try {
+                // NOTE: To stay consistent with the non-staged install flow, we don't fail the
+                // entire install if rollbacks can't be enabled.
+                if (!rm.notifyStagedSession(session.sessionId)) {
+                    Slog.e(TAG, "Unable to enable rollback for session: " + session.sessionId);
+                }
+            } catch (RemoteException re) {
+                // Cannot happen, the rollback manager is in the same process.
+            }
+        }
+
         session.setStagedSessionReady();
         if (!sendMarkStagedSessionReadyRequest(session.sessionId)) {
             session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
@@ -336,6 +356,7 @@
 
         PackageInstaller.SessionParams params = originalSession.params.copy();
         params.isStaged = false;
+        params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
         int apkSessionId = mPi.createSession(
                 params, originalSession.getInstallerPackageName(), originalSession.userId);
         PackageInstallerSession apkSession = mPi.getSession(apkSessionId);
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 09bacd6..0892b32 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -18,6 +18,14 @@
                     "include-filter": "android.permission.cts.SplitPermissionTest"
                 }
             ]
+        },
+        {
+            "name": "CtsStatsdHostTestCases",
+            "options": [
+                {
+                    "include-filter": "android.cts.statsd.atom.UidAtomTests#testDangerousPermissionState"
+                }
+            ]
         }
     ]
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/role/RemoteRoleControllerService.java b/services/core/java/com/android/server/role/RemoteRoleControllerService.java
index be2544d..107cb2c 100644
--- a/services/core/java/com/android/server/role/RemoteRoleControllerService.java
+++ b/services/core/java/com/android/server/role/RemoteRoleControllerService.java
@@ -101,6 +101,20 @@
                 callback));
     }
 
+    /**
+     * @see RoleControllerService#onSmsKillSwitchToggled(boolean)
+     */
+    public void onSmsKillSwitchToggled(boolean smsRestrictionEnabled) {
+        mConnection.enqueueCall(new Connection.Call(
+                (s, cb) -> s.onSmsKillSwitchToggled(smsRestrictionEnabled),
+                new IRoleManagerCallback.Default() {
+                    @Override
+                    public void onFailure() {
+                        Slog.e(LOG_TAG, "Failed onSmsKillSwitchToggled");
+                    }
+                }));
+    }
+
     private static final class Connection implements ServiceConnection {
 
         private static final long UNBIND_DELAY_MILLIS = 15 * 1000;
diff --git a/services/core/java/com/android/server/role/RoleManagerServiceInternal.java b/services/core/java/com/android/server/role/RoleManagerInternal.java
similarity index 71%
rename from services/core/java/com/android/server/role/RoleManagerServiceInternal.java
rename to services/core/java/com/android/server/role/RoleManagerInternal.java
index 3afc3f7..7598bf7 100644
--- a/services/core/java/com/android/server/role/RoleManagerServiceInternal.java
+++ b/services/core/java/com/android/server/role/RoleManagerInternal.java
@@ -17,22 +17,23 @@
 package com.android.server.role;
 
 import android.annotation.NonNull;
-import android.os.UserHandle;
+import android.annotation.UserIdInt;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
 /**
- * Internal calls into {@link RoleManagerService}
+ * Internal calls into {@link RoleManagerService}.
  */
-public abstract class RoleManagerServiceInternal {
+public abstract class RoleManagerInternal {
+
     /**
-     * Get all roles and packages hold them.
+     * Get all roles and their holders.
      *
-     * @param user The user to query to roles for
+     * @param userId The user to query to roles for
      *
      * @return The roles and their holders
      */
     @NonNull
-    public abstract ArrayMap<String, ArraySet<String>> getRoleHoldersAsUser(
-            @NonNull UserHandle user);
+    public abstract ArrayMap<String, ArraySet<String>> getRolesAndHolders(
+            @UserIdInt int userId);
 }
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index d72270e..84305be 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -38,7 +38,9 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
+import android.database.ContentObserver;
 import android.database.CursorWindow;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -49,6 +51,7 @@
 import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
+import android.provider.Settings;
 import android.service.sms.FinancialSmsService;
 import android.telephony.IFinancialSmsCallback;
 import android.text.TextUtils;
@@ -146,8 +149,11 @@
         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
         mAppOpsManager = context.getSystemService(AppOpsManager.class);
 
-        LocalServices.addService(RoleManagerServiceInternal.class,
-                new RoleManagerServiceInternalImpl());
+        LocalServices.addService(RoleManagerInternal.class, new Internal());
+
+        PackageManagerInternal packageManagerInternal = LocalServices.getService(
+                PackageManagerInternal.class);
+        packageManagerInternal.setDefaultBrowserProvider(new DefaultBrowserProvider());
 
         registerUserRemovedReceiver();
     }
@@ -189,6 +195,18 @@
                 performInitialGrantsIfNecessary(userId);
             }
         }, UserHandle.SYSTEM, intentFilter, null /* broadcastPermission */, null /* handler */);
+
+        getContext().getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED), false,
+                new ContentObserver(getContext().getMainThreadHandler()) {
+                    @Override
+                    public void onChange(boolean selfChange, Uri uri, int userId) {
+                        getOrCreateControllerService(userId).onSmsKillSwitchToggled(
+                                Settings.Global.getInt(
+                                        getContext().getContentResolver(),
+                                        Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, 0) == 1);
+                    }
+                }, UserHandle.USER_ALL);
     }
 
     @Override
@@ -360,10 +378,10 @@
             notifyRoleHoldersChangedForListeners(listeners, roleName, userId);
         }
 
-        RemoteCallbackList<IOnRoleHoldersChangedListener> allUserListeners = getListeners(
+        RemoteCallbackList<IOnRoleHoldersChangedListener> allUsersListeners = getListeners(
                 UserHandle.USER_ALL);
-        if (allUserListeners != null) {
-            notifyRoleHoldersChangedForListeners(allUserListeners, roleName, userId);
+        if (allUsersListeners != null) {
+            notifyRoleHoldersChangedForListeners(allUsersListeners, roleName, userId);
         }
     }
 
@@ -386,19 +404,6 @@
         }
     }
 
-    /**
-     * Get all roles and packages hold them.
-     *
-     * @param user The user to query to roles for
-     *
-     * @return The roles and their holders
-     */
-    @NonNull
-    private ArrayMap<String, ArraySet<String>> getRoleHoldersAsUser(@NonNull UserHandle user) {
-        RoleUserState userState = getOrCreateUserState(user.getIdentifier());
-        return userState.getRoleHolders();
-    }
-
     private class Stub extends IRoleManager.Stub {
 
         @Override
@@ -406,8 +411,7 @@
             Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
 
             int userId = UserHandle.getUserId(getCallingUid());
-            RoleUserState userState = getOrCreateUserState(userId);
-            return userState.isRoleAvailable(roleName);
+            return getOrCreateUserState(userId).isRoleAvailable(roleName);
         }
 
         @Override
@@ -418,7 +422,7 @@
             mAppOpsManager.checkPackage(callingUid, packageName);
 
             int userId = UserHandle.getUserId(callingUid);
-            ArraySet<String> roleHolders = getRoleHoldersInternal(roleName, userId);
+            ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
             if (roleHolders == null) {
                 return false;
             }
@@ -433,24 +437,17 @@
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return Collections.emptyList();
             }
-            userId = handleIncomingUser(userId, "getRoleHoldersAsUser", false);
+            userId = handleIncomingUser(userId, false, "getRoleHoldersAsUser");
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "getRoleHoldersAsUser");
 
-            ArraySet<String> roleHolders = getRoleHoldersInternal(roleName, userId);
+            ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
             if (roleHolders == null) {
                 return Collections.emptyList();
             }
             return new ArrayList<>(roleHolders);
         }
 
-        @Nullable
-        private ArraySet<String> getRoleHoldersInternal(@NonNull String roleName,
-                @UserIdInt int userId) {
-            RoleUserState userState = getOrCreateUserState(userId);
-            return userState.getRoleHolders(roleName);
-        }
-
         @Override
         public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
                 @UserIdInt int userId, @NonNull IRoleManagerCallback callback) {
@@ -461,7 +458,7 @@
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
             }
-            userId = handleIncomingUser(userId, "addRoleHolderAsUser", false);
+            userId = handleIncomingUser(userId, false, "addRoleHolderAsUser");
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "addRoleHolderAsUser");
 
@@ -478,7 +475,7 @@
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
             }
-            userId = handleIncomingUser(userId, "removeRoleHolderAsUser", false);
+            userId = handleIncomingUser(userId, false, "removeRoleHolderAsUser");
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "removeRoleHolderAsUser");
 
@@ -495,7 +492,7 @@
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
             }
-            userId = handleIncomingUser(userId, "clearRoleHoldersAsUser", false);
+            userId = handleIncomingUser(userId, false, "clearRoleHoldersAsUser");
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "clearRoleHoldersAsUser");
 
@@ -510,8 +507,7 @@
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
             }
-            userId = handleIncomingUser(userId, "addOnRoleHoldersChangedListenerAsUser",
-                    true);
+            userId = handleIncomingUser(userId, true, "addOnRoleHoldersChangedListenerAsUser");
             getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
                     "addOnRoleHoldersChangedListenerAsUser");
 
@@ -528,8 +524,7 @@
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
             }
-            userId = handleIncomingUser(userId, "removeOnRoleHoldersChangedListenerAsUser",
-                    true);
+            userId = handleIncomingUser(userId, true, "removeOnRoleHoldersChangedListenerAsUser");
             getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
                     "removeOnRoleHoldersChangedListenerAsUser");
 
@@ -548,8 +543,7 @@
                     "setRoleNamesFromController");
 
             int userId = UserHandle.getCallingUserId();
-            RoleUserState userState = getOrCreateUserState(userId);
-            userState.setRoleNames(roleNames);
+            getOrCreateUserState(userId).setRoleNames(roleNames);
         }
 
         @Override
@@ -562,8 +556,7 @@
                     "addRoleHolderFromController");
 
             int userId = UserHandle.getCallingUserId();
-            RoleUserState userState = getOrCreateUserState(userId);
-            return userState.addRoleHolder(roleName, packageName);
+            return getOrCreateUserState(userId).addRoleHolder(roleName, packageName);
         }
 
         @Override
@@ -576,8 +569,7 @@
                     "removeRoleHolderFromController");
 
             int userId = UserHandle.getCallingUserId();
-            RoleUserState userState = getOrCreateUserState(userId);
-            return userState.removeRoleHolder(roleName, packageName);
+            return getOrCreateUserState(userId).removeRoleHolder(roleName, packageName);
         }
 
         @Override
@@ -588,13 +580,12 @@
                     "getRolesHeldFromController");
 
             int userId = UserHandle.getCallingUserId();
-            RoleUserState userState = getOrCreateUserState(userId);
-            return userState.getHeldRoles(packageName);
+            return getOrCreateUserState(userId).getHeldRoles(packageName);
         }
 
         @CheckResult
-        private int handleIncomingUser(@UserIdInt int userId, @NonNull String name,
-                boolean allowAll) {
+        private int handleIncomingUser(@UserIdInt int userId, boolean allowAll,
+                @NonNull String name) {
             return ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
                     allowAll, true, name, null);
         }
@@ -694,15 +685,51 @@
         }
     }
 
-    /**
-     * Entry point for internal calls into role manager
-     */
-    private final class RoleManagerServiceInternalImpl extends RoleManagerServiceInternal {
+    private class Internal extends RoleManagerInternal {
 
         @NonNull
         @Override
-        public ArrayMap<String, ArraySet<String>> getRoleHoldersAsUser(@NonNull UserHandle user) {
-            return RoleManagerService.this.getRoleHoldersAsUser(user);
+        public ArrayMap<String, ArraySet<String>> getRolesAndHolders(@UserIdInt int userId) {
+            return getOrCreateUserState(userId).getRolesAndHolders();
+        }
+    }
+
+    private class DefaultBrowserProvider implements PackageManagerInternal.DefaultBrowserProvider {
+
+        @Nullable
+        @Override
+        public String getDefaultBrowser(@UserIdInt int userId) {
+            return CollectionUtils.firstOrNull(getOrCreateUserState(userId).getRoleHolders(
+                    RoleManager.ROLE_BROWSER));
+        }
+
+        @Override
+        public boolean setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId) {
+            CompletableFuture<Void> future = new CompletableFuture<>();
+            IRoleManagerCallback callback = new IRoleManagerCallback.Stub() {
+                @Override
+                public void onSuccess() {
+                    future.complete(null);
+                }
+                @Override
+                public void onFailure() {
+                    future.completeExceptionally(new RuntimeException());
+                }
+            };
+            if (packageName != null) {
+                getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
+                        packageName, callback);
+            } else {
+                getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER,
+                        callback);
+            }
+            try {
+                future.get(5, TimeUnit.SECONDS);
+                return true;
+            } catch (InterruptedException | ExecutionException | TimeoutException e) {
+                Slog.e(LOG_TAG, "Exception while setting default browser: " + packageName, e);
+                return false;
+            }
         }
     }
 }
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 5030e34..c7e3fa4 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -576,13 +576,14 @@
      * @return A copy of the roles and their holders
      */
     @NonNull
-    public ArrayMap<String, ArraySet<String>> getRoleHolders() {
+    public ArrayMap<String, ArraySet<String>> getRolesAndHolders() {
         synchronized (mLock) {
             return snapshotRolesLocked();
         }
     }
 
     @GuardedBy("mLock")
+    @NonNull
     private ArrayMap<String, ArraySet<String>> snapshotRolesLocked() {
         ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>();
         for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) {
@@ -615,7 +616,8 @@
         }
     }
 
-    private static @NonNull File getFile(@UserIdInt int userId) {
+    @NonNull
+    private static File getFile(@UserIdInt int userId) {
         return new File(Environment.getUserSystemDirectory(userId), ROLES_FILE_NAME);
     }
 
diff --git a/services/core/java/com/android/server/role/TEST_MAPPING b/services/core/java/com/android/server/role/TEST_MAPPING
new file mode 100644
index 0000000..9efd292
--- /dev/null
+++ b/services/core/java/com/android/server/role/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+    "presubmit": [
+        {
+            "name": "CtsStatsdHostTestCases",
+            "options": [
+                {
+                    "include-filter": "android.cts.statsd.atom.UidAtomTests#testRoleHolder"
+                }
+            ]
+        },
+        {
+            "name": "CtsRoleTestCases"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/rollback/RollbackData.java b/services/core/java/com/android/server/rollback/RollbackData.java
index a4f3064..467bb28 100644
--- a/services/core/java/com/android/server/rollback/RollbackData.java
+++ b/services/core/java/com/android/server/rollback/RollbackData.java
@@ -50,6 +50,12 @@
     public Instant timestamp;
 
     /**
+     * The session ID for the staged session if this rollback data represents a staged session,
+     * {@code -1} otherwise.
+     */
+    public int stagedSessionId;
+
+    /**
      * Whether this Rollback is currently in progress. This field is true from the point
      * we commit a {@code PackageInstaller} session containing these packages to the point the
      * {@code PackageInstaller} calls into the {@code onFinished} callback.
@@ -57,8 +63,9 @@
     // NOTE: All accesses to this field are from the RollbackManager handler thread.
     public boolean inProgress = false;
 
-    RollbackData(int rollbackId, File backupDir) {
+    RollbackData(int rollbackId, File backupDir, int stagedSessionId) {
         this.rollbackId = rollbackId;
         this.backupDir = backupDir;
+        this.stagedSessionId = stagedSessionId;
     }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index f5b37b4..7885abe 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -59,6 +59,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
+import java.util.concurrent.LinkedBlockingQueue;
 
 /**
  * Implementation of service that manages APK level rollbacks.
@@ -156,6 +157,17 @@
             }
         }, filter, null, getHandler());
 
+        // NOTE: A new intent filter is being created here because this broadcast
+        // doesn't use a data scheme ("package") like above.
+        IntentFilter sessionUpdatedFilter = new IntentFilter();
+        sessionUpdatedFilter.addAction(PackageInstaller.ACTION_SESSION_UPDATED);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                onStagedSessionUpdated(intent);
+            }
+        }, sessionUpdatedFilter, null, getHandler());
+
         IntentFilter enableRollbackFilter = new IntentFilter();
         enableRollbackFilter.addAction(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
         try {
@@ -718,7 +730,7 @@
             return false;
         }
 
-        return enableRollbackForSession(session, installedUsers);
+        return enableRollbackForSession(session, installedUsers, true);
     }
 
     /**
@@ -727,7 +739,7 @@
      * the child sessions, not the parent session.
      */
     private boolean enableRollbackForSession(PackageInstaller.SessionInfo session,
-            int[] installedUsers) {
+            int[] installedUsers, boolean snapshotUserData) {
         // TODO: Don't attempt to enable rollback for split installs.
         final int installFlags = session.installFlags;
         if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
@@ -749,15 +761,17 @@
         }
 
         String packageName = newPackage.packageName;
-        Log.i(TAG, "Enabling rollback for install of " + packageName);
+        Log.i(TAG, "Enabling rollback for install of " + packageName
+                + ", session:" + session.sessionId);
 
         VersionedPackage newVersion = new VersionedPackage(packageName, newPackage.versionCode);
+        final boolean isApex = ((installFlags & PackageManager.INSTALL_APEX) != 0);
 
         // Get information about the currently installed package.
         PackageManager pm = mContext.getPackageManager();
         PackageInfo pkgInfo = null;
         try {
-            pkgInfo = pm.getPackageInfo(packageName, 0);
+            pkgInfo = pm.getPackageInfo(packageName, isApex ? PackageManager.MATCH_APEX : 0);
         } catch (PackageManager.NameNotFoundException e) {
             // TODO: Support rolling back fresh package installs rather than
             // fail here. Test this case.
@@ -768,17 +782,13 @@
         VersionedPackage installedVersion = new VersionedPackage(packageName,
                 pkgInfo.getLongVersionCode());
 
-        final boolean isApex = ((installFlags & PackageManager.INSTALL_APEX) != 0);
-        final IntArray pendingBackups;
-        if (isApex) {
-            pendingBackups = IntArray.wrap(new int[0]);
-        } else {
+        IntArray pendingBackups = IntArray.wrap(new int[0]);
+        if (snapshotUserData && !isApex) {
             pendingBackups = mUserdataHelper.snapshotAppData(packageName, installedUsers);
         }
 
-        // TODO: Record if this is an apex or not.
         PackageRollbackInfo info = new PackageRollbackInfo(newVersion, installedVersion,
-                pendingBackups, new ArrayList<>());
+                pendingBackups, new ArrayList<>(), isApex);
         RollbackData data;
         try {
             int childSessionId = session.getSessionId();
@@ -786,6 +796,7 @@
             if (parentSessionId == PackageInstaller.SessionInfo.INVALID_ID) {
                 parentSessionId = childSessionId;
             }
+
             synchronized (mLock) {
                 // TODO: no need to add to mChildSessions if childSessionId is
                 // the same as parentSessionId.
@@ -793,7 +804,12 @@
                 data = mPendingRollbacks.get(parentSessionId);
                 if (data == null) {
                     int rollbackId = allocateRollbackIdLocked();
-                    data = mRollbackStore.createAvailableRollback(rollbackId);
+                    if (session.isStaged()) {
+                        data = mRollbackStore.createPendingStagedRollback(rollbackId,
+                                parentSessionId);
+                    } else {
+                        data = mRollbackStore.createAvailableRollback(rollbackId);
+                    }
                     mPendingRollbacks.put(parentSessionId, data);
                 }
                 data.packages.add(info);
@@ -844,6 +860,56 @@
         });
     }
 
+    @Override
+    public boolean notifyStagedSession(int sessionId) {
+        final LinkedBlockingQueue<Boolean> result = new LinkedBlockingQueue<>();
+
+        // NOTE: We post this runnable on the RollbackManager's binder thread because we'd prefer
+        // to preserve the invariant that all operations that modify state happen there.
+        getHandler().post(() -> {
+            PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
+
+            final PackageInstaller.SessionInfo session = installer.getSessionInfo(sessionId);
+            if (session == null) {
+                Log.e(TAG, "No matching install session for: " + sessionId);
+                result.offer(false);
+                return;
+            }
+
+            if (!session.isMultiPackage()) {
+                if (!enableRollbackForSession(session, null, false)) {
+                    Log.e(TAG, "Unable to enable rollback for session: " + sessionId);
+                    result.offer(false);
+                    return;
+                }
+            } else {
+                for (int childSessionId : session.getChildSessionIds()) {
+                    final PackageInstaller.SessionInfo childSession =
+                            installer.getSessionInfo(childSessionId);
+                    if (childSession == null) {
+                        Log.e(TAG, "No matching child install session for: " + childSessionId);
+                        result.offer(false);
+                        return;
+                    }
+                    if (!enableRollbackForSession(childSession, null, false)) {
+                        Log.e(TAG, "Unable to enable rollback for session: " + sessionId);
+                        result.offer(false);
+                        return;
+                    }
+                }
+            }
+
+            result.offer(true);
+        });
+
+        try {
+            return result.take();
+        } catch (InterruptedException ie) {
+            Log.e(TAG, "Interrupted while waiting for notifyStagedSession response");
+            return false;
+        }
+    }
+
     /**
      * Gets the version of the package currently installed.
      * Returns null if the package is not currently installed.
@@ -881,60 +947,100 @@
 
         @Override
         public void onFinished(int sessionId, boolean success) {
-            RollbackData data = null;
-            synchronized (mLock) {
-                Integer parentSessionId = mChildSessions.remove(sessionId);
-                if (parentSessionId != null) {
-                    sessionId = parentSessionId;
-                }
-                data = mPendingRollbacks.remove(sessionId);
+            // If sessionId refers to a staged session, we can't deal with it here since the
+            // session might take an unbounded amount of time to become "ready" after the package
+            // installer session is committed. In those cases, we respond to it in response to
+            // a session ready broadcast.
+            PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller();
+            PackageInstaller.SessionInfo si = packageInstaller.getSessionInfo(sessionId);
+            if (si != null && si.isStaged()) {
+                return;
             }
 
-            if (data != null) {
-                if (success) {
-                    try {
-                        data.timestamp = Instant.now();
+            completeEnableRollback(sessionId, success);
+        }
+    }
 
-                        mRollbackStore.saveAvailableRollback(data);
-                        synchronized (mLock) {
-                            // Note: There is a small window of time between when
-                            // the session has been committed by the package
-                            // manager and when we make the rollback available
-                            // here. Presumably the window is small enough that
-                            // nobody will want to roll back the newly installed
-                            // package before we make the rollback available.
-                            // TODO: We'll lose the rollback data if the
-                            // device reboots between when the session is
-                            // committed and this point. Revisit this after
-                            // adding support for rollback of staged installs.
-                            ensureRollbackDataLoadedLocked();
-                            mAvailableRollbacks.add(data);
-                        }
-                        // TODO(zezeozue): Provide API to explicitly start observing instead
-                        // of doing this for all rollbacks. If we do this for all rollbacks,
-                        // should document in PackageInstaller.SessionParams#setEnableRollback
-                        // After enabling and commiting any rollback, observe packages and
-                        // prepare to rollback if packages crashes too frequently.
-                        List<String> packages = new ArrayList<>();
-                        for (int i = 0; i < data.packages.size(); i++) {
-                            packages.add(data.packages.get(i).getPackageName());
-                        }
-                        mPackageHealthObserver.startObservingHealth(packages,
-                                ROLLBACK_LIFETIME_DURATION_MILLIS);
-                        scheduleExpiration(ROLLBACK_LIFETIME_DURATION_MILLIS);
-                    } catch (IOException e) {
-                        Log.e(TAG, "Unable to enable rollback", e);
-                        mRollbackStore.deleteAvailableRollback(data);
+    private void completeEnableRollback(int sessionId, boolean success) {
+        RollbackData data = null;
+        synchronized (mLock) {
+            Integer parentSessionId = mChildSessions.remove(sessionId);
+            if (parentSessionId != null) {
+                sessionId = parentSessionId;
+            }
+
+            data = mPendingRollbacks.remove(sessionId);
+        }
+
+        if (data != null) {
+            if (success) {
+                try {
+                    data.timestamp = Instant.now();
+
+                    mRollbackStore.saveAvailableRollback(data);
+                    synchronized (mLock) {
+                        // Note: There is a small window of time between when
+                        // the session has been committed by the package
+                        // manager and when we make the rollback available
+                        // here. Presumably the window is small enough that
+                        // nobody will want to roll back the newly installed
+                        // package before we make the rollback available.
+                        // TODO: We'll lose the rollback data if the
+                        // device reboots between when the session is
+                        // committed and this point. Revisit this after
+                        // adding support for rollback of staged installs.
+                        ensureRollbackDataLoadedLocked();
+                        mAvailableRollbacks.add(data);
                     }
-                } else {
-                    // The install session was aborted, clean up the pending
-                    // install.
+                    // TODO(zezeozue): Provide API to explicitly start observing instead
+                    // of doing this for all rollbacks. If we do this for all rollbacks,
+                    // should document in PackageInstaller.SessionParams#setEnableRollback
+                    // After enabling and commiting any rollback, observe packages and
+                    // prepare to rollback if packages crashes too frequently.
+                    List<String> packages = new ArrayList<>();
+                    for (int i = 0; i < data.packages.size(); i++) {
+                        packages.add(data.packages.get(i).getPackageName());
+                    }
+                    mPackageHealthObserver.startObservingHealth(packages,
+                            ROLLBACK_LIFETIME_DURATION_MILLIS);
+                    scheduleExpiration(ROLLBACK_LIFETIME_DURATION_MILLIS);
+                } catch (IOException e) {
+                    Log.e(TAG, "Unable to enable rollback", e);
                     mRollbackStore.deleteAvailableRollback(data);
                 }
+            } else {
+                // The install session was aborted, clean up the pending
+                // install.
+                mRollbackStore.deleteAvailableRollback(data);
             }
         }
     }
 
+    private void onStagedSessionUpdated(Intent intent) {
+        PackageInstaller.SessionInfo pi = intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
+        if (pi == null) {
+            Log.e(TAG, "Missing intent extra: " + PackageInstaller.EXTRA_SESSION);
+            return;
+        }
+
+        if (pi.isStaged()) {
+            if (!pi.isSessionFailed()) {
+                // TODO: The session really isn't "enabled" at this point, since more work might
+                // be required post reboot.
+                // TODO: We need to make this case consistent with the call from onFinished.
+                //  Ideally, we'd call completeEnableRollback excatly once per multi-package session
+                //  with the parentSessionId only.
+                completeEnableRollback(pi.sessionId, pi.isSessionReady());
+            } else {
+                // TODO: Clean up the saved rollback when the session fails. This may need to be
+                // unified with the case where things fail post reboot.
+            }
+        } else {
+            Log.e(TAG, "Received onStagedSessionUpdated for: " + pi.sessionId
+                    + ", which isn't staged");
+        }
+    }
+
     /*
      * Returns the RollbackData, if any, for an available rollback that would
      * roll back the given package. Note: This assumes we have at most one
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 8e04160..3c6a54a 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -26,6 +26,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.text.TextUtils;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.StatsLog;
 
@@ -64,10 +65,8 @@
             return PackageHealthObserverImpact.USER_IMPACT_NONE;
         }
 
-        RollbackInfo rollback =
-                getAvailableMainlineRollback(mContext.getSystemService(RollbackManager.class),
-                        failedPackage, moduleMetadataPackage);
-        if (rollback == null) {
+        if (getAvailableRollback(mContext.getSystemService(RollbackManager.class),
+                        failedPackage, moduleMetadataPackage) == null) {
             // Don't handle the notification, no rollbacks available for the package
             return PackageHealthObserverImpact.USER_IMPACT_NONE;
         }
@@ -84,38 +83,46 @@
         }
 
         RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
-        RollbackInfo rollback = getAvailableMainlineRollback(rollbackManager,
+        Pair<RollbackInfo, Boolean> rollbackPair = getAvailableRollback(rollbackManager,
                 failedPackage, moduleMetadataPackage);
-        if (rollback == null) {
-            Slog.w(TAG, "Expected rollback but no mainline rollback found for package: [ "
+        if (rollbackPair == null) {
+            Slog.w(TAG, "Expected rollback but no valid rollback found for package: [ "
                     + failedPackage.getPackageName() + "] with versionCode: ["
                     + failedPackage.getVersionCode() + "]");
             return false;
         }
+        RollbackInfo rollback = rollbackPair.first;
+        // We only log mainline package rollbacks, so check if rollback contains the
+        // module metadata provider, if it does, the rollback is a mainline rollback
+        boolean hasModuleMetadataPackage = rollbackPair.second;
 
-        StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
-                StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE,
-                moduleMetadataPackage.getPackageName(),
-                moduleMetadataPackage.getVersionCode());
+        if (hasModuleMetadataPackage) {
+            StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
+                    StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE,
+                    moduleMetadataPackage.getPackageName(),
+                    moduleMetadataPackage.getVersionCode());
+        }
         LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
-            int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
-                    RollbackManager.STATUS_FAILURE);
-            if (status == RollbackManager.STATUS_SUCCESS) {
-                StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
-                        StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
-                        moduleMetadataPackage.getPackageName(),
-                        moduleMetadataPackage.getVersionCode());
-            } else {
-                StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
-                        StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
-                        moduleMetadataPackage.getPackageName(),
-                        moduleMetadataPackage.getVersionCode());
+            if (hasModuleMetadataPackage) {
+                int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
+                        RollbackManager.STATUS_FAILURE);
+                if (status == RollbackManager.STATUS_SUCCESS) {
+                    StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
+                            StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
+                            moduleMetadataPackage.getPackageName(),
+                            moduleMetadataPackage.getVersionCode());
+                } else {
+                    StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
+                            StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
+                            moduleMetadataPackage.getPackageName(),
+                            moduleMetadataPackage.getVersionCode());
+                }
             }
         });
 
         mHandler.post(() ->
                 rollbackManager.commitRollback(rollback.getRollbackId(),
-                    Collections.singletonList(moduleMetadataPackage),
+                    Collections.singletonList(failedPackage),
                     rollbackReceiver.getIntentSender()));
         // Assume rollback executed successfully
         return true;
@@ -134,7 +141,7 @@
         PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
     }
 
-    private RollbackInfo getAvailableMainlineRollback(RollbackManager rollbackManager,
+    private Pair<RollbackInfo, Boolean> getAvailableRollback(RollbackManager rollbackManager,
             VersionedPackage failedPackage, VersionedPackage moduleMetadataPackage) {
         for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) {
             // We only rollback mainline packages, so check if rollback contains the
@@ -149,8 +156,8 @@
                         && packageRollback.getVersionRolledBackFrom().getVersionCode()
                         == failedPackage.getVersionCode();
             }
-            if (hasModuleMetadataPackage && hasFailedPackage) {
-                return rollback;
+            if (hasFailedPackage) {
+                return new Pair<RollbackInfo, Boolean>(rollback, hasModuleMetadataPackage);
             }
         }
         return null;
@@ -159,7 +166,7 @@
     private VersionedPackage getModuleMetadataPackage() {
         String packageName = mContext.getResources().getString(
                 R.string.config_defaultModuleMetadataProvider);
-        if (!TextUtils.isEmpty(packageName)) {
+        if (TextUtils.isEmpty(packageName)) {
             return null;
         }
 
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 1069530..ff51690 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -201,7 +201,13 @@
      */
     RollbackData createAvailableRollback(int rollbackId) throws IOException {
         File backupDir = new File(mAvailableRollbacksDir, Integer.toString(rollbackId));
-        return new RollbackData(rollbackId, backupDir);
+        return new RollbackData(rollbackId, backupDir, -1);
+    }
+
+    RollbackData createPendingStagedRollback(int rollbackId, int stagedSessionId)
+            throws IOException {
+        File backupDir = new File(mAvailableRollbacksDir, Integer.toString(rollbackId));
+        return new RollbackData(rollbackId, backupDir, stagedSessionId);
     }
 
     /**
@@ -240,6 +246,7 @@
             dataJson.put("rollbackId", data.rollbackId);
             dataJson.put("packages", toJson(data.packages));
             dataJson.put("timestamp", data.timestamp.toString());
+            dataJson.put("stagedSessionId", data.stagedSessionId);
 
             PrintWriter pw = new PrintWriter(new File(data.backupDir, "rollback.json"));
             pw.println(dataJson.toString());
@@ -299,7 +306,9 @@
                     IoUtils.readFileAsString(rollbackJsonFile.getAbsolutePath()));
 
             int rollbackId = dataJson.getInt("rollbackId");
-            RollbackData data = new RollbackData(rollbackId, backupDir);
+            int stagedSessionId = dataJson.getInt("stagedSessionId");
+            RollbackData data = new RollbackData(rollbackId, backupDir,
+                    stagedSessionId);
             data.packages.addAll(packageRollbackInfosFromJson(dataJson.getJSONArray("packages")));
             data.timestamp = Instant.parse(dataJson.getString("timestamp"));
             return data;
@@ -331,6 +340,8 @@
         json.put("pendingBackups", convertToJsonArray(pendingBackups));
         json.put("pendingRestores", convertToJsonArray(pendingRestores));
 
+        json.put("isApex", info.isApex());
+
         return json;
     }
 
@@ -345,8 +356,10 @@
         final ArrayList<RestoreInfo> pendingRestores = convertToRestoreInfoArray(
                 json.getJSONArray("pendingRestores"));
 
+        final boolean isApex = json.getBoolean("isApex");
+
         return new PackageRollbackInfo(versionRolledBackFrom, versionRolledBackTo,
-                pendingBackups, pendingRestores);
+                pendingBackups, pendingRestores, isApex);
     }
 
     private JSONArray versionedPackagesToJson(List<VersionedPackage> packages)
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 48e64338..3586772 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -118,7 +118,7 @@
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
 import com.android.server.am.MemoryStatUtil.MemoryStat;
-import com.android.server.role.RoleManagerServiceInternal;
+import com.android.server.role.RoleManagerInternal;
 import com.android.server.storage.DiskStatsFileLogger;
 import com.android.server.storage.DiskStatsLoggingService;
 
@@ -1780,8 +1780,8 @@
             long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
         StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
         final long elapsedMillis = SystemClock.elapsedRealtime();
-        // Fails every 10 buckets.
-        if (mDebugFailingElapsedClockPullCount++ % 10 == 0) {
+        // Fails every 5 buckets.
+        if (mDebugFailingElapsedClockPullCount++ % 5 == 0) {
             mDebugFailingElapsedClockPreviousValue = elapsedMillis;
             throw new RuntimeException("Failing debug elapsed clock");
         }
@@ -1867,16 +1867,16 @@
         long callingToken = Binder.clearCallingIdentity();
         try {
             PackageManager pm = mContext.getPackageManager();
-            RoleManagerServiceInternal rm =
-                    LocalServices.getService(RoleManagerServiceInternal.class);
+            RoleManagerInternal rmi = LocalServices.getService(RoleManagerInternal.class);
 
             List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
 
             int numUsers = users.size();
             for (int userNum = 0; userNum < numUsers; userNum++) {
-                UserHandle user = users.get(userNum).getUserHandle();
+                int userId = users.get(userNum).getUserHandle().getIdentifier();
 
-                ArrayMap<String, ArraySet<String>> roles = rm.getRoleHoldersAsUser(user);
+                ArrayMap<String, ArraySet<String>> roles = rmi.getRolesAndHolders(
+                        userId);
 
                 int numRoles = roles.size();
                 for (int roleNum = 0; roleNum < numRoles; roleNum++) {
@@ -1889,7 +1889,7 @@
 
                         PackageInfo pkg;
                         try {
-                            pkg = pm.getPackageInfoAsUser(holderName, 0, user.getIdentifier());
+                            pkg = pm.getPackageInfoAsUser(holderName, 0, userId);
                         } catch (PackageManager.NameNotFoundException e) {
                             Log.w(TAG, "Role holder " + holderName + " not found");
                             return;
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index d932a40..0493ae90 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -1280,12 +1280,12 @@
 
     @Override
     public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount,
-            int smartActionCount, boolean generatedByAssistant) {
+            int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) {
         enforceStatusBarService();
         long identity = Binder.clearCallingIdentity();
         try {
             mNotificationDelegate.onNotificationSmartSuggestionsAdded(key, smartReplyCount,
-                    smartActionCount, generatedByAssistant);
+                    smartActionCount, generatedByAssistant, editBeforeSending);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -1293,13 +1293,13 @@
 
     @Override
     public void onNotificationSmartReplySent(
-            String key, int replyIndex, CharSequence reply, boolean generatedByAssistant,
-            int notificationLocation) throws RemoteException {
+            String key, int replyIndex, CharSequence reply, int notificationLocation,
+            boolean modifiedBeforeSending) throws RemoteException {
         enforceStatusBarService();
         long identity = Binder.clearCallingIdentity();
         try {
             mNotificationDelegate.onNotificationSmartReplySent(key, replyIndex, reply,
-                    generatedByAssistant, notificationLocation);
+                    notificationLocation, modifiedBeforeSending);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 111808b..18df88b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -20,8 +20,10 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -3250,6 +3252,7 @@
         mInputMethodTarget = target;
         mInputMethodTargetWaitingAnim = targetWaitingAnim;
         assignWindowLayers(false /* setLayoutNeeded */);
+        mInsetsStateController.onImeTargetChanged(target);
     }
 
     boolean getNeedsMenu(WindowState top, WindowManagerPolicy.WindowState bottom) {
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 66666e6..f67b11b 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -26,6 +26,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.proto.ProtoOutputStream;
 import android.view.InsetsState;
@@ -135,6 +136,12 @@
             mTmpRect.inset(mWin.mGivenContentInsets);
         }
         mSource.setFrame(mTmpRect);
+        if (mControl != null) {
+            final Rect frame = mWin.getWindowFrames().mFrame;
+            if (mControl.setSurfacePosition(frame.left, frame.top)) {
+                mStateController.notifyControlChanged(mControllingWin);
+            }
+        }
         setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.mPolicyVisibility
                 && !mWin.mGivenInsetsPending);
     }
@@ -157,7 +164,8 @@
         mWin.startAnimation(mDisplayContent.getPendingTransaction(), mAdapter,
                 !mClientVisible /* hidden */);
         mControllingWin = target;
-        mControl = new InsetsSourceControl(mSource.getType(), mAdapter.mCapturedLeash);
+        mControl = new InsetsSourceControl(mSource.getType(), mAdapter.mCapturedLeash,
+                new Point(mWin.getWindowFrames().mFrame.left, mWin.getWindowFrames().mFrame.top));
     }
 
     boolean onInsetsModified(WindowState caller, InsetsSource modifiedSource) {
@@ -213,7 +221,8 @@
         public void startAnimation(SurfaceControl animationLeash, Transaction t,
                 OnAnimationFinishedCallback finishCallback) {
             mCapturedLeash = animationLeash;
-            t.setPosition(mCapturedLeash, mSource.getFrame().left, mSource.getFrame().top);
+            final Rect frame = mWin.getWindowFrames().mFrame;
+            t.setPosition(mCapturedLeash, frame.left, frame.top);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index bb0cbb1..afae9c4 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -204,6 +204,11 @@
         mTypeWinControlMap.put(type, win);
     }
 
+    void notifyControlChanged(WindowState target) {
+        mPendingControlChanged.add(target);
+        notifyPendingInsetsControlChanged();
+    }
+
     private void notifyPendingInsetsControlChanged() {
         if (mPendingControlChanged.isEmpty()) {
             return;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 146a8ed..3bb6608 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4433,7 +4433,8 @@
                         if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Losing focus: " + lastFocus);
                         lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
                     }
-                } break;
+                    break;
+                }
 
                 case REPORT_LOSING_FOCUS: {
                     final DisplayContent displayContent = (DisplayContent) msg.obj;
@@ -4450,7 +4451,8 @@
                                 losers.get(i));
                         losers.get(i).reportFocusChangedSerialized(false, mInTouchMode);
                     }
-                } break;
+                    break;
+                }
 
                 case WINDOW_FREEZE_TIMEOUT: {
                     final DisplayContent displayContent = (DisplayContent) msg.obj;
@@ -4614,12 +4616,13 @@
                     break;
                 }
 
-                case NOTIFY_ACTIVITY_DRAWN:
+                case NOTIFY_ACTIVITY_DRAWN: {
                     try {
                         mActivityTaskManager.notifyActivityDrawn((IBinder) msg.obj);
                     } catch (RemoteException e) {
                     }
                     break;
+                }
                 case ALL_WINDOWS_DRAWN: {
                     Runnable callback;
                     synchronized (mGlobalLock) {
@@ -4656,8 +4659,8 @@
                             }
                         }
                     }
+                    break;
                 }
-                break;
                 case CHECK_IF_BOOT_ANIMATION_FINISHED: {
                     final boolean bootAnimationComplete;
                     synchronized (mGlobalLock) {
@@ -4667,15 +4670,15 @@
                     if (bootAnimationComplete) {
                         performEnableScreen();
                     }
+                    break;
                 }
-                break;
                 case RESET_ANR_MESSAGE: {
                     synchronized (mGlobalLock) {
                         mLastANRState = null;
                     }
                     mAtmInternal.clearSavedANRState();
+                    break;
                 }
-                break;
                 case WALLPAPER_DRAW_PENDING_TIMEOUT: {
                     synchronized (mGlobalLock) {
                         final WallpaperController wallpaperController =
@@ -4685,16 +4688,16 @@
                             mWindowPlacerLocked.performSurfacePlacement();
                         }
                     }
+                    break;
                 }
-                break;
                 case UPDATE_DOCKED_STACK_DIVIDER: {
                     synchronized (mGlobalLock) {
                         final DisplayContent displayContent = getDefaultDisplayContentLocked();
                         displayContent.getDockedDividerController().reevaluateVisibility(false);
                         displayContent.adjustForImeIfNeeded();
                     }
+                    break;
                 }
-                break;
                 case WINDOW_REPLACEMENT_TIMEOUT: {
                     synchronized (mGlobalLock) {
                         for (int i = mWindowReplacementTimeouts.size() - 1; i >= 0; i--) {
@@ -4703,8 +4706,8 @@
                         }
                         mWindowReplacementTimeouts.clear();
                     }
+                    break;
                 }
-                break;
                 case WINDOW_HIDE_TIMEOUT: {
                     final WindowState window = (WindowState) msg.obj;
                     synchronized (mGlobalLock) {
@@ -4724,44 +4727,44 @@
                         window.setDisplayLayoutNeeded();
                         mWindowPlacerLocked.performSurfacePlacement();
                     }
+                    break;
                 }
-                break;
                 case RESTORE_POINTER_ICON: {
                     synchronized (mGlobalLock) {
                         restorePointerIconLocked((DisplayContent)msg.obj, msg.arg1, msg.arg2);
                     }
+                    break;
                 }
-                break;
                 case SEAMLESS_ROTATION_TIMEOUT: {
                     final DisplayContent displayContent = (DisplayContent) msg.obj;
                     synchronized (mGlobalLock) {
                         displayContent.onSeamlessRotationTimeout();
                     }
+                    break;
                 }
-                break;
                 case SET_HAS_OVERLAY_UI: {
                     mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1);
+                    break;
                 }
-                break;
                 case SET_RUNNING_REMOTE_ANIMATION: {
                     mAmInternal.setRunningRemoteAnimation(msg.arg1, msg.arg2 == 1);
+                    break;
                 }
-                break;
                 case ANIMATION_FAILSAFE: {
                     synchronized (mGlobalLock) {
                         if (mRecentsAnimationController != null) {
                             mRecentsAnimationController.scheduleFailsafe();
                         }
                     }
+                    break;
                 }
-                break;
                 case RECOMPUTE_FOCUS: {
                     synchronized (mGlobalLock) {
                         updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
                                 true /* updateInputWindows */);
                     }
+                    break;
                 }
-                break;
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG_WM, "handleMessage: exit");
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 3729eaf..5c7b287 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -127,6 +127,7 @@
         "android.frameworks.schedulerservice@1.0",
         "android.frameworks.sensorservice@1.0",
         "android.system.suspend@1.0",
+        "suspend_control_aidl_interface-cpp",
     ],
 
     static_libs: [
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 024760d..5c19ad3 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -32,8 +32,8 @@
 #include <android/hardware/power/1.0/IPower.h>
 #include <android/hardware/power/1.1/IPower.h>
 #include <android/hardware/power/stats/1.0/IPowerStats.h>
-#include <android/system/suspend/1.0/ISystemSuspend.h>
-#include <android/system/suspend/1.0/ISystemSuspendCallback.h>
+#include <android/system/suspend/BnSuspendCallback.h>
+#include <android/system/suspend/ISuspendControlService.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <jni.h>
 
@@ -46,14 +46,14 @@
 
 using android::hardware::Return;
 using android::hardware::Void;
+using android::system::suspend::BnSuspendCallback;
 using android::hardware::power::V1_0::PowerStatePlatformSleepState;
 using android::hardware::power::V1_0::PowerStateVoter;
 using android::hardware::power::V1_0::Status;
 using android::hardware::power::V1_1::PowerStateSubsystem;
 using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
 using android::hardware::hidl_vec;
-using android::system::suspend::V1_0::ISystemSuspend;
-using android::system::suspend::V1_0::ISystemSuspendCallback;
+using android::system::suspend::ISuspendControlService;
 using IPowerV1_1 = android::hardware::power::V1_1::IPower;
 using IPowerV1_0 = android::hardware::power::V1_0::IPower;
 
@@ -68,7 +68,7 @@
 extern sp<IPowerV1_0> getPowerHalV1_0();
 extern sp<IPowerV1_1> getPowerHalV1_1();
 extern bool processPowerHalReturn(const Return<void> &ret, const char* functionName);
-extern sp<ISystemSuspend> getSuspendHal();
+extern sp<ISuspendControlService> getSuspendControl();
 
 // Java methods used in getLowPowerStats
 static jmethodID jgetAndUpdatePlatformState = NULL;
@@ -103,17 +103,17 @@
 
 sp<PowerHalDeathRecipient> gDeathRecipient = new PowerHalDeathRecipient();
 
-class WakeupCallback : public ISystemSuspendCallback {
-public:
-    Return<void> notifyWakeup(bool success) override {
-        ALOGV("In wakeup_callback: %s", success ? "resumed from suspend" : "suspend aborted");
+class WakeupCallback : public BnSuspendCallback {
+   public:
+    binder::Status notifyWakeup(bool success) override {
+        ALOGI("In wakeup_callback: %s", success ? "resumed from suspend" : "suspend aborted");
         int ret = sem_post(&wakeup_sem);
         if (ret < 0) {
             char buf[80];
             strerror_r(errno, buf, sizeof(buf));
             ALOGE("Error posting wakeup sem: %s\n", buf);
         }
-        return Void();
+        return binder::Status::ok();
     }
 };
 
@@ -136,9 +136,12 @@
             jniThrowException(env, "java/lang/IllegalStateException", buf);
             return -1;
         }
-        ALOGV("Registering callback...");
-        sp<ISystemSuspend> suspendHal = getSuspendHal();
-        suspendHal->registerCallback(new WakeupCallback());
+        sp<ISuspendControlService> suspendControl = getSuspendControl();
+        bool isRegistered = false;
+        suspendControl->registerCallback(new WakeupCallback(), &isRegistered);
+        if (!isRegistered) {
+            ALOGE("Failed to register wakeup callback");
+        }
     }
 
     // Wait for wakeup.
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 0c9b5f4..9be728b 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -20,6 +20,7 @@
 
 #include <android/hardware/power/1.1/IPower.h>
 #include <android/system/suspend/1.0/ISystemSuspend.h>
+#include <android/system/suspend/ISuspendControlService.h>
 #include <nativehelper/JNIHelp.h>
 #include "jni.h"
 
@@ -30,13 +31,14 @@
 #include <android-base/chrono_utils.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/Log.h>
+#include <binder/IServiceManager.h>
+#include <hardware/power.h>
+#include <hardware_legacy/power.h>
+#include <hidl/ServiceManagement.h>
 #include <utils/Timers.h>
 #include <utils/misc.h>
 #include <utils/String8.h>
 #include <utils/Log.h>
-#include <hardware/power.h>
-#include <hardware_legacy/power.h>
-#include <hidl/ServiceManagement.h>
 
 #include "com_android_server_power_PowerManagerService.h"
 
@@ -48,6 +50,7 @@
 using android::system::suspend::V1_0::ISystemSuspend;
 using android::system::suspend::V1_0::IWakeLock;
 using android::system::suspend::V1_0::WakeLockType;
+using android::system::suspend::ISuspendControlService;
 using IPowerV1_1 = android::hardware::power::V1_1::IPower;
 using IPowerV1_0 = android::hardware::power::V1_0::IPower;
 
@@ -176,6 +179,7 @@
 }
 
 static sp<ISystemSuspend> gSuspendHal = nullptr;
+static sp<ISuspendControlService> gSuspendControl = nullptr;
 static sp<IWakeLock> gSuspendBlocker = nullptr;
 static std::mutex gSuspendMutex;
 
@@ -191,18 +195,33 @@
     return gSuspendHal;
 }
 
+sp<ISuspendControlService> getSuspendControl() {
+    static std::once_flag suspendControlFlag;
+    std::call_once(suspendControlFlag, [](){
+        while(gSuspendControl == nullptr) {
+            sp<IBinder> control =
+                    defaultServiceManager()->getService(String16("suspend_control"));
+            if (control != nullptr) {
+                gSuspendControl = interface_cast<ISuspendControlService>(control);
+            }
+        }
+    });
+    return gSuspendControl;
+}
+
 void enableAutoSuspend() {
     static bool enabled = false;
-
-    std::lock_guard<std::mutex> lock(gSuspendMutex);
     if (!enabled) {
-        sp<ISystemSuspend> suspendHal = getSuspendHal();
-        suspendHal->enableAutosuspend();
-        enabled = true;
+        sp<ISuspendControlService> suspendControl = getSuspendControl();
+        suspendControl->enableAutosuspend(&enabled);
     }
-    if (gSuspendBlocker) {
-        gSuspendBlocker->release();
-        gSuspendBlocker.clear();
+
+    {
+        std::lock_guard<std::mutex> lock(gSuspendMutex);
+        if (gSuspendBlocker) {
+            gSuspendBlocker->release();
+            gSuspendBlocker.clear();
+        }
     }
 }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index caeedee..ab30cda 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1285,47 +1285,45 @@
             }
             traceEnd();
 
-            if (!mOnlyCore) {
-                if (context.getPackageManager().hasSystemFeature(
-                        PackageManager.FEATURE_WIFI)) {
-                    // Wifi Service must be started first for wifi-related services.
-                    traceBeginAndSlog("StartWifi");
-                    mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
-                    traceEnd();
-                    traceBeginAndSlog("StartWifiScanning");
-                    mSystemServiceManager.startService(
-                            "com.android.server.wifi.scanner.WifiScanningService");
-                    traceEnd();
-                }
+            if (context.getPackageManager().hasSystemFeature(
+                    PackageManager.FEATURE_WIFI)) {
+                // Wifi Service must be started first for wifi-related services.
+                traceBeginAndSlog("StartWifi");
+                mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
+                traceEnd();
+                traceBeginAndSlog("StartWifiScanning");
+                mSystemServiceManager.startService(
+                        "com.android.server.wifi.scanner.WifiScanningService");
+                traceEnd();
+            }
 
-                if (context.getPackageManager().hasSystemFeature(
-                        PackageManager.FEATURE_WIFI_RTT)) {
-                    traceBeginAndSlog("StartRttService");
-                    mSystemServiceManager.startService(
-                            "com.android.server.wifi.rtt.RttService");
-                    traceEnd();
-                }
+            if (context.getPackageManager().hasSystemFeature(
+                    PackageManager.FEATURE_WIFI_RTT)) {
+                traceBeginAndSlog("StartRttService");
+                mSystemServiceManager.startService(
+                        "com.android.server.wifi.rtt.RttService");
+                traceEnd();
+            }
 
-                if (context.getPackageManager().hasSystemFeature(
-                        PackageManager.FEATURE_WIFI_AWARE)) {
-                    traceBeginAndSlog("StartWifiAware");
-                    mSystemServiceManager.startService(WIFI_AWARE_SERVICE_CLASS);
-                    traceEnd();
-                }
+            if (context.getPackageManager().hasSystemFeature(
+                    PackageManager.FEATURE_WIFI_AWARE)) {
+                traceBeginAndSlog("StartWifiAware");
+                mSystemServiceManager.startService(WIFI_AWARE_SERVICE_CLASS);
+                traceEnd();
+            }
 
-                if (context.getPackageManager().hasSystemFeature(
-                        PackageManager.FEATURE_WIFI_DIRECT)) {
-                    traceBeginAndSlog("StartWifiP2P");
-                    mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
-                    traceEnd();
-                }
+            if (context.getPackageManager().hasSystemFeature(
+                    PackageManager.FEATURE_WIFI_DIRECT)) {
+                traceBeginAndSlog("StartWifiP2P");
+                mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
+                traceEnd();
+            }
 
-                if (context.getPackageManager().hasSystemFeature(
-                        PackageManager.FEATURE_LOWPAN)) {
-                    traceBeginAndSlog("StartLowpan");
-                    mSystemServiceManager.startService(LOWPAN_SERVICE_CLASS);
-                    traceEnd();
-                }
+            if (context.getPackageManager().hasSystemFeature(
+                    PackageManager.FEATURE_LOWPAN)) {
+                traceBeginAndSlog("StartLowpan");
+                mSystemServiceManager.startService(LOWPAN_SERVICE_CLASS);
+                traceEnd();
             }
 
             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
index 48c8902..11bd29d 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
@@ -23,8 +23,10 @@
 import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.Looper;
 import android.os.test.TestLooper;
+
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -42,9 +44,8 @@
     private TestLooper mTestLooper = new TestLooper();
     private boolean mSendCecCommandSuccess;
     private boolean mShouldDispatchReportArcTerminated;
-    private boolean mArcEnabled;
-    private boolean mSetArcStatusCalled;
     private Instrumentation mInstrumentation;
+    @Nullable private Boolean mArcEnabled = null;
 
     @Before
     public void setUp() {
@@ -102,7 +103,6 @@
 
                     @Override
                     void setArcStatus(boolean enabled) {
-                        mSetArcStatusCalled = true;
                         mArcEnabled = enabled;
                     }
                 };
@@ -110,45 +110,38 @@
         Looper looper = mTestLooper.getLooper();
         hdmiControlService.setIoLooper(looper);
 
-        mArcEnabled = true;
         mAction = new ArcTerminationActionFromAvr(mHdmiCecLocalDeviceAudioSystem);
     }
 
     @Test
-    public void testSendMessage_NotSuccess() {
+    public void testSendMessage_notSuccess() {
         mSendCecCommandSuccess = false;
         mShouldDispatchReportArcTerminated = false;
-        mSetArcStatusCalled = false;
         mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
 
         mTestLooper.dispatchAll();
-        assertThat(mSetArcStatusCalled).isFalse();
-        assertThat(mArcEnabled).isTrue();
+        assertThat(mArcEnabled).isNull();
     }
 
     @Test
-    public void testReportArcTerminated_NotReceived() {
+    public void testReportArcTerminated_notReceived() {
         mSendCecCommandSuccess = true;
         mShouldDispatchReportArcTerminated = false;
-        mSetArcStatusCalled = false;
         mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
 
         mTestLooper.moveTimeForward(1000);
         mTestLooper.dispatchAll();
-        assertThat(mSetArcStatusCalled).isFalse();
-        assertThat(mArcEnabled).isTrue();
+        assertThat(mArcEnabled).isNull();
     }
 
     @Test
-    public void testReportArcTerminated_Received() {
+    public void testReportArcTerminated_received() {
         mSendCecCommandSuccess = true;
         mShouldDispatchReportArcTerminated = true;
-        mSetArcStatusCalled = false;
         mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
 
         mTestLooper.moveTimeForward(1000);
         mTestLooper.dispatchAll();
-        assertThat(mSetArcStatusCalled).isTrue();
         assertThat(mArcEnabled).isFalse();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
index 33cbf7a..f1e6bc2 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
@@ -80,10 +80,10 @@
     }
 
     private static RollbackData createInProgressRollbackData(String packageName) {
-        RollbackData data = new RollbackData(1, new File("/does/not/exist"));
+        RollbackData data = new RollbackData(1, new File("/does/not/exist"), -1);
         data.packages.add(new PackageRollbackInfo(
                 new VersionedPackage(packageName, 1), new VersionedPackage(packageName, 1),
-                new IntArray(), new ArrayList<>()));
+                new IntArray(), new ArrayList<>(), false));
         data.inProgress = true;
 
         return data;
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 4cae3b3..72aa0f2 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3925,13 +3925,16 @@
     public void testOnNotificationSmartReplySent() {
         final int replyIndex = 2;
         final String reply = "Hello";
+        final boolean modifiedBeforeSending = true;
         final boolean generatedByAssistant = true;
 
         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+        r.setSuggestionsGeneratedByAssistant(generatedByAssistant);
         mService.addNotification(r);
 
         mService.mNotificationDelegate.onNotificationSmartReplySent(
-                r.getKey(), replyIndex, reply, generatedByAssistant, NOTIFICATION_LOCATION_UNKNOWN);
+                r.getKey(), replyIndex, reply, NOTIFICATION_LOCATION_UNKNOWN,
+                modifiedBeforeSending);
         verify(mAssistants).notifyAssistantSuggestedReplySent(
                 eq(r.sbn), eq(reply), eq(generatedByAssistant));
     }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 85939d4..a6d7ee6 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -432,6 +432,7 @@
         synchronized (mLock) {
             mHandler.removeMessages(MSG_REPORT_EVENT);
             Event event = new Event(DEVICE_SHUTDOWN, SystemClock.elapsedRealtime());
+            event.mPackage = Event.DEVICE_EVENT_PACKAGE_NAME;
             // orderly shutdown, the last event is DEVICE_SHUTDOWN.
             reportEventToAllUserId(event);
             flushToDiskLocked();
@@ -449,6 +450,7 @@
      */
     void prepareForPossibleShutdown() {
         Event event = new Event(DEVICE_SHUTDOWN, SystemClock.elapsedRealtime());
+        event.mPackage = Event.DEVICE_EVENT_PACKAGE_NAME;
         mHandler.obtainMessage(MSG_REPORT_EVENT_TO_ALL_USERID, event).sendToTarget();
         mHandler.sendEmptyMessage(MSG_FLUSH_TO_DISK);
     }
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index d52d32f..3cb2216 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -143,6 +143,7 @@
             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);
+                event.mPackage = Event.DEVICE_EVENT_PACKAGE_NAME;
                 currentDailyStats.addEvent(event);
             }
         }
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index f5b4308..37caeb2 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -58,6 +58,8 @@
         "util.cc",
         "layout_validation.cc",
     ],
+    // b/123880763, clang-tidy analyzer has segmentation fault with dex_builder.cc
+    tidy_checks: ["-clang-analyzer-*"],
     host_supported: true,
 }
 
diff --git a/telephony/java/android/telephony/AvailableNetworkInfo.java b/telephony/java/android/telephony/AvailableNetworkInfo.java
index 4da79b3..b407b2a 100644
--- a/telephony/java/android/telephony/AvailableNetworkInfo.java
+++ b/telephony/java/android/telephony/AvailableNetworkInfo.java
@@ -114,7 +114,7 @@
         in.readStringList(mMccMncs);
     }
 
-    public AvailableNetworkInfo(int subId, int priority, ArrayList<String> mccMncs) {
+    public AvailableNetworkInfo(int subId, int priority, List<String> mccMncs) {
         mSubId = subId;
         mPriority = priority;
         mMccMncs = new ArrayList<String>(mccMncs);
diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
index a4cce9c..0d4f09f 100644
--- a/telephony/java/android/telephony/CallAttributes.java
+++ b/telephony/java/android/telephony/CallAttributes.java
@@ -117,9 +117,9 @@
 
         CallAttributes s = (CallAttributes) o;
 
-        return (mPreciseCallState == s.mPreciseCallState
+        return (Objects.equals(mPreciseCallState, s.mPreciseCallState)
                 && mNetworkType == s.mNetworkType
-                && mCallQuality == s.mCallQuality);
+                && Objects.equals(mCallQuality, s.mCallQuality));
     }
 
     /**
diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java
index 59f3e1f..19e1931 100644
--- a/telephony/java/android/telephony/PreciseCallState.java
+++ b/telephony/java/android/telephony/PreciseCallState.java
@@ -287,11 +287,11 @@
             return false;
         }
         PreciseCallState other = (PreciseCallState) obj;
-        return (mRingingCallState != other.mRingingCallState &&
-            mForegroundCallState != other.mForegroundCallState &&
-            mBackgroundCallState != other.mBackgroundCallState &&
-            mDisconnectCause != other.mDisconnectCause &&
-            mPreciseDisconnectCause != other.mPreciseDisconnectCause);
+        return (mRingingCallState == other.mRingingCallState
+                && mForegroundCallState == other.mForegroundCallState
+                && mBackgroundCallState == other.mBackgroundCallState
+                && mDisconnectCause == other.mDisconnectCause
+                && mPreciseDisconnectCause == other.mPreciseDisconnectCause);
     }
 
     @Override
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7c3bde4..f2a9340 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -7974,9 +7974,7 @@
      * support for the feature and device firmware support.
      *
      * @return {@code true} if the device and carrier both support RTT, {@code false} otherwise.
-     * @hide
      */
-    @TestApi
     public boolean isRttSupported() {
         try {
             ITelephony telephony = getITelephony();
@@ -9702,10 +9700,10 @@
      *
      * <p>
      * Requires Permission:
-     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *   {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public boolean isOpportunisticNetworkEnabled() {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         boolean isEnabled = false;
@@ -10093,12 +10091,17 @@
      * Get preferred opportunistic data subscription Id
      *
      * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}),
-     * or has permission {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}.
+     * or has either READ_PRIVILEGED_PHONE_STATE
+     * or {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} permission.
      * @return subId preferred opportunistic subscription id or
      * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} if there are no preferred
      * subscription id
      *
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+            android.Manifest.permission.READ_PHONE_STATE
+    })
     public int getPreferredOpportunisticDataSubscription() {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index 4d95e55..d8d2d9e 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -465,7 +465,7 @@
     public static final int CODE_USER_REJECTED_SESSION_MODIFICATION = 511;
 
     /**
-    * Upgrade Downgrade request cacncelled by the user who initiated it
+    * Upgrade Downgrade request cancelled by the user who initiated it
     */
     public static final int CODE_USER_CANCELLED_SESSION_MODIFICATION = 512;
 
@@ -887,6 +887,185 @@
     public static final int CODE_OEM_CAUSE_15 = 0xf00f;
 
     /**
+     * @hide
+     */
+    @IntDef(value = {
+            CODE_UNSPECIFIED,
+            CODE_LOCAL_ILLEGAL_ARGUMENT,
+            CODE_LOCAL_ILLEGAL_STATE,
+            CODE_LOCAL_INTERNAL_ERROR,
+            CODE_LOCAL_IMS_SERVICE_DOWN,
+            CODE_LOCAL_NO_PENDING_CALL,
+            CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE,
+            CODE_LOCAL_POWER_OFF,
+            CODE_LOCAL_LOW_BATTERY,
+            CODE_LOCAL_NETWORK_NO_SERVICE,
+            CODE_LOCAL_NETWORK_NO_LTE_COVERAGE,
+            CODE_LOCAL_NETWORK_ROAMING,
+            CODE_LOCAL_NETWORK_IP_CHANGED,
+            CODE_LOCAL_SERVICE_UNAVAILABLE,
+            CODE_LOCAL_NOT_REGISTERED,
+            CODE_LOCAL_CALL_EXCEEDED,
+            CODE_LOCAL_CALL_BUSY,
+            CODE_LOCAL_CALL_DECLINE,
+            CODE_LOCAL_CALL_VCC_ON_PROGRESSING,
+            CODE_LOCAL_CALL_RESOURCE_RESERVATION_FAILED,
+            CODE_LOCAL_CALL_CS_RETRY_REQUIRED,
+            CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED,
+            CODE_LOCAL_CALL_TERMINATED,
+            CODE_LOCAL_HO_NOT_FEASIBLE,
+            CODE_TIMEOUT_1XX_WAITING,
+            CODE_TIMEOUT_NO_ANSWER,
+            CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE,
+            CODE_CALL_BARRED,
+            CODE_FDN_BLOCKED,
+            CODE_IMEI_NOT_ACCEPTED,
+            CODE_DIAL_MODIFIED_TO_USSD,
+            CODE_DIAL_MODIFIED_TO_SS,
+            CODE_DIAL_MODIFIED_TO_DIAL,
+            CODE_DIAL_MODIFIED_TO_DIAL_VIDEO,
+            CODE_DIAL_VIDEO_MODIFIED_TO_DIAL,
+            CODE_DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO,
+            CODE_DIAL_VIDEO_MODIFIED_TO_SS,
+            CODE_DIAL_VIDEO_MODIFIED_TO_USSD,
+            CODE_SIP_REDIRECTED,
+            CODE_SIP_BAD_REQUEST,
+            CODE_SIP_FORBIDDEN,
+            CODE_SIP_NOT_FOUND,
+            CODE_SIP_NOT_SUPPORTED,
+            CODE_SIP_REQUEST_TIMEOUT,
+            CODE_SIP_TEMPRARILY_UNAVAILABLE,
+            CODE_SIP_BAD_ADDRESS,
+            CODE_SIP_BUSY,
+            CODE_SIP_REQUEST_CANCELLED,
+            CODE_SIP_NOT_ACCEPTABLE,
+            CODE_SIP_NOT_REACHABLE,
+            CODE_SIP_CLIENT_ERROR,
+            CODE_SIP_TRANSACTION_DOES_NOT_EXIST,
+            CODE_SIP_SERVER_INTERNAL_ERROR,
+            CODE_SIP_SERVICE_UNAVAILABLE,
+            CODE_SIP_SERVER_TIMEOUT,
+            CODE_SIP_SERVER_ERROR,
+            CODE_SIP_USER_REJECTED,
+            CODE_SIP_GLOBAL_ERROR,
+            CODE_EMERGENCY_TEMP_FAILURE,
+            CODE_EMERGENCY_PERM_FAILURE,
+            CODE_SIP_USER_MARKED_UNWANTED,
+            CODE_SIP_METHOD_NOT_ALLOWED,
+            CODE_SIP_PROXY_AUTHENTICATION_REQUIRED,
+            CODE_SIP_REQUEST_ENTITY_TOO_LARGE,
+            CODE_SIP_REQUEST_URI_TOO_LARGE,
+            CODE_SIP_EXTENSION_REQUIRED,
+            CODE_SIP_INTERVAL_TOO_BRIEF,
+            CODE_SIP_CALL_OR_TRANS_DOES_NOT_EXIST,
+            CODE_SIP_LOOP_DETECTED,
+            CODE_SIP_TOO_MANY_HOPS,
+            CODE_SIP_AMBIGUOUS,
+            CODE_SIP_REQUEST_PENDING,
+            CODE_SIP_UNDECIPHERABLE,
+            CODE_MEDIA_INIT_FAILED,
+            CODE_MEDIA_NO_DATA,
+            CODE_MEDIA_NOT_ACCEPTABLE,
+            CODE_MEDIA_UNSPECIFIED,
+            CODE_USER_TERMINATED,
+            CODE_USER_NOANSWER,
+            CODE_USER_IGNORE,
+            CODE_USER_DECLINE,
+            CODE_LOW_BATTERY,
+            CODE_BLACKLISTED_CALL_ID,
+            CODE_USER_TERMINATED_BY_REMOTE,
+            CODE_USER_REJECTED_SESSION_MODIFICATION,
+            CODE_USER_CANCELLED_SESSION_MODIFICATION,
+            CODE_SESSION_MODIFICATION_FAILED,
+            CODE_UT_NOT_SUPPORTED,
+            CODE_UT_SERVICE_UNAVAILABLE,
+            CODE_UT_OPERATION_NOT_ALLOWED,
+            CODE_UT_NETWORK_ERROR,
+            CODE_UT_CB_PASSWORD_MISMATCH,
+            CODE_UT_SS_MODIFIED_TO_DIAL,
+            CODE_UT_SS_MODIFIED_TO_USSD,
+            CODE_UT_SS_MODIFIED_TO_SS,
+            CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO,
+            CODE_ECBM_NOT_SUPPORTED,
+            CODE_MULTIENDPOINT_NOT_SUPPORTED,
+            CODE_REGISTRATION_ERROR,
+            CODE_ANSWERED_ELSEWHERE,
+            CODE_CALL_PULL_OUT_OF_SYNC,
+            CODE_CALL_END_CAUSE_CALL_PULL,
+            CODE_CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE,
+            CODE_REJECTED_ELSEWHERE,
+            CODE_SUPP_SVC_FAILED,
+            CODE_SUPP_SVC_CANCELLED,
+            CODE_SUPP_SVC_REINVITE_COLLISION,
+            CODE_IWLAN_DPD_FAILURE,
+            CODE_EPDG_TUNNEL_ESTABLISH_FAILURE,
+            CODE_EPDG_TUNNEL_REKEY_FAILURE,
+            CODE_EPDG_TUNNEL_LOST_CONNECTION,
+            CODE_MAXIMUM_NUMBER_OF_CALLS_REACHED,
+            CODE_REMOTE_CALL_DECLINE,
+            CODE_DATA_LIMIT_REACHED,
+            CODE_DATA_DISABLED,
+            CODE_WIFI_LOST,
+            CODE_IKEV2_AUTH_FAILURE,
+            CODE_RADIO_OFF,
+            CODE_NO_VALID_SIM,
+            CODE_RADIO_INTERNAL_ERROR,
+            CODE_NETWORK_RESP_TIMEOUT,
+            CODE_NETWORK_REJECT,
+            CODE_RADIO_ACCESS_FAILURE,
+            CODE_RADIO_LINK_FAILURE,
+            CODE_RADIO_LINK_LOST,
+            CODE_RADIO_UPLINK_FAILURE,
+            CODE_RADIO_SETUP_FAILURE,
+            CODE_RADIO_RELEASE_NORMAL,
+            CODE_RADIO_RELEASE_ABNORMAL,
+            CODE_ACCESS_CLASS_BLOCKED,
+            CODE_NETWORK_DETACH,
+            CODE_SIP_ALTERNATE_EMERGENCY_CALL,
+            CODE_UNOBTAINABLE_NUMBER,
+            CODE_NO_CSFB_IN_CS_ROAM,
+            CODE_REJECT_UNKNOWN,
+            CODE_REJECT_ONGOING_CALL_WAITING_DISABLED,
+            CODE_REJECT_CALL_ON_OTHER_SUB,
+            CODE_REJECT_1X_COLLISION,
+            CODE_REJECT_SERVICE_NOT_REGISTERED,
+            CODE_REJECT_CALL_TYPE_NOT_ALLOWED,
+            CODE_REJECT_ONGOING_E911_CALL,
+            CODE_REJECT_ONGOING_CALL_SETUP,
+            CODE_REJECT_MAX_CALL_LIMIT_REACHED,
+            CODE_REJECT_UNSUPPORTED_SIP_HEADERS,
+            CODE_REJECT_UNSUPPORTED_SDP_HEADERS,
+            CODE_REJECT_ONGOING_CALL_TRANSFER,
+            CODE_REJECT_INTERNAL_ERROR,
+            CODE_REJECT_QOS_FAILURE,
+            CODE_REJECT_ONGOING_HANDOVER,
+            CODE_REJECT_VT_TTY_NOT_ALLOWED,
+            CODE_REJECT_ONGOING_CALL_UPGRADE,
+            CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED,
+            CODE_REJECT_ONGOING_CONFERENCE_CALL,
+            CODE_REJECT_VT_AVPF_NOT_ALLOWED,
+            CODE_REJECT_ONGOING_ENCRYPTED_CALL,
+            CODE_REJECT_ONGOING_CS_CALL,
+            CODE_OEM_CAUSE_1,
+            CODE_OEM_CAUSE_2,
+            CODE_OEM_CAUSE_3,
+            CODE_OEM_CAUSE_4,
+            CODE_OEM_CAUSE_5,
+            CODE_OEM_CAUSE_6,
+            CODE_OEM_CAUSE_7,
+            CODE_OEM_CAUSE_8,
+            CODE_OEM_CAUSE_9,
+            CODE_OEM_CAUSE_10,
+            CODE_OEM_CAUSE_11,
+            CODE_OEM_CAUSE_12,
+            CODE_OEM_CAUSE_13,
+            CODE_OEM_CAUSE_14,
+            CODE_OEM_CAUSE_15
+    }, prefix = "CODE_")
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ImsCode {}
+
+    /**
      * Network string error messages.
      * mExtraMessage may have these values.
      */
@@ -964,7 +1143,7 @@
     /**
      * @return an integer representing more information about the completion of an operation.
      */
-    public int getCode() {
+    public @ImsCode int getCode() {
         return mCode;
     }
 
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index b171f79..6e98a0a 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -372,14 +372,6 @@
         }
     }
 
-    private static SubscriptionManager getSubscriptionManager(Context context) {
-        SubscriptionManager manager = context.getSystemService(SubscriptionManager.class);
-        if (manager == null) {
-            throw new RuntimeException("Could not find SubscriptionManager.");
-        }
-        return manager;
-    }
-
     private static ITelephony getITelephony() {
         ITelephony binder = ITelephony.Stub.asInterface(
                 ServiceManager.getService(Context.TELEPHONY_SERVICE));
diff --git a/telephony/java/android/telephony/mbms/GroupCallCallback.java b/telephony/java/android/telephony/mbms/GroupCallCallback.java
index 77e36bb..603f4e6 100644
--- a/telephony/java/android/telephony/mbms/GroupCallCallback.java
+++ b/telephony/java/android/telephony/mbms/GroupCallCallback.java
@@ -57,7 +57,7 @@
      * @param errorCode The error code.
      * @param message A human-readable message generated by the middleware for debugging purposes.
      */
-    void onError(@GroupCallError int errorCode, @Nullable String message);
+    default void onError(@GroupCallError int errorCode, @Nullable String message) {}
 
     /**
      * Called to indicate this call has changed state.
@@ -65,8 +65,8 @@
      * See {@link GroupCall#STATE_STOPPED}, {@link GroupCall#STATE_STARTED}
      * and {@link GroupCall#STATE_STALLED}.
      */
-    void onGroupCallStateChanged(@GroupCall.GroupCallState int state,
-            @GroupCall.GroupCallStateChangeReason int reason);
+    default void onGroupCallStateChanged(@GroupCall.GroupCallState int state,
+            @GroupCall.GroupCallStateChangeReason int reason) {}
 
     /**
      * Broadcast Signal Strength updated.
@@ -78,5 +78,6 @@
      * {@link #SIGNAL_STRENGTH_UNAVAILABLE} if broadcast is not available
      * for this call due to timing, geography or popularity.
      */
-    void onBroadcastSignalStrengthUpdated(@IntRange(from = -1, to = 4) int signalStrength);
+    default void onBroadcastSignalStrengthUpdated(
+            @IntRange(from = -1, to = 4) int signalStrength) {}
 }
diff --git a/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
index 04e7ba1..ac7e172 100644
--- a/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
@@ -57,7 +57,7 @@
      * @param errorCode The error code.
      * @param message A human-readable message generated by the middleware for debugging purposes.
      */
-    void onError(@GroupCallError int errorCode, @Nullable String message);
+    default void onError(@GroupCallError int errorCode, @Nullable String message) {}
 
     /**
      * Indicates that the list of currently available SAIs has been updated. The app may use this
@@ -70,8 +70,8 @@
      * @param availableSais A list of lists of available SAIS in neighboring cells, where each list
      *                      contains the available SAIs in an individual cell.
      */
-    void onAvailableSaisUpdated(@NonNull List<Integer> currentSais,
-            @NonNull List<List<Integer>> availableSais);
+    default void onAvailableSaisUpdated(@NonNull List<Integer> currentSais,
+            @NonNull List<List<Integer>> availableSais) {}
 
     /**
      * Called soon after the app calls {@link MbmsGroupCallSession#create}. The information supplied
@@ -85,7 +85,7 @@
      * @param interfaceName The interface name for the data link.
      * @param index The index for the data link.
      */
-    void onServiceInterfaceAvailable(@NonNull String interfaceName, int index);
+    default void onServiceInterfaceAvailable(@NonNull String interfaceName, int index) {}
 
     /**
      * Called to indicate that the middleware has been initialized and is ready.
@@ -95,5 +95,5 @@
      * delivered via {@link #onError(int, String)} with error code
      * {@link MbmsErrors.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}.
      */
-    void onMiddlewareReady();
+    default void onMiddlewareReady() {}
 }
diff --git a/tests/RollbackTest/Android.mk b/tests/RollbackTest/Android.mk
index 780bb24..40d4eff 100644
--- a/tests/RollbackTest/Android.mk
+++ b/tests/RollbackTest/Android.mk
@@ -76,12 +76,14 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
 LOCAL_COMPATIBILITY_SUITE := general-tests
+LOCAL_COMPATIBILITY_SUPPORT_FILES := $(ROLLBACK_TEST_APEX_V1)
 LOCAL_JAVA_RESOURCE_FILES := \
   $(ROLLBACK_TEST_APP_AV1) \
   $(ROLLBACK_TEST_APP_AV2) \
   $(ROLLBACK_TEST_APP_A_CRASHING_V2) \
   $(ROLLBACK_TEST_APP_BV1) \
-  $(ROLLBACK_TEST_APP_BV2)
+  $(ROLLBACK_TEST_APP_BV2) \
+  $(ROLLBACK_TEST_APEX_V2)
 LOCAL_SDK_VERSION := system_current
 LOCAL_TEST_CONFIG := RollbackTest.xml
 include $(BUILD_PACKAGE)
diff --git a/tests/RollbackTest/TestApex/Android.bp b/tests/RollbackTest/TestApex/Android.bp
new file mode 100644
index 0000000..a2a8e17
--- /dev/null
+++ b/tests/RollbackTest/TestApex/Android.bp
@@ -0,0 +1,56 @@
+// 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.
+
+apex {
+    name: "com.android.tests.rollback.testapex.RollbackTestApexV1",
+    manifest: "RollbackTestApexV1.json",
+    file_contexts: "apex.test",
+    prebuilts: ["RollbackTestApex.prebuilt.txt"],
+    key: "RollbackTestApex.key",
+    installable: false,
+}
+
+apex {
+    name: "com.android.tests.rollback.testapex.RollbackTestApexV2",
+    manifest: "RollbackTestApexV2.json",
+    file_contexts: "apex.test",
+    prebuilts: ["RollbackTestApex.prebuilt.txt"],
+    key: "RollbackTestApex.key",
+    installable: false,
+}
+
+apex_key {
+    name: "RollbackTestApex.key",
+    public_key: "com.android.tests.rollback.testapex.avbpubkey",
+    private_key: "com.android.tests.rollback.testapex.pem",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "RollbackTestApex.prebuilt.txt",
+    src: "RollbackTestApex.prebuilt.txt",
+}
+
+filegroup {
+    name: "RollbackTestApexV1_filegroup",
+    srcs: [":com.android.tests.rollback.testapex.RollbackTestApexV1"],
+    export_to_make_var: "ROLLBACK_TEST_APEX_V1",
+}
+
+filegroup {
+    name: "RollbackTestApexV2_filegroup",
+    srcs: [":com.android.tests.rollback.testapex.RollbackTestApexV2"],
+    export_to_make_var: "ROLLBACK_TEST_APEX_V2",
+}
+
diff --git a/tests/RollbackTest/TestApex/RollbackTestApex.prebuilt.txt b/tests/RollbackTest/TestApex/RollbackTestApex.prebuilt.txt
new file mode 100644
index 0000000..e871146
--- /dev/null
+++ b/tests/RollbackTest/TestApex/RollbackTestApex.prebuilt.txt
@@ -0,0 +1,3 @@
+
+This file contains dummy content to include in the RollbackTestApex.
+
diff --git a/tests/RollbackTest/TestApex/RollbackTestApexV1.json b/tests/RollbackTest/TestApex/RollbackTestApexV1.json
new file mode 100644
index 0000000..c3239ca
--- /dev/null
+++ b/tests/RollbackTest/TestApex/RollbackTestApexV1.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.tests.rollback.testapex",
+    "version": 1
+}
diff --git a/tests/RollbackTest/TestApex/RollbackTestApexV2.json b/tests/RollbackTest/TestApex/RollbackTestApexV2.json
new file mode 100644
index 0000000..9de3f45
--- /dev/null
+++ b/tests/RollbackTest/TestApex/RollbackTestApexV2.json
@@ -0,0 +1,4 @@
+{
+    "name": "com.android.tests.rollback.testapex",
+    "version": 2
+}
diff --git a/tests/RollbackTest/TestApex/com.android.tests.rollback.testapex.avbpubkey b/tests/RollbackTest/TestApex/com.android.tests.rollback.testapex.avbpubkey
new file mode 100644
index 0000000..b347331
--- /dev/null
+++ b/tests/RollbackTest/TestApex/com.android.tests.rollback.testapex.avbpubkey
Binary files differ
diff --git a/tests/RollbackTest/TestApex/com.android.tests.rollback.testapex.pem b/tests/RollbackTest/TestApex/com.android.tests.rollback.testapex.pem
new file mode 100644
index 0000000..7181ce5
--- /dev/null
+++ b/tests/RollbackTest/TestApex/com.android.tests.rollback.testapex.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEArBLX+v6RMiK6soQFgbc0RZ+wticTD5sCbu9Q5B5WT7UnV1Wt
+cNI/n2bjks3UYNxTneOzMQOVjd4ln0BYZoNvoDtrc1BsYABpt4FywSq1zz/3sp3L
+3Vp8vaUyRsx0Da+PcOdYHPFs1WPX3Shw3MSPhUO/72KTm6GhO/cHEPEzSQLaw/zO
+8FiPpDdRqILqVJlu1DZ+i1DO+To9mKt59uLlxy3F+HAMnQaNW6+2NCV/vdCxQrEL
+m7PpsM6DymsFKcvVra1Il4apKkYNgcgTQ+AlmyPxGo6twfZvRMrU3bcrUmrg3OAx
+tMD7MufXlKkoFMlT5clrQ7P2ErKoFxhTVWhBL5ZJv/lKwaTfxCLyNvYQ7JALKtOL
+9xx4c77NdyYVjxMDAJ7E+Uj3QjdOv3FxM38Fcvt0zN4SSlmDjEDtm2e2w53Ztgz1
+zHAuNllIW1zGdPqa+ROoa9JLJePlyNXG9Rn1sSkjM9WwteaJ3nrdje6uBsvo7I9g
+1MWab2XNXQwJNHACICtyU7QPryGP4U/lyHqWEkdoXrs8O36gmTGU/EsJYSIVILax
+0HZC3zkmxHgiN95ZvD+Y5Y9HDXAN04kT8O1V/QD4QUCP8MGXNrkQP/JZAnu5Y2D1
+Wrn/7Tft2ON3OpH5vUgR99bKR549LcRrYgxeTnci3xkOsnTjZRxEUJFQgVUCAwEA
+AQKCAgEAlBzIMbDLk+cW4rAG+WeTo9ZXygKKQqV/i7OM4j5GtudMTL1fxDwFLZTn
+kCaBhzo+8ynaxPa71ViA87n0HZFHFRnwXFq+XkgctyrCdwjnY9RAxktS/l5z/t1i
+EFTOFDWod1t6mbcpoegGF8RGmZDLpL7zR/+G5LBUU4RHXcrwBQli+s3x5imkwoon
+TLAbOeSz5BBgDlTpQtdhy7bWDa+ybya0QCtagBLyvBfb8rjQYrduzOQOBODw5xJr
+mGFUGWztqUf9swfjNpMD71EjXApk9EwUrXJgmBMiJYmdfpa6wH9kvFpyDo8J6gBr
+rPeJm5LMF3+vR6Bw0Bld3DtBB8PsTrockOdeJNHfnY54480e7AahfM5gkeuIYC4P
+E3CIbyAgpS8+OLpsXP207AOjFz1TLiOqyDUDsBqSMNEQ7QbIPTQw8UZ/o0vEoqEv
+RrJAvIAv0KUcFNUL0t6VX2OXbV+i+T85wPey3XqK9P8Zzc8NUEGJ2paDUkSuemKC
+nF9/siGaoBHXsNUkQuV9xYo4co66MHDGAx/OdUM5lPiUcrF/bR+ZUA3p1BLUQXbQ
+aJD9uKlvJ4ZRSwhR/fQc5UiVWl3l76k+0Ia/Ddd1ArphVhbvGPOsm3W7wJ6KukSk
+rBJh1PPV1HnA+icS2Wvu2kVdz9+39cQUYJIICO1uwWfPIb/R5MUCggEBAOSwkwXs
+jqewNc6X4mc19RGKIMUvOrRrQkOOY33pI+BjoqI8cl+NOHNB7F8/gVnHIfhZpOG6
+WD5St1/qlSPT1Nte+38P+woAp5mdclZyRgYb4MjZybZihUPIPVgUbxiZTDHy1Sw0
+kRgmvaV3ccvG9/9bBUKNr9Z+XySsIhq5DzY+yIZ33vhLB/0g05x2HVIsSlsRWzri
+lw0iX/v07bdIRUIv7QB8xcLY/23pIbHAXS8DaknN8YxpKtjilOnUWVp/dx4SIcJY
+6PtSBfPcwVJ2MA/xXWBvDP82/XxvbxKnjj8lvkbfqMC6jrXJBw3NT/he8b932IBb
+PwLGU4hoKvjXfUcCggEBAMCfa4N1KUXW0Mo3BcDk2Hk8zVYuTPDNTWg1Mxb46sn+
+HNVJKU0OrejM2hNNCwzJG7eVQBorJj5XefhaQFTvWoLKbf1YZuWKaQrRwKkHEqDi
+edplA2RkpUebeS4KYIr22rzu3ZrZqiJmRU5kAS9hwOzwFvnXUgGy7IoZKXhpo0HK
+xvwylb/C5FXh97tecDdH/5evB/DC515TIhPzUQ5tpT0oAl9MU7Pe1E/opzrD/0sR
+dqKVJcl9vBRbtcAIkCOVpLoA9T2VvisafZAJaRXc3ACFMceewgpVAtBCsWUtLfvW
+fHMHWfti5je19SWg7bUK56uHJ0vdAI+irkfpe1t0aoMCggEAR5cPL3eSYOREs9vQ
+QEcf5NG82H2kfv5kzAkzFCN7267VJryNgWQQG+SzPk3/DD/OXpSRjShsn3X9ecVR
+0tlpdRMS3//8snDqBqjHNlCnoxnvEHE9OB83YLS6n2wmKykyNSCzoxcBpPHbxITT
+1tr+n626w87fEOKWnkBUnND59h1JYO79mfTDF3bDR+Oh4iuDS2bvjEuKxc3RBmry
+T8IMDGA8bT6iGhEcRSgKKD7z7NfA2kHiL/ZsN2EXBOw43J+yhnNephx3MtXGj0S4
+MDxXZ2ZDuQCKrQpl6CJqPwi8+v+xxTYW+d5s9nNsBeIT+sieHTZDTEtEOnYjiDwz
+15p92QKCAQEAkMwGNQawpOhLgYcFEzC0LcbwEFWzztx10N0U77LkRD16jTZ3Do73
+WmYLlLC4mr7e0A0o58MB96EodfHaJD7dSi5Dqkt25hw6xEBS1H0Vms1EjlCa0S/7
+Mq4D1QFF+5B/c8EX4ty20S8R8FCqt2SDc1kz3FHpOo+20kUB8Jtwdveox1J7UXB+
+1rSL1lSyhEviLbMMhAbvh+90UYz5pJ/1s9hMmDi3PyJFdWBNvZYyZcrV5He7tRCI
+fsFGCfol6CoIby5jLA1Rq/M46jq4vQ+ObfGyLv3/nWa0O7u2wHjK9WIRoSKomJmK
+t9xXURb9Obfd2Qo7FwMl9dNzsWkpKuGDYwKCAQB+hiWu2C+0foJ4Z8auM1SK8be4
+waplfD7qIvONE/vtl+VAN+eVpz5kkQJfXiafktAHahgEdSx43bofR0Kv0/R7IRs3
+M1WYAr0w+19TXLXkuh2oYIbcoGrIN3HMmlKMv44xh/QUhRe337cCLejP0SESNN+k
+5wT91SbJwuCw/QsG3sD6NIMtCNWdcsAQq/ruhz7pQ/JZUFOueV0tkzbK+oNHWbNU
+lS99qjPaVCXZFlz/t2/89cljh9mtRjcfXIBfuTijN9sXNcLTXsfLsyHJ86eEbI2U
+o2JQ7Sjs10LpiwBbNNHBmulARgRONNMgik6tpNIS0tk9eke0lCX42bDFtAD4
+-----END RSA PRIVATE KEY-----
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index ace0e6d..4b277ae 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -37,7 +37,6 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.fail;
 
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -629,12 +628,9 @@
         assertEquals(versionRolledBackTo, info.getVersionRolledBackTo().getLongVersionCode());
     }
 
-    // TODO: Allow installing test app along atomically with module metadata package so that
-    // a failed test app will be flagged as a failed mainline app
     /**
      * Test bad update automatic rollback.
      */
-    @Ignore
     @Test
     public void testBadUpdateRollback() throws Exception {
         BroadcastReceiver crashCountReceiver = null;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index c50e6a7..c5b9cf1 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1099,9 +1099,13 @@
          */
         public static final int DISABLED_BY_WRONG_PASSWORD = 13;
         /**
+         * This network is disabled because service is not subscribed
+         */
+        public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 14;
+        /**
          * This Maximum disable reason value
          */
-        public static final int NETWORK_SELECTION_DISABLED_MAX = 14;
+        public static final int NETWORK_SELECTION_DISABLED_MAX = 15;
 
         /**
          * Quality network selection disable reason String (for debug purpose)
@@ -1120,7 +1124,8 @@
                 "NETWORK_SELECTION_DISABLED_NO_INTERNET_PERMANENT",
                 "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER",
                 "NETWORK_SELECTION_DISABLED_BY_USER_SWITCH",
-                "NETWORK_SELECTION_DISABLED_BY_WRONG_PASSWORD"
+                "NETWORK_SELECTION_DISABLED_BY_WRONG_PASSWORD",
+                "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_SUBSCRIPTION"
         };
 
         /**