Merge "Move chunk proto definitions into the BackupEncrypter APK"
diff --git a/api/current.txt b/api/current.txt
index 2e099ed..eeaabf6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2812,12 +2812,12 @@
     method public void onClicked(android.accessibilityservice.AccessibilityButtonController);
   }
 
-  public final class AccessibilityGestureInfo implements android.os.Parcelable {
+  public final class AccessibilityGestureEvent implements android.os.Parcelable {
     method public int describeContents();
     method public int getDisplayId();
     method public int getGestureId();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.accessibilityservice.AccessibilityGestureInfo> CREATOR;
+    field @NonNull public static final android.os.Parcelable.Creator<android.accessibilityservice.AccessibilityGestureEvent> CREATOR;
   }
 
   public abstract class AccessibilityService extends android.app.Service {
@@ -2836,7 +2836,7 @@
     method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public final android.os.IBinder onBind(android.content.Intent);
     method @Deprecated protected boolean onGesture(int);
-    method public boolean onGesture(@NonNull android.accessibilityservice.AccessibilityGestureInfo);
+    method public boolean onGesture(@NonNull android.accessibilityservice.AccessibilityGestureEvent);
     method public abstract void onInterrupt();
     method protected boolean onKeyEvent(android.view.KeyEvent);
     method protected void onServiceConnected();
@@ -23968,6 +23968,7 @@
     method @Nullable public long[] getThumbnailRange();
     method public boolean hasAttribute(@NonNull String);
     method public boolean hasThumbnail();
+    method public static boolean isSupportedMimeType(@NonNull String);
     method public boolean isThumbnailCompressed();
     method public void saveAttributes() throws java.io.IOException;
     method public void setAttribute(@NonNull String, @Nullable String);
diff --git a/api/system-current.txt b/api/system-current.txt
index 4859d54..c4c01af 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8242,6 +8242,7 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int, @Nullable String, int);
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String);
     method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
     method public boolean isDataConnectivityPossible();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
@@ -9516,7 +9517,8 @@
     method public void onReady();
     method public final void onSendSmsResult(int, int, int, int) throws java.lang.RuntimeException;
     method public final void onSmsReceived(int, String, byte[]) throws java.lang.RuntimeException;
-    method public final void onSmsStatusReportReceived(int, int, String, byte[]) throws java.lang.RuntimeException;
+    method @Deprecated public final void onSmsStatusReportReceived(int, int, String, byte[]) throws java.lang.RuntimeException;
+    method public final void onSmsStatusReportReceived(int, String, byte[]) throws java.lang.RuntimeException;
     method public void sendSms(int, int, String, String, boolean, byte[]);
     field public static final int DELIVER_STATUS_ERROR_GENERIC = 2; // 0x2
     field public static final int DELIVER_STATUS_ERROR_NO_MEMORY = 3; // 0x3
diff --git a/api/test-current.txt b/api/test-current.txt
index 6e28f67..3718c4c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -34,8 +34,8 @@
 
 package android.accessibilityservice {
 
-  public final class AccessibilityGestureInfo implements android.os.Parcelable {
-    ctor public AccessibilityGestureInfo(int, int);
+  public final class AccessibilityGestureEvent implements android.os.Parcelable {
+    ctor public AccessibilityGestureEvent(int, int);
   }
 
 }
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index c9a4b3b..43058d5 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -51,11 +51,6 @@
     srcs: [
         ":statsd_aidl",
         "src/active_config_list.proto",
-        "src/statsd_config.proto",
-        "src/uid_data.proto",
-        "src/FieldValue.cpp",
-        "src/hash.cpp",
-        "src/stats_log_util.cpp",
         "src/anomaly/AlarmMonitor.cpp",
         "src/anomaly/AlarmTracker.cpp",
         "src/anomaly/AnomalyTracker.cpp",
@@ -63,51 +58,56 @@
         "src/anomaly/subscriber_util.cpp",
         "src/condition/CombinationConditionTracker.cpp",
         "src/condition/condition_util.cpp",
-        "src/condition/SimpleConditionTracker.cpp",
         "src/condition/ConditionWizard.cpp",
+        "src/condition/SimpleConditionTracker.cpp",
         "src/condition/StateConditionTracker.cpp",
         "src/config/ConfigKey.cpp",
         "src/config/ConfigListener.cpp",
         "src/config/ConfigManager.cpp",
         "src/external/GpuStatsPuller.cpp",
         "src/external/Perfetto.cpp",
-        "src/external/StatsPuller.cpp",
+        "src/external/PowerStatsPuller.cpp",
+        "src/external/puller_util.cpp",
+        "src/external/ResourceHealthManagerPuller.cpp",
         "src/external/StatsCallbackPuller.cpp",
         "src/external/StatsCompanionServicePuller.cpp",
-        "src/external/SubsystemSleepStatePuller.cpp",
-        "src/external/PowerStatsPuller.cpp",
-        "src/external/ResourceHealthManagerPuller.cpp",
-        "src/external/TrainInfoPuller.cpp",
+        "src/external/StatsPuller.cpp",
         "src/external/StatsPullerManager.cpp",
-        "src/external/puller_util.cpp",
+        "src/external/SubsystemSleepStatePuller.cpp",
+        "src/external/TrainInfoPuller.cpp",
+        "src/FieldValue.cpp",
+        "src/guardrail/StatsdStats.cpp",
+        "src/hash.cpp",
+        "src/HashableDimensionKey.cpp",
         "src/logd/LogEvent.cpp",
         "src/logd/LogEventQueue.cpp",
         "src/matchers/CombinationLogMatchingTracker.cpp",
         "src/matchers/EventMatcherWizard.cpp",
         "src/matchers/matcher_util.cpp",
         "src/matchers/SimpleLogMatchingTracker.cpp",
-        "src/metrics/MetricProducer.cpp",
-        "src/metrics/EventMetricProducer.cpp",
         "src/metrics/CountMetricProducer.cpp",
-        "src/metrics/DurationMetricProducer.cpp",
-        "src/metrics/duration_helper/OringDurationTracker.cpp",
         "src/metrics/duration_helper/MaxDurationTracker.cpp",
-        "src/metrics/ValueMetricProducer.cpp",
+        "src/metrics/duration_helper/OringDurationTracker.cpp",
+        "src/metrics/DurationMetricProducer.cpp",
+        "src/metrics/EventMetricProducer.cpp",
         "src/metrics/GaugeMetricProducer.cpp",
-        "src/metrics/MetricsManager.cpp",
+        "src/metrics/MetricProducer.cpp",
         "src/metrics/metrics_manager_util.cpp",
+        "src/metrics/MetricsManager.cpp",
+        "src/metrics/ValueMetricProducer.cpp",
         "src/packages/UidMap.cpp",
-        "src/storage/StorageManager.cpp",
+        "src/shell/shell_config.proto",
+        "src/shell/ShellSubscriber.cpp",
+        "src/socket/StatsSocketListener.cpp",
+        "src/stats_log_util.cpp",
+        "src/statscompanion_util.cpp",
+        "src/statsd_config.proto",
         "src/StatsLogProcessor.cpp",
         "src/StatsService.cpp",
-        "src/statscompanion_util.cpp",
+        "src/storage/StorageManager.cpp",
         "src/subscriber/IncidentdReporter.cpp",
         "src/subscriber/SubscriberReporter.cpp",
-        "src/HashableDimensionKey.cpp",
-        "src/guardrail/StatsdStats.cpp",
-        "src/socket/StatsSocketListener.cpp",
-        "src/shell/ShellSubscriber.cpp",
-        "src/shell/shell_config.proto",
+        "src/uid_data.proto",
     ],
 
     local_include_dirs: [
@@ -120,23 +120,23 @@
     ],
 
     shared_libs: [
-        "libbase",
-        "libbinder",
-        "libgraphicsenv",
-        "libincident",
-        "liblog",
-        "libutils",
-        "libservices",
-        "libprotoutil",
-        "libstatslog",
-        "libhidlbase",
         "android.frameworks.stats@1.0",
         "android.hardware.health@2.0",
+        "android.hardware.power.stats@1.0",
         "android.hardware.power@1.0",
         "android.hardware.power@1.1",
-        "android.hardware.power.stats@1.0",
-        "libsysutils",
+        "libbase",
+        "libbinder",
         "libcutils",
+        "libgraphicsenv",
+        "libhidlbase",
+        "libincident",
+        "liblog",
+        "libprotoutil",
+        "libservices",
+        "libstatslog",
+        "libsysutils",
+        "libutils",
     ],
 }
 
@@ -210,54 +210,54 @@
 
         "src/atom_field_options.proto",
         "src/atoms.proto",
-        "src/stats_log.proto",
         "src/shell/shell_data.proto",
+        "src/stats_log.proto",
         "tests/AlarmMonitor_test.cpp",
         "tests/anomaly/AlarmTracker_test.cpp",
         "tests/anomaly/AnomalyTracker_test.cpp",
-        "tests/ConfigManager_test.cpp",
-        "tests/external/puller_util_test.cpp",
-        "tests/external/GpuStatsPuller_test.cpp",
-        "tests/external/IncidentReportArgs_test.cpp",
-        "tests/external/StatsPuller_test.cpp",
-        "tests/indexed_priority_queue_test.cpp",
-        "tests/LogEntryMatcher_test.cpp",
-        "tests/LogEvent_test.cpp",
-        "tests/log_event/LogEventQueue_test.cpp",
-        "tests/MetricsManager_test.cpp",
-        "tests/StatsLogProcessor_test.cpp",
-        "tests/StatsService_test.cpp",
-        "tests/UidMap_test.cpp",
-        "tests/FieldValue_test.cpp",
         "tests/condition/CombinationConditionTracker_test.cpp",
+        "tests/condition/ConditionTimer_test.cpp",
         "tests/condition/SimpleConditionTracker_test.cpp",
         "tests/condition/StateConditionTracker_test.cpp",
-        "tests/condition/ConditionTimer_test.cpp",
-        "tests/metrics/OringDurationTracker_test.cpp",
-        "tests/metrics/MaxDurationTracker_test.cpp",
+        "tests/ConfigManager_test.cpp",
+        "tests/e2e/Alarm_e2e_test.cpp",
+        "tests/e2e/Anomaly_count_e2e_test.cpp",
+        "tests/e2e/Anomaly_duration_sum_e2e_test.cpp",
+        "tests/e2e/Attribution_e2e_test.cpp",
+        "tests/e2e/ConfigTtl_e2e_test.cpp",
+        "tests/e2e/DurationMetric_e2e_test.cpp",
+        "tests/e2e/GaugeMetric_e2e_pull_test.cpp",
+        "tests/e2e/GaugeMetric_e2e_push_test.cpp",
+        "tests/e2e/MetricActivation_e2e_test.cpp",
+        "tests/e2e/MetricConditionLink_e2e_test.cpp",
+        "tests/e2e/PartialBucket_e2e_test.cpp",
+        "tests/e2e/ValueMetric_pull_e2e_test.cpp",
+        "tests/e2e/WakelockDuration_e2e_test.cpp",
+        "tests/external/GpuStatsPuller_test.cpp",
+        "tests/external/IncidentReportArgs_test.cpp",
+        "tests/external/puller_util_test.cpp",
+        "tests/external/StatsPuller_test.cpp",
+        "tests/FieldValue_test.cpp",
+        "tests/guardrail/StatsdStats_test.cpp",
+        "tests/indexed_priority_queue_test.cpp",
+        "tests/log_event/LogEventQueue_test.cpp",
+        "tests/LogEntryMatcher_test.cpp",
+        "tests/LogEvent_test.cpp",
         "tests/metrics/CountMetricProducer_test.cpp",
         "tests/metrics/DurationMetricProducer_test.cpp",
         "tests/metrics/EventMetricProducer_test.cpp",
-        "tests/metrics/ValueMetricProducer_test.cpp",
         "tests/metrics/GaugeMetricProducer_test.cpp",
-        "tests/guardrail/StatsdStats_test.cpp",
+        "tests/metrics/MaxDurationTracker_test.cpp",
         "tests/metrics/metrics_test_helper.cpp",
-        "tests/statsd_test_util.cpp",
-        "tests/storage/StorageManager_test.cpp",
-        "tests/e2e/WakelockDuration_e2e_test.cpp",
-        "tests/e2e/MetricActivation_e2e_test.cpp",
-        "tests/e2e/MetricConditionLink_e2e_test.cpp",
-        "tests/e2e/Alarm_e2e_test.cpp",
-        "tests/e2e/Attribution_e2e_test.cpp",
-        "tests/e2e/GaugeMetric_e2e_push_test.cpp",
-        "tests/e2e/GaugeMetric_e2e_pull_test.cpp",
-        "tests/e2e/ValueMetric_pull_e2e_test.cpp",
-        "tests/e2e/Anomaly_count_e2e_test.cpp",
-        "tests/e2e/Anomaly_duration_sum_e2e_test.cpp",
-        "tests/e2e/ConfigTtl_e2e_test.cpp",
-        "tests/e2e/PartialBucket_e2e_test.cpp",
-        "tests/e2e/DurationMetric_e2e_test.cpp",
+        "tests/metrics/OringDurationTracker_test.cpp",
+        "tests/metrics/ValueMetricProducer_test.cpp",
+        "tests/MetricsManager_test.cpp",
         "tests/shell/ShellSubscriber_test.cpp",
+        "tests/statsd_test_util.cpp",
+        "tests/StatsLogProcessor_test.cpp",
+        "tests/StatsService_test.cpp",
+        "tests/storage/StorageManager_test.cpp",
+        "tests/UidMap_test.cpp",
     ],
 
     static_libs: [
@@ -287,17 +287,17 @@
         // not included in libprotobuf-cpp-lite, so compile it here.
         ":libprotobuf-internal-protos",
 
+        "benchmark/duration_metric_benchmark.cpp",
+        "benchmark/filter_value_benchmark.cpp",
+        "benchmark/get_dimensions_for_condition_benchmark.cpp",
+        "benchmark/hello_world_benchmark.cpp",
+        "benchmark/log_event_benchmark.cpp",
+        "benchmark/main.cpp",
+        "benchmark/metric_util.cpp",
+        "benchmark/stats_write_benchmark.cpp",
         "src/atom_field_options.proto",
         "src/atoms.proto",
         "src/stats_log.proto",
-        "benchmark/main.cpp",
-        "benchmark/hello_world_benchmark.cpp",
-        "benchmark/log_event_benchmark.cpp",
-        "benchmark/stats_write_benchmark.cpp",
-        "benchmark/filter_value_benchmark.cpp",
-        "benchmark/get_dimensions_for_condition_benchmark.cpp",
-        "benchmark/metric_util.cpp",
-        "benchmark/duration_metric_benchmark.cpp",
     ],
 
     proto: {
@@ -337,11 +337,11 @@
     },
 
     srcs: [
-        "src/stats_log.proto",
-        "src/statsd_config.proto",
         "src/atoms.proto",
         "src/shell/shell_config.proto",
         "src/shell/shell_data.proto",
+        "src/stats_log.proto",
+        "src/statsd_config.proto",
     ],
 
     static_libs: [
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index b50ec8a..f8a3ede 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -335,6 +335,8 @@
         UpdateEngineUpdateAttemptReported update_engine_update_attempt_reported = 225;
         UpdateEngineSuccessfulUpdateReported update_engine_successful_update_reported = 226;
         CameraActionEvent camera_action_event = 227;
+        AppCompatibilityChangeReported app_compatibility_change_reported =
+            228 [(allow_from_any_uid) = true];
     }
 
     // Pulled events will start at field 10000.
@@ -7170,7 +7172,6 @@
     repeated int64 frame_counts = 2;
 }
 
-
 /**
  * Information about camera facing and API level usage.
  * Logged from:
@@ -7195,3 +7196,39 @@
     }
     optional Facing facing = 4;
 }
+
+/**
+ * Logs when a compatibility change is affecting an app.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/android/app/AppCompatCallbacks.java and
+ *   frameworks/base/services/core/java/com/android/server/compat/PlatformCompat.java
+ */
+message AppCompatibilityChangeReported {
+    // The UID of the app being affected by the compatibilty change.
+    optional int32 uid = 1 [(is_uid) = true];
+
+    // The ID of the change affecting the app.
+    optional int64 change_id = 2;
+
+    enum State {
+        UNKNOWN_STATE = 0;
+        ENABLED = 1;
+        DISABLED = 2;
+        LOGGED = 3;
+    }
+
+    // The state of the change - if logged from gating whether it was enabled or disabled, or just
+    // logged otherwise.
+    optional State state = 3;
+
+    enum Source {
+        UNKNOWN_SOURCE = 0;
+        APP_PROCESS = 1;
+        SYSTEM_SERVER = 2;
+    }
+
+    // Where it was logged from.
+    optional Source source = 4;
+
+}
diff --git a/core/java/android/accessibilityservice/AccessibilityGestureInfo.aidl b/core/java/android/accessibilityservice/AccessibilityGestureEvent.aidl
similarity index 94%
rename from core/java/android/accessibilityservice/AccessibilityGestureInfo.aidl
rename to core/java/android/accessibilityservice/AccessibilityGestureEvent.aidl
index 2539051..58a9b64 100644
--- a/core/java/android/accessibilityservice/AccessibilityGestureInfo.aidl
+++ b/core/java/android/accessibilityservice/AccessibilityGestureEvent.aidl
@@ -16,4 +16,4 @@
 
 package android.accessibilityservice;
 
-parcelable AccessibilityGestureInfo;
+parcelable AccessibilityGestureEvent;
diff --git a/core/java/android/accessibilityservice/AccessibilityGestureInfo.java b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
similarity index 86%
rename from core/java/android/accessibilityservice/AccessibilityGestureInfo.java
rename to core/java/android/accessibilityservice/AccessibilityGestureEvent.java
index 28c1dea..b540175 100644
--- a/core/java/android/accessibilityservice/AccessibilityGestureInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
@@ -44,17 +44,17 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * This class describes the gesture information including gesture id and which display it happens
+ * This class describes the gesture event including gesture id and which display it happens
  * on.
  * <p>
  * <strong>Note:</strong> Accessibility services setting the
  * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}
  * flag can receive gestures.
  *
- * @see AccessibilityService#onGesture(AccessibilityGestureInfo)
+ * @see AccessibilityService#onGesture(AccessibilityGestureEvent)
  */
 
-public final class AccessibilityGestureInfo implements Parcelable {
+public final class AccessibilityGestureEvent implements Parcelable {
 
     /** @hide */
     @IntDef(prefix = { "GESTURE_" }, value = {
@@ -84,12 +84,12 @@
 
     /** @hide */
     @TestApi
-    public AccessibilityGestureInfo(int gestureId, int displayId) {
+    public AccessibilityGestureEvent(int gestureId, int displayId) {
         mGestureId = gestureId;
         mDisplayId = displayId;
     }
 
-    private AccessibilityGestureInfo(@NonNull Parcel parcel) {
+    private AccessibilityGestureEvent(@NonNull Parcel parcel) {
         mGestureId = parcel.readInt();
         mDisplayId = parcel.readInt();
     }
@@ -117,7 +117,7 @@
     @NonNull
     @Override
     public String toString() {
-        StringBuilder stringBuilder = new StringBuilder("AccessibilityGestureInfo[");
+        StringBuilder stringBuilder = new StringBuilder("AccessibilityGestureEvent[");
         stringBuilder.append("gestureId: ").append(mGestureId);
         stringBuilder.append(", ");
         stringBuilder.append("displayId: ").append(mDisplayId);
@@ -142,14 +142,14 @@
     /**
      * @see Parcelable.Creator
      */
-    public static final @NonNull Parcelable.Creator<AccessibilityGestureInfo> CREATOR =
-            new Parcelable.Creator<AccessibilityGestureInfo>() {
-        public AccessibilityGestureInfo createFromParcel(Parcel parcel) {
-            return new AccessibilityGestureInfo(parcel);
+    public static final @NonNull Parcelable.Creator<AccessibilityGestureEvent> CREATOR =
+            new Parcelable.Creator<AccessibilityGestureEvent>() {
+        public AccessibilityGestureEvent createFromParcel(Parcel parcel) {
+            return new AccessibilityGestureEvent(parcel);
         }
 
-        public AccessibilityGestureInfo[] newArray(int size) {
-            return new AccessibilityGestureInfo[size];
+        public AccessibilityGestureEvent[] newArray(int size) {
+            return new AccessibilityGestureEvent[size];
         }
     };
 
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index a8daf91..d3c274f 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -382,7 +382,7 @@
         void onServiceConnected();
         void init(int connectionId, IBinder windowToken);
         /** The detected gesture information for different displays */
-        boolean onGesture(AccessibilityGestureInfo gestureInfo);
+        boolean onGesture(AccessibilityGestureEvent gestureInfo);
         boolean onKeyEvent(KeyEvent event);
         /** Magnification changed callbacks for different displays */
         void onMagnificationChanged(int displayId, @NonNull Region region,
@@ -517,7 +517,7 @@
     }
 
     /**
-     * Called by {@link #onGesture(AccessibilityGestureInfo)} when the user performs a specific
+     * Called by {@link #onGesture(AccessibilityGestureEvent)} when the user performs a specific
      * gesture on the default display.
      *
      * <strong>Note:</strong> To receive gestures an accessibility service must
@@ -528,7 +528,7 @@
      * @param gestureId The unique id of the performed gesture.
      *
      * @return Whether the gesture was handled.
-     * @deprecated Override {@link #onGesture(AccessibilityGestureInfo)} instead.
+     * @deprecated Override {@link #onGesture(AccessibilityGestureEvent)} instead.
      *
      * @see #GESTURE_SWIPE_UP
      * @see #GESTURE_SWIPE_UP_AND_LEFT
@@ -564,14 +564,14 @@
      * <strong>Note:</strong> The default implementation calls {@link #onGesture(int)} when the
      * touch screen is default display.
      *
-     * @param gestureInfo The information of gesture.
+     * @param gestureEvent The information of gesture.
      *
      * @return Whether the gesture was handled.
      *
      */
-    public boolean onGesture(@NonNull AccessibilityGestureInfo gestureInfo) {
-        if (gestureInfo.getDisplayId() == Display.DEFAULT_DISPLAY) {
-            onGesture(gestureInfo.getGestureId());
+    public boolean onGesture(@NonNull AccessibilityGestureEvent gestureEvent) {
+        if (gestureEvent.getDisplayId() == Display.DEFAULT_DISPLAY) {
+            onGesture(gestureEvent.getGestureId());
         }
         return false;
     }
@@ -1725,8 +1725,8 @@
             }
 
             @Override
-            public boolean onGesture(AccessibilityGestureInfo gestureInfo) {
-                return AccessibilityService.this.onGesture(gestureInfo);
+            public boolean onGesture(AccessibilityGestureEvent gestureEvent) {
+                return AccessibilityService.this.onGesture(gestureEvent);
             }
 
             @Override
@@ -1826,7 +1826,7 @@
         }
 
         @Override
-        public void onGesture(AccessibilityGestureInfo gestureInfo) {
+        public void onGesture(AccessibilityGestureEvent gestureInfo) {
             Message message = mCaller.obtainMessageO(DO_ON_GESTURE, gestureInfo);
             mCaller.sendMessage(message);
         }
@@ -1942,7 +1942,7 @@
 
                 case DO_ON_GESTURE: {
                     if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
-                        mCallback.onGesture((AccessibilityGestureInfo) message.obj);
+                        mCallback.onGesture((AccessibilityGestureEvent) message.obj);
                     }
                 } return;
 
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index e0d5e44..8ec3aea 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -20,7 +20,7 @@
 import android.graphics.Region;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityWindowInfo;
-import android.accessibilityservice.AccessibilityGestureInfo;
+import android.accessibilityservice.AccessibilityGestureEvent;
 import android.view.KeyEvent;
 
 /**
@@ -36,7 +36,7 @@
 
     void onInterrupt();
 
-    void onGesture(in AccessibilityGestureInfo gestureInfo);
+    void onGesture(in AccessibilityGestureEvent gestureEvent);
 
     void clearAccessibilityCache();
 
diff --git a/core/java/android/app/AppCompatCallbacks.java b/core/java/android/app/AppCompatCallbacks.java
index 17697db..08c97eb 100644
--- a/core/java/android/app/AppCompatCallbacks.java
+++ b/core/java/android/app/AppCompatCallbacks.java
@@ -19,6 +19,9 @@
 import android.compat.Compatibility;
 import android.os.Process;
 import android.util.Log;
+import android.util.StatsLog;
+
+import com.android.internal.compat.ChangeReporter;
 
 import java.util.Arrays;
 
@@ -28,10 +31,10 @@
  * @hide
  */
 public final class AppCompatCallbacks extends Compatibility.Callbacks {
-
     private static final String TAG = "Compatibility";
 
     private final long[] mDisabledChanges;
+    private final ChangeReporter mChangeReporter;
 
     /**
      * Install this class into the current process.
@@ -45,20 +48,29 @@
     private AppCompatCallbacks(long[] disabledChanges) {
         mDisabledChanges = Arrays.copyOf(disabledChanges, disabledChanges.length);
         Arrays.sort(mDisabledChanges);
+        mChangeReporter = new ChangeReporter();
     }
 
     protected void reportChange(long changeId) {
-        Log.d(TAG, "Compat change reported: " + changeId + "; UID " + Process.myUid());
-        // TODO log via StatsLog
+        reportChange(changeId, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED);
     }
 
     protected boolean isChangeEnabled(long changeId) {
         if (Arrays.binarySearch(mDisabledChanges, changeId) < 0) {
             // Not present in the disabled array
-            reportChange(changeId);
+            reportChange(changeId, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED);
             return true;
         }
+        reportChange(changeId, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__DISABLED);
         return false;
     }
 
+    private void reportChange(long changeId, int state) {
+        int uid = Process.myUid();
+        //TODO(b/138374585): Implement rate limiting for the logs.
+        Log.d(TAG, ChangeReporter.createLogString(uid, changeId, state));
+        mChangeReporter.reportChange(uid, changeId,
+                state, /* source */StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__APP_PROCESS);
+    }
+
 }
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index f9b96c5..fd93450 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import android.accessibilityservice.AccessibilityGestureInfo;
+import android.accessibilityservice.AccessibilityGestureEvent;
 import android.accessibilityservice.AccessibilityService.Callbacks;
 import android.accessibilityservice.AccessibilityService.IAccessibilityServiceClientWrapper;
 import android.accessibilityservice.AccessibilityServiceInfo;
@@ -1246,7 +1246,7 @@
                 }
 
                 @Override
-                public boolean onGesture(AccessibilityGestureInfo gestureInfo) {
+                public boolean onGesture(AccessibilityGestureEvent gestureEvent) {
                     /* do nothing */
                     return false;
                 }
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 9d52363..099dea2 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -60,9 +60,7 @@
  * multiple possible matching values (via {@link #addAction},
  * {@link #addDataType}, {@link #addDataScheme}, {@link #addDataSchemeSpecificPart},
  * {@link #addDataAuthority}, {@link #addDataPath}, and {@link #addCategory}, respectively).
- * For actions, the field
- * will not be tested if no values have been given (treating it as a wildcard);
- * if no data characteristics are specified, however, then the filter will
+ * For actions, if no data characteristics are specified, then the filter will
  * only match intents that contain no data.
  *
  * <p>The data characteristic is
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index de61d70..24ee213 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.annotation.AppIdInt;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -321,25 +322,24 @@
             Bundle verificationBundle, int userId);
 
     /**
-     * Grants access to the package metadata for an ephemeral application.
+     * Grants implicit access based on an interaction between two apps. This grants the target app
+     * access to the calling application's package metadata.
      * <p>
-     * When an ephemeral application explicitly tries to interact with a full
-     * install application [via an activity, service or provider that has been
-     * exposed using the {@code visibleToInstantApp} attribute], the normal
-     * application must be able to see metadata about the connecting ephemeral
-     * app. If the ephemeral application uses an implicit intent [ie action VIEW,
-     * category BROWSABLE], it remains hidden from the launched activity.
+     * When an application explicitly tries to interact with another application [via an
+     * activity, service or provider that is either declared in the caller's
+     * manifest via the {@code <queries>} tag or has been exposed via the target apps manifest using
+     * the {@code visibleToInstantApp} attribute], the target application must be able to see
+     * metadata about the calling app. If the calling application uses an implicit intent [ie
+     * action VIEW, category BROWSABLE], it remains hidden from the launched app.
      * <p>
-     * If the {@code sourceUid} is not for an ephemeral app or {@code targetUid}
-     * is not for a fully installed app, this method will be a no-op.
-     *
      * @param userId the user
      * @param intent the intent that triggered the grant
-     * @param targetAppId The app ID of the fully installed application
-     * @param ephemeralAppId The app ID of the ephemeral application
+     * @param callingAppId The app ID of the calling application
+     * @param targetAppId The app ID of the target application
      */
-    public abstract void grantEphemeralAccess(int userId, Intent intent,
-            int targetAppId, int ephemeralAppId);
+    public abstract void grantImplicitAccess(
+            @UserIdInt int userId, Intent intent, @AppIdInt int callingAppId,
+            @AppIdInt int targetAppId);
 
     public abstract boolean isInstantAppInstallerComponent(ComponentName component);
     /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3b40c00..8b20f0b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2103,10 +2103,6 @@
     private static final String TAG = "Settings";
     private static final boolean LOCAL_LOGV = false;
 
-    // Lock ensures that when enabling/disabling the master location switch, we don't end up
-    // with a partial enable/disable state in multi-threaded situations.
-    private static final Object mLocationSettingsLock = new Object();
-
     // Used in system server calling uid workaround in call()
     private static boolean sInSystemServer = false;
     private static final Object sInSystemServerLock = new Object();
@@ -12920,8 +12916,7 @@
         }
 
         /**
-          * Subscription to be used for voice call on a multi sim device. The supported values
-          * are 0 = SUB1, 1 = SUB2 and etc.
+          * Subscription Id to be used for voice call on a multi sim device.
           * @hide
           */
         public static final String MULTI_SIM_VOICE_CALL_SUBSCRIPTION = "multi_sim_voice_call";
@@ -12935,15 +12930,13 @@
         public static final String MULTI_SIM_VOICE_PROMPT = "multi_sim_voice_prompt";
 
         /**
-          * Subscription to be used for data call on a multi sim device. The supported values
-          * are 0 = SUB1, 1 = SUB2 and etc.
+          * Subscription Id to be used for data call on a multi sim device.
           * @hide
           */
         public static final String MULTI_SIM_DATA_CALL_SUBSCRIPTION = "multi_sim_data_call";
 
         /**
-          * Subscription to be used for SMS on a multi sim device. The supported values
-          * are 0 = SUB1, 1 = SUB2 and etc.
+          * Subscription Id to be used for SMS on a multi sim device.
           * @hide
           */
         public static final String MULTI_SIM_SMS_SUBSCRIPTION = "multi_sim_sms";
diff --git a/core/java/android/service/carrier/ApnService.java b/core/java/android/service/carrier/ApnService.java
index 57e4b1b..0c12fd4 100644
--- a/core/java/android/service/carrier/ApnService.java
+++ b/core/java/android/service/carrier/ApnService.java
@@ -26,7 +26,7 @@
 import android.os.IBinder;
 import android.util.Log;
 
-import com.android.internal.telephony.IApnSourceService;
+import android.service.carrier.IApnSourceService;
 
 import java.util.List;
 
diff --git a/telephony/java/com/android/internal/telephony/IApnSourceService.aidl b/core/java/android/service/carrier/IApnSourceService.aidl
similarity index 93%
rename from telephony/java/com/android/internal/telephony/IApnSourceService.aidl
rename to core/java/android/service/carrier/IApnSourceService.aidl
index 34c9067..fadd2ff 100644
--- a/telephony/java/com/android/internal/telephony/IApnSourceService.aidl
+++ b/core/java/android/service/carrier/IApnSourceService.aidl
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony;
+package android.service.carrier;
 
 import android.content.ContentValues;
 
+/** @hide */
 interface IApnSourceService {
     /** Retreive APNs. */
     ContentValues[] getApns(int subId);
diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl
index f1d152b..d2dcb568 100644
--- a/core/java/android/view/IPinnedStackController.aidl
+++ b/core/java/android/view/IPinnedStackController.aidl
@@ -16,8 +16,6 @@
 
 package android.view;
 
-import android.graphics.Rect;
-
 /**
  * An interface to the PinnedStackController to update it of state changes, and to query
  * information based on the current state.
@@ -32,17 +30,15 @@
     oneway void setIsMinimized(boolean isMinimized);
 
     /**
+     * Notifies the controller of the current min edge size, this is needed to allow the system to
+     * properly calculate the aspect ratio of the expanded PIP.  The given {@param minEdgeSize} is
+     * always bounded to be larger than the default minEdgeSize, so the caller can call this method
+     * with 0 to reset to the default size.
+     */
+    oneway void setMinEdgeSize(int minEdgeSize);
+
+    /**
      * @return what WM considers to be the current device rotation.
      */
     int getDisplayRotation();
-
-    /**
-     * Notifies the controller to actually start the PiP animation.
-     * The bounds would be calculated based on the last save reentry fraction internally.
-     * {@param destinationBounds} is the stack bounds of the final PiP window
-     * and {@param sourceRectHint} is the source bounds hint used when entering picture-in-picture,
-     * expect the same bound passed via IPinnedStackListener#onPrepareAnimation.
-     * {@param animationDuration} suggests the animation duration transitioning to PiP window.
-     */
-    void startAnimation(in Rect destinationBounds, in Rect sourceRectHint, int animationDuration);
 }
diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl
index 806d81e..2da353b 100644
--- a/core/java/android/view/IPinnedStackListener.aidl
+++ b/core/java/android/view/IPinnedStackListener.aidl
@@ -16,10 +16,8 @@
 
 package android.view;
 
-import android.content.ComponentName;
 import android.content.pm.ParceledListSlice;
 import android.graphics.Rect;
-import android.view.DisplayInfo;
 import android.view.IPinnedStackController;
 
 /**
@@ -38,13 +36,18 @@
     /**
      * Called when the window manager has detected a change that would cause the movement bounds
      * to be changed (ie. after configuration change, aspect ratio change, etc). It then provides
-     * the components that allow the listener to calculate the movement bounds itself.
-     * The {@param animatingBounds} are provided to indicate the current target bounds of the
-     * pinned stack (the final bounds if animating, the current bounds if not),
-     * which may be helpful in calculating dependent animation bounds.
+     * the components that allow the listener to calculate the movement bounds itself. The
+     * {@param normalBounds} are also the default bounds that the PiP would be entered in its
+     * current state with the aspect ratio applied.  The {@param animatingBounds} are provided
+     * to indicate the current target bounds of the pinned stack (the final bounds if animating,
+     * the current bounds if not), which may be helpful in calculating dependent animation bounds.
+     *
+     * The {@param displayRotation} is provided so that the client can verify when making certain
+     * calls that it will not provide stale information based on an old display rotation (ie. if
+     * the WM has changed in the mean time but the client has not received onMovementBoundsChanged).
      */
-    void onMovementBoundsChanged(in Rect animatingBounds, boolean fromImeAdjustment,
-            boolean fromShelfAdjustment);
+    void onMovementBoundsChanged(in Rect insetBounds, in Rect normalBounds, in Rect animatingBounds,
+            boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation);
 
     /**
      * Called when window manager decides to adjust the pinned stack bounds because of the IME, or
@@ -73,47 +76,4 @@
      * is first registered to allow the listener to synchronized its state with the controller.
      */
     void onActionsChanged(in ParceledListSlice actions);
-
-    /**
-     * Called by the window manager to notify the listener to save the reentry fraction,
-     * typically when an Activity leaves PiP (picture-in-picture) mode to fullscreen.
-     * {@param componentName} represents the application component of PiP window
-     * while {@param bounds} is the current PiP bounds used to calculate the
-     * reentry snap fraction.
-     */
-    void onSaveReentrySnapFraction(in ComponentName componentName, in Rect bounds);
-
-    /**
-     * Called by the window manager to notify the listener to reset saved reentry fraction,
-     * typically when an Activity enters PiP (picture-in-picture) mode from fullscreen.
-     * {@param componentName} represents the application component of PiP window.
-     */
-    void onResetReentrySnapFraction(in ComponentName componentName);
-
-    /**
-     * Called when the window manager has detected change on DisplayInfo,  or
-     * when the listener is first registered to allow the listener to synchronized its state with
-     * the controller.
-     */
-    void onDisplayInfoChanged(in DisplayInfo displayInfo);
-
-    /**
-     * Called by the window manager at the beginning of a configuration update cascade
-     * since the metrics from these resources are used for bounds calculations.
-     */
-    void onConfigurationChanged();
-
-    /**
-     * Called by the window manager when the aspect ratio is reset.
-     */
-    void onAspectRatioChanged(float aspectRatio);
-
-    /**
-     * Called by the window manager to notify the listener to prepare for PiP animation.
-     * Internally, the target bounds would be calculated from the given {@param aspectRatio}
-     * and {@param bounds}, the saved reentry snap fraction also contributes.
-     * Caller would wait for a IPinnedStackController#startAnimation callback to actually
-     * start the animation, see details in IPinnedStackController.
-     */
-    void onPrepareAnimation(in Rect sourceRectHint, float aspectRatio, in Rect bounds);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index bdfb3e3..cfb6a79a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -14466,8 +14466,8 @@
         }
 
         notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible);
-        if (isVisible != oldVisible) {
-            updateSystemGestureExclusionRects();
+        if (!getSystemGestureExclusionRects().isEmpty() && isVisible != oldVisible) {
+            postUpdateSystemGestureExclusionRects();
         }
     }
 
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 2f44d6e..1cb1148 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -4109,7 +4109,7 @@
         final int rowsCount = getCount();
         final int selectionMode = getSelectionModeForAccessibility();
         final CollectionInfo collectionInfo = CollectionInfo.obtain(
-                rowsCount, 1, false, selectionMode);
+                -1, -1, false, selectionMode);
         info.setCollectionInfo(collectionInfo);
 
         if (rowsCount > 0) {
diff --git a/core/java/com/android/internal/compat/ChangeReporter.java b/core/java/com/android/internal/compat/ChangeReporter.java
new file mode 100644
index 0000000..1ce071b
--- /dev/null
+++ b/core/java/com/android/internal/compat/ChangeReporter.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.compat;
+
+import android.util.StatsLog;
+
+/**
+ * A helper class to report changes to stats log.
+ *
+ * @hide
+ */
+public final class ChangeReporter {
+
+    /**
+     * Transforms StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE enum to a string.
+     *
+     * @param state to transform
+     * @return a string representing the state
+     */
+    private static String stateToString(int state) {
+        switch (state) {
+            case StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED:
+                return "LOGGED";
+            case StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED:
+                return "ENABLED";
+            case StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__DISABLED:
+                return "DISABLED";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
+    /**
+     * Constructs and returns a string to be logged to logcat when a change is reported.
+     *
+     * @param uid      affected by the change
+     * @param changeId the reported change id
+     * @param state    of the reported change - enabled/disabled/only logged
+     * @return string to log
+     */
+    public static String createLogString(int uid, long changeId, int state) {
+        return String.format("Compat change id reported: %d; UID %d; state: %s", changeId, uid,
+                stateToString(state));
+    }
+
+    /**
+     * Report the change to stats log.
+     *
+     * @param uid      affected by the change
+     * @param changeId the reported change id
+     * @param state    of the reported change - enabled/disabled/only logged
+     * @param source   of the logging - app process or system server
+     */
+    public void reportChange(int uid, long changeId, int state, int source) {
+        //TODO(b/138374585): Implement rate limiting for stats log.
+        StatsLog.write(StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED, uid, changeId,
+                state, source);
+    }
+}
diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp
index 03057dc..0002f8b 100644
--- a/core/jni/android_hardware_SoundTrigger.cpp
+++ b/core/jni/android_hardware_SoundTrigger.cpp
@@ -606,12 +606,12 @@
         goto exit;
     }
     memory = memoryDealer->allocate(offset + size);
-    if (memory == 0 || memory->pointer() == NULL) {
+    if (memory == 0 || memory->unsecurePointer() == NULL) {
         status = SOUNDTRIGGER_STATUS_ERROR;
         goto exit;
     }
 
-    nSoundModel = (struct sound_trigger_sound_model *)memory->pointer();
+    nSoundModel = (struct sound_trigger_sound_model *)memory->unsecurePointer();
 
     nSoundModel->type = type;
     nSoundModel->uuid = nUuid;
@@ -737,18 +737,18 @@
         return SOUNDTRIGGER_STATUS_ERROR;
     }
     sp<IMemory> memory = memoryDealer->allocate(totalSize);
-    if (memory == 0 || memory->pointer() == NULL) {
+    if (memory == 0 || memory->unsecurePointer() == NULL) {
         return SOUNDTRIGGER_STATUS_ERROR;
     }
     if (dataSize != 0) {
-        memcpy((char *)memory->pointer() + sizeof(struct sound_trigger_recognition_config),
+        memcpy((char *)memory->unsecurePointer() + sizeof(struct sound_trigger_recognition_config),
                 nData,
                 dataSize);
         env->ReleaseByteArrayElements(jData, nData, 0);
     }
     env->DeleteLocalRef(jData);
     struct sound_trigger_recognition_config *config =
-                                    (struct sound_trigger_recognition_config *)memory->pointer();
+                                    (struct sound_trigger_recognition_config *)memory->unsecurePointer();
     config->data_size = dataSize;
     config->data_offset = sizeof(struct sound_trigger_recognition_config);
     config->capture_requested = env->GetBooleanField(jConfig,
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index daa6347..c5049ec 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -649,7 +649,7 @@
         if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
             sizeInBytes = track->sharedBuffer()->size();
         }
-        memcpy(track->sharedBuffer()->pointer(), data + offsetInSamples, sizeInBytes);
+        memcpy(track->sharedBuffer()->unsecurePointer(), data + offsetInSamples, sizeInBytes);
         written = sizeInBytes;
     }
     if (written >= 0) {
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index cbae2da..b6427c9a 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -152,7 +152,7 @@
         uint32_t flags,
         TransactCallback callback) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
-    bool isOneway = (flags & TF_ONE_WAY) != 0;
+    bool isOneway = (flags & IBinder::FLAG_ONEWAY) != 0;
     ScopedLocalRef<jobject> replyObj(env, nullptr);
     sp<JHwParcel> replyContext = nullptr;
 
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index 8553a2c..af34e7b7 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "InputChannel-JNI"
 
+#include "android-base/stringprintf.h"
 #include <nativehelper/JNIHelp.h>
 #include "nativehelper/scoped_utf_chars.h"
 #include <android_runtime/AndroidRuntime.h>
@@ -60,7 +61,7 @@
 // ----------------------------------------------------------------------------
 
 NativeInputChannel::NativeInputChannel(const sp<InputChannel>& inputChannel) :
-    mInputChannel(inputChannel), mDisposeCallback(NULL) {
+    mInputChannel(inputChannel), mDisposeCallback(nullptr) {
 }
 
 NativeInputChannel::~NativeInputChannel() {
@@ -74,8 +75,8 @@
 void NativeInputChannel::invokeAndRemoveDisposeCallback(JNIEnv* env, jobject obj) {
     if (mDisposeCallback) {
         mDisposeCallback(env, obj, mInputChannel, mDisposeData);
-        mDisposeCallback = NULL;
-        mDisposeData = NULL;
+        mDisposeCallback = nullptr;
+        mDisposeData = nullptr;
     }
 }
 
@@ -96,14 +97,14 @@
 sp<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* env, jobject inputChannelObj) {
     NativeInputChannel* nativeInputChannel =
             android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
-    return nativeInputChannel != NULL ? nativeInputChannel->getInputChannel() : NULL;
+    return nativeInputChannel != nullptr ? nativeInputChannel->getInputChannel() : nullptr;
 }
 
 void android_view_InputChannel_setDisposeCallback(JNIEnv* env, jobject inputChannelObj,
         InputChannelObjDisposeCallback callback, void* data) {
     NativeInputChannel* nativeInputChannel =
             android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
-    if (nativeInputChannel == NULL) {
+    if (nativeInputChannel == nullptr) {
         ALOGW("Cannot set dispose callback because input channel object has not been initialized.");
     } else {
         nativeInputChannel->setDisposeCallback(callback, data);
@@ -131,27 +132,27 @@
     status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
 
     if (result) {
-        String8 message;
-        message.appendFormat("Could not open input channel pair.  status=%d", result);
-        jniThrowRuntimeException(env, message.string());
-        return NULL;
+        std::string message = android::base::StringPrintf(
+                "Could not open input channel pair : %s", strerror(-result));
+        jniThrowRuntimeException(env, message.c_str());
+        return nullptr;
     }
 
-    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
+    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, nullptr);
     if (env->ExceptionCheck()) {
-        return NULL;
+        return nullptr;
     }
 
     jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
             std::make_unique<NativeInputChannel>(serverChannel));
     if (env->ExceptionCheck()) {
-        return NULL;
+        return nullptr;
     }
 
     jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
             std::make_unique<NativeInputChannel>(clientChannel));
     if (env->ExceptionCheck()) {
-        return NULL;
+        return nullptr;
     }
 
     env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
@@ -170,7 +171,7 @@
 
         nativeInputChannel->invokeAndRemoveDisposeCallback(env, obj);
 
-        android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
+        android_view_InputChannel_setNativeInputChannel(env, obj, nullptr);
         delete nativeInputChannel;
     }
 }
@@ -179,14 +180,14 @@
     NativeInputChannel* nativeInputChannel =
             android_view_InputChannel_getNativeInputChannel(env, obj);
     if (nativeInputChannel) {
-        android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
+        android_view_InputChannel_setNativeInputChannel(env, obj, nullptr);
         delete nativeInputChannel;
     }
 }
 
 static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
         jobject otherObj) {
-    if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {
+    if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != nullptr) {
         jniThrowException(env, "java/lang/IllegalStateException",
                 "Other object already has a native input channel.");
         return;
@@ -195,12 +196,12 @@
     NativeInputChannel* nativeInputChannel =
             android_view_InputChannel_getNativeInputChannel(env, obj);
     android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
-    android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
+    android_view_InputChannel_setNativeInputChannel(env, obj, nullptr);
 }
 
 static void android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject obj,
         jobject parcelObj) {
-    if (android_view_InputChannel_getNativeInputChannel(env, obj) != NULL) {
+    if (android_view_InputChannel_getNativeInputChannel(env, obj) != nullptr) {
         jniThrowException(env, "java/lang/IllegalStateException",
                 "This object already has a native input channel.");
         return;
@@ -222,25 +223,26 @@
 static void android_view_InputChannel_nativeWriteToParcel(JNIEnv* env, jobject obj,
         jobject parcelObj) {
     Parcel* parcel = parcelForJavaObject(env, parcelObj);
-    if (parcel) {
-        NativeInputChannel* nativeInputChannel =
-                android_view_InputChannel_getNativeInputChannel(env, obj);
-        if (nativeInputChannel) {
-            sp<InputChannel> inputChannel = nativeInputChannel->getInputChannel();
-
-            parcel->writeInt32(1);
-            inputChannel->write(*parcel);
-        } else {
-            parcel->writeInt32(0);
-        }
+    if (parcel == nullptr) {
+        ALOGE("Could not obtain parcel for Java object");
+        return;
     }
+
+    NativeInputChannel* nativeInputChannel =
+            android_view_InputChannel_getNativeInputChannel(env, obj);
+    if (!nativeInputChannel) {
+        parcel->writeInt32(0); // not initialized
+        return;
+    }
+    parcel->writeInt32(1); // initialized
+    nativeInputChannel->getInputChannel()->write(*parcel);
 }
 
 static jstring android_view_InputChannel_nativeGetName(JNIEnv* env, jobject obj) {
     NativeInputChannel* nativeInputChannel =
             android_view_InputChannel_getNativeInputChannel(env, obj);
     if (! nativeInputChannel) {
-        return NULL;
+        return nullptr;
     }
 
     jstring name = env->NewStringUTF(nativeInputChannel->getInputChannel()->getName().c_str());
@@ -250,10 +252,24 @@
 static void android_view_InputChannel_nativeDup(JNIEnv* env, jobject obj, jobject otherObj) {
     NativeInputChannel* nativeInputChannel =
             android_view_InputChannel_getNativeInputChannel(env, obj);
-    if (nativeInputChannel) {
-        android_view_InputChannel_setNativeInputChannel(env, otherObj,
-                new NativeInputChannel(nativeInputChannel->getInputChannel()->dup()));
+    if (nativeInputChannel == nullptr) {
+        jniThrowRuntimeException(env, "InputChannel has no valid NativeInputChannel");
+        return;
     }
+
+    sp<InputChannel> inputChannel = nativeInputChannel->getInputChannel();
+    if (inputChannel == nullptr) {
+        jniThrowRuntimeException(env, "NativeInputChannel has no corresponding InputChannel");
+        return;
+    }
+    sp<InputChannel> dupInputChannel = inputChannel->dup();
+    if (dupInputChannel == nullptr) {
+        std::string message = android::base::StringPrintf(
+                "Could not duplicate input channel %s", inputChannel->getName().c_str());
+        jniThrowRuntimeException(env, message.c_str());
+    }
+    android_view_InputChannel_setNativeInputChannel(env, otherObj,
+            new NativeInputChannel(dupInputChannel));
 }
 
 static jobject android_view_InputChannel_nativeGetToken(JNIEnv* env, jobject obj) {
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 1670d49..a4c504b 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -43,7 +43,6 @@
 
     libs: [
         "android.test.runner",
-        "telephony-common",
         "testables",
         "org.apache.http.legacy",
         "android.test.base",
diff --git a/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
index e1ccd75..8891d3f 100644
--- a/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
@@ -65,8 +65,10 @@
                         null,
                         null,
                         null,
-                        0,
-                        0);
+                        null,
+                        0L,
+                        0L,
+                        0d);
 
         List<LabeledIntent> intents = mLegacyIntentClassificationFactory.create(
                 InstrumentationRegistry.getContext(),
@@ -101,8 +103,10 @@
                         null,
                         null,
                         null,
-                        0,
-                        0);
+                        null,
+                        0L,
+                        0L,
+                        0d);
 
         List<LabeledIntent> intents = mLegacyIntentClassificationFactory.create(
                 InstrumentationRegistry.getContext(),
diff --git a/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
index b9a1a8c..bcea5fe 100644
--- a/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
@@ -83,9 +83,11 @@
                         null,
                         null,
                         null,
+                        null,
                         createRemoteActionTemplates(),
-                        0,
-                        0);
+                        0L,
+                        0L,
+                        0d);
 
         List<LabeledIntent> intents =
                 mTemplateClassificationIntentFactory.create(
@@ -124,9 +126,11 @@
                         null,
                         null,
                         null,
+                        null,
                         createRemoteActionTemplates(),
-                        0,
-                        0);
+                        0L,
+                        0L,
+                        0d);
 
         List<LabeledIntent> intents =
                 mTemplateClassificationIntentFactory.create(
@@ -162,8 +166,10 @@
                         null,
                         null,
                         null,
-                        0,
-                        0);
+                        null,
+                        0L,
+                        0L,
+                        0d);
 
         mTemplateClassificationIntentFactory.create(
                 InstrumentationRegistry.getContext(),
@@ -196,9 +202,11 @@
                         null,
                         null,
                         null,
+                        null,
                         new RemoteActionTemplate[0],
-                        0,
-                        0);
+                        0L,
+                        0L,
+                        0d);
 
         mTemplateClassificationIntentFactory.create(
                 InstrumentationRegistry.getContext(),
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 08f4176..54995ac 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -16,11 +16,12 @@
 
 package android.security;
 
+import android.annotation.UnsupportedAppUsage;
+
 import com.android.org.bouncycastle.util.io.pem.PemObject;
 import com.android.org.bouncycastle.util.io.pem.PemReader;
 import com.android.org.bouncycastle.util.io.pem.PemWriter;
 
-import android.annotation.UnsupportedAppUsage;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -90,9 +91,9 @@
     public static final String EXTRA_INSTALL_AS_UID = "install_as_uid";
 
     /**
-     * Intent extra: name for the user's private key.
+     * Intent extra: name for the user's key pair.
      */
-    public static final String EXTRA_USER_PRIVATE_KEY_NAME = "user_private_key_name";
+    public static final String EXTRA_USER_KEY_ALIAS = "user_key_pair_name";
 
     /**
      * Intent extra: data for the user's private key in PEM-encoded PKCS#8.
@@ -100,21 +101,11 @@
     public static final String EXTRA_USER_PRIVATE_KEY_DATA = "user_private_key_data";
 
     /**
-     * Intent extra: name for the user's certificate.
-     */
-    public static final String EXTRA_USER_CERTIFICATE_NAME = "user_certificate_name";
-
-    /**
      * Intent extra: data for the user's certificate in PEM-encoded X.509.
      */
     public static final String EXTRA_USER_CERTIFICATE_DATA = "user_certificate_data";
 
     /**
-     * Intent extra: name for CA certificate chain
-     */
-    public static final String EXTRA_CA_CERTIFICATES_NAME = "ca_certificates_name";
-
-    /**
      * Intent extra: data for CA certificate chain in PEM-encoded X.509.
      */
     public static final String EXTRA_CA_CERTIFICATES_DATA = "ca_certificates_data";
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index b3cdff7..97da3cc 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -43,7 +43,8 @@
     String installCaCertificate(in byte[] caCertificate);
 
     // APIs used by DevicePolicyManager
-    boolean installKeyPair(in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias);
+    boolean installKeyPair(
+        in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias, int uid);
     boolean removeKeyPair(String alias);
 
     // APIs used by Settings
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 55583d5..5b53565 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -62,6 +62,7 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.TimeZone;
@@ -1451,6 +1452,37 @@
     }
 
     /**
+     * Returns whether ExifInterface currently supports parsing data from the specified mime type
+     * or not.
+     *
+     * @param mimeType the string value of mime type
+     */
+    public static boolean isSupportedMimeType(@NonNull String mimeType) {
+        if (mimeType == null) {
+            throw new NullPointerException("mimeType shouldn't be null");
+        }
+
+        switch (mimeType.toLowerCase(Locale.ROOT)) {
+            case "image/jpeg":
+            case "image/x-adobe-dng":
+            case "image/x-canon-cr2":
+            case "image/x-nikon-nef":
+            case "image/x-nikon-nrw":
+            case "image/x-sony-arw":
+            case "image/x-panasonic-rw2":
+            case "image/x-olympus-orf":
+            case "image/x-pentax-pef":
+            case "image/x-samsung-srw":
+            case "image/x-fuji-raf":
+            case "image/heic":
+            case "image/heif":
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
      * Returns the EXIF attribute of the specified tag or {@code null} if there is no such tag in
      * the image file.
      *
diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp
index 8c38d88..9705b91 100644
--- a/media/jni/android_media_MediaDataSource.cpp
+++ b/media/jni/android_media_MediaDataSource.cpp
@@ -106,7 +106,8 @@
     }
 
     ALOGV("readAt %lld / %zu => %d.", (long long)offset, size, numread);
-    env->GetByteArrayRegion(mByteArrayObj, 0, numread, (jbyte*)mMemory->pointer());
+    env->GetByteArrayRegion(mByteArrayObj, 0, numread,
+        (jbyte*)mMemory->unsecurePointer());
     return numread;
 }
 
diff --git a/media/jni/android_media_MediaDescrambler.cpp b/media/jni/android_media_MediaDescrambler.cpp
index aa79ce0..c61365a 100644
--- a/media/jni/android_media_MediaDescrambler.cpp
+++ b/media/jni/android_media_MediaDescrambler.cpp
@@ -220,7 +220,7 @@
         return NO_MEMORY;
     }
 
-    memcpy(mMem->pointer(),
+    memcpy(mMem->unsecurePointer(),
             (const void*)((const uint8_t*)srcPtr + srcOffset), totalLength);
 
     DestinationBuffer dstBuffer;
@@ -248,7 +248,8 @@
 
     if (*status == Status::OK) {
         if (*bytesWritten > 0 && (ssize_t) *bytesWritten <= totalLength) {
-            memcpy((void*)((uint8_t*)dstPtr + dstOffset), mMem->pointer(), *bytesWritten);
+            memcpy((void*)((uint8_t*)dstPtr + dstOffset), mMem->unsecurePointer(),
+                *bytesWritten);
         } else {
             // status seems OK but bytesWritten is invalid, we really
             // have no idea what is wrong.
diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp
index 365e045..53adff3 100644
--- a/media/jni/android_media_MediaHTTPConnection.cpp
+++ b/media/jni/android_media_MediaHTTPConnection.cpp
@@ -148,7 +148,7 @@
                 byteArrayObj,
                 0,
                 n,
-                (jbyte *)conn->getIMemory()->pointer());
+                (jbyte *)conn->getIMemory()->unsecurePointer());
     }
 
     return n;
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 3809bc4..18fd1a0 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -396,8 +396,12 @@
     // Call native method to retrieve a video frame
     VideoFrame *videoFrame = NULL;
     sp<IMemory> frameMemory = retriever->getFrameAtTime(timeUs, option);
+    // TODO: Using unsecurePointer() has some associated security pitfalls
+    //       (see declaration for details).
+    //       Either document why it is safe in this case or address the
+    //       issue (e.g. by copying).
     if (frameMemory != 0) {  // cast the shared structure to a VideoFrame object
-        videoFrame = static_cast<VideoFrame *>(frameMemory->pointer());
+        videoFrame = static_cast<VideoFrame *>(frameMemory->unsecurePointer());
     }
     if (videoFrame == NULL) {
         ALOGE("getFrameAtTime: videoFrame is a NULL pointer");
@@ -423,7 +427,11 @@
     VideoFrame *videoFrame = NULL;
     sp<IMemory> frameMemory = retriever->getImageAtIndex(index, colorFormat);
     if (frameMemory != 0) {  // cast the shared structure to a VideoFrame object
-        videoFrame = static_cast<VideoFrame *>(frameMemory->pointer());
+        // TODO: Using unsecurePointer() has some associated security pitfalls
+        //       (see declaration for details).
+        //       Either document why it is safe in this case or address the
+        //       issue (e.g. by copying).
+        videoFrame = static_cast<VideoFrame *>(frameMemory->unsecurePointer());
     }
     if (videoFrame == NULL) {
         ALOGE("getImageAtIndex: videoFrame is a NULL pointer");
@@ -454,7 +462,11 @@
     sp<IMemory> frameMemory = retriever->getImageAtIndex(
             index, colorFormat, true /*metaOnly*/, true /*thumbnail*/);
     if (frameMemory != 0) {
-        videoFrame = static_cast<VideoFrame *>(frameMemory->pointer());
+        // TODO: Using unsecurePointer() has some associated security pitfalls
+        //       (see declaration for details).
+        //       Either document why it is safe in this case or address the
+        //       issue (e.g. by copying).
+        videoFrame = static_cast<VideoFrame *>(frameMemory->unsecurePointer());
         int32_t thumbWidth = videoFrame->mWidth;
         int32_t thumbHeight = videoFrame->mHeight;
         videoFrame = NULL;
@@ -467,7 +479,11 @@
                 || thumbPixels * 6 >= maxPixels) {
             frameMemory = retriever->getImageAtIndex(
                     index, colorFormat, false /*metaOnly*/, true /*thumbnail*/);
-            videoFrame = static_cast<VideoFrame *>(frameMemory->pointer());
+            // TODO: Using unsecurePointer() has some associated security pitfalls
+            //       (see declaration for details).
+            //       Either document why it is safe in this case or address the
+            //       issue (e.g. by copying).
+            videoFrame = static_cast<VideoFrame *>(frameMemory->unsecurePointer());
 
             if (thumbPixels > maxPixels) {
                 int downscale = ceil(sqrt(thumbPixels / (float)maxPixels));
@@ -514,11 +530,15 @@
     size_t i = 0;
     for (; i < numFrames; i++) {
         sp<IMemory> frame = retriever->getFrameAtIndex(frameIndex + i, colorFormat);
-        if (frame == NULL || frame->pointer() == NULL) {
+        if (frame == NULL || frame->unsecurePointer() == NULL) {
             ALOGE("video frame at index %zu is a NULL pointer", frameIndex + i);
             break;
         }
-        VideoFrame *videoFrame = static_cast<VideoFrame *>(frame->pointer());
+        // TODO: Using unsecurePointer() has some associated security pitfalls
+        //       (see declaration for details).
+        //       Either document why it is safe in this case or address the
+        //       issue (e.g. by copying).
+        VideoFrame *videoFrame = static_cast<VideoFrame *>(frame->unsecurePointer());
         jobject bitmapObj = getBitmapFromVideoFrame(env, videoFrame, -1, -1, outColorType);
         env->CallBooleanMethod(arrayList, fields.arrayListAdd, bitmapObj);
         env->DeleteLocalRef(bitmapObj);
@@ -551,7 +571,11 @@
     // the method name to getEmbeddedPicture().
     sp<IMemory> albumArtMemory = retriever->extractAlbumArt();
     if (albumArtMemory != 0) {  // cast the shared structure to a MediaAlbumArt object
-        mediaAlbumArt = static_cast<MediaAlbumArt *>(albumArtMemory->pointer());
+        // TODO: Using unsecurePointer() has some associated security pitfalls
+        //       (see declaration for details).
+        //       Either document why it is safe in this case or address the
+        //       issue (e.g. by copying).
+        mediaAlbumArt = static_cast<MediaAlbumArt *>(albumArtMemory->unsecurePointer());
     }
     if (mediaAlbumArt == NULL) {
         ALOGE("getEmbeddedPicture: Call to getEmbeddedPicture failed.");
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
index 9d74103..01e4faa 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -61,7 +61,7 @@
     audio_channel_mask_t channelMask() { return mChannelMask; }
     size_t size() { return mSize; }
     int state() { return mState; }
-    uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); }
+    uint8_t* data() { return static_cast<uint8_t*>(mData->unsecurePointer()); }
     status_t doLoad();
     void startLoad() { mState = LOADING; }
     sp<IMemory> getIMemory() { return mData; }
diff --git a/media/tests/audiotests/shared_mem_test.cpp b/media/tests/audiotests/shared_mem_test.cpp
index 2f57499..d586b6a 100644
--- a/media/tests/audiotests/shared_mem_test.cpp
+++ b/media/tests/audiotests/shared_mem_test.cpp
@@ -92,7 +92,7 @@
 
         iMem = heap->allocate(BUF_SZ*sizeof(short));
 
-        p = static_cast<uint8_t*>(iMem->pointer());
+        p = static_cast<uint8_t*>(iMem->unsecurePointer());
         memcpy(p, smpBuf, BUF_SZ*sizeof(short));
 
         sp<AudioTrack> track = new AudioTrack(AUDIO_STREAM_MUSIC,// stream type
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/CryptoSettings.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/CryptoSettings.java
index 2010620..033f1b1 100644
--- a/packages/BackupEncryption/src/com/android/server/backup/encryption/CryptoSettings.java
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/CryptoSettings.java
@@ -30,6 +30,7 @@
 
 import java.security.KeyStoreException;
 import java.util.Optional;
+import java.util.concurrent.TimeUnit;
 
 /**
  * State about encrypted backups that needs to be remembered.
@@ -51,6 +52,9 @@
         SECONDARY_KEY_LAST_ROTATED_AT
     };
 
+    private static final long DEFAULT_SECONDARY_KEY_ROTATION_PERIOD =
+            TimeUnit.MILLISECONDS.convert(31, TimeUnit.DAYS);
+
     private static final String KEY_ANCESTRAL_SECONDARY_KEY_VERSION =
             "ancestral_secondary_key_version";
 
@@ -202,6 +206,11 @@
                 .apply();
     }
 
+    /** The number of milliseconds between secondary key rotation */
+    public long backupSecondaryKeyRotationIntervalMs() {
+        return DEFAULT_SECONDARY_KEY_ROTATION_PERIOD;
+    }
+
     /** Deletes all crypto settings related to backup (as opposed to restore). */
     public void clearAllSettingsForBackup() {
         Editor sharedPrefsEditor = mSharedPreferences.edit();
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/keys/SecondaryKeyRotationScheduler.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/keys/SecondaryKeyRotationScheduler.java
new file mode 100644
index 0000000..91b57cf
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/keys/SecondaryKeyRotationScheduler.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.keys;
+
+import android.content.Context;
+import android.util.Slog;
+
+import com.android.server.backup.encryption.CryptoSettings;
+import com.android.server.backup.encryption.tasks.StartSecondaryKeyRotationTask;
+
+import java.io.File;
+import java.time.Clock;
+import java.util.Optional;
+
+/**
+ * Helps schedule rotations of secondary keys.
+ *
+ * <p>TODO(b/72028016) Replace with a job.
+ */
+public class SecondaryKeyRotationScheduler {
+
+    private static final String TAG = "SecondaryKeyRotationScheduler";
+    private static final String SENTINEL_FILE_PATH = "force_secondary_key_rotation";
+
+    private final Context mContext;
+    private final RecoverableKeyStoreSecondaryKeyManager mSecondaryKeyManager;
+    private final CryptoSettings mCryptoSettings;
+    private final Clock mClock;
+
+    public SecondaryKeyRotationScheduler(
+            Context context,
+            RecoverableKeyStoreSecondaryKeyManager secondaryKeyManager,
+            CryptoSettings cryptoSettings,
+            Clock clock) {
+        mContext = context;
+        mCryptoSettings = cryptoSettings;
+        mClock = clock;
+        mSecondaryKeyManager = secondaryKeyManager;
+    }
+
+    /**
+     * Returns {@code true} if a sentinel file for forcing secondary key rotation is present. This
+     * is only for testing purposes.
+     */
+    private boolean isForceRotationTestSentinelPresent() {
+        File file = new File(mContext.getFilesDir(), SENTINEL_FILE_PATH);
+        if (file.exists()) {
+            file.delete();
+            return true;
+        }
+        return false;
+    }
+
+    /** Start the key rotation task if it's time to do so */
+    public void startRotationIfScheduled() {
+        if (isForceRotationTestSentinelPresent()) {
+            Slog.i(TAG, "Found force flag for secondary rotation. Starting now.");
+            startRotation();
+            return;
+        }
+
+        Optional<Long> maybeLastRotated = mCryptoSettings.getSecondaryLastRotated();
+        if (!maybeLastRotated.isPresent()) {
+            Slog.v(TAG, "No previous rotation, scheduling from now.");
+            scheduleRotationFromNow();
+            return;
+        }
+
+        long lastRotated = maybeLastRotated.get();
+        long now = mClock.millis();
+
+        if (lastRotated > now) {
+            Slog.i(TAG, "Last rotation was in the future. Clock must have changed. Rotate now.");
+            startRotation();
+            return;
+        }
+
+        long millisSinceLastRotation = now - lastRotated;
+        long rotationInterval = mCryptoSettings.backupSecondaryKeyRotationIntervalMs();
+        if (millisSinceLastRotation >= rotationInterval) {
+            Slog.i(
+                    TAG,
+                    "Last rotation was more than "
+                            + rotationInterval
+                            + "ms ("
+                            + millisSinceLastRotation
+                            + "ms) in the past. Rotate now.");
+            startRotation();
+        }
+
+        Slog.v(TAG, "No rotation required, last " + lastRotated + ".");
+    }
+
+    private void startRotation() {
+        scheduleRotationFromNow();
+        new StartSecondaryKeyRotationTask(mCryptoSettings, mSecondaryKeyManager).run();
+    }
+
+    private void scheduleRotationFromNow() {
+        mCryptoSettings.setSecondaryLastRotated(mClock.millis());
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/StartSecondaryKeyRotationTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/StartSecondaryKeyRotationTask.java
new file mode 100644
index 0000000..77cfded
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/StartSecondaryKeyRotationTask.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.tasks;
+
+import android.security.keystore.recovery.InternalRecoveryServiceException;
+import android.security.keystore.recovery.LockScreenRequiredException;
+import android.util.Slog;
+
+import com.android.internal.util.Preconditions;
+import com.android.server.backup.encryption.CryptoSettings;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager;
+
+import java.security.UnrecoverableKeyException;
+import java.util.Optional;
+
+/**
+ * Starts rotating to a new secondary key. Cannot complete until the screen is unlocked and the new
+ * key is synced.
+ */
+public class StartSecondaryKeyRotationTask {
+    private static final String TAG = "BE-StSecondaryKeyRotTsk";
+
+    private final CryptoSettings mCryptoSettings;
+    private final RecoverableKeyStoreSecondaryKeyManager mSecondaryKeyManager;
+
+    public StartSecondaryKeyRotationTask(
+            CryptoSettings cryptoSettings,
+            RecoverableKeyStoreSecondaryKeyManager secondaryKeyManager) {
+        mCryptoSettings = Preconditions.checkNotNull(cryptoSettings);
+        mSecondaryKeyManager = Preconditions.checkNotNull(secondaryKeyManager);
+    }
+
+    /** Begin the key rotation */
+    public void run() {
+        Slog.i(TAG, "Attempting to initiate a secondary key rotation.");
+
+        Optional<String> maybeCurrentAlias = mCryptoSettings.getActiveSecondaryKeyAlias();
+        if (!maybeCurrentAlias.isPresent()) {
+            Slog.w(TAG, "No active current alias. Cannot trigger a secondary rotation.");
+            return;
+        }
+        String currentAlias = maybeCurrentAlias.get();
+
+        Optional<String> maybeNextAlias = mCryptoSettings.getNextSecondaryKeyAlias();
+        if (maybeNextAlias.isPresent()) {
+            String nextAlias = maybeNextAlias.get();
+            if (nextAlias.equals(currentAlias)) {
+                // Shouldn't be possible, but guard against accidentally deleting the active key.
+                Slog.e(TAG, "Was already trying to rotate to what is already the active key.");
+            } else {
+                Slog.w(TAG, "Was already rotating to another key. Cancelling that.");
+                try {
+                    mSecondaryKeyManager.remove(nextAlias);
+                } catch (Exception e) {
+                    Slog.wtf(TAG, "Could not remove old key", e);
+                }
+            }
+            mCryptoSettings.removeNextSecondaryKeyAlias();
+        }
+
+        RecoverableKeyStoreSecondaryKey newSecondaryKey;
+        try {
+            newSecondaryKey = mSecondaryKeyManager.generate();
+        } catch (LockScreenRequiredException e) {
+            Slog.e(TAG, "No lock screen is set - cannot generate a new key to rotate to.", e);
+            return;
+        } catch (InternalRecoveryServiceException e) {
+            Slog.e(TAG, "Internal error in Recovery Controller, failed to rotate key.", e);
+            return;
+        } catch (UnrecoverableKeyException e) {
+            Slog.e(TAG, "Failed to get key after generating, failed to rotate", e);
+            return;
+        }
+
+        String alias = newSecondaryKey.getAlias();
+        Slog.i(TAG, "Generated a new secondary key with alias '" + alias + "'.");
+        try {
+            mCryptoSettings.setNextSecondaryAlias(alias);
+            Slog.i(TAG, "Successfully set '" + alias + "' as next key to rotate to");
+        } catch (IllegalArgumentException e) {
+            Slog.e(TAG, "Unexpected error setting next alias", e);
+            try {
+                mSecondaryKeyManager.remove(alias);
+            } catch (Exception err) {
+                Slog.wtf(TAG, "Failed to remove generated key after encountering error", err);
+            }
+        }
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/keys/SecondaryKeyRotationSchedulerTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/keys/SecondaryKeyRotationSchedulerTest.java
new file mode 100644
index 0000000..c31d19d
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/keys/SecondaryKeyRotationSchedulerTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.keys;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.server.backup.encryption.CryptoSettings;
+import com.android.server.backup.encryption.tasks.StartSecondaryKeyRotationTask;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+import java.io.File;
+import java.time.Clock;
+
+@Config(shadows = SecondaryKeyRotationSchedulerTest.ShadowStartSecondaryKeyRotationTask.class)
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class SecondaryKeyRotationSchedulerTest {
+    private static final String SENTINEL_FILE_PATH = "force_secondary_key_rotation";
+
+    @Mock private RecoverableKeyStoreSecondaryKeyManager mSecondaryKeyManager;
+    @Mock private Clock mClock;
+
+    private CryptoSettings mCryptoSettings;
+    private SecondaryKeyRotationScheduler mScheduler;
+    private long mRotationIntervalMillis;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        Context application = ApplicationProvider.getApplicationContext();
+
+        mCryptoSettings = CryptoSettings.getInstanceForTesting(application);
+        mRotationIntervalMillis = mCryptoSettings.backupSecondaryKeyRotationIntervalMs();
+
+        mScheduler =
+                new SecondaryKeyRotationScheduler(
+                        application, mSecondaryKeyManager, mCryptoSettings, mClock);
+        ShadowStartSecondaryKeyRotationTask.reset();
+    }
+
+    @Test
+    public void startRotationIfScheduled_rotatesIfRotationWasFarEnoughInThePast() {
+        long lastRotated = 100009;
+        mCryptoSettings.setSecondaryLastRotated(lastRotated);
+        setNow(lastRotated + mRotationIntervalMillis);
+
+        mScheduler.startRotationIfScheduled();
+
+        assertThat(ShadowStartSecondaryKeyRotationTask.sRan).isTrue();
+    }
+
+    @Test
+    public void startRotationIfScheduled_setsNewRotationTimeIfRotationWasFarEnoughInThePast() {
+        long lastRotated = 100009;
+        long now = lastRotated + mRotationIntervalMillis;
+        mCryptoSettings.setSecondaryLastRotated(lastRotated);
+        setNow(now);
+
+        mScheduler.startRotationIfScheduled();
+
+        assertThat(mCryptoSettings.getSecondaryLastRotated().get()).isEqualTo(now);
+    }
+
+    @Test
+    public void startRotationIfScheduled_rotatesIfClockHasChanged() {
+        long lastRotated = 100009;
+        mCryptoSettings.setSecondaryLastRotated(lastRotated);
+        setNow(lastRotated - 1);
+
+        mScheduler.startRotationIfScheduled();
+
+        assertThat(ShadowStartSecondaryKeyRotationTask.sRan).isTrue();
+    }
+
+    @Test
+    public void startRotationIfScheduled_rotatesIfSentinelFileIsPresent() throws Exception {
+        File file = new File(RuntimeEnvironment.application.getFilesDir(), SENTINEL_FILE_PATH);
+        file.createNewFile();
+
+        mScheduler.startRotationIfScheduled();
+
+        assertThat(ShadowStartSecondaryKeyRotationTask.sRan).isTrue();
+    }
+
+    @Test
+    public void startRotationIfScheduled_setsNextRotationIfClockHasChanged() {
+        long lastRotated = 100009;
+        long now = lastRotated - 1;
+        mCryptoSettings.setSecondaryLastRotated(lastRotated);
+        setNow(now);
+
+        mScheduler.startRotationIfScheduled();
+
+        assertThat(mCryptoSettings.getSecondaryLastRotated().get()).isEqualTo(now);
+    }
+
+    @Test
+    public void startRotationIfScheduled_doesNothingIfRotationWasRecentEnough() {
+        long lastRotated = 100009;
+        mCryptoSettings.setSecondaryLastRotated(lastRotated);
+        setNow(lastRotated + mRotationIntervalMillis - 1);
+
+        mScheduler.startRotationIfScheduled();
+
+        assertThat(ShadowStartSecondaryKeyRotationTask.sRan).isFalse();
+    }
+
+    @Test
+    public void startRotationIfScheduled_doesNotSetRotationTimeIfRotationWasRecentEnough() {
+        long lastRotated = 100009;
+        mCryptoSettings.setSecondaryLastRotated(lastRotated);
+        setNow(lastRotated + mRotationIntervalMillis - 1);
+
+        mScheduler.startRotationIfScheduled();
+
+        assertThat(mCryptoSettings.getSecondaryLastRotated().get()).isEqualTo(lastRotated);
+    }
+
+    @Test
+    public void startRotationIfScheduled_setsLastRotatedToNowIfNeverRotated() {
+        long now = 13295436;
+        setNow(now);
+
+        mScheduler.startRotationIfScheduled();
+
+        assertThat(mCryptoSettings.getSecondaryLastRotated().get()).isEqualTo(now);
+    }
+
+    private void setNow(long timestamp) {
+        when(mClock.millis()).thenReturn(timestamp);
+    }
+
+    @Implements(StartSecondaryKeyRotationTask.class)
+    public static class ShadowStartSecondaryKeyRotationTask {
+        private static boolean sRan = false;
+
+        @Implementation
+        public void run() {
+            sRan = true;
+        }
+
+        @Resetter
+        public static void reset() {
+            sRan = false;
+        }
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/StartSecondaryKeyRotationTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/StartSecondaryKeyRotationTaskTest.java
new file mode 100644
index 0000000..4ac4fa8
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/StartSecondaryKeyRotationTaskTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.tasks;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+import android.security.keystore.recovery.RecoveryController;
+
+import com.android.server.backup.encryption.CryptoSettings;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager;
+import com.android.server.testing.shadows.ShadowRecoveryController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.security.SecureRandom;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowRecoveryController.class})
+@Presubmit
+public class StartSecondaryKeyRotationTaskTest {
+
+    private CryptoSettings mCryptoSettings;
+    private RecoverableKeyStoreSecondaryKeyManager mSecondaryKeyManager;
+    private StartSecondaryKeyRotationTask mStartSecondaryKeyRotationTask;
+
+    @Before
+    public void setUp() throws Exception {
+        mSecondaryKeyManager =
+                new RecoverableKeyStoreSecondaryKeyManager(
+                        RecoveryController.getInstance(RuntimeEnvironment.application),
+                        new SecureRandom());
+        mCryptoSettings = CryptoSettings.getInstanceForTesting(RuntimeEnvironment.application);
+        mStartSecondaryKeyRotationTask =
+                new StartSecondaryKeyRotationTask(mCryptoSettings, mSecondaryKeyManager);
+
+        ShadowRecoveryController.reset();
+    }
+
+    @Test
+    public void run_doesNothingIfNoActiveSecondaryExists() {
+        mStartSecondaryKeyRotationTask.run();
+
+        assertThat(mCryptoSettings.getNextSecondaryKeyAlias().isPresent()).isFalse();
+    }
+
+    @Test
+    public void run_doesNotRemoveExistingNextSecondaryKeyIfItIsAlreadyActive() throws Exception {
+        generateAnActiveKey();
+        String activeAlias = mCryptoSettings.getActiveSecondaryKeyAlias().get();
+        mCryptoSettings.setNextSecondaryAlias(activeAlias);
+
+        mStartSecondaryKeyRotationTask.run();
+
+        assertThat(mSecondaryKeyManager.get(activeAlias).isPresent()).isTrue();
+    }
+
+    @Test
+    public void run_doesRemoveExistingNextSecondaryKeyIfItIsNotYetActive() throws Exception {
+        generateAnActiveKey();
+        RecoverableKeyStoreSecondaryKey nextKey = mSecondaryKeyManager.generate();
+        String nextAlias = nextKey.getAlias();
+        mCryptoSettings.setNextSecondaryAlias(nextAlias);
+
+        mStartSecondaryKeyRotationTask.run();
+
+        assertThat(mSecondaryKeyManager.get(nextAlias).isPresent()).isFalse();
+    }
+
+    @Test
+    public void run_generatesANewNextSecondaryKey() throws Exception {
+        generateAnActiveKey();
+
+        mStartSecondaryKeyRotationTask.run();
+
+        assertThat(mCryptoSettings.getNextSecondaryKeyAlias().isPresent()).isTrue();
+    }
+
+    @Test
+    public void run_generatesANewKeyThatExistsInKeyStore() throws Exception {
+        generateAnActiveKey();
+
+        mStartSecondaryKeyRotationTask.run();
+
+        String nextAlias = mCryptoSettings.getNextSecondaryKeyAlias().get();
+        assertThat(mSecondaryKeyManager.get(nextAlias).isPresent()).isTrue();
+    }
+
+    private void generateAnActiveKey() throws Exception {
+        RecoverableKeyStoreSecondaryKey secondaryKey = mSecondaryKeyManager.generate();
+        mCryptoSettings.setActiveSecondaryKeyAlias(secondaryKey.getAlias());
+    }
+}
diff --git a/packages/CarrierDefaultApp/tests/unit/Android.bp b/packages/CarrierDefaultApp/tests/unit/Android.bp
index 96144cf..5655abb 100644
--- a/packages/CarrierDefaultApp/tests/unit/Android.bp
+++ b/packages/CarrierDefaultApp/tests/unit/Android.bp
@@ -17,7 +17,6 @@
     certificate: "platform",
     libs: [
         "android.test.runner",
-        "telephony-common",
         "android.test.base",
     ],
     static_libs: [
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 32fc7ff..720266a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1521,14 +1521,14 @@
             return false;
         }
 
-        // Special cases for location providers (sigh).
-        if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
-            return updateLocationProvidersAllowedLocked(value, tag, owningUserId, makeDefault,
-                    forceNotify);
-        }
-
         // Mutate the value.
         synchronized (mLock) {
+            // Special cases for location providers (sigh).
+            if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
+                return updateLocationProvidersAllowedLocked(value, tag, owningUserId, makeDefault,
+                        forceNotify);
+            }
+
             switch (operation) {
                 case MUTATION_OPERATION_INSERT: {
                     return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SECURE,
diff --git a/packages/SystemUI/res/drawable/biometric_dialog_bg.xml b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
deleted file mode 100644
index 0c6d57d..0000000
--- a/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
-  ~ Copyright (C) 2018 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="?android:attr/colorBackgroundFloating" />
-    <corners
-        android:topLeftRadius="@dimen/biometric_dialog_corner_size"
-        android:topRightRadius="@dimen/biometric_dialog_corner_size"
-        android:bottomLeftRadius="@dimen/biometric_dialog_corner_size"
-        android:bottomRightRadius="@dimen/biometric_dialog_corner_size"/>
-</shape>
diff --git a/packages/SystemUI/res/layout/biometric_dialog.xml b/packages/SystemUI/res/layout/biometric_dialog.xml
deleted file mode 100644
index e687cdf..0000000
--- a/packages/SystemUI/res/layout/biometric_dialog.xml
+++ /dev/null
@@ -1,190 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2018 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/layout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <ImageView
-        android:id="@+id/background"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:scaleType="center" />
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:gravity="bottom"
-        android:background="@color/biometric_dialog_dim_color"
-        android:orientation="vertical">
-
-        <!-- This is not a Space since Spaces cannot be clicked -->
-        <View
-            android:id="@+id/space"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_weight="1"
-            android:contentDescription="@string/biometric_dialog_empty_space_description"/>
-
-        <ScrollView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-
-            <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal">
-
-                <!-- This is not a Space since Spaces cannot be clicked. The width of this changes
-                depending on horizontal/portrait orientation -->
-                <View
-                    android:id="@+id/left_space"
-                    android:layout_weight="1"
-                    android:layout_width="0dp"
-                    android:layout_height="match_parent"
-                    android:contentDescription="@string/biometric_dialog_empty_space_description"/>
-
-                    <LinearLayout
-                        android:id="@+id/dialog"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:orientation="vertical"
-                        android:background="@drawable/biometric_dialog_bg"
-                        android:layout_marginBottom="@dimen/biometric_dialog_border_padding"
-                        android:layout_marginLeft="@dimen/biometric_dialog_border_padding"
-                        android:layout_marginRight="@dimen/biometric_dialog_border_padding">
-
-                        <TextView
-                            android:id="@+id/title"
-                            android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
-                            android:layout_width="match_parent"
-                            android:layout_height="wrap_content"
-                            android:layout_marginEnd="24dp"
-                            android:layout_marginStart="24dp"
-                            android:layout_marginTop="24dp"
-                            android:gravity="@integer/biometric_dialog_text_gravity"
-                            android:textSize="20sp"
-                            android:textColor="?android:attr/textColorPrimary"/>
-
-                        <TextView
-                            android:id="@+id/subtitle"
-                            android:layout_width="match_parent"
-                            android:layout_height="wrap_content"
-                            android:layout_marginTop="8dp"
-                            android:layout_marginStart="24dp"
-                            android:layout_marginEnd="24dp"
-                            android:gravity="@integer/biometric_dialog_text_gravity"
-                            android:textSize="16sp"
-                            android:textColor="?android:attr/textColorPrimary"/>
-
-                        <TextView
-                            android:id="@+id/description"
-                            android:layout_width="match_parent"
-                            android:layout_height="wrap_content"
-                            android:layout_marginEnd="24dp"
-                            android:layout_marginStart="24dp"
-                            android:gravity="@integer/biometric_dialog_text_gravity"
-                            android:paddingTop="8dp"
-                            android:textSize="16sp"
-                            android:textColor="?android:attr/textColorPrimary"/>
-
-                        <ImageView
-                            android:id="@+id/biometric_icon"
-                            android:layout_width="@dimen/biometric_dialog_biometric_icon_size"
-                            android:layout_height="@dimen/biometric_dialog_biometric_icon_size"
-                            android:layout_gravity="center_horizontal"
-                            android:layout_marginTop="48dp"
-                            android:scaleType="fitXY" />
-
-                        <TextView
-                            android:id="@+id/error"
-                            android:layout_width="match_parent"
-                            android:layout_height="wrap_content"
-                            android:layout_marginEnd="24dp"
-                            android:layout_marginStart="24dp"
-                            android:paddingTop="16dp"
-                            android:paddingBottom="24dp"
-                            android:textSize="12sp"
-                            android:gravity="center_horizontal"
-                            android:accessibilityLiveRegion="polite"
-                            android:textColor="@color/biometric_dialog_gray"/>
-
-                        <LinearLayout
-                            android:layout_width="match_parent"
-                            android:layout_height="72dip"
-                            android:paddingTop="24dp"
-                            android:layout_gravity="center_vertical"
-                            style="?android:attr/buttonBarStyle"
-                            android:orientation="horizontal"
-                            android:measureWithLargestChild="true">
-                            <Space android:id="@+id/leftSpacer"
-                                android:layout_width="12dp"
-                                android:layout_height="match_parent"
-                                android:visibility="visible" />
-                            <!-- Negative Button -->
-                            <Button android:id="@+id/button2"
-                                android:layout_width="wrap_content"
-                                android:layout_height="match_parent"
-                                style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
-                                android:gravity="center"
-                                android:maxLines="2" />
-                            <Space android:id="@+id/middleSpacer"
-                                android:layout_width="0dp"
-                                android:layout_height="match_parent"
-                                android:layout_weight="1"
-                                android:visibility="visible" />
-                            <!-- Positive Button -->
-                            <Button android:id="@+id/button1"
-                                android:layout_width="wrap_content"
-                                android:layout_height="match_parent"
-                                style="@*android:style/Widget.DeviceDefault.Button.Colored"
-                                android:gravity="center"
-                                android:maxLines="2"
-                                android:text="@string/biometric_dialog_confirm"
-                                android:visibility="gone"/>
-                            <!-- Try Again Button -->
-                            <Button android:id="@+id/button_try_again"
-                                android:layout_width="wrap_content"
-                                android:layout_height="match_parent"
-                                style="@*android:style/Widget.DeviceDefault.Button.Colored"
-                                android:gravity="center"
-                                android:maxLines="2"
-                                android:text="@string/biometric_dialog_try_again"
-                                android:visibility="gone"/>
-                            <Space android:id="@+id/rightSpacer"
-                                android:layout_width="12dip"
-                                android:layout_height="match_parent"
-                                android:visibility="visible" />
-                        </LinearLayout>
-                    </LinearLayout>
-
-                <!-- This is not a Space since Spaces cannot be clicked. The width of this changes
-                depending on horizontal/portrait orientation -->
-                <View
-                    android:id="@+id/right_space"
-                    android:layout_weight="1"
-                    android:layout_width="0dp"
-                    android:layout_height="match_parent"
-                    android:contentDescription="@string/biometric_dialog_empty_space_description"/>
-
-            </LinearLayout>
-
-        </ScrollView>
-
-    </LinearLayout>
-
-</FrameLayout>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 38293bf..61210d3 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -480,4 +480,7 @@
     <!-- Preferred refresh rate at keyguard, if supported by the display -->
     <integer name="config_keyguardRefreshRate">-1</integer>
 
+    <!-- Whether or not to add a "people" notifications section -->
+    <bool name="config_usePeopleFiltering">false</bool>
+
 </resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java
index 2797042..3ae2df5b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java
@@ -16,10 +16,9 @@
 
 package com.android.systemui.shared.system;
 
-import android.content.ComponentName;
 import android.content.pm.ParceledListSlice;
 import android.graphics.Rect;
-import android.view.DisplayInfo;
+import android.os.RemoteException;
 import android.view.IPinnedStackController;
 import android.view.IPinnedStackListener;
 
@@ -33,132 +32,62 @@
  * previously set listener.
  */
 public class PinnedStackListenerForwarder extends IPinnedStackListener.Stub {
-    private List<PinnedStackListener> mListeners = new ArrayList<>();
+    private List<IPinnedStackListener> mListeners = new ArrayList<>();
 
     /** Adds a listener to receive updates from the WindowManagerService. */
-    public void addListener(PinnedStackListener listener) {
+    public void addListener(IPinnedStackListener listener) {
         mListeners.add(listener);
     }
 
     /** Removes a listener so it will no longer receive updates from the WindowManagerService. */
-    public void removeListener(PinnedStackListener listener) {
+    public void removeListener(IPinnedStackListener listener) {
         mListeners.remove(listener);
     }
 
     @Override
-    public void onListenerRegistered(IPinnedStackController controller) {
-        for (PinnedStackListener listener : mListeners) {
+    public void onListenerRegistered(IPinnedStackController controller) throws RemoteException {
+        for (IPinnedStackListener listener : mListeners) {
             listener.onListenerRegistered(controller);
         }
     }
 
     @Override
-    public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment,
-            boolean fromShelfAdjustment) {
-        for (PinnedStackListener listener : mListeners) {
-            listener.onMovementBoundsChanged(animatingBounds, fromImeAdjustment,
-                    fromShelfAdjustment);
+    public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, Rect animatingBounds,
+            boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation)
+            throws RemoteException {
+        for (IPinnedStackListener listener : mListeners) {
+            listener.onMovementBoundsChanged(
+                    insetBounds, normalBounds, animatingBounds,
+                    fromImeAdjustment, fromShelfAdjustment, displayRotation);
         }
     }
 
     @Override
-    public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
-        for (PinnedStackListener listener : mListeners) {
+    public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) throws RemoteException {
+        for (IPinnedStackListener listener : mListeners) {
             listener.onImeVisibilityChanged(imeVisible, imeHeight);
         }
     }
 
     @Override
-    public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {
-        for (PinnedStackListener listener : mListeners) {
+    public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight)
+            throws RemoteException {
+        for (IPinnedStackListener listener : mListeners) {
             listener.onShelfVisibilityChanged(shelfVisible, shelfHeight);
         }
     }
 
     @Override
-    public void onMinimizedStateChanged(boolean isMinimized) {
-        for (PinnedStackListener listener : mListeners) {
+    public void onMinimizedStateChanged(boolean isMinimized) throws RemoteException {
+        for (IPinnedStackListener listener : mListeners) {
             listener.onMinimizedStateChanged(isMinimized);
         }
     }
 
     @Override
-    public void onActionsChanged(ParceledListSlice actions) {
-        for (PinnedStackListener listener : mListeners) {
+    public void onActionsChanged(ParceledListSlice actions) throws RemoteException {
+        for (IPinnedStackListener listener : mListeners) {
             listener.onActionsChanged(actions);
         }
     }
-
-    @Override
-    public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {
-        for (PinnedStackListener listener : mListeners) {
-            listener.onSaveReentrySnapFraction(componentName, bounds);
-        }
-    }
-
-    @Override
-    public void onResetReentrySnapFraction(ComponentName componentName) {
-        for (PinnedStackListener listener : mListeners) {
-            listener.onResetReentrySnapFraction(componentName);
-        }
-    }
-
-    @Override
-    public void onDisplayInfoChanged(DisplayInfo displayInfo) {
-        for (PinnedStackListener listener : mListeners) {
-            listener.onDisplayInfoChanged(displayInfo);
-        }
-    }
-
-    @Override
-    public void onConfigurationChanged() {
-        for (PinnedStackListener listener : mListeners) {
-            listener.onConfigurationChanged();
-        }
-    }
-
-    @Override
-    public void onAspectRatioChanged(float aspectRatio) {
-        for (PinnedStackListener listener : mListeners) {
-            listener.onAspectRatioChanged(aspectRatio);
-        }
-    }
-
-    @Override
-    public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) {
-        for (PinnedStackListener listener : mListeners) {
-            listener.onPrepareAnimation(sourceRectHint, aspectRatio, bounds);
-        }
-    }
-
-    /**
-     * A counterpart of {@link IPinnedStackListener} with empty implementations.
-     * Subclasses can ignore those methods they do not intend to take action upon.
-     */
-    public static class PinnedStackListener {
-        public void onListenerRegistered(IPinnedStackController controller) {}
-
-        public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment,
-                boolean fromShelfAdjustment) {}
-
-        public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {}
-
-        public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {}
-
-        public void onMinimizedStateChanged(boolean isMinimized) {}
-
-        public void onActionsChanged(ParceledListSlice actions) {}
-
-        public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {}
-
-        public void onResetReentrySnapFraction(ComponentName componentName) {}
-
-        public void onDisplayInfoChanged(DisplayInfo displayInfo) {}
-
-        public void onConfigurationChanged() {}
-
-        public void onAspectRatioChanged(float aspectRatio) {}
-
-        public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) {}
-    }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index 9f1a1fa..794c30a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -27,12 +27,12 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.IPinnedStackListener;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
 import com.android.systemui.shared.recents.view.RecentsTransition;
-import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
 
 public class WindowManagerWrapper {
 
@@ -212,7 +212,7 @@
      * Adds a pinned stack listener, which will receive updates from the window manager service
      * along with any other pinned stack listeners that were added via this method.
      */
-    public void addPinnedStackListener(PinnedStackListener listener) throws RemoteException {
+    public void addPinnedStackListener(IPinnedStackListener listener) throws RemoteException {
         mPinnedStackListenerForwarder.addListener(listener);
         WindowManagerGlobal.getWindowManagerService().registerPinnedStackListener(
                 DEFAULT_DISPLAY, mPinnedStackListenerForwarder);
@@ -221,7 +221,7 @@
     /**
      * Removes a pinned stack listener.
      */
-    public void removePinnedStackListener(PinnedStackListener listener) {
+    public void removePinnedStackListener(IPinnedStackListener listener) {
         mPinnedStackListenerForwarder.removeListener(listener);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index 1c5e800..8f1fcae 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -84,7 +84,7 @@
             }
         } else {
             String svc = args[0].toLowerCase();
-            if (Dependency.class.getName().endsWith(svc)) {
+            if (Dependency.class.getName().toLowerCase().endsWith(svc)) {
                 Dependency.staticDump(fd, pw, args);
             }
             for (SystemUI ui: services) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 43576a4..67fc3e3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -48,6 +48,7 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ParceledListSlice;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.RemoteException;
@@ -60,6 +61,8 @@
 import android.util.Pair;
 import android.util.SparseSetArray;
 import android.view.Display;
+import android.view.IPinnedStackController;
+import android.view.IPinnedStackListener;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
@@ -73,7 +76,6 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.PinnedStackListenerForwarder;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -991,12 +993,32 @@
     }
 
     /** PinnedStackListener that dispatches IME visibility updates to the stack. */
-    private class BubblesImeListener extends PinnedStackListenerForwarder.PinnedStackListener {
+    private class BubblesImeListener extends IPinnedStackListener.Stub {
+
+        @Override
+        public void onListenerRegistered(IPinnedStackController controller) throws RemoteException {
+        }
+
+        @Override
+        public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
+                Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment,
+                int displayRotation) throws RemoteException {}
+
         @Override
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
             if (mStackView != null && mStackView.getBubbleCount() > 0) {
                 mStackView.post(() -> mStackView.onImeVisibilityChanged(imeVisible, imeHeight));
             }
         }
+
+        @Override
+        public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight)
+                throws RemoteException {}
+
+        @Override
+        public void onMinimizedStateChanged(boolean isMinimized) throws RemoteException {}
+
+        @Override
+        public void onActionsChanged(ParceledListSlice actions) throws RemoteException {}
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index 6795bff..30be775 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -18,7 +18,6 @@
 
 import static android.util.TypedValue.COMPLEX_UNIT_DIP;
 
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Point;
@@ -47,6 +46,9 @@
     private static final String TAG = PipBoundsHandler.class.getSimpleName();
     private static final float INVALID_SNAP_FRACTION = -1f;
 
+    // System.identityHashCode guarantees zero for null object.
+    private static final int INVALID_SYSTEM_IDENTITY_TOKEN = 0;
+
     private final Context mContext;
     private final IWindowManager mWindowManager;
     private final PipSnapAlgorithm mSnapAlgorithm;
@@ -56,7 +58,7 @@
     private final Point mTmpDisplaySize = new Point();
 
     private IPinnedStackController mPinnedStackController;
-    private ComponentName mLastPipComponentName;
+    private int mLastPipToken;
     private float mReentrySnapFraction = INVALID_SNAP_FRACTION;
 
     private float mDefaultAspectRatio;
@@ -78,11 +80,8 @@
         mContext = context;
         mSnapAlgorithm = new PipSnapAlgorithm(context);
         mWindowManager = WindowManagerGlobal.getWindowManagerService();
-        reloadResources();
-        // Initialize the aspect ratio to the default aspect ratio.  Don't do this in reload
-        // resources as it would clobber mAspectRatio when entering PiP from fullscreen which
-        // triggers a configuration change and the resources to be reloaded.
         mAspectRatio = mDefaultAspectRatio;
+        reloadResources();
     }
 
     /**
@@ -162,27 +161,27 @@
     }
 
     /**
-     * Responds to IPinnedStackListener on saving reentry snap fraction
-     * for a given {@link ComponentName}.
+     * Responds to IPinnedStackListener on saving reentry snap fraction for a given token.
+     * Token should be generated via {@link System#identityHashCode(Object)}
      */
-    public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {
-        mReentrySnapFraction = getSnapFraction(bounds);
-        mLastPipComponentName = componentName;
+    public void onSaveReentrySnapFraction(int token, Rect stackBounds) {
+        mReentrySnapFraction = getSnapFraction(stackBounds);
+        mLastPipToken = token;
     }
 
     /**
-     * Responds to IPinnedStackListener on resetting reentry snap fraction
-     * for a given {@link ComponentName}.
+     * Responds to IPinnedStackListener on resetting reentry snap fraction for a given token.
+     * Token should be generated via {@link System#identityHashCode(Object)}
      */
-    public void onResetReentrySnapFraction(ComponentName componentName) {
-        if (componentName.equals(mLastPipComponentName)) {
+    public void onResetReentrySnapFraction(int token) {
+        if (mLastPipToken == token) {
             onResetReentrySnapFractionUnchecked();
         }
     }
 
     private void onResetReentrySnapFractionUnchecked() {
         mReentrySnapFraction = INVALID_SNAP_FRACTION;
-        mLastPipComponentName = null;
+        mLastPipToken = INVALID_SYSTEM_IDENTITY_TOKEN;
     }
 
     /**
@@ -213,28 +212,24 @@
     /**
      * Responds to IPinnedStackListener on preparing the pinned stack animation.
      */
-    public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) {
-        final Rect destinationBounds;
-        if (bounds == null) {
-            destinationBounds = getDefaultBounds(mReentrySnapFraction);
+    public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect stackBounds) {
+        final Rect targetStackBounds;
+        if (stackBounds == null) {
+            targetStackBounds = getDefaultBounds(mReentrySnapFraction);
         } else {
-            destinationBounds = new Rect(bounds);
+            targetStackBounds = new Rect();
+            targetStackBounds.set(stackBounds);
         }
         if (isValidPictureInPictureAspectRatio(aspectRatio)) {
-            transformBoundsToAspectRatio(destinationBounds, aspectRatio,
-                    false /* useCurrentMinEdgeSize */);
+            transformBoundsToAspectRatio(targetStackBounds, aspectRatio,
+                    true /* useCurrentMinEdgeSize */);
         }
-        if (destinationBounds.equals(bounds)) {
+        if (targetStackBounds.equals(stackBounds)) {
             return;
         }
         mAspectRatio = aspectRatio;
         onResetReentrySnapFractionUnchecked();
-        try {
-            mPinnedStackController.startAnimation(destinationBounds, sourceRectHint,
-                    -1 /* animationDuration */);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to start PiP animation from SysUI", e);
-        }
+        // TODO: callback Window Manager on starting animation with calculated bounds
     }
 
     /**
@@ -363,7 +358,6 @@
     public void dump(PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
         pw.println(prefix + TAG);
-        pw.println(innerPrefix + "mLastPipComponentName=" + mLastPipComponentName);
         pw.println(innerPrefix + "mReentrySnapFraction=" + mReentrySnapFraction);
         pw.println(innerPrefix + "mDisplayInfo=" + mDisplayInfo);
         pw.println(innerPrefix + "mDefaultAspectRatio=" + mDefaultAspectRatio);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 8dfae32..3be3422 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -32,16 +32,14 @@
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.Pair;
-import android.view.DisplayInfo;
 import android.view.IPinnedStackController;
+import android.view.IPinnedStackListener;
 
 import com.android.systemui.Dependency;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.pip.BasePipManager;
-import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.InputConsumerController;
-import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 
@@ -60,12 +58,8 @@
     private IActivityTaskManager mActivityTaskManager;
     private Handler mHandler = new Handler();
 
-    private final PinnedStackListener mPinnedStackListener = new PipManagerPinnedStackListener();
-    private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
-    private final Rect mTmpInsetBounds = new Rect();
-    private final Rect mTmpNormalBounds = new Rect();
+    private final PinnedStackListener mPinnedStackListener = new PinnedStackListener();
 
-    private PipBoundsHandler mPipBoundsHandler;
     private InputConsumerController mInputConsumerController;
     private PipMenuActivityController mMenuController;
     private PipMediaController mMediaController;
@@ -125,11 +119,11 @@
     /**
      * Handler for messages from the PIP controller.
      */
-    private class PipManagerPinnedStackListener extends PinnedStackListener {
+    private class PinnedStackListener extends IPinnedStackListener.Stub {
+
         @Override
         public void onListenerRegistered(IPinnedStackController controller) {
             mHandler.post(() -> {
-                mPipBoundsHandler.setPinnedStackController(controller);
                 mTouchHandler.setPinnedStackController(controller);
             });
         }
@@ -137,7 +131,6 @@
         @Override
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
             mHandler.post(() -> {
-                mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight);
                 mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight);
             });
         }
@@ -145,66 +138,31 @@
         @Override
         public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {
             mHandler.post(() -> {
-                mPipBoundsHandler.onShelfVisibilityChanged(shelfVisible, shelfHeight);
-                mTouchHandler.onShelfVisibilityChanged(shelfVisible, shelfHeight);
+               mTouchHandler.onShelfVisibilityChanged(shelfVisible, shelfHeight);
             });
         }
 
         @Override
         public void onMinimizedStateChanged(boolean isMinimized) {
             mHandler.post(() -> {
-                mPipBoundsHandler.onMinimizedStateChanged(isMinimized);
                 mTouchHandler.setMinimizedState(isMinimized, true /* fromController */);
             });
         }
 
         @Override
-        public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment,
-                boolean fromShelfAdjustment) {
+        public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
+                Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment,
+                int displayRotation) {
             mHandler.post(() -> {
-                // Populate the inset / normal bounds and DisplayInfo from mPipBoundsHandler first.
-                mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
-                        animatingBounds, mTmpDisplayInfo);
-                mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
-                        animatingBounds, fromImeAdjustment, fromShelfAdjustment,
-                        mTmpDisplayInfo.rotation);
+                mTouchHandler.onMovementBoundsChanged(insetBounds, normalBounds, animatingBounds,
+                        fromImeAdjustment, fromShelfAdjustment, displayRotation);
             });
         }
 
         @Override
         public void onActionsChanged(ParceledListSlice actions) {
-            mHandler.post(() -> mMenuController.setAppActions(actions));
-        }
-
-        @Override
-        public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {
-            mHandler.post(() -> mPipBoundsHandler.onSaveReentrySnapFraction(componentName, bounds));
-        }
-
-        @Override
-        public void onResetReentrySnapFraction(ComponentName componentName) {
-            mHandler.post(() -> mPipBoundsHandler.onResetReentrySnapFraction(componentName));
-        }
-
-        @Override
-        public void onDisplayInfoChanged(DisplayInfo displayInfo) {
-            mHandler.post(() -> mPipBoundsHandler.onDisplayInfoChanged(displayInfo));
-        }
-
-        @Override
-        public void onConfigurationChanged() {
-            mHandler.post(() -> mPipBoundsHandler.onConfigurationChanged());
-        }
-
-        @Override
-        public void onAspectRatioChanged(float aspectRatio) {
-            mHandler.post(() -> mPipBoundsHandler.onAspectRatioChanged(aspectRatio));
-        }
-
-        @Override
-        public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) {
             mHandler.post(() -> {
-                mPipBoundsHandler.onPrepareAnimation(sourceRectHint, aspectRatio, bounds);
+                mMenuController.setAppActions(actions);
             });
         }
     }
@@ -226,13 +184,12 @@
         }
         ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
 
-        mPipBoundsHandler = new PipBoundsHandler(context);
         mInputConsumerController = InputConsumerController.getPipInputConsumer();
         mMediaController = new PipMediaController(context, mActivityManager);
         mMenuController = new PipMenuActivityController(context, mActivityManager, mMediaController,
                 mInputConsumerController);
         mTouchHandler = new PipTouchHandler(context, mActivityManager, mActivityTaskManager,
-                mMenuController, mInputConsumerController, mPipBoundsHandler);
+                mMenuController, mInputConsumerController);
         mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
                 mTouchHandler.getMotionHelper());
 
@@ -295,6 +252,5 @@
         mInputConsumerController.dump(pw, innerPrefix);
         mMenuController.dump(pw, innerPrefix);
         mTouchHandler.dump(pw, innerPrefix);
-        mPipBoundsHandler.dump(pw, innerPrefix);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 1f36d97..30cf412 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -48,7 +48,6 @@
 import com.android.internal.os.logging.MetricsLoggerWrapper;
 import com.android.internal.policy.PipSnapAlgorithm;
 import com.android.systemui.R;
-import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
@@ -76,7 +75,6 @@
     private final IActivityTaskManager mActivityTaskManager;
     private final ViewConfiguration mViewConfig;
     private final PipMenuListener mMenuListener = new PipMenuListener();
-    private final PipBoundsHandler mPipBoundsHandler;
     private IPinnedStackController mPinnedStackController;
 
     private final PipMenuActivityController mMenuController;
@@ -180,8 +178,7 @@
 
     public PipTouchHandler(Context context, IActivityManager activityManager,
             IActivityTaskManager activityTaskManager, PipMenuActivityController menuController,
-            InputConsumerController inputConsumerController,
-            PipBoundsHandler pipBoundsHandler) {
+            InputConsumerController inputConsumerController) {
 
         // Initialize the Pip input consumer
         mContext = context;
@@ -214,8 +211,6 @@
         inputConsumerController.setInputListener(this::handleTouchEvent);
         inputConsumerController.setRegistrationListener(this::onRegistrationChanged);
         onRegistrationChanged(inputConsumerController.isRegistered());
-
-        mPipBoundsHandler = pipBoundsHandler;
     }
 
     public void setTouchEnabled(boolean enabled) {
@@ -792,8 +787,14 @@
         mMovementBounds = isMenuExpanded
                 ? mExpandedMovementBounds
                 : mNormalMovementBounds;
-        mPipBoundsHandler.setMinEdgeSize(
-                isMenuExpanded ? mExpandedShortestEdgeSize : 0);
+        try {
+            if (mPinnedStackController != null) {
+                mPinnedStackController.setMinEdgeSize(
+                        isMenuExpanded ? mExpandedShortestEdgeSize : 0);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not set minimized state", e);
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 81d6973..918af4f 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -19,10 +19,13 @@
 import static android.app.ActivityTaskManager.INVALID_STACK_ID;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.view.Display.DEFAULT_DISPLAY;
 
+import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityTaskManager;
+import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -43,15 +46,16 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
-import android.view.DisplayInfo;
+import android.view.IPinnedStackController;
+import android.view.IPinnedStackListener;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
 
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.pip.BasePipManager;
-import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 
@@ -107,8 +111,9 @@
     private int mSuspendPipResizingReason;
 
     private Context mContext;
-    private PipBoundsHandler mPipBoundsHandler;
+    private IActivityManager mActivityManager;
     private IActivityTaskManager mActivityTaskManager;
+    private IWindowManager mWindowManager;
     private MediaSessionManager mMediaSessionManager;
     private int mState = STATE_NO_PIP;
     private int mResumeResizePinnedStackRunnableState = STATE_NO_PIP;
@@ -130,16 +135,11 @@
     private PipNotification mPipNotification;
     private ParceledListSlice mCustomActions;
 
-    // Used to calculate the movement bounds
-    private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
-    private final Rect mTmpInsetBounds = new Rect();
-    private final Rect mTmpNormalBounds = new Rect();
-
     // Keeps track of the IME visibility to adjust the PiP when the IME is visible
     private boolean mImeVisible;
     private int mImeHeightAdjustment;
 
-    private final PinnedStackListener mPinnedStackListener = new PipManagerPinnedStackListener();
+    private final PinnedStackListener mPinnedStackListener = new PinnedStackListener();
 
     private final Runnable mResizePinnedStackRunnable = new Runnable() {
         @Override
@@ -181,7 +181,11 @@
     /**
      * Handler for messages from the PIP controller.
      */
-    private class PipManagerPinnedStackListener extends PinnedStackListener {
+    private class PinnedStackListener extends IPinnedStackListener.Stub {
+
+        @Override
+        public void onListenerRegistered(IPinnedStackController controller) {}
+
         @Override
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
             if (mState == STATE_PIP) {
@@ -201,13 +205,17 @@
         }
 
         @Override
-        public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment,
-                boolean fromShelfAdjustment) {
+        public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {}
+
+        @Override
+        public void onMinimizedStateChanged(boolean isMinimized) {}
+
+        @Override
+        public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
+                Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment,
+                int displayRotation) {
             mHandler.post(() -> {
-                // Populate the inset / normal bounds and DisplayInfo from mPipBoundsHandler first.
-                mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
-                        animatingBounds, mTmpDisplayInfo);
-                mDefaultPipBounds.set(animatingBounds);
+                mDefaultPipBounds.set(normalBounds);
             });
         }
 
@@ -233,8 +241,10 @@
         }
         mInitialized = true;
         mContext = context;
-        mPipBoundsHandler = new PipBoundsHandler(context);
+
+        mActivityManager = ActivityManager.getService();
         mActivityTaskManager = ActivityTaskManager.getService();
+        mWindowManager = WindowManagerGlobal.getWindowManagerService();
         ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
@@ -281,7 +291,7 @@
                 (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
 
         try {
-            WindowManagerWrapper.getInstance().addPinnedStackListener(mPinnedStackListener);
+            mWindowManager.registerPinnedStackListener(DEFAULT_DISPLAY, mPinnedStackListener);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to register pinned stack listener", e);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 289277e..f782fab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -18,6 +18,7 @@
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
 
 import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
 
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
@@ -316,7 +317,7 @@
         boolean exceedsPriorityThreshold;
         if (NotificationUtils.useNewInterruptionModel(mContext)
                 && hideSilentNotificationsOnLockscreen()) {
-            exceedsPriorityThreshold = entry.isTopBucket();
+            exceedsPriorityThreshold = entry.getBucket() != BUCKET_SILENT;
         } else {
             exceedsPriorityThreshold =
                     !getEntryManager().getNotificationData().isAmbient(entry.key);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 4a27a4e..b6b149d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -124,7 +124,7 @@
 
     @Inject
     public NotificationEntryManager(Context context) {
-        mNotificationData = new NotificationData();
+        mNotificationData = new NotificationData(context);
     }
 
     /** Adds a {@link NotificationEntryListener}. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index 1af47dd..dfbbf98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -36,6 +36,7 @@
     private static final int[] sLocationOffset = new int[2];
 
     @Nullable private static Boolean sUseNewInterruptionModel = null;
+    @Nullable private static Boolean sUsePeopleFiltering = null;
 
     public static boolean isGrayscale(ImageView v, ContrastColorUtil colorUtil) {
         Object isGrayscale = v.getTag(R.id.icon_is_grayscale);
@@ -87,4 +88,17 @@
         }
         return sUseNewInterruptionModel;
     }
+
+    /**
+     * Caches and returns the value of the people filtering setting. Cannot change except through
+     * process restarts.
+     */
+    public static boolean usePeopleFiltering(Context context) {
+        if (sUsePeopleFiltering == null) {
+            sUsePeopleFiltering = context.getResources().getBoolean(
+                    R.bool.config_usePeopleFiltering);
+        }
+
+        return sUsePeopleFiltering;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index 727e245..aacb2dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -16,10 +16,15 @@
 
 package com.android.systemui.statusbar.notification.collection;
 
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
+
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.Person;
+import android.content.Context;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.SnoozeCriterion;
@@ -30,6 +35,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
@@ -44,6 +50,7 @@
  * The list of currently displaying notifications.
  */
 public class NotificationData {
+    private static final String TAG = "NotificationData";
 
     private final NotificationFilter mNotificationFilter = Dependency.get(NotificationFilter.class);
 
@@ -64,6 +71,11 @@
 
     private RankingMap mRankingMap;
     private final Ranking mTmpRanking = new Ranking();
+    private final boolean mUsePeopleFiltering;
+
+    public NotificationData(Context context) {
+        mUsePeopleFiltering = NotificationUtils.usePeopleFiltering(context);
+    }
 
     public void setHeadsUpManager(HeadsUpManager headsUpManager) {
         mHeadsUpManager = headsUpManager;
@@ -72,52 +84,25 @@
     @VisibleForTesting
     protected final Comparator<NotificationEntry> mRankingComparator =
             new Comparator<NotificationEntry>() {
-        private final Ranking mRankingA = new Ranking();
-        private final Ranking mRankingB = new Ranking();
-
         @Override
         public int compare(NotificationEntry a, NotificationEntry b) {
             final StatusBarNotification na = a.notification;
             final StatusBarNotification nb = b.notification;
-            int aImportance = NotificationManager.IMPORTANCE_DEFAULT;
-            int bImportance = NotificationManager.IMPORTANCE_DEFAULT;
-            int aRank = 0;
-            int bRank = 0;
+            int aRank = getRank(a.key);
+            int bRank = getRank(b.key);
 
-            if (mRankingMap != null) {
-                // RankingMap as received from NoMan
-                getRanking(a.key, mRankingA);
-                getRanking(b.key, mRankingB);
-                aImportance = mRankingA.getImportance();
-                bImportance = mRankingB.getImportance();
-                aRank = mRankingA.getRank();
-                bRank = mRankingB.getRank();
-            }
+            boolean aMedia = isImportantMedia(a);
+            boolean bMedia = isImportantMedia(b);
 
-            String mediaNotification = getMediaManager().getMediaNotificationKey();
+            boolean aSystemMax = isSystemMax(a);
+            boolean bSystemMax = isSystemMax(b);
 
-            // IMPORTANCE_MIN media streams are allowed to drift to the bottom
-            final boolean aMedia = a.key.equals(mediaNotification)
-                    && aImportance > NotificationManager.IMPORTANCE_MIN;
-            final boolean bMedia = b.key.equals(mediaNotification)
-                    && bImportance > NotificationManager.IMPORTANCE_MIN;
+            boolean aHeadsUp = a.isRowHeadsUp();
+            boolean bHeadsUp = b.isRowHeadsUp();
 
-            boolean aSystemMax = aImportance >= NotificationManager.IMPORTANCE_HIGH
-                    && isSystemNotification(na);
-            boolean bSystemMax = bImportance >= NotificationManager.IMPORTANCE_HIGH
-                    && isSystemNotification(nb);
-
-
-            boolean aHeadsUp = a.getRow().isHeadsUp();
-            boolean bHeadsUp = b.getRow().isHeadsUp();
-
-            // HACK: This should really go elsewhere, but it's currently not straightforward to
-            // extract the comparison code and we're guaranteed to touch every element, so this is
-            // the best place to set the buckets for the moment.
-            a.setIsTopBucket(aHeadsUp || aMedia || aSystemMax || a.isHighPriority());
-            b.setIsTopBucket(bHeadsUp || bMedia || bSystemMax || b.isHighPriority());
-
-            if (aHeadsUp != bHeadsUp) {
+            if (mUsePeopleFiltering && a.hasAssociatedPeople() != b.hasAssociatedPeople()) {
+                return a.hasAssociatedPeople() ? -1 : 1;
+            } else if (aHeadsUp != bHeadsUp) {
                 return aHeadsUp ? -1 : 1;
             } else if (aHeadsUp) {
                 // Provide consistent ranking with headsUpManager
@@ -317,14 +302,6 @@
         return Ranking.VISIBILITY_NO_OVERRIDE;
     }
 
-    public int getImportance(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.getImportance();
-        }
-        return NotificationManager.IMPORTANCE_UNSPECIFIED;
-    }
-
     public List<SnoozeCriterion> getSnoozeCriteria(String key) {
         if (mRankingMap != null) {
             getRanking(key, mTmpRanking);
@@ -349,6 +326,22 @@
         return 0;
     }
 
+    private boolean isImportantMedia(NotificationEntry e) {
+        int importance = e.ranking().getImportance();
+        boolean media = e.key.equals(getMediaManager().getMediaNotificationKey())
+                && importance > NotificationManager.IMPORTANCE_MIN;
+
+        return media;
+    }
+
+    private boolean isSystemMax(NotificationEntry e) {
+        int importance = e.ranking().getImportance();
+        boolean sys = importance  >= NotificationManager.IMPORTANCE_HIGH
+                && isSystemNotification(e.notification);
+
+        return sys;
+    }
+
     public boolean shouldHide(String key) {
         if (mRankingMap != null) {
             getRanking(key, mTmpRanking);
@@ -414,13 +407,37 @@
             }
         }
 
-        if (mSortedAndFiltered.size() == 1) {
-            // HACK: We need the comparator to run on all children in order to set the
-            // isHighPriority field. If there is only one child, then the comparison won't be run,
-            // so we have to trigger it manually. Get rid of this code as soon as possible.
-            mRankingComparator.compare(mSortedAndFiltered.get(0), mSortedAndFiltered.get(0));
+        Collections.sort(mSortedAndFiltered, mRankingComparator);
+
+        int bucket = BUCKET_PEOPLE;
+        for (NotificationEntry e : mSortedAndFiltered) {
+            assignBucketForEntry(e);
+            if (e.getBucket() < bucket) {
+                android.util.Log.wtf(TAG, "Detected non-contiguous bucket!");
+            }
+            bucket = e.getBucket();
+        }
+    }
+
+    private void assignBucketForEntry(NotificationEntry e) {
+        boolean isHeadsUp = e.isRowHeadsUp();
+        boolean isMedia = isImportantMedia(e);
+        boolean isSystemMax = isSystemMax(e);
+
+        setBucket(e, isHeadsUp, isMedia, isSystemMax);
+    }
+
+    private void setBucket(
+            NotificationEntry e,
+            boolean isHeadsUp,
+            boolean isMedia,
+            boolean isSystemMax) {
+        if (mUsePeopleFiltering && e.hasAssociatedPeople()) {
+            e.setBucket(BUCKET_PEOPLE);
+        } else if (isHeadsUp || isMedia || isSystemMax || e.isHighPriority()) {
+            e.setBucket(BUCKET_ALERTING);
         } else {
-            Collections.sort(mSortedAndFiltered, mRankingComparator);
+            e.setBucket(BUCKET_SILENT);
         }
     }
 
@@ -466,6 +483,19 @@
     }
 
     /**
+     * Get the current set of buckets for notification entries, as defined here
+     */
+    public static int[] getNotificationBuckets(Context context) {
+        if (NotificationUtils.usePeopleFiltering(context)) {
+            return new int[]{BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT};
+        } else if (NotificationUtils.useNewInterruptionModel(context)) {
+            return new int[]{BUCKET_ALERTING, BUCKET_SILENT};
+        } else {
+            return new int[]{BUCKET_ALERTING};
+        }
+    }
+
+    /**
      * Provides access to keyguard state and user settings dependent data.
      */
     public interface KeyguardEnvironment {
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 71cdcf7..a33d23c 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
@@ -21,6 +21,7 @@
 import static android.app.Notification.CATEGORY_EVENT;
 import static android.app.Notification.CATEGORY_MESSAGE;
 import static android.app.Notification.CATEGORY_REMINDER;
+import static android.app.Notification.EXTRA_MESSAGES;
 import static android.app.Notification.FLAG_BUBBLE;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
@@ -29,6 +30,8 @@
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
 
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
+
 import android.annotation.NonNull;
 import android.app.Notification;
 import android.app.Notification.MessagingStyle.Message;
@@ -38,6 +41,7 @@
 import android.content.Context;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
+import android.os.Parcelable;
 import android.os.SystemClock;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.SnoozeCriterion;
@@ -58,6 +62,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
 import com.android.systemui.statusbar.notification.row.NotificationGuts;
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -99,6 +104,7 @@
     public int targetSdk;
     private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
     public CharSequence remoteInputText;
+    private final List<Person> mAssociatedPeople = new ArrayList<>();
 
     /**
      * If {@link android.app.RemoteInput#getEditChoicesBeforeSending} is enabled, and the user is
@@ -140,12 +146,11 @@
      */
     private boolean mHighPriority;
 
-    private boolean mIsTopBucket;
-
     private boolean mSensitive = true;
     private Runnable mOnSensitiveChangedListener;
     private boolean mAutoHeadsUp;
     private boolean mPulseSupressed;
+    private int mBucket = BUCKET_ALERTING;
 
     public NotificationEntry(
             @NonNull StatusBarNotification sbn,
@@ -173,11 +178,12 @@
      * TODO: Make this package-private
      */
     public void setNotification(StatusBarNotification sbn) {
-        if (!sbn.getKey().equals(key)) {
+        if (sbn.getKey() != null && key != null && !sbn.getKey().equals(key)) {
             throw new IllegalArgumentException("New key " + sbn.getKey()
                     + " doesn't match existing key " + key);
         }
         notification = sbn;
+        updatePeopleList();
     }
 
     /**
@@ -263,22 +269,41 @@
         this.mHighPriority = highPriority;
     }
 
-    /**
-     * @return True if the notif should appear in the "top" or "important" section of notifications
-     * (as opposed to the "bottom" or "silent" section). This is usually the same as
-     * {@link #isHighPriority()}, but there are certain exceptions, such as media notifs.
-     */
-    public boolean isTopBucket() {
-        return mIsTopBucket;
-    }
-    public void setIsTopBucket(boolean isTopBucket) {
-        mIsTopBucket = isTopBucket;
-    }
-
     public boolean isBubble() {
         return (notification.getNotification().flags & FLAG_BUBBLE) != 0;
     }
 
+    private void updatePeopleList() {
+        mAssociatedPeople.clear();
+
+        Bundle extras = notification.getNotification().extras;
+        if (extras == null) {
+            return;
+        }
+
+        List<Person> p = extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST);
+
+        if (p != null) {
+            mAssociatedPeople.addAll(p);
+        }
+
+        if (Notification.MessagingStyle.class.equals(
+                notification.getNotification().getNotificationStyle())) {
+            final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES);
+            if (!ArrayUtils.isEmpty(messages)) {
+                for (Notification.MessagingStyle.Message message :
+                        Notification.MessagingStyle.Message
+                                .getMessagesFromBundleArray(messages)) {
+                    mAssociatedPeople.add(message.getSenderPerson());
+                }
+            }
+        }
+    }
+
+    boolean hasAssociatedPeople() {
+        return mAssociatedPeople.size() > 0;
+    }
+
     /**
      * Returns the data needed for a bubble for this notification, if it exists.
      */
@@ -295,6 +320,15 @@
         }
     }
 
+    @NotificationSectionsManager.PriorityBucket
+    public int getBucket() {
+        return mBucket;
+    }
+
+    public void setBucket(@NotificationSectionsManager.PriorityBucket int bucket) {
+        mBucket = bucket;
+    }
+
     public ExpandableNotificationRow getRow() {
         return row;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
index 4221846..ec0c634 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
@@ -16,11 +16,10 @@
 
 package com.android.systemui.statusbar.notification.stack;
 
-import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.NUM_SECTIONS;
-
-
+import android.content.Context;
 import android.util.MathUtils;
 
+import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -51,11 +50,14 @@
     private float mAppearFraction;
 
     @Inject
-    NotificationRoundnessManager(KeyguardBypassController keyguardBypassController) {
-        mFirstInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
-        mLastInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
-        mTmpFirstInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
-        mTmpLastInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
+    NotificationRoundnessManager(
+            KeyguardBypassController keyguardBypassController,
+            Context context) {
+        int numberOfSections = NotificationData.getNotificationBuckets(context).length;
+        mFirstInSectionViews = new ActivatableNotificationView[numberOfSections];
+        mLastInSectionViews = new ActivatableNotificationView[numberOfSections];
+        mTmpFirstInSectionViews = new ActivatableNotificationView[numberOfSections];
+        mTmpLastInSectionViews = new ActivatableNotificationView[numberOfSections];
         mBypassController = keyguardBypassController;
     }
 
@@ -157,7 +159,7 @@
 
     public void updateRoundedChildren(NotificationSection[] sections) {
         boolean anyChanged = false;
-        for (int i = 0; i < NUM_SECTIONS; i++) {
+        for (int i = 0; i < sections.length; i++) {
             mTmpFirstInSectionViews[i] = mFirstInSectionViews[i];
             mTmpLastInSectionViews[i] = mLastInSectionViews[i];
             mFirstInSectionViews[i] = sections[i].getFirstVisibleChild();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index f39ed2e..9d456ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -33,6 +33,7 @@
  * bounds change.
  */
 class NotificationSection {
+    private @NotificationSectionsManager.PriorityBucket int mBucket;
     private View mOwningView;
     private Rect mBounds = new Rect();
     private Rect mCurrentBounds = new Rect(-1, -1, -1, -1);
@@ -43,8 +44,9 @@
     private ActivatableNotificationView mFirstVisibleChild;
     private ActivatableNotificationView mLastVisibleChild;
 
-    NotificationSection(View owningView) {
+    NotificationSection(View owningView, @NotificationSectionsManager.PriorityBucket int bucket) {
         mOwningView = owningView;
+        mBucket = bucket;
     }
 
     public void cancelAnimators() {
@@ -72,6 +74,11 @@
         return mBottomAnimator != null || mTopAnimator != null;
     }
 
+    @NotificationSectionsManager.PriorityBucket
+    public int getBucket() {
+        return mBucket;
+    }
+
     public void startBackgroundAnimation(boolean animateTop, boolean animateBottom) {
         // Left and right bounds are always applied immediately.
         mCurrentBounds.left = mBounds.left;
@@ -199,12 +206,16 @@
         return mLastVisibleChild;
     }
 
-    public void setFirstVisibleChild(ActivatableNotificationView child) {
+    public boolean setFirstVisibleChild(ActivatableNotificationView child) {
+        boolean changed = mFirstVisibleChild != child;
         mFirstVisibleChild = child;
+        return changed;
     }
 
-    public void setLastVisibleChild(ActivatableNotificationView child) {
+    public boolean setLastVisibleChild(ActivatableNotificationView child) {
+        boolean changed = mLastVisibleChild != child;
         mLastVisibleChild = child;
+        return changed;
     }
 
     public void resetCurrentBounds() {
@@ -291,5 +302,4 @@
         mBounds.bottom = bottom;
         return bottom;
     }
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index d119fb79..d0444ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -18,6 +18,10 @@
 
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Intent;
 import android.provider.Settings;
@@ -34,23 +38,31 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 
+import java.lang.annotation.Retention;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Manages the boundaries of the two notification sections (high priority and low priority). Also
  * shows/hides the headers for those sections where appropriate.
  *
  * TODO: Move remaining sections logic from NSSL into this class.
  */
-class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvider {
+public class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvider {
+
+    private static final String TAG = "NotifSectionsManager";
+    private static final boolean DEBUG = false;
+
     private final NotificationStackScrollLayout mParent;
     private final ActivityStarter mActivityStarter;
     private final StatusBarStateController mStatusBarStateController;
     private final ConfigurationController mConfigurationController;
-    private final boolean mUseMultipleSections;
+    private final int mNumberOfSections;
 
     private boolean mInitialized = false;
     private SectionHeaderView mGentleHeader;
     private boolean mGentleHeaderVisible = false;
-    @Nullable private ExpandableNotificationRow mFirstGentleNotif;
+
     @Nullable private View.OnClickListener mOnClearGentleNotifsClickListener;
 
     NotificationSectionsManager(
@@ -58,12 +70,21 @@
             ActivityStarter activityStarter,
             StatusBarStateController statusBarStateController,
             ConfigurationController configurationController,
-            boolean useMultipleSections) {
+            int numberOfSections) {
         mParent = parent;
         mActivityStarter = activityStarter;
         mStatusBarStateController = statusBarStateController;
         mConfigurationController = configurationController;
-        mUseMultipleSections = useMultipleSections;
+        mNumberOfSections = numberOfSections;
+    }
+
+    NotificationSection[] createSectionsForBuckets(int[] buckets) {
+        NotificationSection[] sections = new NotificationSection[buckets.length];
+        for (int i = 0; i < buckets.length; i++) {
+            sections[i] = new NotificationSection(mParent, buckets[i] /* bucket */);
+        }
+
+        return sections;
     }
 
     /** Must be called before use. */
@@ -111,8 +132,38 @@
     }
 
     @Override
-    public boolean beginsSection(View view) {
-        return view == getFirstLowPriorityChild();
+    public boolean beginsSection(@NonNull View view, @Nullable View previous) {
+        boolean begin = false;
+        if (view instanceof ExpandableNotificationRow) {
+            if (previous instanceof ExpandableNotificationRow) {
+                // If we're drawing the first non-person notification, break out a section
+                ExpandableNotificationRow curr = (ExpandableNotificationRow) view;
+                ExpandableNotificationRow prev = (ExpandableNotificationRow) previous;
+
+                begin =  curr.getEntry().getBucket() != prev.getEntry().getBucket();
+            }
+        }
+
+        if (!begin) {
+            begin = view == mGentleHeader;
+        }
+
+        return begin;
+    }
+
+    private boolean isUsingMultipleSections() {
+        return mNumberOfSections > 1;
+    }
+
+    private @PriorityBucket int getBucket(ActivatableNotificationView view)
+            throws IllegalArgumentException {
+        if (view instanceof ExpandableNotificationRow) {
+            return ((ExpandableNotificationRow) view).getEntry().getBucket();
+        } else if (view == mGentleHeader) {
+            return BUCKET_SILENT;
+        }
+
+        throw new IllegalArgumentException("I don't know how to find a bucket for this view :(");
     }
 
     /**
@@ -120,11 +171,10 @@
      * bookkeeping and adds/moves/removes section headers if appropriate.
      */
     void updateSectionBoundaries() {
-        if (!mUseMultipleSections) {
+        if (!isUsingMultipleSections()) {
             return;
         }
 
-        mFirstGentleNotif = null;
         int firstGentleNotifIndex = -1;
 
         final int n = mParent.getChildCount();
@@ -133,9 +183,8 @@
             if (child instanceof ExpandableNotificationRow
                     && child.getVisibility() != View.GONE) {
                 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                if (!row.getEntry().isTopBucket()) {
+                if (row.getEntry().getBucket() == BUCKET_SILENT) {
                     firstGentleNotifIndex = i;
-                    mFirstGentleNotif = row;
                     break;
                 }
             }
@@ -184,80 +233,75 @@
     }
 
     /**
-     * Updates the boundaries (as tracked by their first and last views) of the high and low
-     * priority sections.
+     * Updates the boundaries (as tracked by their first and last views) of the priority sections.
      *
      * @return {@code true} If the last view in the top section changed (so we need to animate).
      */
-    boolean updateFirstAndLastViewsInSections(
-            final NotificationSection highPrioritySection,
-            final NotificationSection lowPrioritySection,
-            ActivatableNotificationView firstChild,
-            ActivatableNotificationView lastChild) {
-        if (mUseMultipleSections) {
-            ActivatableNotificationView previousLastHighPriorityChild =
-                    highPrioritySection.getLastVisibleChild();
-            ActivatableNotificationView previousFirstLowPriorityChild =
-                    lowPrioritySection.getFirstVisibleChild();
-            ActivatableNotificationView lastHighPriorityChild = getLastHighPriorityChild();
-            ActivatableNotificationView firstLowPriorityChild = getFirstLowPriorityChild();
-            if (lastHighPriorityChild != null && firstLowPriorityChild != null) {
-                highPrioritySection.setFirstVisibleChild(firstChild);
-                highPrioritySection.setLastVisibleChild(lastHighPriorityChild);
-                lowPrioritySection.setFirstVisibleChild(firstLowPriorityChild);
-                lowPrioritySection.setLastVisibleChild(lastChild);
-            } else if (lastHighPriorityChild != null) {
-                highPrioritySection.setFirstVisibleChild(firstChild);
-                highPrioritySection.setLastVisibleChild(lastChild);
-                lowPrioritySection.setFirstVisibleChild(null);
-                lowPrioritySection.setLastVisibleChild(null);
-            } else {
-                highPrioritySection.setFirstVisibleChild(null);
-                highPrioritySection.setLastVisibleChild(null);
-                lowPrioritySection.setFirstVisibleChild(firstChild);
-                lowPrioritySection.setLastVisibleChild(lastChild);
+    boolean updateFirstAndLastViewsForAllSections(
+            NotificationSection[] sections,
+            List<ActivatableNotificationView> children) {
+
+        if (sections.length <= 0 || children.size() <= 0) {
+            for (NotificationSection s : sections) {
+                s.setFirstVisibleChild(null);
+                s.setLastVisibleChild(null);
             }
-            return lastHighPriorityChild != previousLastHighPriorityChild
-                    || firstLowPriorityChild != previousFirstLowPriorityChild;
-        } else {
-            highPrioritySection.setFirstVisibleChild(firstChild);
-            highPrioritySection.setLastVisibleChild(lastChild);
             return false;
         }
+
+        boolean changed = false;
+        ArrayList<ActivatableNotificationView> viewsInBucket = new ArrayList<>();
+        for (NotificationSection s : sections) {
+            int filter = s.getBucket();
+            viewsInBucket.clear();
+
+            //TODO: do this in a single pass, and more better
+            for (ActivatableNotificationView v : children)  {
+                if (getBucket(v) == filter) {
+                    viewsInBucket.add(v);
+                }
+
+                if (viewsInBucket.size() >= 1) {
+                    changed |= s.setFirstVisibleChild(viewsInBucket.get(0));
+                    changed |= s.setLastVisibleChild(viewsInBucket.get(viewsInBucket.size() - 1));
+                } else {
+                    changed |= s.setFirstVisibleChild(null);
+                    changed |= s.setLastVisibleChild(null);
+                }
+            }
+        }
+
+        if (DEBUG) {
+            logSections(sections);
+        }
+
+        return changed;
     }
 
+    private void logSections(NotificationSection[] sections) {
+        for (int i = 0; i < sections.length; i++) {
+            NotificationSection s = sections[i];
+            ActivatableNotificationView first = s.getFirstVisibleChild();
+            String fs = first == null ? "(null)"
+                    :  (first instanceof ExpandableNotificationRow)
+                            ? ((ExpandableNotificationRow) first).getEntry().key
+                            : Integer.toHexString(System.identityHashCode(first));
+            ActivatableNotificationView last = s.getLastVisibleChild();
+            String ls = last == null ? "(null)"
+                    :  (last instanceof ExpandableNotificationRow)
+                            ? ((ExpandableNotificationRow) last).getEntry().key
+                            : Integer.toHexString(System.identityHashCode(last));
+            android.util.Log.d(TAG, "updateSections: f=" + fs + " s=" + i);
+            android.util.Log.d(TAG, "updateSections: l=" + ls + " s=" + i);
+        }
+    }
+
+
     @VisibleForTesting
     SectionHeaderView getGentleHeaderView() {
         return mGentleHeader;
     }
 
-    @Nullable
-    private ActivatableNotificationView getFirstLowPriorityChild() {
-        if (mGentleHeaderVisible) {
-            return mGentleHeader;
-        } else {
-            return mFirstGentleNotif;
-        }
-    }
-
-    @Nullable
-    private ActivatableNotificationView getLastHighPriorityChild() {
-        ActivatableNotificationView lastChildBeforeGap = null;
-        int childCount = mParent.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = mParent.getChildAt(i);
-            if (child.getVisibility() != View.GONE && child instanceof ExpandableNotificationRow) {
-                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                if (!row.getEntry().isTopBucket()) {
-                    break;
-                } else {
-                    lastChildBeforeGap = row;
-                }
-            }
-        }
-        return lastChildBeforeGap;
-    }
-
     private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
         @Override
         public void onLocaleListChanged() {
@@ -279,4 +323,20 @@
             mOnClearGentleNotifsClickListener.onClick(v);
         }
     }
+
+    /**
+     * For now, declare the available notification buckets (sections) here so that other
+     * presentation code can decide what to do based on an entry's buckets
+     *
+     */
+    @Retention(SOURCE)
+    @IntDef(prefix = { "BUCKET_" }, value = {
+            BUCKET_PEOPLE,
+            BUCKET_ALERTING,
+            BUCKET_SILENT
+    })
+    public @interface PriorityBucket {}
+    public static final int BUCKET_PEOPLE = 0;
+    public static final int BUCKET_ALERTING = 1;
+    public static final int BUCKET_SILENT = 2;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 1c9b225..a67018e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -18,6 +18,7 @@
 
 import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
 import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
 import static com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.ANCHOR_SCROLLING;
 import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE;
 import static com.android.systemui.statusbar.phone.NotificationIconAreaController.HIGH_PRIORITY;
@@ -112,6 +113,7 @@
 import com.android.systemui.statusbar.notification.ShadeViewRefactor;
 import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -172,7 +174,6 @@
      * Sentinel value for no current active pointer. Used by {@link #mActivePointerId}.
      */
     private static final int INVALID_POINTER = -1;
-    static final int NUM_SECTIONS = 2;
     /**
      * The distance in pixels between sections when the sections are directly adjacent (no visible
      * gap is drawn between them). In this case we don't want to round their corners.
@@ -351,7 +352,7 @@
             return true;
         }
     };
-    private NotificationSection[] mSections = new NotificationSection[NUM_SECTIONS];
+    private NotificationSection[] mSections;
     private boolean mAnimateNextBackgroundTop;
     private boolean mAnimateNextBackgroundBottom;
     private boolean mAnimateNextSectionBoundsChange;
@@ -522,9 +523,6 @@
 
         mAllowLongPress = allowLongPress;
 
-        for (int i = 0; i < NUM_SECTIONS; i++) {
-            mSections[i] = new NotificationSection(this);
-        }
         mRoundnessManager = notificationRoundnessManager;
 
         mHeadsUpManager = headsUpManager;
@@ -533,19 +531,21 @@
         mKeyguardBypassController = keyguardBypassController;
         mFalsingManager = falsingManager;
 
+        int[] buckets = NotificationData.getNotificationBuckets(context);
         mSectionsManager =
                 new NotificationSectionsManager(
                         this,
                         activityStarter,
                         statusBarStateController,
                         configurationController,
-                        NotificationUtils.useNewInterruptionModel(context));
+                        buckets.length);
         mSectionsManager.initialize(LayoutInflater.from(context));
         mSectionsManager.setOnClearGentleNotifsClickListener(v -> {
             // Leave the shade open if there will be other notifs left over to clear
             final boolean closeShade = !hasActiveClearableNotifications(ROWS_HIGH_PRIORITY);
             clearNotifications(ROWS_GENTLE, closeShade);
         });
+        mSections = mSectionsManager.createSectionsForBuckets(buckets);
 
         mAmbientState = new AmbientState(context, mSectionsManager, mHeadsUpManager);
         mBgColor = context.getColor(R.color.notification_shade_background_color);
@@ -773,7 +773,7 @@
     protected void onDraw(Canvas canvas) {
         if (mShouldDrawNotificationBackground
                 && (mSections[0].getCurrentBounds().top
-                < mSections[NUM_SECTIONS - 1].getCurrentBounds().bottom
+                < mSections[mSections.length - 1].getCurrentBounds().bottom
                 || mAmbientState.isDozing())) {
             drawBackground(canvas);
         } else if (mInHeadsUpPinnedMode || mHeadsUpAnimatingAway) {
@@ -819,7 +819,7 @@
         int lockScreenLeft = mSidePaddings;
         int lockScreenRight = getWidth() - mSidePaddings;
         int lockScreenTop = mSections[0].getCurrentBounds().top;
-        int lockScreenBottom = mSections[NUM_SECTIONS - 1].getCurrentBounds().bottom;
+        int lockScreenBottom = mSections[mSections.length - 1].getCurrentBounds().bottom;
         int hiddenLeft = getWidth() / 2;
         int hiddenTop = mTopPadding;
 
@@ -2636,6 +2636,21 @@
         return null;
     }
 
+    //TODO: We shouldn't have to generate this list every time
+    private List<ActivatableNotificationView> getChildrenWithBackground() {
+        ArrayList<ActivatableNotificationView> children = new ArrayList<>();
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            if (child.getVisibility() != View.GONE && child instanceof ActivatableNotificationView
+                    && child != mShelf) {
+                children.add((ActivatableNotificationView) child);
+            }
+        }
+
+        return children;
+    }
+
     /**
      * Fling the scroll view
      *
@@ -3198,8 +3213,8 @@
 
         ActivatableNotificationView firstChild = getFirstChildWithBackground();
         ActivatableNotificationView lastChild = getLastChildWithBackground();
-        boolean sectionViewsChanged = mSectionsManager.updateFirstAndLastViewsInSections(
-                mSections[0], mSections[1], firstChild, lastChild);
+        boolean sectionViewsChanged = mSectionsManager.updateFirstAndLastViewsForAllSections(
+                mSections, getChildrenWithBackground());
 
         if (mAnimationsEnabled && mIsExpanded) {
             mAnimateNextBackgroundTop = firstChild != previousFirstChild;
@@ -5780,7 +5795,7 @@
             currentIndex++;
             boolean beforeSpeedBump;
             if (mHighPriorityBeforeSpeedBump) {
-                beforeSpeedBump = row.getEntry().isTopBucket();
+                beforeSpeedBump = row.getEntry().getBucket() < BUCKET_SILENT;
             } else {
                 beforeSpeedBump = !row.getEntry().isAmbient();
             }
@@ -5838,9 +5853,9 @@
             case ROWS_ALL:
                 return true;
             case ROWS_HIGH_PRIORITY:
-                return row.getEntry().isTopBucket();
+                return row.getEntry().getBucket() < BUCKET_SILENT;
             case ROWS_GENTLE:
-                return !row.getEntry().isTopBucket();
+                return row.getEntry().getBucket() == BUCKET_SILENT;
             default:
                 throw new IllegalArgumentException("Unknown selection: " + selection);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index ef80484..4b61064 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.notification.stack;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Resources;
 import android.util.Log;
@@ -411,8 +413,10 @@
             float currentYPosition,
             boolean reverse) {
         ExpandableView child = algorithmState.visibleChildren.get(i);
+        ExpandableView previousChild = i > 0 ? algorithmState.visibleChildren.get(i - 1) : null;
         final boolean applyGapHeight =
-                childNeedsGapHeight(ambientState.getSectionProvider(), algorithmState, i, child);
+                childNeedsGapHeight(
+                        ambientState.getSectionProvider(), algorithmState, i, child, previousChild);
         ExpandableViewState childViewState = child.getViewState();
         childViewState.location = ExpandableViewState.LOCATION_UNKNOWN;
 
@@ -477,8 +481,11 @@
             SectionProvider sectionProvider,
             StackScrollAlgorithmState algorithmState,
             int visibleIndex,
-            View child) {
-        boolean needsGapHeight = sectionProvider.beginsSection(child) && visibleIndex > 0;
+            View child,
+            View previousChild) {
+
+        boolean needsGapHeight = sectionProvider.beginsSection(child, previousChild)
+                && visibleIndex > 0;
         if (ANCHOR_SCROLLING) {
             needsGapHeight &= visibleIndex != algorithmState.anchorViewIndex;
         }
@@ -749,6 +756,6 @@
          * True if this view starts a new "section" of notifications, such as the gentle
          * notifications section. False if sections are not enabled.
          */
-        boolean beginsSection(View view);
+        boolean beginsSection(@NonNull View view, @Nullable View previous);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index 4cd3ad2..575b559 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -18,6 +18,7 @@
 import static android.view.Display.INVALID_DISPLAY;
 
 import android.content.Context;
+import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
@@ -35,6 +36,8 @@
 import android.util.MathUtils;
 import android.util.StatsLog;
 import android.view.Gravity;
+import android.view.IPinnedStackController;
+import android.view.IPinnedStackListener;
 import android.view.ISystemGestureExclusionListener;
 import android.view.InputChannel;
 import android.view.InputDevice;
@@ -54,7 +57,6 @@
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.recents.OverviewProxyService;
-import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 
@@ -70,13 +72,35 @@
     private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt(
             "gestures.back_timeout", 250);
 
-    private final PinnedStackListener mImeChangedListener = new PinnedStackListener() {
+    private final IPinnedStackListener.Stub mImeChangedListener = new IPinnedStackListener.Stub() {
+        @Override
+        public void onListenerRegistered(IPinnedStackController controller) {
+        }
+
         @Override
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
             // No need to thread jump, assignments are atomic
             mImeHeight = imeVisible ? imeHeight : 0;
             // TODO: Probably cancel any existing gesture
         }
+
+        @Override
+        public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {
+        }
+
+        @Override
+        public void onMinimizedStateChanged(boolean isMinimized) {
+        }
+
+        @Override
+        public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
+                Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment,
+                int displayRotation) {
+        }
+
+        @Override
+        public void onActionsChanged(ParceledListSlice actions) {
+        }
     };
 
     private ISystemGestureExclusionListener mGestureExclusionListener =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index a79ecd9..ea113df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -102,6 +102,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -177,12 +178,22 @@
     @VisibleForTesting
     final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
             new KeyguardUpdateMonitorCallback() {
+
+                @Override
+                public void onBiometricAuthenticated(int userId,
+                        BiometricSourceType biometricSourceType) {
+                    if (mFirstBypassAttempt && mUpdateMonitor.isUnlockingWithBiometricAllowed()) {
+                        mDelayShowingKeyguardStatusBar = true;
+                    }
+                }
+
                 @Override
                 public void onBiometricRunningStateChanged(boolean running,
                         BiometricSourceType biometricSourceType) {
                     boolean keyguardOrShadeLocked = mBarState == StatusBarState.KEYGUARD
                             || mBarState == StatusBarState.SHADE_LOCKED;
-                    if (!running && mFirstBypassAttempt && keyguardOrShadeLocked && !mDozing) {
+                    if (!running && mFirstBypassAttempt && keyguardOrShadeLocked && !mDozing
+                            && !mDelayShowingKeyguardStatusBar) {
                         mFirstBypassAttempt = false;
                         animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
                     }
@@ -191,6 +202,17 @@
                 @Override
                 public void onFinishedGoingToSleep(int why) {
                     mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
+                    mDelayShowingKeyguardStatusBar = false;
+                }
+            };
+    private final KeyguardMonitor.Callback mKeyguardMonitorCallback =
+            new KeyguardMonitor.Callback() {
+                @Override
+                public void onKeyguardFadingAwayChanged() {
+                    if (!mKeyguardMonitor.isKeyguardFadingAway()) {
+                        mFirstBypassAttempt = false;
+                        mDelayShowingKeyguardStatusBar = false;
+                    }
                 }
             };
 
@@ -413,7 +435,17 @@
     private boolean mShowingKeyguardHeadsUp;
     private boolean mAllowExpandForSmallExpansion;
     private Runnable mExpandAfterLayoutRunnable;
+
+    /**
+     * If face auth with bypass is running for the first time after you turn on the screen.
+     * (From aod or screen off)
+     */
     private boolean mFirstBypassAttempt;
+    /**
+     * If auth happens successfully during {@code mFirstBypassAttempt}, and we should wait until
+     * the keyguard is dismissed to show the status bar.
+     */
+    private boolean mDelayShowingKeyguardStatusBar;
 
     private PluginManager mPluginManager;
     private FrameLayout mPluginFrame;
@@ -450,6 +482,7 @@
         mKeyguardBypassController = bypassController;
         mUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
         mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
+        mKeyguardMonitor.addCallback(mKeyguardMonitorCallback);
         dynamicPrivacyController.addListener(this);
 
         mBottomAreaShadeAlphaAnimator = ValueAnimator.ofFloat(1f, 0);
@@ -2391,7 +2424,8 @@
                 * mKeyguardStatusBarAnimateAlpha;
         newAlpha *= 1.0f - mKeyguardHeadsUpShowingAmount;
         mKeyguardStatusBar.setAlpha(newAlpha);
-        boolean hideForBypass = mFirstBypassAttempt && mUpdateMonitor.shouldListenForFace();
+        boolean hideForBypass = mFirstBypassAttempt && mUpdateMonitor.shouldListenForFace()
+                || mDelayShowingKeyguardStatusBar;
         mKeyguardStatusBar.setVisibility(newAlpha != 0f && !mDozing && !hideForBypass
                 ? VISIBLE : INVISIBLE);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index f853b63..8c95b84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -503,8 +503,8 @@
      * device is dozing when the light sensor is on.
      */
     public void setAodFrontScrimAlpha(float alpha) {
-        if (((mState == ScrimState.AOD && mDozeParameters.getAlwaysOn())
-                || mState == ScrimState.PULSING) && mInFrontAlpha != alpha) {
+        if (mState == ScrimState.AOD && mDozeParameters.getAlwaysOn()
+                && mInFrontAlpha != alpha) {
             mInFrontAlpha = alpha;
             updateScrims();
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 57dd8c9..a027643 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -19,11 +19,12 @@
 import static android.content.Intent.ACTION_USER_SWITCHED;
 import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL;
 
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
+
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -166,7 +167,10 @@
                 Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1);
         when(mNotificationData.isHighPriority(any())).thenReturn(false);
 
-        assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(mock(NotificationEntry.class)));
+        NotificationEntry entry = new NotificationEntryBuilder().build();
+        entry.setBucket(BUCKET_SILENT);
+
+        assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(entry));
     }
 
     @Test
@@ -179,7 +183,9 @@
                 Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0);
         when(mNotificationData.isHighPriority(any())).thenReturn(false);
 
-        assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(mock(NotificationEntry.class)));
+        NotificationEntry entry = new NotificationEntryBuilder().build();
+        entry.setBucket(BUCKET_SILENT);
+        assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(entry));
     }
 
     private class TestNotificationLockscreenUserManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
index a145c12..8d496a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
@@ -73,7 +73,7 @@
     private DeviceProvisionedListener mProvisionedListener;
 
     // TODO: Remove this once EntryManager no longer needs to be mocked
-    private NotificationData mNotificationData = new NotificationData();
+    private NotificationData mNotificationData = new NotificationData(mContext);
 
     private int mNextNotifId = 0;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
index 9bcbfbc..ab7f960 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
@@ -32,6 +32,8 @@
 import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_IMPORTANCE;
 import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_RANK;
 import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_VIS_EFFECTS;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
 
 import static junit.framework.Assert.assertEquals;
 
@@ -48,6 +50,7 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Person;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
@@ -136,7 +139,7 @@
         mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
         when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
         when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
-        mNotificationData = new TestableNotificationData();
+        mNotificationData = new TestableNotificationData(mContext);
         mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class));
         mRow = new NotificationTestHelper(getContext()).createRow();
         Dependency.get(InitController.class).executePostInitTasks();
@@ -527,8 +530,7 @@
 
     @Test
     public void testSort_samePriorityUsesNMSRank() {
-        // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
-        // front
+        // NMS rank says A and then B, and they are the same priority so use that rank
         Notification aN = new Notification.Builder(mContext, "test")
                 .setStyle(new Notification.MessagingStyle(""))
                 .build();
@@ -571,8 +573,7 @@
     }
 
     @Test
-    public void testSort_properlySetsIsTopBucket() {
-
+    public void testSort_properlySetsAlertingBucket() {
         Notification notification = new Notification.Builder(mContext, "test")
                 .build();
         NotificationEntry entry = new NotificationEntryBuilder()
@@ -591,11 +592,11 @@
         entry.setRow(mRow);
         mNotificationData.add(entry);
 
-        assertTrue(entry.isTopBucket());
+        assertEquals(entry.getBucket(), BUCKET_ALERTING);
     }
 
     @Test
-    public void testSort_properlySetsIsNotTopBucket() {
+    public void testSort_properlySetsSilentBucket() {
         Notification notification = new Notification.Builder(mContext, "test")
                 .build();
 
@@ -613,10 +614,9 @@
         mNotificationData.rankingOverrides.put(entry.key(), override);
 
         entry.setRow(mRow);
-
         mNotificationData.add(entry);
 
-        assertFalse(entry.isTopBucket());
+        assertEquals(entry.getBucket(), BUCKET_SILENT);
     }
 
     private void initStatusBarNotification(boolean allowDuringSetup) {
@@ -631,8 +631,8 @@
     }
 
     public static class TestableNotificationData extends NotificationData {
-        public TestableNotificationData() {
-            super();
+        public TestableNotificationData(Context context) {
+            super(context);
         }
 
         public static final String OVERRIDE_RANK = "r";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
index 524ad85..addceb5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
@@ -64,7 +64,7 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mRoundnessManager = new NotificationRoundnessManager(mBypassController);
+        mRoundnessManager = new NotificationRoundnessManager(mBypassController, mContext);
         com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
         NotificationTestHelper testHelper = new NotificationTestHelper(getContext());
         mFirst = testHelper.createRow();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 59d0f91..56ed0e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -18,6 +18,9 @@
 
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -74,7 +77,7 @@
                         mActivityStarterDelegate,
                         mStatusBarStateController,
                         mConfigurationController,
-                        true);
+                        2);
         // Required in order for the header inflation to work properly
         when(mNssl.generateLayoutParams(any(AttributeSet.class)))
                 .thenReturn(new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
@@ -263,8 +266,8 @@
                     when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
                     when(notifRow.getEntry().isHighPriority())
                             .thenReturn(children[i] == ChildType.HIPRI);
-                    when(notifRow.getEntry().isTopBucket())
-                            .thenReturn(children[i] == ChildType.HIPRI);
+                    when(notifRow.getEntry().getBucket()).thenReturn(
+                            children[i] == ChildType.HIPRI ? BUCKET_ALERTING : BUCKET_SILENT);
                     when(notifRow.getParent()).thenReturn(mNssl);
                     child = notifRow;
                     break;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 5d3cdc8..2623b46 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -243,7 +243,7 @@
     }
 
     @Test
-    public void transitionToPulsing_withFrontAlphaUpdates() {
+    public void transitionToPulsing() {
         // Pre-condition
         // Need to go to AoD first because PULSING doesn't change
         // the back scrim opacity - otherwise it would hide AoD wallpapers.
@@ -267,22 +267,11 @@
                 true /* behind */,
                 false /* bubble */);
 
-        // ... and when ambient goes dark, front scrim should be semi-transparent
-        mScrimController.setAodFrontScrimAlpha(0.5f);
-        mScrimController.finishAnimationsImmediately();
-        // Front scrim should be semi-transparent
-        assertScrimAlpha(SEMI_TRANSPARENT /* front */,
-                OPAQUE /* back */,
-                TRANSPARENT /* bubble */);
-
         mScrimController.setWakeLockScreenSensorActive(true);
         mScrimController.finishAnimationsImmediately();
-        assertScrimAlpha(SEMI_TRANSPARENT /* front */,
+        assertScrimAlpha(TRANSPARENT /* front */,
                 SEMI_TRANSPARENT /* back */,
                 TRANSPARENT /* bubble */);
-
-        // Reset value since enums are static.
-        mScrimController.setAodFrontScrimAlpha(0f);
     }
 
     @Test
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index cdb062d..4f021ad 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -23,7 +23,7 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
 
-import android.accessibilityservice.AccessibilityGestureInfo;
+import android.accessibilityservice.AccessibilityGestureEvent;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.accessibilityservice.IAccessibilityServiceConnection;
@@ -1173,9 +1173,9 @@
         }
     }
 
-    public void notifyGesture(AccessibilityGestureInfo gestureInfo) {
+    public void notifyGesture(AccessibilityGestureEvent gestureEvent) {
         mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE,
-                gestureInfo).sendToTarget();
+                gestureEvent).sendToTarget();
     }
 
     public void notifyClearAccessibilityNodeInfoCache() {
@@ -1264,7 +1264,7 @@
         }
     }
 
-    private void notifyGestureInternal(AccessibilityGestureInfo gestureInfo) {
+    private void notifyGestureInternal(AccessibilityGestureEvent gestureInfo) {
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
@@ -1469,7 +1469,7 @@
             final int type = message.what;
             switch (type) {
                 case MSG_ON_GESTURE: {
-                    notifyGestureInternal((AccessibilityGestureInfo) message.obj);
+                    notifyGestureInternal((AccessibilityGestureEvent) message.obj);
                 } break;
 
                 case MSG_CLEAR_ACCESSIBILITY_CACHE: {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index feb7329..ba4d89c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -27,7 +27,7 @@
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
 import android.Manifest;
-import android.accessibilityservice.AccessibilityGestureInfo;
+import android.accessibilityservice.AccessibilityGestureEvent;
 import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.IAccessibilityServiceClient;
@@ -828,12 +828,17 @@
         }
     }
 
-
-    public boolean onGesture(AccessibilityGestureInfo gestureInfo) {
+    /**
+     * Called when a gesture is detected on a display.
+     *
+     * @param gestureEvent the detail of the gesture.
+     * @return true if the event is handled.
+     */
+    public boolean onGesture(AccessibilityGestureEvent gestureEvent) {
         synchronized (mLock) {
-            boolean handled = notifyGestureLocked(gestureInfo, false);
+            boolean handled = notifyGestureLocked(gestureEvent, false);
             if (!handled) {
-                handled = notifyGestureLocked(gestureInfo, true);
+                handled = notifyGestureLocked(gestureEvent, true);
             }
             return handled;
         }
@@ -1028,7 +1033,7 @@
         }
     }
 
-    private boolean notifyGestureLocked(AccessibilityGestureInfo gestureInfo, boolean isDefault) {
+    private boolean notifyGestureLocked(AccessibilityGestureEvent gestureEvent, boolean isDefault) {
         // TODO: Now we are giving the gestures to the last enabled
         //       service that can handle them which is the last one
         //       in our list since we write the last enabled as the
@@ -1042,7 +1047,7 @@
         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
             AccessibilityServiceConnection service = state.mBoundServices.get(i);
             if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) {
-                service.notifyGesture(gestureInfo);
+                service.notifyGesture(gestureEvent);
                 return true;
             }
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java
index 9101a01..7e8fb29 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java
@@ -16,7 +16,7 @@
 
 package com.android.server.accessibility.gestures;
 
-import android.accessibilityservice.AccessibilityGestureInfo;
+import android.accessibilityservice.AccessibilityGestureEvent;
 import android.accessibilityservice.AccessibilityService;
 import android.content.Context;
 import android.gesture.GesturePoint;
@@ -119,11 +119,11 @@
         /**
          * Called when an event stream is recognized as a gesture.
          *
-         * @param gestureInfo Information about the gesture.
+         * @param gestureEvent Information about the gesture.
          *
          * @return true if the event is consumed, else false
          */
-        boolean onGestureCompleted(AccessibilityGestureInfo gestureInfo);
+        boolean onGestureCompleted(AccessibilityGestureEvent gestureEvent);
 
         /**
          * Called when the system has decided an event stream doesn't match any
@@ -567,19 +567,19 @@
             switch (direction) {
                 case LEFT:
                     return mListener.onGestureCompleted(
-                            new AccessibilityGestureInfo(AccessibilityService.GESTURE_SWIPE_LEFT,
+                            new AccessibilityGestureEvent(AccessibilityService.GESTURE_SWIPE_LEFT,
                                     displayId));
                 case RIGHT:
                     return mListener.onGestureCompleted(
-                            new AccessibilityGestureInfo(AccessibilityService.GESTURE_SWIPE_RIGHT,
+                            new AccessibilityGestureEvent(AccessibilityService.GESTURE_SWIPE_RIGHT,
                                     displayId));
                 case UP:
                     return mListener.onGestureCompleted(
-                            new AccessibilityGestureInfo(AccessibilityService.GESTURE_SWIPE_UP,
+                            new AccessibilityGestureEvent(AccessibilityService.GESTURE_SWIPE_UP,
                                     displayId));
                 case DOWN:
                     return mListener.onGestureCompleted(
-                            new AccessibilityGestureInfo(AccessibilityService.GESTURE_SWIPE_DOWN,
+                            new AccessibilityGestureEvent(AccessibilityService.GESTURE_SWIPE_DOWN,
                                     displayId));
                 default:
                     // Do nothing.
@@ -600,7 +600,7 @@
             int segmentDirection1 = toDirection(dX1, dY1);
             int gestureId = DIRECTIONS_TO_GESTURE_ID[segmentDirection0][segmentDirection1];
             return mListener.onGestureCompleted(
-                    new AccessibilityGestureInfo(gestureId, displayId));
+                    new AccessibilityGestureEvent(gestureId, displayId));
         }
         // else if (path.size() < 2 || 3 < path.size()) then no gesture recognized.
         return mListener.onGestureCancelled(event, policyFlags);
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index a338b90..7044c4d 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -20,7 +20,7 @@
 
 import static com.android.server.accessibility.gestures.TouchState.ALL_POINTER_ID_BITS;
 
-import android.accessibilityservice.AccessibilityGestureInfo;
+import android.accessibilityservice.AccessibilityGestureEvent;
 import android.content.Context;
 import android.graphics.Point;
 import android.os.Handler;
@@ -343,14 +343,14 @@
     }
 
     @Override
-    public boolean onGestureCompleted(AccessibilityGestureInfo gestureInfo) {
+    public boolean onGestureCompleted(AccessibilityGestureEvent gestureEvent) {
         if (!mState.isGestureDetecting()) {
             return false;
         }
 
         endGestureDetection(true);
 
-        mAms.onGesture(gestureInfo);
+        mAms.onGesture(gestureEvent);
 
         return true;
     }
diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java
index 79b1226..6bc1a57 100644
--- a/services/core/java/com/android/server/MountServiceIdler.java
+++ b/services/core/java/com/android/server/MountServiceIdler.java
@@ -99,32 +99,28 @@
     public static void scheduleIdlePass(Context context) {
         JobScheduler tm = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
 
-        final long today3AM = MidnightInTime(0, 0).getTimeInMillis();
-        final long today4AM = MidnightInTime(0, 1).getTimeInMillis();
+        final long today3AM = offsetFromTodayMidnight(0, 3).getTimeInMillis();
+        final long today4AM = offsetFromTodayMidnight(0, 4).getTimeInMillis();
+        final long tomorrow3AM = offsetFromTodayMidnight(1, 3).getTimeInMillis();
 
-        long nextScheduleTime, maxScheduleTime;
+        long nextScheduleTime;
         if (System.currentTimeMillis() > today3AM && System.currentTimeMillis() < today4AM) {
             nextScheduleTime = TimeUnit.SECONDS.toMillis(10);
-            maxScheduleTime = today4AM - System.currentTimeMillis();
         } else {
-            final long tomorrow3AM = MidnightInTime(1, 0).getTimeInMillis();
-            final long twodays3AM = MidnightInTime(2, 0).getTimeInMillis();
             nextScheduleTime = tomorrow3AM - System.currentTimeMillis(); // 3AM tomorrow
-            maxScheduleTime = twodays3AM - System.currentTimeMillis();   // 3AM in two days
         }
 
         JobInfo.Builder builder = new JobInfo.Builder(MOUNT_JOB_ID, sIdleService);
         builder.setRequiresDeviceIdle(true);
-        builder.setRequiresCharging(true);
+        builder.setRequiresBatteryNotLow(true);
         builder.setMinimumLatency(nextScheduleTime);
-        builder.setOverrideDeadline(maxScheduleTime);
         tm.schedule(builder.build());
     }
 
-    private static Calendar MidnightInTime(int nDays, int nHours) {
+    private static Calendar offsetFromTodayMidnight(int nDays, int nHours) {
         Calendar calendar = Calendar.getInstance();
         calendar.setTimeInMillis(System.currentTimeMillis());
-        calendar.set(Calendar.HOUR_OF_DAY, 3 + nHours);
+        calendar.set(Calendar.HOUR_OF_DAY, nHours);
         calendar.set(Calendar.MINUTE, 0);
         calendar.set(Calendar.SECOND, 0);
         calendar.set(Calendar.MILLISECOND, 0);
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 4403efc..bc50956 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -87,6 +87,8 @@
     // Number of package failures within the duration above before we notify observers
     @VisibleForTesting
     static final int DEFAULT_TRIGGER_FAILURE_COUNT = 5;
+    @VisibleForTesting
+    static final long DEFAULT_OBSERVING_DURATION_MS = TimeUnit.DAYS.toMillis(2);
     // Whether explicit health checks are enabled or not
     private static final boolean DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED = true;
 
@@ -225,8 +227,10 @@
      * check state will be reset to a default depending on if the package is contained in
      * {@link mPackagesWithExplicitHealthCheckEnabled}.
      *
-     * @throws IllegalArgumentException if {@code packageNames} is empty
-     * or {@code durationMs} is less than 1
+     * <p>If {@code packageNames} is empty, this will be a no-op.
+     *
+     * <p>If {@code durationMs} is less than 1, a default monitoring duration
+     * {@link #DEFAULT_OBSERVING_DURATION_MS} will be used.
      */
     public void startObservingHealth(PackageHealthObserver observer, List<String> packageNames,
             long durationMs) {
@@ -235,9 +239,9 @@
             return;
         }
         if (durationMs < 1) {
-            // TODO: Instead of failing, monitor for default? 48hrs?
-            throw new IllegalArgumentException("Invalid duration " + durationMs + "ms for observer "
+            Slog.wtf(TAG, "Invalid duration " + durationMs + "ms for observer "
                     + observer.getName() + ". Not observing packages " + packageNames);
+            durationMs = DEFAULT_OBSERVING_DURATION_MS;
         }
 
         List<MonitoredPackage> packages = new ArrayList<>();
@@ -808,7 +812,6 @@
      */
     private static class ObserverInternal {
         public final String name;
-        //TODO(b/120598832): Add getter for mPackages
         @GuardedBy("mLock")
         public final ArrayMap<String, MonitoredPackage> packages = new ArrayMap<>();
         @Nullable
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 1675b94..e7569be 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1748,8 +1748,8 @@
                     s.instanceName, s.processName);
             // Once the apps have become associated, if one of them is caller is ephemeral
             // the target app should now be able to see the calling app
-            mAm.grantEphemeralAccessLocked(callerApp.userId, service,
-                    UserHandle.getAppId(s.appInfo.uid), UserHandle.getAppId(callerApp.uid));
+            mAm.grantImplicitAccess(callerApp.userId, service,
+                    UserHandle.getAppId(callerApp.uid), UserHandle.getAppId(s.appInfo.uid));
 
             AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
             ConnectionRecord c = new ConnectionRecord(b, activity,
@@ -2802,8 +2802,9 @@
                 mAm.mUgmInternal.grantUriPermissionUncheckedFromIntent(si.neededGrants,
                         si.getUriPermissionsLocked());
             }
-            mAm.grantEphemeralAccessLocked(r.userId, si.intent, UserHandle.getAppId(r.appInfo.uid),
-                    UserHandle.getAppId(si.callingId));
+            mAm.grantImplicitAccess(r.userId, si.intent, UserHandle.getAppId(si.callingId),
+                    UserHandle.getAppId(r.appInfo.uid)
+            );
             bumpServiceExecutingLocked(r, execInFg, "start");
             if (!oomAdjusted) {
                 oomAdjusted = true;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 55d422d..217a6c6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6115,10 +6115,9 @@
     }
 
     @VisibleForTesting
-    public void grantEphemeralAccessLocked(int userId, Intent intent,
-            int targetAppId, int ephemeralAppId) {
+    public void grantImplicitAccess(int userId, Intent intent, int callingAppId, int targetAppId) {
         getPackageManagerInternalLocked().
-                grantEphemeralAccess(userId, intent, targetAppId, ephemeralAppId);
+                grantImplicitAccess(userId, intent, callingAppId, targetAppId);
     }
 
     /**
@@ -7088,9 +7087,10 @@
             }
             checkTime(startTime, "getContentProviderImpl: done!");
 
-            grantEphemeralAccessLocked(userId, null /*intent*/,
-                    UserHandle.getAppId(cpi.applicationInfo.uid),
-                    UserHandle.getAppId(Binder.getCallingUid()));
+            grantImplicitAccess(userId, null /*intent*/,
+                    UserHandle.getAppId(Binder.getCallingUid()),
+                    UserHandle.getAppId(cpi.applicationInfo.uid)
+            );
         }
 
         // Wait for the provider to be published...
@@ -19296,12 +19296,6 @@
             // null permissions means all permissions are targeted
             return (mPermissions == null || ArrayUtils.contains(mPermissions, permission));
         }
-
-        @Override
-        public String toString() {
-            return "ShellDelegate{targetPackageName=" + mTargetPackageName
-                    + ", permissions=" + mPermissions + "}";
-        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index fc38735..81e507c 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -19,7 +19,9 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.util.Slog;
+import android.util.StatsLog;
 
+import com.android.internal.compat.ChangeReporter;
 import com.android.internal.compat.IPlatformCompat;
 import com.android.internal.util.DumpUtils;
 
@@ -34,23 +36,27 @@
     private static final String TAG = "Compatibility";
 
     private final Context mContext;
+    private final ChangeReporter mChangeReporter;
 
     public PlatformCompat(Context context) {
         mContext = context;
+        mChangeReporter = new ChangeReporter();
     }
 
     @Override
     public void reportChange(long changeId, ApplicationInfo appInfo) {
-        Slog.d(TAG, "Compat change reported: " + changeId + "; UID " + appInfo.uid);
-        // TODO log via StatsLog
+        reportChange(changeId, appInfo, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED);
     }
 
     @Override
     public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
         if (CompatConfig.get().isChangeEnabled(changeId, appInfo)) {
-            reportChange(changeId, appInfo);
+            reportChange(changeId, appInfo,
+                    StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED);
             return true;
         }
+        reportChange(changeId, appInfo,
+                StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__DISABLED);
         return false;
     }
 
@@ -59,4 +65,13 @@
         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
         CompatConfig.get().dumpConfig(pw);
     }
+
+    private void reportChange(long changeId, ApplicationInfo appInfo, int state) {
+        int uid = appInfo.uid;
+        //TODO(b/138374585): Implement rate limiting for the logs.
+        Slog.d(TAG, ChangeReporter.createLogString(uid, changeId, state));
+        mChangeReporter.reportChange(uid, changeId,
+                state, /* source */
+                StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER);
+    }
 }
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 48678bf..ab46daf 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -246,25 +246,25 @@
     }
 
     /**
-     * Marks that a package initiated an interaction with another package, granting visibility of
-     * the prior from the former.
+     * Grants access based on an interaction between a calling and target package, granting
+     * visibility of the caller from the target.
      *
-     * @param initiatingPackage the package initiating the interaction
+     * @param callingPackage    the package initiating the interaction
      * @param targetPackage     the package being interacted with and thus gaining visibility of the
      *                          initiating package.
      * @param userId            the user in which this interaction was taking place
      */
-    private void markAppInteraction(
-            PackageSetting initiatingPackage, PackageSetting targetPackage, int userId) {
+    public void grantImplicitAccess(
+            String callingPackage, String targetPackage, int userId) {
         HashMap<String, Set<String>> currentUser = mImplicitlyQueryable.get(userId);
         if (currentUser == null) {
             currentUser = new HashMap<>();
             mImplicitlyQueryable.put(userId, currentUser);
         }
-        if (!currentUser.containsKey(targetPackage.pkg.packageName)) {
-            currentUser.put(targetPackage.pkg.packageName, new HashSet<>());
+        if (!currentUser.containsKey(targetPackage)) {
+            currentUser.put(targetPackage, new HashSet<>());
         }
-        currentUser.get(targetPackage.pkg.packageName).add(initiatingPackage.pkg.packageName);
+        currentUser.get(targetPackage).add(callingPackage);
     }
 
     public void onSystemReady() {
@@ -374,8 +374,6 @@
             callingPkgSetting = (PackageSetting) callingSetting;
             if (!shouldFilterApplicationInternal(callingPkgSetting, targetPkgSetting,
                     userId)) {
-                // TODO: actually base this on a start / launch (not just a query)
-                markAppInteraction(callingPkgSetting, targetPkgSetting, userId);
                 return false;
             }
         } else if (callingSetting instanceof SharedUserSetting) {
@@ -386,8 +384,6 @@
                     final PackageSetting packageSetting = packageSettings.valueAt(i);
                     if (!shouldFilterApplicationInternal(packageSetting, targetPkgSetting,
                             userId)) {
-                        // TODO: actually base this on a start / launch (not just a query)
-                        markAppInteraction(packageSetting, targetPkgSetting, userId);
                         return false;
                     }
                     if (callingPkgSetting == null && packageSetting.pkg != null) {
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 5eaddf9..9e04c4b 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -401,7 +401,7 @@
 
     @GuardedBy("mService.mLock")
     public void grantInstantAccessLPw(@UserIdInt int userId, @Nullable Intent intent,
-            int targetAppId, int instantAppId) {
+            int instantAppId, int targetAppId) {
         if (mInstalledInstantAppUids == null) {
             return;     // no instant apps installed; no need to grant
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 58596aa..fe3d2c8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -23380,11 +23380,24 @@
         }
 
         @Override
-        public void grantEphemeralAccess(int userId, Intent intent,
-                int targetAppId, int ephemeralAppId) {
+        public void grantImplicitAccess(int userId, Intent intent,
+                int callingAppId, int targetAppId) {
             synchronized (mLock) {
-                mInstantAppRegistry.grantInstantAccessLPw(userId, intent,
-                        targetAppId, ephemeralAppId);
+                final PackageParser.Package callingPackage = getPackage(
+                        UserHandle.getUid(userId, callingAppId));
+                final PackageParser.Package targetPackage = getPackage(
+                        UserHandle.getUid(userId, targetAppId));
+                if (callingPackage == null || targetPackage == null) {
+                    return;
+                }
+
+                if (isInstantApp(callingPackage.packageName, userId)) {
+                    mInstantAppRegistry.grantInstantAccessLPw(userId, intent,
+                            callingAppId, targetAppId);
+                } else {
+                    mAppsFilter.grantImplicitAccess(
+                            callingPackage.packageName, targetPackage.packageName, userId);
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 226adc8..a57321e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -793,62 +793,68 @@
 
         final CheckPermissionDelegate checkPermissionDelegate;
         synchronized (mLock) {
-            if (mCheckPermissionDelegate == null)  {
-                return checkPermissionImpl(permName, pkgName, userId);
-            }
             checkPermissionDelegate = mCheckPermissionDelegate;
         }
+        if (checkPermissionDelegate == null)  {
+            return checkPermissionImpl(permName, pkgName, userId);
+        }
         return checkPermissionDelegate.checkPermission(permName, pkgName, userId,
-                PermissionManagerService.this::checkPermissionImpl);
+                this::checkPermissionImpl);
     }
 
-    private int checkPermissionImpl(String permName, String pkgName, int userId) {
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(pkgName);
+    private int checkPermissionImpl(@NonNull String permissionName, @NonNull String packageName,
+            @UserIdInt int userId) {
+        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null) {
             return PackageManager.PERMISSION_DENIED;
         }
-        return checkPermissionInternal(pkg, true, permName, userId);
+        return checkPermissionInternal(pkg, true, permissionName, true, userId)
+                ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED;
     }
 
-    private int checkPermissionInternal(@NonNull Package pkg, boolean isPackageExplicit,
-            @NonNull String permissionName, @UserIdInt int userId) {
+    private boolean checkPermissionInternal(@NonNull Package pkg, boolean isPackageExplicit,
+            @NonNull String permissionName, boolean useRequestedPermissionsForLegacyApps,
+            @UserIdInt int userId) {
         final int callingUid = getCallingUid();
         if (isPackageExplicit || pkg.mSharedUserId == null) {
             if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
-                return PackageManager.PERMISSION_DENIED;
+                return false;
             }
         } else {
             if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
-                return PackageManager.PERMISSION_DENIED;
+                return false;
             }
         }
 
         final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
         final PackageSetting ps = (PackageSetting) pkg.mExtras;
         if (ps == null) {
-            return PackageManager.PERMISSION_DENIED;
+            return false;
         }
         final PermissionsState permissionsState = ps.getPermissionsState();
 
-        if (checkSinglePermissionInternal(uid, permissionsState, permissionName)) {
-            return PackageManager.PERMISSION_GRANTED;
+        if (checkSinglePermissionInternal(uid, permissionsState, permissionName,
+                useRequestedPermissionsForLegacyApps)) {
+            return true;
         }
 
         final String fullerPermissionName = FULLER_PERMISSION_MAP.get(permissionName);
-        if (fullerPermissionName != null
-                && checkSinglePermissionInternal(uid, permissionsState, fullerPermissionName)) {
-            return PackageManager.PERMISSION_GRANTED;
+        if (fullerPermissionName != null && checkSinglePermissionInternal(uid, permissionsState,
+                fullerPermissionName, useRequestedPermissionsForLegacyApps)) {
+            return true;
         }
 
-        return PackageManager.PERMISSION_DENIED;
+        return false;
     }
 
     private boolean checkSinglePermissionInternal(int uid,
-            @NonNull PermissionsState permissionsState, @NonNull String permissionName) {
+            @NonNull PermissionsState permissionsState, @NonNull String permissionName,
+            boolean useRequestedPermissionsForLegacyApps) {
         boolean hasPermission = permissionsState.hasPermission(permissionName,
                 UserHandle.getUserId(uid));
 
-        if (!hasPermission && mSettings.isPermissionRuntime(permissionName)) {
+        if (!hasPermission && useRequestedPermissionsForLegacyApps
+                && mSettings.isPermissionRuntime(permissionName)) {
             final String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
             final int packageNamesSize = packageNames != null ? packageNames.length : 0;
             for (int i = 0; i < packageNamesSize; i++) {
@@ -891,12 +897,13 @@
             checkPermissionDelegate = mCheckPermissionDelegate;
         }
         return checkPermissionDelegate.checkUidPermission(permName, uid,
-                PermissionManagerService.this::checkUidPermissionImpl);
+                this::checkUidPermissionImpl);
     }
 
-    private int checkUidPermissionImpl(String permName, int uid) {
+    private int checkUidPermissionImpl(@NonNull String permissionName, int uid) {
         final PackageParser.Package pkg = mPackageManagerInt.getPackage(uid);
-        return checkUidPermissionInternal(pkg, uid, permName);
+        return checkUidPermissionInternal(uid, pkg, permissionName, true)
+                ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED;
     }
 
     /**
@@ -906,24 +913,25 @@
      *
      * @see SystemConfig#getSystemPermissions()
      */
-    private int checkUidPermissionInternal(@Nullable Package pkg, int uid,
-            @NonNull String permissionName) {
+    private boolean checkUidPermissionInternal(int uid, @Nullable Package pkg,
+            @NonNull String permissionName, boolean useRequestedPermissionsForLegacyApps) {
         if (pkg != null) {
             final int userId = UserHandle.getUserId(uid);
-            return checkPermissionInternal(pkg, false, permissionName, userId);
+            return checkPermissionInternal(pkg, false, permissionName,
+                    useRequestedPermissionsForLegacyApps, userId);
         }
 
         if (checkSingleUidPermissionInternal(uid, permissionName)) {
-            return PackageManager.PERMISSION_GRANTED;
+            return true;
         }
 
         final String fullerPermissionName = FULLER_PERMISSION_MAP.get(permissionName);
         if (fullerPermissionName != null
                 && checkSingleUidPermissionInternal(uid, fullerPermissionName)) {
-            return PackageManager.PERMISSION_GRANTED;
+            return true;
         }
 
-        return PackageManager.PERMISSION_DENIED;
+        return false;
     }
 
     private boolean checkSingleUidPermissionInternal(int uid, @NonNull String permissionName) {
@@ -933,6 +941,17 @@
         }
     }
 
+    private int computeRuntimePermissionAppOpMode(int uid, @NonNull String permissionName) {
+        boolean granted = isUidPermissionGranted(uid, permissionName);
+        // TODO: Foreground permissions.
+        return granted ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
+    }
+
+    private boolean isUidPermissionGranted(int uid, @NonNull String permissionName) {
+        final PackageParser.Package pkg = mPackageManagerInt.getPackage(uid);
+        return checkUidPermissionInternal(uid, pkg, permissionName, false);
+    }
+
     @Override
     public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
         mContext.enforceCallingOrSelfPermission(
@@ -4283,7 +4302,6 @@
         public void setCheckPermissionDelegate(CheckPermissionDelegate delegate) {
             synchronized (mLock) {
                 mCheckPermissionDelegate = delegate;
-                Slog.d(TAG, "CheckPermissionDelegate set to " + delegate);
             }
         }
 
@@ -4447,6 +4465,12 @@
                         StorageManager.UUID_PRIVATE_INTERNAL, true, mDefaultPermissionCallback);
             }
         }
+
+        @Override
+        public int computeRuntimePermissionAppOpMode(int uid, @NonNull String permissionName) {
+            return PermissionManagerService.this.computeRuntimePermissionAppOpMode(uid,
+                    permissionName);
+        }
     }
 
     private static final class OnPermissionChangeListeners extends Handler {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 04ec5ba..8f22f92 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -445,4 +445,13 @@
 
     /** Called when a new user has been created. */
     public abstract void onNewUserCreated(@UserIdInt int userId);
+
+    /**
+     * Compute an app op mode based on its runtime permission state.
+     *
+     * @param uid the uid for the app op
+     * @param permissionName the permission name for the app op
+     * @return the computed mode
+     */
+    public abstract int computeRuntimePermissionAppOpMode(int uid, @NonNull String permissionName);
 }
diff --git a/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java b/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java
index b27d5ea..f8ffb7c 100644
--- a/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java
+++ b/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java
@@ -23,7 +23,6 @@
 import android.media.tv.ITvRemoteProvider;
 import android.media.tv.ITvRemoteServiceInput;
 import android.os.Binder;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -49,7 +48,6 @@
     private final ComponentName mComponentName;
     private final int mUserId;
     private final int mUid;
-    private final Handler mHandler;
 
     /**
      * State guarded by mLock.
@@ -65,15 +63,14 @@
     private boolean mRunning;
     private boolean mBound;
     private Connection mActiveConnection;
-    private boolean mConnectionReady;
 
-    public TvRemoteProviderProxy(Context context, ComponentName componentName, int userId,
-                                 int uid) {
+    TvRemoteProviderProxy(Context context, ProviderMethods provider,
+                          ComponentName componentName, int userId, int uid) {
         mContext = context;
+        mProviderMethods = provider;
         mComponentName = componentName;
         mUserId = userId;
         mUid = uid;
-        mHandler = new Handler();
     }
 
     public void dump(PrintWriter pw, String prefix) {
@@ -82,11 +79,6 @@
         pw.println(prefix + "  mRunning=" + mRunning);
         pw.println(prefix + "  mBound=" + mBound);
         pw.println(prefix + "  mActiveConnection=" + mActiveConnection);
-        pw.println(prefix + "  mConnectionReady=" + mConnectionReady);
-    }
-
-    public void setProviderSink(ProviderMethods provider) {
-        mProviderMethods = provider;
     }
 
     public boolean hasComponentName(String packageName, String className) {
@@ -101,7 +93,7 @@
             }
 
             mRunning = true;
-            updateBinding();
+            bind();
         }
     }
 
@@ -112,31 +104,19 @@
             }
 
             mRunning = false;
-            updateBinding();
+            unbind();
         }
     }
 
     public void rebindIfDisconnected() {
         synchronized (mLock) {
-            if (mActiveConnection == null && shouldBind()) {
+            if (mActiveConnection == null && mRunning) {
                 unbind();
                 bind();
             }
         }
     }
 
-    private void updateBinding() {
-        if (shouldBind()) {
-            bind();
-        } else {
-            unbind();
-        }
-    }
-
-    private boolean shouldBind() {
-        return mRunning;
-    }
-
     private void bind() {
         if (!mBound) {
             if (DEBUG) {
@@ -208,48 +188,19 @@
         disconnect();
     }
 
-
-    private void onConnectionReady(Connection connection) {
-        synchronized (mLock) {
-            if (DEBUG) Slog.d(TAG, "onConnectionReady");
-            if (mActiveConnection == connection) {
-                if (DEBUG) Slog.d(TAG, "mConnectionReady = true");
-                mConnectionReady = true;
-            }
-        }
-    }
-
-    private void onConnectionDied(Connection connection) {
-        if (mActiveConnection == connection) {
-            if (DEBUG) Slog.d(TAG, this + ": Service connection died");
-            disconnect();
-        }
-    }
-
     private void disconnect() {
         synchronized (mLock) {
             if (mActiveConnection != null) {
-                mConnectionReady = false;
                 mActiveConnection.dispose();
                 mActiveConnection = null;
             }
         }
     }
 
-    // Provider helpers
-    public void inputBridgeConnected(IBinder token) {
-        synchronized (mLock) {
-            if (DEBUG) Slog.d(TAG, this + ": inputBridgeConnected token: " + token);
-            if (mConnectionReady) {
-                mActiveConnection.onInputBridgeConnected(token);
-            }
-        }
-    }
-
-    public interface ProviderMethods {
+    interface ProviderMethods {
         // InputBridge
-        void openInputBridge(TvRemoteProviderProxy provider, IBinder token, String name,
-                             int width, int height, int maxPointers);
+        boolean openInputBridge(TvRemoteProviderProxy provider, IBinder token, String name,
+                                int width, int height, int maxPointers);
 
         void closeInputBridge(TvRemoteProviderProxy provider, IBinder token);
 
@@ -267,7 +218,7 @@
         void sendPointerSync(TvRemoteProviderProxy provider, IBinder token);
     }
 
-    private final class Connection implements IBinder.DeathRecipient {
+    private final class Connection {
         private final ITvRemoteProvider mTvRemoteProvider;
         private final RemoteServiceInputProvider mServiceInputProvider;
 
@@ -279,24 +230,16 @@
         public boolean register() {
             if (DEBUG) Slog.d(TAG, "Connection::register()");
             try {
-                mTvRemoteProvider.asBinder().linkToDeath(this, 0);
                 mTvRemoteProvider.setRemoteServiceInputSink(mServiceInputProvider);
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        onConnectionReady(Connection.this);
-                    }
-                });
                 return true;
             } catch (RemoteException ex) {
-                binderDied();
+                dispose();
+                return false;
             }
-            return false;
         }
 
         public void dispose() {
             if (DEBUG) Slog.d(TAG, "Connection::dispose()");
-            mTvRemoteProvider.asBinder().unlinkToDeath(this, 0);
             mServiceInputProvider.dispose();
         }
 
@@ -310,16 +253,6 @@
             }
         }
 
-        @Override
-        public void binderDied() {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    onConnectionDied(Connection.this);
-                }
-            });
-        }
-
         void openInputBridge(final IBinder token, final String name, final int width,
                              final int height, final int maxPointers) {
             synchronized (mLock) {
@@ -330,9 +263,9 @@
                     }
                     final long idToken = Binder.clearCallingIdentity();
                     try {
-                        if (mProviderMethods != null) {
-                            mProviderMethods.openInputBridge(TvRemoteProviderProxy.this, token,
-                                    name, width, height, maxPointers);
+                        if (mProviderMethods.openInputBridge(TvRemoteProviderProxy.this, token,
+                                                             name, width, height, maxPointers)) {
+                            onInputBridgeConnected(token);
                         }
                     } finally {
                         Binder.restoreCallingIdentity(idToken);
@@ -356,9 +289,7 @@
                     }
                     final long idToken = Binder.clearCallingIdentity();
                     try {
-                        if (mProviderMethods != null) {
-                            mProviderMethods.closeInputBridge(TvRemoteProviderProxy.this, token);
-                        }
+                        mProviderMethods.closeInputBridge(TvRemoteProviderProxy.this, token);
                     } finally {
                         Binder.restoreCallingIdentity(idToken);
                     }
@@ -381,9 +312,7 @@
                     }
                     final long idToken = Binder.clearCallingIdentity();
                     try {
-                        if (mProviderMethods != null) {
-                            mProviderMethods.clearInputBridge(TvRemoteProviderProxy.this, token);
-                        }
+                        mProviderMethods.clearInputBridge(TvRemoteProviderProxy.this, token);
                     } finally {
                         Binder.restoreCallingIdentity(idToken);
                     }
@@ -412,10 +341,7 @@
                     }
                     final long idToken = Binder.clearCallingIdentity();
                     try {
-                        if (mProviderMethods != null) {
-                            mProviderMethods.sendKeyDown(TvRemoteProviderProxy.this, token,
-                                    keyCode);
-                        }
+                        mProviderMethods.sendKeyDown(TvRemoteProviderProxy.this, token, keyCode);
                     } finally {
                         Binder.restoreCallingIdentity(idToken);
                     }
@@ -438,9 +364,7 @@
                     }
                     final long idToken = Binder.clearCallingIdentity();
                     try {
-                        if (mProviderMethods != null) {
-                            mProviderMethods.sendKeyUp(TvRemoteProviderProxy.this, token, keyCode);
-                        }
+                        mProviderMethods.sendKeyUp(TvRemoteProviderProxy.this, token, keyCode);
                     } finally {
                         Binder.restoreCallingIdentity(idToken);
                     }
@@ -463,10 +387,8 @@
                     }
                     final long idToken = Binder.clearCallingIdentity();
                     try {
-                        if (mProviderMethods != null) {
-                            mProviderMethods.sendPointerDown(TvRemoteProviderProxy.this, token,
-                                    pointerId, x, y);
-                        }
+                        mProviderMethods.sendPointerDown(TvRemoteProviderProxy.this, token,
+                                pointerId, x, y);
                     } finally {
                         Binder.restoreCallingIdentity(idToken);
                     }
@@ -489,10 +411,8 @@
                     }
                     final long idToken = Binder.clearCallingIdentity();
                     try {
-                        if (mProviderMethods != null) {
-                            mProviderMethods.sendPointerUp(TvRemoteProviderProxy.this, token,
-                                    pointerId);
-                        }
+                        mProviderMethods.sendPointerUp(TvRemoteProviderProxy.this, token,
+                                pointerId);
                     } finally {
                         Binder.restoreCallingIdentity(idToken);
                     }
diff --git a/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java b/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java
index d27970f..0d29edd 100644
--- a/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java
+++ b/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java
@@ -45,7 +45,7 @@
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
 
     private final Context mContext;
-    private final ProviderMethods mProvider;
+    private final TvRemoteProviderProxy.ProviderMethods mProvider;
     private final Handler mHandler;
     private final PackageManager mPackageManager;
     private final ArrayList<TvRemoteProviderProxy> mProviderProxies = new ArrayList<>();
@@ -54,10 +54,10 @@
 
     private boolean mRunning;
 
-    public TvRemoteProviderWatcher(Context context, ProviderMethods provider, Handler handler) {
+    TvRemoteProviderWatcher(Context context, TvRemoteProviderProxy.ProviderMethods provider) {
         mContext = context;
         mProvider = provider;
-        mHandler = handler;
+        mHandler = new Handler(true);
         mUserId = UserHandle.myUserId();
         mPackageManager = context.getPackageManager();
         mUnbundledServicePackage = context.getString(
@@ -116,12 +116,11 @@
                 int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
                 if (sourceIndex < 0) {
                     TvRemoteProviderProxy providerProxy =
-                            new TvRemoteProviderProxy(mContext,
+                            new TvRemoteProviderProxy(mContext, mProvider,
                                     new ComponentName(serviceInfo.packageName, serviceInfo.name),
                                     mUserId, serviceInfo.applicationInfo.uid);
                     providerProxy.start();
                     mProviderProxies.add(targetIndex++, providerProxy);
-                    mProvider.addProvider(providerProxy);
                 } else if (sourceIndex >= targetIndex) {
                     TvRemoteProviderProxy provider = mProviderProxies.get(sourceIndex);
                     provider.start(); // restart the provider if needed
@@ -135,7 +134,6 @@
         if (targetIndex < mProviderProxies.size()) {
             for (int i = mProviderProxies.size() - 1; i >= targetIndex; i--) {
                 TvRemoteProviderProxy providerProxy = mProviderProxies.get(i);
-                mProvider.removeProvider(providerProxy);
                 mProviderProxies.remove(providerProxy);
                 providerProxy.stop();
             }
@@ -212,10 +210,4 @@
             scanPackages();
         }
     };
-
-    public interface ProviderMethods {
-        void addProvider(TvRemoteProviderProxy providerProxy);
-
-        void removeProvider(TvRemoteProviderProxy providerProxy);
-    }
 }
diff --git a/services/core/java/com/android/server/tv/TvRemoteService.java b/services/core/java/com/android/server/tv/TvRemoteService.java
index ba74791..bee6fb3 100644
--- a/services/core/java/com/android/server/tv/TvRemoteService.java
+++ b/services/core/java/com/android/server/tv/TvRemoteService.java
@@ -17,11 +17,8 @@
 package com.android.server.tv;
 
 import android.content.Context;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.os.Looper;
-import android.os.Message;
 import android.util.ArrayMap;
 import android.util.Slog;
 
@@ -29,7 +26,6 @@
 import com.android.server.Watchdog;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Map;
 
 /**
@@ -44,9 +40,8 @@
     private static final boolean DEBUG = false;
     private static final boolean DEBUG_KEYS = false;
 
+    private final TvRemoteProviderWatcher mWatcher;
     private Map<IBinder, UinputBridge> mBridgeMap = new ArrayMap();
-    private Map<IBinder, TvRemoteProviderProxy> mProviderMap = new ArrayMap();
-    private ArrayList<TvRemoteProviderProxy> mProviderList = new ArrayList<>();
 
     /**
      * State guarded by mLock.
@@ -60,11 +55,10 @@
      */
     private final Object mLock = new Object();
 
-    public final UserHandler mHandler;
-
     public TvRemoteService(Context context) {
         super(context);
-        mHandler = new UserHandler(new UserProvider(TvRemoteService.this), context);
+        mWatcher = new TvRemoteProviderWatcher(context,
+                                               new UserProvider(TvRemoteService.this));
         Watchdog.getInstance().addMonitor(this);
     }
 
@@ -80,21 +74,17 @@
 
     @Override
     public void onBootPhase(int phase) {
+        // All lifecycle methods are called from the system server's main looper thread.
         if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             if (DEBUG) Slog.d(TAG, "PHASE_THIRD_PARTY_APPS_CAN_START");
-            mHandler.sendEmptyMessage(UserHandler.MSG_START);
+
+            mWatcher.start(); // Also schedules the start of all providers.
         }
     }
 
-    //Outgoing calls.
-    private void informInputBridgeConnected(IBinder token) {
-        mHandler.obtainMessage(UserHandler.MSG_INPUT_BRIDGE_CONNECTED, 0, 0, token).sendToTarget();
-    }
-
-    // Incoming calls.
-    private void openInputBridgeInternalLocked(TvRemoteProviderProxy provider, final IBinder token,
-                                               String name, int width, int height,
-                                               int maxPointers) {
+    private boolean openInputBridgeInternalLocked(final IBinder token,
+                                                  String name, int width, int height,
+                                                  int maxPointers) {
         if (DEBUG) {
             Slog.d(TAG, "openInputBridgeInternalLocked(), token: " + token + ", name: " + name +
                     ", width: " + width + ", height: " + height + ", maxPointers: " + maxPointers);
@@ -104,15 +94,11 @@
             //Create a new bridge, if one does not exist already
             if (mBridgeMap.containsKey(token)) {
                 if (DEBUG) Slog.d(TAG, "RemoteBridge already exists");
-                // Respond back with success.
-                informInputBridgeConnected(token);
-                return;
+                return true;
             }
 
             UinputBridge inputBridge = new UinputBridge(token, name, width, height, maxPointers);
-
             mBridgeMap.put(token, inputBridge);
-            mProviderMap.put(token, provider);
 
             try {
                 token.linkToDeath(new IBinder.DeathRecipient() {
@@ -126,15 +112,13 @@
             } catch (RemoteException e) {
                 if (DEBUG) Slog.d(TAG, "Token is already dead");
                 closeInputBridgeInternalLocked(token);
-                return;
+                return false;
             }
-
-            // Respond back with success.
-            informInputBridgeConnected(token);
-
         } catch (IOException ioe) {
             Slog.e(TAG, "Cannot create device for " + name);
+            return false;
         }
+        return true;
     }
 
     private void closeInputBridgeInternalLocked(IBinder token) {
@@ -149,7 +133,6 @@
         }
 
         mBridgeMap.remove(token);
-        mProviderMap.remove(token);
     }
 
     private void clearInputBridgeInternalLocked(IBinder token) {
@@ -220,47 +203,7 @@
         }
     }
 
-    private final class UserHandler extends Handler {
-
-        public static final int MSG_START = 1;
-        public static final int MSG_INPUT_BRIDGE_CONNECTED = 2;
-
-        private final TvRemoteProviderWatcher mWatcher;
-        private boolean mRunning;
-
-        public UserHandler(UserProvider provider, Context context) {
-            super(Looper.getMainLooper(), null, true);
-            mWatcher = new TvRemoteProviderWatcher(context, provider, this);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_START: {
-                    start();
-                    break;
-                }
-                case MSG_INPUT_BRIDGE_CONNECTED: {
-                    IBinder token = (IBinder) msg.obj;
-                    TvRemoteProviderProxy provider = mProviderMap.get(token);
-                    if (provider != null) {
-                        provider.inputBridgeConnected(token);
-                    }
-                    break;
-                }
-            }
-        }
-
-        private void start() {
-            if (!mRunning) {
-                mRunning = true;
-                mWatcher.start(); // also starts all providers
-            }
-        }
-    }
-
-    private final class UserProvider implements TvRemoteProviderWatcher.ProviderMethods,
-            TvRemoteProviderProxy.ProviderMethods {
+    private final class UserProvider implements TvRemoteProviderProxy.ProviderMethods {
 
         private final TvRemoteService mService;
 
@@ -269,8 +212,8 @@
         }
 
         @Override
-        public void openInputBridge(TvRemoteProviderProxy provider, IBinder token, String name,
-                                    int width, int height, int maxPointers) {
+        public boolean openInputBridge(TvRemoteProviderProxy provider, IBinder token, String name,
+                                       int width, int height, int maxPointers) {
             if (DEBUG) {
                 Slog.d(TAG, "openInputBridge(), token: " + token +
                         ", name: " + name + ", width: " + width +
@@ -278,10 +221,8 @@
             }
 
             synchronized (mLock) {
-                if (mProviderList.contains(provider)) {
-                    mService.openInputBridgeInternalLocked(provider, token, name, width, height,
-                            maxPointers);
-                }
+                return mService.openInputBridgeInternalLocked(token, name, width,
+                               height, maxPointers);
             }
         }
 
@@ -289,9 +230,7 @@
         public void closeInputBridge(TvRemoteProviderProxy provider, IBinder token) {
             if (DEBUG) Slog.d(TAG, "closeInputBridge(), token: " + token);
             synchronized (mLock) {
-                if (mProviderList.contains(provider)) {
                     mService.closeInputBridgeInternalLocked(token);
-                }
             }
         }
 
@@ -299,9 +238,7 @@
         public void clearInputBridge(TvRemoteProviderProxy provider, IBinder token) {
             if (DEBUG) Slog.d(TAG, "clearInputBridge(), token: " + token);
             synchronized (mLock) {
-                if (mProviderList.contains(provider)) {
                     mService.clearInputBridgeInternalLocked(token);
-                }
             }
         }
 
@@ -311,9 +248,7 @@
                 Slog.d(TAG, "sendKeyDown(), token: " + token + ", keyCode: " + keyCode);
             }
             synchronized (mLock) {
-                if (mProviderList.contains(provider)) {
                     mService.sendKeyDownInternalLocked(token, keyCode);
-                }
             }
         }
 
@@ -323,9 +258,7 @@
                 Slog.d(TAG, "sendKeyUp(), token: " + token + ", keyCode: " + keyCode);
             }
             synchronized (mLock) {
-                if (mProviderList.contains(provider)) {
                     mService.sendKeyUpInternalLocked(token, keyCode);
-                }
             }
         }
 
@@ -336,9 +269,7 @@
                 Slog.d(TAG, "sendPointerDown(), token: " + token + ", pointerId: " + pointerId);
             }
             synchronized (mLock) {
-                if (mProviderList.contains(provider)) {
                     mService.sendPointerDownInternalLocked(token, pointerId, x, y);
-                }
             }
         }
 
@@ -348,9 +279,7 @@
                 Slog.d(TAG, "sendPointerUp(), token: " + token + ", pointerId: " + pointerId);
             }
             synchronized (mLock) {
-                if (mProviderList.contains(provider)) {
                     mService.sendPointerUpInternalLocked(token, pointerId);
-                }
             }
         }
 
@@ -358,29 +287,7 @@
         public void sendPointerSync(TvRemoteProviderProxy provider, IBinder token) {
             if (DEBUG_KEYS) Slog.d(TAG, "sendPointerSync(), token: " + token);
             synchronized (mLock) {
-                if (mProviderList.contains(provider)) {
                     mService.sendPointerSyncInternalLocked(token);
-                }
-            }
-        }
-
-        @Override
-        public void addProvider(TvRemoteProviderProxy provider) {
-            if (DEBUG) Slog.d(TAG, "addProvider " + provider);
-            synchronized (mLock) {
-                provider.setProviderSink(this);
-                mProviderList.add(provider);
-                Slog.d(TAG, "provider: " + provider.toString());
-            }
-        }
-
-        @Override
-        public void removeProvider(TvRemoteProviderProxy provider) {
-            if (DEBUG) Slog.d(TAG, "removeProvider " + provider);
-            synchronized (mLock) {
-                if (mProviderList.remove(provider) == false) {
-                    Slog.e(TAG, "Unknown provider " + provider);
-                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 8bb37bb..50200a7c 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -4940,6 +4940,12 @@
         }
     }
 
+
+    Rect getDefaultPictureInPictureBounds(float aspectRatio) {
+        if (getTaskStack() == null) return null;
+        return getTaskStack().getPictureInPictureBounds(aspectRatio, null /* currentStackBounds */);
+    }
+
     void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration,
             boolean fromFullscreen) {
         if (!inPinnedWindowingMode()) return;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 4cc9f4c..c933ece 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1550,10 +1550,11 @@
 
         mService.mUgmInternal.grantUriPermissionFromIntent(mCallingUid, mStartActivity.packageName,
                 mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.mUserId);
-        mService.getPackageManagerInternalLocked().grantEphemeralAccess(
+        mService.getPackageManagerInternalLocked().grantImplicitAccess(
                 mStartActivity.mUserId, mIntent,
-                UserHandle.getAppId(mStartActivity.info.applicationInfo.uid),
-                UserHandle.getAppId(mCallingUid));
+                UserHandle.getAppId(mCallingUid),
+                UserHandle.getAppId(mStartActivity.info.applicationInfo.uid)
+        );
         if (newTask) {
             EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.mUserId,
                     mStartActivity.getTaskRecord().taskId);
@@ -2542,7 +2543,8 @@
             final boolean onTop =
                     (aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind;
             final ActivityStack stack =
-                    mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams);
+                    mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams,
+                            mRequest.realCallingPid, mRequest.realCallingUid);
             return stack;
         }
         // Otherwise handle adjacent launch.
@@ -2660,11 +2662,24 @@
         return this;
     }
 
+    /**
+     * Sets the pid of the caller who originally started the activity.
+     *
+     * Normally, the pid/uid would be the calling pid from the binder call.
+     * However, in case of a {@link PendingIntent}, the pid/uid pair of the caller is considered
+     * the original entity that created the pending intent, in contrast to setRealCallingPid/Uid,
+     * which represents the entity who invoked pending intent via {@link PendingIntent#send}.
+     */
     ActivityStarter setCallingPid(int pid) {
         mRequest.callingPid = pid;
         return this;
     }
 
+    /**
+     * Sets the uid of the caller who originally started the activity.
+     *
+     * @see #setCallingPid
+     */
     ActivityStarter setCallingUid(int uid) {
         mRequest.callingUid = uid;
         return this;
@@ -2675,11 +2690,25 @@
         return this;
     }
 
+    /**
+     * Sets the pid of the caller who requested to launch the activity.
+     *
+     * The pid/uid represents the caller who launches the activity in this request.
+     * It will almost same as setCallingPid/Uid except when processing {@link PendingIntent}:
+     * the pid/uid will be the caller who called {@link PendingIntent#send()}.
+     *
+     * @see #setCallingPid
+     */
     ActivityStarter setRealCallingPid(int pid) {
         mRequest.realCallingPid = pid;
         return this;
     }
 
+    /**
+     * Sets the uid of the caller who requested to launch the activity.
+     *
+     * @see #setRealCallingPid
+     */
     ActivityStarter setRealCallingUid(int uid) {
         mRequest.realCallingUid = uid;
         return this;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 71f02e8..ffd9021 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1021,7 +1021,7 @@
         if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this);
         mAppStopped = true;
         // Reset the last saved PiP snap fraction on app stop.
-        mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(mActivityComponent);
+        mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this);
         destroySurfaces();
         // Remove any starting window that was added for this app if they are still around.
         removeStartingWindow();
@@ -1705,7 +1705,10 @@
             return;
         }
 
-        if (prevWinMode == WINDOWING_MODE_PINNED && winMode != WINDOWING_MODE_UNDEFINED
+        if (prevWinMode != WINDOWING_MODE_UNDEFINED && winMode == WINDOWING_MODE_PINNED) {
+            // Entering PiP from fullscreen, reset the snap fraction
+            mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this);
+        } else if (prevWinMode == WINDOWING_MODE_PINNED && winMode != WINDOWING_MODE_UNDEFINED
                 && !isHidden()) {
             // Leaving PiP to fullscreen, save the snap fraction based on the pre-animation bounds
             // for the next re-entry into PiP (assuming the activity is not hidden or destroyed)
@@ -1723,8 +1726,8 @@
                     stackBounds = mTmpRect;
                     pinnedStack.getBounds(stackBounds);
                 }
-                mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction(
-                        mActivityComponent, stackBounds);
+                mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction(this,
+                        stackBounds);
             }
         } else if (shouldStartChangeTransition(prevWinMode, winMode)) {
             initializeChangeTransition(mTmpPrevBounds);
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 8e57fec..ef0049b 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -27,7 +27,6 @@
 
 import android.annotation.NonNull;
 import android.app.RemoteAction;
-import android.content.ComponentName;
 import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
 import android.graphics.Point;
@@ -51,6 +50,7 @@
 import com.android.server.UiThread;
 
 import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -74,7 +74,7 @@
 
     private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedStackController" : TAG_WM;
 
-    private static final float INVALID_SNAP_FRACTION = -1f;
+    public static final float INVALID_SNAP_FRACTION = -1f;
     private final WindowManagerService mService;
     private final DisplayContent mDisplayContent;
     private final Handler mHandler = UiThread.getHandler();
@@ -106,6 +106,9 @@
     private int mDefaultStackGravity;
     private float mDefaultAspectRatio;
     private Point mScreenEdgeInsets;
+    private int mCurrentMinSize;
+    private float mReentrySnapFraction = INVALID_SNAP_FRACTION;
+    private WeakReference<AppWindowToken> mLastPipActivity = null;
 
     // The aspect ratio bounds of the PIP.
     private float mMinAspectRatio;
@@ -115,6 +118,7 @@
     private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
     private final Rect mTmpInsets = new Rect();
     private final Rect mTmpRect = new Rect();
+    private final Rect mTmpAnimatingBoundsRect = new Rect();
     private final Point mTmpDisplaySize = new Point();
 
 
@@ -132,19 +136,16 @@
         }
 
         @Override
-        public int getDisplayRotation() {
-            synchronized (mService.mGlobalLock) {
-                return mDisplayInfo.rotation;
-            }
+        public void setMinEdgeSize(int minEdgeSize) {
+            mHandler.post(() -> {
+                mCurrentMinSize = Math.max(mDefaultMinSize, minEdgeSize);
+            });
         }
 
         @Override
-        public void startAnimation(Rect destinationBounds, Rect sourceRectHint,
-                int animationDuration) {
+        public int getDisplayRotation() {
             synchronized (mService.mGlobalLock) {
-                final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
-                pinnedStack.animateResizePinnedStack(destinationBounds,
-                        sourceRectHint, animationDuration, true /* fromFullscreen */);
+                return mDisplayInfo.rotation;
             }
         }
     }
@@ -187,6 +188,7 @@
         final Resources res = mService.mContext.getResources();
         mDefaultMinSize = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
+        mCurrentMinSize = mDefaultMinSize;
         mDefaultAspectRatio = res.getFloat(
                 com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
         final String screenEdgeInsetsDpString = res.getString(
@@ -214,7 +216,6 @@
             listener.asBinder().linkToDeath(mPinnedStackListenerDeathHandler, 0);
             listener.onListenerRegistered(mCallbacks);
             mPinnedStackListener = listener;
-            notifyDisplayInfoChanged(mDisplayInfo);
             notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
             notifyShelfVisibilityChanged(mIsShelfShowing, mShelfHeight);
             // The movement bounds notification needs to be sent before the minimized state, since
@@ -237,34 +238,58 @@
     }
 
     /**
+     * Returns the current bounds (or the default bounds if there are no current bounds) with the
+     * specified aspect ratio.
+     */
+    Rect transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio,
+            boolean useCurrentMinEdgeSize) {
+        // Save the snap fraction, calculate the aspect ratio based on screen size
+        final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
+                getMovementBounds(stackBounds));
+
+        final int minEdgeSize = useCurrentMinEdgeSize ? mCurrentMinSize : mDefaultMinSize;
+        final Size size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, minEdgeSize,
+                mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
+        final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
+        final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f);
+        stackBounds.set(left, top, left + size.getWidth(), top + size.getHeight());
+        mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction);
+        if (mIsMinimized) {
+            applyMinimizedOffset(stackBounds, getMovementBounds(stackBounds));
+        }
+        return stackBounds;
+    }
+
+    /**
      * Saves the current snap fraction for re-entry of the current activity into PiP.
      */
-    void saveReentrySnapFraction(final ComponentName componentName, final Rect stackBounds) {
-        if (mPinnedStackListener == null) return;
-        try {
-            mPinnedStackListener.onSaveReentrySnapFraction(componentName, stackBounds);
-        } catch (RemoteException e) {
-            Slog.e(TAG_WM, "Error delivering save reentry fraction event.", e);
-        }
+    void saveReentrySnapFraction(final AppWindowToken token, final Rect stackBounds) {
+        mReentrySnapFraction = getSnapFraction(stackBounds);
+        mLastPipActivity = new WeakReference<>(token);
     }
 
     /**
      * Resets the last saved snap fraction so that the default bounds will be returned.
      */
-    void resetReentrySnapFraction(ComponentName componentName) {
-        if (mPinnedStackListener == null) return;
-        try {
-            mPinnedStackListener.onResetReentrySnapFraction(componentName);
-        } catch (RemoteException e) {
-            Slog.e(TAG_WM, "Error delivering reset reentry fraction event.", e);
+    void resetReentrySnapFraction(AppWindowToken token) {
+        if (mLastPipActivity != null && mLastPipActivity.get() == token) {
+            mReentrySnapFraction = INVALID_SNAP_FRACTION;
+            mLastPipActivity = null;
         }
     }
 
     /**
+     * @return the default bounds to show the PIP when there is no active PIP.
+     */
+    Rect getDefaultOrLastSavedBounds() {
+        return getDefaultBounds(mReentrySnapFraction);
+    }
+
+    /**
      * @return the default bounds to show the PIP, if a {@param snapFraction} is provided, then it
      * will apply the default bounds to the provided snap fraction.
      */
-    private Rect getDefaultBounds(float snapFraction) {
+    Rect getDefaultBounds(float snapFraction) {
         synchronized (mService.mGlobalLock) {
             final Rect insetBounds = new Rect();
             getInsetBounds(insetBounds);
@@ -286,18 +311,13 @@
         }
     }
 
-    private void setDisplayInfo(DisplayInfo displayInfo) {
-        mDisplayInfo.copyFrom(displayInfo);
-        notifyDisplayInfoChanged(mDisplayInfo);
-    }
-
     /**
      * In the case where the display rotation is changed but there is no stack, we can't depend on
      * onTaskStackBoundsChanged() to be called.  But we still should update our known display info
      * with the new state so that we can update SystemUI.
      */
     synchronized void onDisplayInfoChanged(DisplayInfo displayInfo) {
-        setDisplayInfo(displayInfo);
+        mDisplayInfo.copyFrom(displayInfo);
         notifyMovementBoundsChanged(false /* fromImeAdjustment */, false /* fromShelfAdjustment */);
     }
 
@@ -315,7 +335,7 @@
             } else if (targetBounds.isEmpty()) {
                 // The stack is null, we are just initializing the stack, so just store the display
                 // info and ignore
-                setDisplayInfo(displayInfo);
+                mDisplayInfo.copyFrom(displayInfo);
                 outBounds.setEmpty();
                 return false;
             }
@@ -325,8 +345,7 @@
 
             // Calculate the snap fraction of the current stack along the old movement bounds
             final float snapFraction = getSnapFraction(postChangeStackBounds);
-
-            setDisplayInfo(displayInfo);
+            mDisplayInfo.copyFrom(displayInfo);
 
             // Calculate the stack bounds in the new orientation to the same same fraction along the
             // rotated movement bounds.
@@ -387,11 +406,8 @@
     void setAspectRatio(float aspectRatio) {
         if (Float.compare(mAspectRatio, aspectRatio) != 0) {
             mAspectRatio = aspectRatio;
-            notifyAspectRatioChanged(aspectRatio);
             notifyMovementBoundsChanged(false /* fromImeAdjustment */,
                     false /* fromShelfAdjustment */);
-            notifyPrepareAnimation(null /* sourceHintRect */, aspectRatio,
-                    null /* stackBounds */);
         }
     }
 
@@ -413,10 +429,6 @@
         notifyActionsChanged(mActions);
     }
 
-    void prepareAnimation(Rect sourceRectHint, float aspectRatio, Rect stackBounds) {
-        notifyPrepareAnimation(sourceRectHint, aspectRatio, stackBounds);
-    }
-
     private boolean isSameDimensionAndRotation(@NonNull DisplayInfo display1,
             @NonNull DisplayInfo display2) {
         Preconditions.checkNotNull(display1);
@@ -449,15 +461,6 @@
         }
     }
 
-    private void notifyAspectRatioChanged(float aspectRatio) {
-        if (mPinnedStackListener == null) return;
-        try {
-            mPinnedStackListener.onAspectRatioChanged(aspectRatio);
-        } catch (RemoteException e) {
-            Slog.e(TAG_WM, "Error delivering aspect ratio changed event.", e);
-        }
-    }
-
     /**
      * Notifies listeners that the PIP minimized state has changed.
      */
@@ -494,13 +497,23 @@
                 return;
             }
             try {
-                final Rect animatingBounds = new Rect();
+                final Rect insetBounds = new Rect();
+                getInsetBounds(insetBounds);
+                final Rect normalBounds = getDefaultBounds(INVALID_SNAP_FRACTION);
+                if (isValidPictureInPictureAspectRatio(mAspectRatio)) {
+                    transformBoundsToAspectRatio(normalBounds, mAspectRatio,
+                            false /* useCurrentMinEdgeSize */);
+                }
+                final Rect animatingBounds = mTmpAnimatingBoundsRect;
                 final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
                 if (pinnedStack != null) {
                     pinnedStack.getAnimationOrCurrentBounds(animatingBounds);
+                } else {
+                    animatingBounds.set(normalBounds);
                 }
-                mPinnedStackListener.onMovementBoundsChanged(animatingBounds,
-                        fromImeAdjustment, fromShelfAdjustment);
+                mPinnedStackListener.onMovementBoundsChanged(insetBounds, normalBounds,
+                        animatingBounds, fromImeAdjustment, fromShelfAdjustment,
+                        mDisplayInfo.rotation);
             } catch (RemoteException e) {
                 Slog.e(TAG_WM, "Error delivering actions changed event.", e);
             }
@@ -508,30 +521,6 @@
     }
 
     /**
-     * Notifies listeners that the PIP animation is about to happen.
-     */
-    private void notifyDisplayInfoChanged(DisplayInfo displayInfo) {
-        if (mPinnedStackListener == null) return;
-        try {
-            mPinnedStackListener.onDisplayInfoChanged(displayInfo);
-        } catch (RemoteException e) {
-            Slog.e(TAG_WM, "Error delivering DisplayInfo changed event.", e);
-        }
-    }
-
-    /**
-     * Notifies listeners that the PIP animation is about to happen.
-     */
-    private void notifyPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect stackBounds) {
-        if (mPinnedStackListener == null) return;
-        try {
-            mPinnedStackListener.onPrepareAnimation(sourceRectHint, aspectRatio, stackBounds);
-        } catch (RemoteException e) {
-            Slog.e(TAG_WM, "Error delivering prepare animation event.", e);
-        }
-    }
-
-    /**
      * @return the bounds on the screen that the PIP can be visible in.
      */
     private void getInsetBounds(Rect outRect) {
@@ -615,6 +604,7 @@
         pw.println(prefix + "  mImeHeight=" + mImeHeight);
         pw.println(prefix + "  mIsShelfShowing=" + mIsShelfShowing);
         pw.println(prefix + "  mShelfHeight=" + mShelfHeight);
+        pw.println(prefix + "  mReentrySnapFraction=" + mReentrySnapFraction);
         pw.println(prefix + "  mIsMinimized=" + mIsMinimized);
         pw.println(prefix + "  mAspectRatio=" + mAspectRatio);
         pw.println(prefix + "  mMinAspectRatio=" + mMinAspectRatio);
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index d9e30a2..4b2d4ce 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -959,6 +959,10 @@
         // Need to make sure the pinned stack exist so we can resize it below...
         stack = display.getOrCreateStack(WINDOWING_MODE_PINNED, r.getActivityType(), ON_TOP);
 
+        // Calculate the target bounds here before the task is reparented back into pinned windowing
+        // mode (which will reset the saved bounds)
+        final Rect destBounds = stack.getDefaultPictureInPictureBounds(aspectRatio);
+
         try {
             final TaskRecord task = r.getTaskRecord();
             // Resize the pinned stack to match the current size of the task the activity we are
@@ -997,14 +1001,9 @@
             mService.continueWindowLayout();
         }
 
-        // Notify the pinned stack controller to prepare the PiP animation, expect callback
-        // delivered from SystemUI to WM to start the animation.
-        final PinnedStackController pinnedStackController =
-                display.mDisplayContent.getPinnedStackController();
-        pinnedStackController.prepareAnimation(sourceHintBounds, aspectRatio,
-                null /* stackBounds */);
+        stack.animateResizePinnedStack(sourceHintBounds, destBounds, -1 /* animationDuration */,
+                true /* fromFullscreen */);
 
-        // TODO: revisit the following statement after the animation is moved from WM to SysUI.
         // Update the visibility of all activities after the they have been reparented to the new
         // stack.  This MUST run after the animation above is scheduled to ensure that the windows
         // drawn signal is scheduled after the bounds animation start call on the bounds animator
@@ -1615,7 +1614,8 @@
 
     <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r,
             @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop) {
-        return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */);
+        return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */,
+                -1 /* no realCallingPid */, -1 /* no realCallingUid */);
     }
 
     /**
@@ -1624,13 +1624,16 @@
      * @param r The activity we are trying to launch. Can be null.
      * @param options The activity options used to the launch. Can be null.
      * @param candidateTask The possible task the activity might be launched in. Can be null.
-     * @params launchParams The resolved launch params to use.
+     * @param launchParams The resolved launch params to use.
+     * @param realCallingPid The pid from {@link ActivityStarter#setRealCallingPid}
+     * @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid}
      *
      * @return The stack to use for the launch or INVALID_STACK_ID.
      */
     <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r,
             @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop,
-            @Nullable LaunchParamsController.LaunchParams launchParams) {
+            @Nullable LaunchParamsController.LaunchParams launchParams, int realCallingPid,
+            int realCallingUid) {
         int taskId = INVALID_TASK_ID;
         int displayId = INVALID_DISPLAY;
         //Rect bounds = null;
@@ -1661,7 +1664,15 @@
         if (launchParams != null && launchParams.mPreferredDisplayId != INVALID_DISPLAY) {
             displayId = launchParams.mPreferredDisplayId;
         }
-        if (displayId != INVALID_DISPLAY && canLaunchOnDisplay(r, displayId)) {
+        final boolean canLaunchOnDisplayFromStartRequest =
+                realCallingPid != 0 && realCallingUid > 0 && r != null
+                        && mStackSupervisor.canPlaceEntityOnDisplay(displayId, realCallingPid,
+                        realCallingUid, r.info);
+        // Checking if the activity's launch caller, or the realCallerId of the activity from
+        // start request (i.e. entity that invokes PendingIntent) is allowed to launch on the
+        // display.
+        if (displayId != INVALID_DISPLAY && (canLaunchOnDisplay(r, displayId)
+                || canLaunchOnDisplayFromStartRequest)) {
             if (r != null) {
                 stack = (T) getValidLaunchStackOnDisplay(displayId, r, candidateTask, options,
                         launchParams);
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 58542e5..239bd00 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1661,6 +1661,40 @@
     }
 
     /**
+     * @return the current stack bounds transformed to the given {@param aspectRatio}. If
+     *         the default bounds is {@code null}, then the {@param aspectRatio} is applied to the
+     *         default bounds.
+     */
+    Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) {
+        if (!mWmService.mAtmService.mSupportsPictureInPicture) {
+            return null;
+        }
+
+        final DisplayContent displayContent = getDisplayContent();
+        if (displayContent == null) {
+            return null;
+        }
+
+        if (!inPinnedWindowingMode()) {
+            return null;
+        }
+
+        final PinnedStackController pinnedStackController =
+                displayContent.getPinnedStackController();
+        if (stackBounds == null) {
+            // Calculate the aspect ratio bounds from the default bounds
+            stackBounds = pinnedStackController.getDefaultOrLastSavedBounds();
+        }
+
+        if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) {
+            return pinnedStackController.transformBoundsToAspectRatio(stackBounds, aspectRatio,
+                    true /* useCurrentMinEdgeSize */);
+        } else {
+            return stackBounds;
+        }
+    }
+
+    /**
      * Animates the pinned stack.
      */
     void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds,
@@ -1737,11 +1771,6 @@
             return;
         }
 
-        final DisplayContent displayContent = getDisplayContent();
-        if (displayContent == null) {
-            return;
-        }
-
         if (!inPinnedWindowingMode()) {
             return;
         }
@@ -1752,10 +1781,13 @@
         if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) == 0) {
             return;
         }
-
-        // Notify the pinned stack controller about aspect ratio change.
-        // This would result a callback delivered from SystemUI to WM to start animation,
-        // if the bounds are ought to be altered due to aspect ratio change.
+        getAnimationOrCurrentBounds(mTmpFromBounds);
+        mTmpToBounds.set(mTmpFromBounds);
+        getPictureInPictureBounds(aspectRatio, mTmpToBounds);
+        if (!mTmpToBounds.equals(mTmpFromBounds)) {
+            animateResizePinnedStack(mTmpToBounds, null /* sourceHintBounds */,
+                    -1 /* duration */, false /* fromFullscreen */);
+        }
         pinnedStackController.setAspectRatio(
                 pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
                         ? aspectRatio : -1f);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 478bc88..704c808 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1113,142 +1113,107 @@
             info.writePoliciesToXml(out);
             out.endTag(null, TAG_POLICIES);
             if (minimumPasswordMetrics.quality != PASSWORD_QUALITY_UNSPECIFIED) {
-                out.startTag(null, TAG_PASSWORD_QUALITY);
-                out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordMetrics.quality));
-                out.endTag(null, TAG_PASSWORD_QUALITY);
+                writeAttributeValueToXml(
+                        out, TAG_PASSWORD_QUALITY, minimumPasswordMetrics.quality);
                 if (minimumPasswordMetrics.length != DEF_MINIMUM_PASSWORD_LENGTH) {
-                    out.startTag(null, TAG_MIN_PASSWORD_LENGTH);
-                    out.attribute(
-                            null, ATTR_VALUE, Integer.toString(minimumPasswordMetrics.length));
-                    out.endTag(null, TAG_MIN_PASSWORD_LENGTH);
-                }
-                if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
-                    out.startTag(null, TAG_PASSWORD_HISTORY_LENGTH);
-                    out.attribute(null, ATTR_VALUE, Integer.toString(passwordHistoryLength));
-                    out.endTag(null, TAG_PASSWORD_HISTORY_LENGTH);
+                    writeAttributeValueToXml(
+                            out, TAG_MIN_PASSWORD_LENGTH, minimumPasswordMetrics.length);
                 }
                 if (minimumPasswordMetrics.upperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
-                    out.startTag(null, TAG_MIN_PASSWORD_UPPERCASE);
-                    out.attribute(
-                            null, ATTR_VALUE, Integer.toString(minimumPasswordMetrics.upperCase));
-                    out.endTag(null, TAG_MIN_PASSWORD_UPPERCASE);
+                    writeAttributeValueToXml(
+                            out, TAG_MIN_PASSWORD_UPPERCASE, minimumPasswordMetrics.upperCase);
                 }
                 if (minimumPasswordMetrics.lowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
-                    out.startTag(null, TAG_MIN_PASSWORD_LOWERCASE);
-                    out.attribute(
-                            null, ATTR_VALUE, Integer.toString(minimumPasswordMetrics.lowerCase));
-                    out.endTag(null, TAG_MIN_PASSWORD_LOWERCASE);
+                    writeAttributeValueToXml(
+                            out, TAG_MIN_PASSWORD_LOWERCASE, minimumPasswordMetrics.lowerCase);
                 }
                 if (minimumPasswordMetrics.letters != DEF_MINIMUM_PASSWORD_LETTERS) {
-                    out.startTag(null, TAG_MIN_PASSWORD_LETTERS);
-                    out.attribute(
-                            null, ATTR_VALUE, Integer.toString(minimumPasswordMetrics.letters));
-                    out.endTag(null, TAG_MIN_PASSWORD_LETTERS);
+                    writeAttributeValueToXml(
+                            out, TAG_MIN_PASSWORD_LETTERS, minimumPasswordMetrics.letters);
                 }
                 if (minimumPasswordMetrics.numeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
-                    out.startTag(null, TAG_MIN_PASSWORD_NUMERIC);
-                    out.attribute(
-                            null, ATTR_VALUE, Integer.toString(minimumPasswordMetrics.numeric));
-                    out.endTag(null, TAG_MIN_PASSWORD_NUMERIC);
+                    writeAttributeValueToXml(
+                            out, TAG_MIN_PASSWORD_NUMERIC, minimumPasswordMetrics.numeric);
                 }
                 if (minimumPasswordMetrics.symbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
-                    out.startTag(null, TAG_MIN_PASSWORD_SYMBOLS);
-                    out.attribute(
-                            null, ATTR_VALUE, Integer.toString(minimumPasswordMetrics.symbols));
-                    out.endTag(null, TAG_MIN_PASSWORD_SYMBOLS);
+                    writeAttributeValueToXml(
+                            out, TAG_MIN_PASSWORD_SYMBOLS, minimumPasswordMetrics.symbols);
                 }
                 if (minimumPasswordMetrics.nonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
-                    out.startTag(null, TAG_MIN_PASSWORD_NONLETTER);
-                    out.attribute(
-                            null, ATTR_VALUE, Integer.toString(minimumPasswordMetrics.nonLetter));
-                    out.endTag(null, TAG_MIN_PASSWORD_NONLETTER);
+                    writeAttributeValueToXml(
+                            out, TAG_MIN_PASSWORD_NONLETTER, minimumPasswordMetrics.nonLetter);
                 }
             }
+            if (passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
+                writeAttributeValueToXml(
+                        out, TAG_PASSWORD_HISTORY_LENGTH, passwordHistoryLength);
+            }
             if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
-                out.startTag(null, TAG_MAX_TIME_TO_UNLOCK);
-                out.attribute(null, ATTR_VALUE, Long.toString(maximumTimeToUnlock));
-                out.endTag(null, TAG_MAX_TIME_TO_UNLOCK);
+                writeAttributeValueToXml(
+                        out, TAG_MAX_TIME_TO_UNLOCK, maximumTimeToUnlock);
             }
             if (strongAuthUnlockTimeout != DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) {
-                out.startTag(null, TAG_STRONG_AUTH_UNLOCK_TIMEOUT);
-                out.attribute(null, ATTR_VALUE, Long.toString(strongAuthUnlockTimeout));
-                out.endTag(null, TAG_STRONG_AUTH_UNLOCK_TIMEOUT);
+                writeAttributeValueToXml(
+                        out, TAG_STRONG_AUTH_UNLOCK_TIMEOUT, strongAuthUnlockTimeout);
             }
             if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
-                out.startTag(null, TAG_MAX_FAILED_PASSWORD_WIPE);
-                out.attribute(null, ATTR_VALUE, Integer.toString(maximumFailedPasswordsForWipe));
-                out.endTag(null, TAG_MAX_FAILED_PASSWORD_WIPE);
+                writeAttributeValueToXml(
+                        out, TAG_MAX_FAILED_PASSWORD_WIPE, maximumFailedPasswordsForWipe);
             }
             if (specifiesGlobalProxy) {
-                out.startTag(null, TAG_SPECIFIES_GLOBAL_PROXY);
-                out.attribute(null, ATTR_VALUE, Boolean.toString(specifiesGlobalProxy));
-                out.endTag(null, TAG_SPECIFIES_GLOBAL_PROXY);
+                writeAttributeValueToXml(
+                        out, TAG_SPECIFIES_GLOBAL_PROXY, specifiesGlobalProxy);
                 if (globalProxySpec != null) {
-                    out.startTag(null, TAG_GLOBAL_PROXY_SPEC);
-                    out.attribute(null, ATTR_VALUE, globalProxySpec);
-                    out.endTag(null, TAG_GLOBAL_PROXY_SPEC);
+                    writeAttributeValueToXml(out, TAG_GLOBAL_PROXY_SPEC, globalProxySpec);
                 }
                 if (globalProxyExclusionList != null) {
-                    out.startTag(null, TAG_GLOBAL_PROXY_EXCLUSION_LIST);
-                    out.attribute(null, ATTR_VALUE, globalProxyExclusionList);
-                    out.endTag(null, TAG_GLOBAL_PROXY_EXCLUSION_LIST);
+                    writeAttributeValueToXml(
+                            out, TAG_GLOBAL_PROXY_EXCLUSION_LIST, globalProxyExclusionList);
                 }
             }
             if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
-                out.startTag(null, TAG_PASSWORD_EXPIRATION_TIMEOUT);
-                out.attribute(null, ATTR_VALUE, Long.toString(passwordExpirationTimeout));
-                out.endTag(null, TAG_PASSWORD_EXPIRATION_TIMEOUT);
+                writeAttributeValueToXml(
+                        out, TAG_PASSWORD_EXPIRATION_TIMEOUT, passwordExpirationTimeout);
             }
             if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
-                out.startTag(null, TAG_PASSWORD_EXPIRATION_DATE);
-                out.attribute(null, ATTR_VALUE, Long.toString(passwordExpirationDate));
-                out.endTag(null, TAG_PASSWORD_EXPIRATION_DATE);
+                writeAttributeValueToXml(
+                        out, TAG_PASSWORD_EXPIRATION_DATE, passwordExpirationDate);
             }
             if (encryptionRequested) {
-                out.startTag(null, TAG_ENCRYPTION_REQUESTED);
-                out.attribute(null, ATTR_VALUE, Boolean.toString(encryptionRequested));
-                out.endTag(null, TAG_ENCRYPTION_REQUESTED);
+                writeAttributeValueToXml(
+                        out, TAG_ENCRYPTION_REQUESTED, encryptionRequested);
             }
             if (testOnlyAdmin) {
-                out.startTag(null, TAG_TEST_ONLY_ADMIN);
-                out.attribute(null, ATTR_VALUE, Boolean.toString(testOnlyAdmin));
-                out.endTag(null, TAG_TEST_ONLY_ADMIN);
+                writeAttributeValueToXml(
+                        out, TAG_TEST_ONLY_ADMIN, testOnlyAdmin);
             }
             if (disableCamera) {
-                out.startTag(null, TAG_DISABLE_CAMERA);
-                out.attribute(null, ATTR_VALUE, Boolean.toString(disableCamera));
-                out.endTag(null, TAG_DISABLE_CAMERA);
+                writeAttributeValueToXml(
+                        out, TAG_DISABLE_CAMERA, disableCamera);
             }
             if (disableCallerId) {
-                out.startTag(null, TAG_DISABLE_CALLER_ID);
-                out.attribute(null, ATTR_VALUE, Boolean.toString(disableCallerId));
-                out.endTag(null, TAG_DISABLE_CALLER_ID);
+                writeAttributeValueToXml(
+                        out, TAG_DISABLE_CALLER_ID, disableCallerId);
             }
             if (disableContactsSearch) {
-                out.startTag(null, TAG_DISABLE_CONTACTS_SEARCH);
-                out.attribute(null, ATTR_VALUE, Boolean.toString(disableContactsSearch));
-                out.endTag(null, TAG_DISABLE_CONTACTS_SEARCH);
+                writeAttributeValueToXml(
+                        out, TAG_DISABLE_CONTACTS_SEARCH, disableContactsSearch);
             }
             if (!disableBluetoothContactSharing) {
-                out.startTag(null, TAG_DISABLE_BLUETOOTH_CONTACT_SHARING);
-                out.attribute(null, ATTR_VALUE,
-                        Boolean.toString(disableBluetoothContactSharing));
-                out.endTag(null, TAG_DISABLE_BLUETOOTH_CONTACT_SHARING);
+                writeAttributeValueToXml(
+                        out, TAG_DISABLE_BLUETOOTH_CONTACT_SHARING, disableBluetoothContactSharing);
             }
             if (disableScreenCapture) {
-                out.startTag(null, TAG_DISABLE_SCREEN_CAPTURE);
-                out.attribute(null, ATTR_VALUE, Boolean.toString(disableScreenCapture));
-                out.endTag(null, TAG_DISABLE_SCREEN_CAPTURE);
+                writeAttributeValueToXml(
+                        out, TAG_DISABLE_SCREEN_CAPTURE, disableScreenCapture);
             }
             if (requireAutoTime) {
-                out.startTag(null, TAG_REQUIRE_AUTO_TIME);
-                out.attribute(null, ATTR_VALUE, Boolean.toString(requireAutoTime));
-                out.endTag(null, TAG_REQUIRE_AUTO_TIME);
+                writeAttributeValueToXml(
+                        out, TAG_REQUIRE_AUTO_TIME, requireAutoTime);
             }
             if (forceEphemeralUsers) {
-                out.startTag(null, TAG_FORCE_EPHEMERAL_USERS);
-                out.attribute(null, ATTR_VALUE, Boolean.toString(forceEphemeralUsers));
-                out.endTag(null, TAG_FORCE_EPHEMERAL_USERS);
+                writeAttributeValueToXml(
+                        out, TAG_FORCE_EPHEMERAL_USERS, forceEphemeralUsers);
             }
             if (isNetworkLoggingEnabled) {
                 out.startTag(null, TAG_IS_NETWORK_LOGGING_ENABLED);
@@ -1260,15 +1225,13 @@
                 out.endTag(null, TAG_IS_NETWORK_LOGGING_ENABLED);
             }
             if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
-                out.startTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
-                out.attribute(null, ATTR_VALUE, Integer.toString(disabledKeyguardFeatures));
-                out.endTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
+                writeAttributeValueToXml(
+                        out, TAG_DISABLE_KEYGUARD_FEATURES, disabledKeyguardFeatures);
             }
             if (!accountTypesWithManagementDisabled.isEmpty()) {
-                out.startTag(null, TAG_DISABLE_ACCOUNT_MANAGEMENT);
                 writeAttributeValuesToXml(
-                        out, TAG_ACCOUNT_TYPE, accountTypesWithManagementDisabled);
-                out.endTag(null,  TAG_DISABLE_ACCOUNT_MANAGEMENT);
+                        out, TAG_DISABLE_ACCOUNT_MANAGEMENT, TAG_ACCOUNT_TYPE,
+                        accountTypesWithManagementDisabled);
             }
             if (!trustAgentInfos.isEmpty()) {
                 Set<Entry<String, TrustAgentInfo>> set = trustAgentInfos.entrySet();
@@ -1291,9 +1254,9 @@
                 out.endTag(null, TAG_MANAGE_TRUST_AGENT_FEATURES);
             }
             if (crossProfileWidgetProviders != null && !crossProfileWidgetProviders.isEmpty()) {
-                out.startTag(null, TAG_CROSS_PROFILE_WIDGET_PROVIDERS);
-                writeAttributeValuesToXml(out, TAG_PROVIDER, crossProfileWidgetProviders);
-                out.endTag(null, TAG_CROSS_PROFILE_WIDGET_PROVIDERS);
+                writeAttributeValuesToXml(
+                        out, TAG_CROSS_PROFILE_WIDGET_PROVIDERS, TAG_PROVIDER,
+                        crossProfileWidgetProviders);
             }
             writePackageListToXml(out, TAG_PERMITTED_ACCESSIBILITY_SERVICES,
                     permittedAccessiblityServices);
@@ -1307,20 +1270,15 @@
                         out, userRestrictions, TAG_USER_RESTRICTIONS);
             }
             if (!defaultEnabledRestrictionsAlreadySet.isEmpty()) {
-                out.startTag(null, TAG_DEFAULT_ENABLED_USER_RESTRICTIONS);
-                writeAttributeValuesToXml(
-                        out, TAG_RESTRICTION, defaultEnabledRestrictionsAlreadySet);
-                out.endTag(null, TAG_DEFAULT_ENABLED_USER_RESTRICTIONS);
+                writeAttributeValuesToXml(out, TAG_DEFAULT_ENABLED_USER_RESTRICTIONS,
+                        TAG_RESTRICTION,
+                        defaultEnabledRestrictionsAlreadySet);
             }
             if (!TextUtils.isEmpty(shortSupportMessage)) {
-                out.startTag(null, TAG_SHORT_SUPPORT_MESSAGE);
-                out.text(shortSupportMessage.toString());
-                out.endTag(null, TAG_SHORT_SUPPORT_MESSAGE);
+                writeTextToXml(out, TAG_SHORT_SUPPORT_MESSAGE, shortSupportMessage.toString());
             }
             if (!TextUtils.isEmpty(longSupportMessage)) {
-                out.startTag(null, TAG_LONG_SUPPORT_MESSAGE);
-                out.text(longSupportMessage.toString());
-                out.endTag(null, TAG_LONG_SUPPORT_MESSAGE);
+                writeTextToXml(out, TAG_LONG_SUPPORT_MESSAGE, longSupportMessage.toString());
             }
             if (parentAdmin != null) {
                 out.startTag(null, TAG_PARENT_ADMIN);
@@ -1328,29 +1286,20 @@
                 out.endTag(null, TAG_PARENT_ADMIN);
             }
             if (organizationColor != DEF_ORGANIZATION_COLOR) {
-                out.startTag(null, TAG_ORGANIZATION_COLOR);
-                out.attribute(null, ATTR_VALUE, Integer.toString(organizationColor));
-                out.endTag(null, TAG_ORGANIZATION_COLOR);
+                writeAttributeValueToXml(out, TAG_ORGANIZATION_COLOR, organizationColor);
             }
             if (organizationName != null) {
-                out.startTag(null, TAG_ORGANIZATION_NAME);
-                out.text(organizationName);
-                out.endTag(null, TAG_ORGANIZATION_NAME);
+                writeTextToXml(out, TAG_ORGANIZATION_NAME, organizationName);
             }
             if (isLogoutEnabled) {
-                out.startTag(null, TAG_IS_LOGOUT_ENABLED);
-                out.attribute(null, ATTR_VALUE, Boolean.toString(isLogoutEnabled));
-                out.endTag(null, TAG_IS_LOGOUT_ENABLED);
+                writeAttributeValueToXml(
+                        out, TAG_IS_LOGOUT_ENABLED, isLogoutEnabled);
             }
             if (startUserSessionMessage != null) {
-                out.startTag(null, TAG_START_USER_SESSION_MESSAGE);
-                out.text(startUserSessionMessage);
-                out.endTag(null, TAG_START_USER_SESSION_MESSAGE);
+                writeTextToXml(out, TAG_START_USER_SESSION_MESSAGE, startUserSessionMessage);
             }
             if (endUserSessionMessage != null) {
-                out.startTag(null, TAG_END_USER_SESSION_MESSAGE);
-                out.text(endUserSessionMessage);
-                out.endTag(null, TAG_END_USER_SESSION_MESSAGE);
+                writeTextToXml(out, TAG_END_USER_SESSION_MESSAGE, endUserSessionMessage);
             }
             if (mCrossProfileCalendarPackages == null) {
                 out.startTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL);
@@ -1361,25 +1310,58 @@
             }
         }
 
+        void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException {
+            out.startTag(null, tag);
+            out.text(text);
+            out.endTag(null, tag);
+        }
+
         void writePackageListToXml(XmlSerializer out, String outerTag,
                 List<String> packageList)
                 throws IllegalArgumentException, IllegalStateException, IOException {
             if (packageList == null) {
                 return;
             }
-
-            out.startTag(null, outerTag);
-            writeAttributeValuesToXml(out, TAG_PACKAGE_LIST_ITEM, packageList);
-            out.endTag(null, outerTag);
+            writeAttributeValuesToXml(out, outerTag, TAG_PACKAGE_LIST_ITEM, packageList);
         }
 
-        void writeAttributeValuesToXml(XmlSerializer out, String tag,
+        void writeAttributeValueToXml(XmlSerializer out, String tag, String value)
+                throws IOException {
+            out.startTag(null, tag);
+            out.attribute(null, ATTR_VALUE, value);
+            out.endTag(null, tag);
+        }
+
+        void writeAttributeValueToXml(XmlSerializer out, String tag, int value)
+                throws IOException {
+            out.startTag(null, tag);
+            out.attribute(null, ATTR_VALUE, Integer.toString(value));
+            out.endTag(null, tag);
+        }
+
+        void writeAttributeValueToXml(XmlSerializer out, String tag, long value)
+                throws IOException {
+            out.startTag(null, tag);
+            out.attribute(null, ATTR_VALUE, Long.toString(value));
+            out.endTag(null, tag);
+        }
+
+        void writeAttributeValueToXml(XmlSerializer out, String tag, boolean value)
+                throws IOException {
+            out.startTag(null, tag);
+            out.attribute(null, ATTR_VALUE, Boolean.toString(value));
+            out.endTag(null, tag);
+        }
+
+        void writeAttributeValuesToXml(XmlSerializer out, String outerTag, String innerTag,
                 @NonNull Collection<String> values) throws IOException {
+            out.startTag(null, outerTag);
             for (String value : values) {
-                out.startTag(null, tag);
+                out.startTag(null, innerTag);
                 out.attribute(null, ATTR_VALUE, value);
-                out.endTag(null, tag);
+                out.endTag(null, innerTag);
             }
+            out.endTag(null, outerTag);
         }
 
         void readFromXml(XmlPullParser parser, boolean shouldOverridePolicies)
@@ -1999,6 +1981,10 @@
             return LocalServices.getService(LockSettingsInternal.class);
         }
 
+        boolean hasUserSetupCompleted(DevicePolicyData userData) {
+            return userData.mUserSetupComplete;
+        }
+
         boolean isBuildDebuggable() {
             return Build.IS_DEBUGGABLE;
         }
@@ -5659,7 +5645,7 @@
                     KeyChain.bindAsUser(mContext, UserHandle.getUserHandleForUid(callingUid));
             try {
                 IKeyChainService keyChain = keyChainConnection.getService();
-                if (!keyChain.installKeyPair(privKey, cert, chain, alias)) {
+                if (!keyChain.installKeyPair(privKey, cert, chain, alias, KeyStore.UID_SELF)) {
                     return false;
                 }
                 if (requestAccess) {
@@ -8271,7 +8257,7 @@
         if (!mHasFeature) {
             return true;
         }
-        return getUserData(userHandle).mUserSetupComplete;
+        return mInjector.hasUserSetupCompleted(getUserData(userHandle));
     }
 
     private boolean hasPaired(int userHandle) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/AccessibilityGestureDetectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/AccessibilityGestureDetectorTest.java
index 2585a28..b707912 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/AccessibilityGestureDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/AccessibilityGestureDetectorTest.java
@@ -176,6 +176,6 @@
 
         // Check that correct gesture was recognized.
         verify(mResultListener).onGestureCompleted(
-                argThat(gestureInfo -> gestureInfo.getGestureId() == gestureId));
+                argThat(gestureEvent -> gestureEvent.getGestureId() == gestureId));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index d6cb9826..d900910 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -765,7 +765,38 @@
     }
 
     /**
-     * Test for: @{link DevicePolicyManager#reportPasswordChanged}
+     * Test for: {@link DevicePolicyManager#setPasswordHistoryLength(ComponentName, int)}
+     *
+     * Validates that when the password history length is set, it is persisted after rebooting
+     */
+    public void testSaveAndLoadPasswordHistoryLength_persistedAfterReboot() throws Exception {
+        int passwordHistoryLength = 2;
+
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        // Install admin1 on system user.
+        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+
+        // Set admin1 to active admin and device owner
+        dpm.setActiveAdmin(admin1, false);
+        dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM);
+
+        // Save password history length
+        dpm.setPasswordHistoryLength(admin1, passwordHistoryLength);
+
+        assertEquals(dpm.getPasswordHistoryLength(admin1), passwordHistoryLength);
+
+        initializeDpms();
+        reset(mContext.spiedContext);
+
+        // Password history length should persist after rebooted
+        assertEquals(dpm.getPasswordHistoryLength(admin1), passwordHistoryLength);
+    }
+
+    /**
+     * Test for: {@link DevicePolicyManager#reportPasswordChanged}
      *
      * Validates that when the password for a user changes, the notification broadcast intent
      * {@link DeviceAdminReceiver#ACTION_PASSWORD_CHANGED} is sent to managed profile owners, in
diff --git a/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java b/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java
index bd3d9ab..3852b9f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.content.pm.ModuleInfo;
+import android.content.pm.PackageManager;
 import android.test.InstrumentationTestCase;
 
 import com.android.frameworks.servicestests.R;
@@ -28,7 +29,7 @@
     public void testSuccessfulParse() {
         ModuleInfoProvider provider = getProvider(R.xml.well_formed_metadata);
 
-        List<ModuleInfo> mi = provider.getInstalledModules(0);
+        List<ModuleInfo> mi = provider.getInstalledModules(PackageManager.MATCH_ALL);
         assertEquals(2, mi.size());
 
         Collections.sort(mi, (ModuleInfo m1, ModuleInfo m2) ->
@@ -49,18 +50,18 @@
 
     public void testParseFailure_incorrectTopLevelElement() {
         ModuleInfoProvider provider = getProvider(R.xml.unparseable_metadata1);
-        assertEquals(0, provider.getInstalledModules(0).size());
+        assertEquals(0, provider.getInstalledModules(PackageManager.MATCH_ALL).size());
     }
 
     public void testParseFailure_incorrectModuleElement() {
         ModuleInfoProvider provider = getProvider(R.xml.unparseable_metadata2);
-        assertEquals(0, provider.getInstalledModules(0).size());
+        assertEquals(0, provider.getInstalledModules(PackageManager.MATCH_ALL).size());
     }
 
     public void testParse_unknownAttributesIgnored() {
         ModuleInfoProvider provider = getProvider(R.xml.well_formed_metadata);
 
-        List<ModuleInfo> mi = provider.getInstalledModules(0);
+        List<ModuleInfo> mi = provider.getInstalledModules(PackageManager.MATCH_ALL);
         assertEquals(2, mi.size());
 
         ModuleInfo mi1 = provider.getModuleInfo("com.android.module1", 0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 60730fe..1f672c0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -354,7 +354,7 @@
             doReturn(stack).when(mRootActivityContainer)
                     .getLaunchStack(any(), any(), any(), anyBoolean());
             doReturn(stack).when(mRootActivityContainer)
-                    .getLaunchStack(any(), any(), any(), anyBoolean(), any());
+                    .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
         }
 
         // Set up mock package manager internal and make sure no unmocked methods are called
@@ -366,7 +366,7 @@
 
         // Never review permissions
         doReturn(false).when(mockPackageManager).isPermissionsReviewRequired(any(), anyInt());
-        doNothing().when(mockPackageManager).grantEphemeralAccess(
+        doNothing().when(mockPackageManager).grantImplicitAccess(
                 anyInt(), any(), anyInt(), anyInt());
 
         final Intent intent = new Intent();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 1731f7c..4f00383 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -38,6 +38,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
+import android.graphics.Rect;
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
 import android.testing.DexmakerShareClassLoaderRule;
@@ -139,6 +140,8 @@
         private int mScreenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
         private boolean mLaunchTaskBehind;
         private int mConfigChanges;
+        private int mLaunchedFromPid;
+        private int mLaunchedFromUid;
 
         ActivityBuilder(ActivityTaskManagerService service) {
             mService = service;
@@ -214,6 +217,16 @@
             return this;
         }
 
+        ActivityBuilder setLaunchedFromPid(int pid) {
+            mLaunchedFromPid = pid;
+            return this;
+        }
+
+        ActivityBuilder setLaunchedFromUid(int uid) {
+            mLaunchedFromUid = uid;
+            return this;
+        }
+
         ActivityRecord build() {
             if (mComponent == null) {
                 final int id = sCurrentActivityId++;
@@ -250,10 +263,11 @@
             }
 
             final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
-                    0 /* launchedFromPid */, 0, null, intent, null,
-                    aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */,
-                    0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */,
-                    mService.mStackSupervisor, options, null /* sourceRecord */);
+                    mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */,
+                    null, intent, null, aInfo /*aInfo*/, new Configuration(), null /* resultTo */,
+                    null /* resultWho */, 0 /* reqCode */, false /*componentSpecified*/,
+                    false /* rootVoiceInteraction */, mService.mStackSupervisor, options,
+                    null /* sourceRecord */);
             spyOn(activity);
             if (mTaskRecord != null) {
                 // fullscreen value is normally read from resources in ctor, so for testing we need
@@ -432,7 +446,12 @@
             final ActivityStackSupervisor supervisor = mRootActivityContainer.mStackSupervisor;
             if (mWindowingMode == WINDOWING_MODE_PINNED) {
                 stack = new ActivityStack(mDisplay, stackId, supervisor,
-                        mWindowingMode, ACTIVITY_TYPE_STANDARD, mOnTop);
+                        mWindowingMode, ACTIVITY_TYPE_STANDARD, mOnTop) {
+                    @Override
+                    Rect getDefaultPictureInPictureBounds(float aspectRatio) {
+                        return new Rect(50, 50, 100, 100);
+                    }
+                };
             } else {
                 stack = new ActivityStack(mDisplay, stackId, supervisor,
                         mWindowingMode, mActivityType, mOnTop);
diff --git a/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java
index e9c2263..efd468f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java
@@ -66,8 +66,8 @@
 
         verify(mIPinnedStackListener).onImeVisibilityChanged(false, 0);
         verify(mIPinnedStackListener).onShelfVisibilityChanged(false, 0);
-        verify(mIPinnedStackListener).onMovementBoundsChanged(any(), eq(false),
-                eq(false));
+        verify(mIPinnedStackListener).onMovementBoundsChanged(any(), any(), any(), eq(false),
+                eq(false), anyInt());
         verify(mIPinnedStackListener).onActionsChanged(any());
         verify(mIPinnedStackListener).onMinimizedStateChanged(anyBoolean());
 
@@ -75,8 +75,8 @@
 
         mWm.setShelfHeight(true, SHELF_HEIGHT);
         verify(mIPinnedStackListener).onShelfVisibilityChanged(true, SHELF_HEIGHT);
-        verify(mIPinnedStackListener).onMovementBoundsChanged(any(), eq(false),
-                eq(true));
+        verify(mIPinnedStackListener).onMovementBoundsChanged(any(), any(), any(), eq(false),
+                eq(true), anyInt());
         verify(mIPinnedStackListener, never()).onImeVisibilityChanged(anyBoolean(), anyInt());
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index c67b860..aa97de72 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -25,6 +25,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.TYPE_VIRTUAL;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -61,6 +62,7 @@
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.util.Pair;
+import android.view.DisplayInfo;
 
 import androidx.test.filters.MediumTest;
 
@@ -820,6 +822,41 @@
     }
 
     /**
+     * Test that {@link RootActivityContainer#getLaunchStack} with the real caller id will get the
+     * expected stack when requesting the activity launch on the secondary display.
+     */
+    @Test
+    public void testGetLaunchStackWithRealCallerId() {
+        // Create a non-system owned virtual display.
+        final DisplayInfo info = new DisplayInfo();
+        mSupervisor.mService.mContext.getDisplay().getDisplayInfo(info);
+        info.type = TYPE_VIRTUAL;
+        info.ownerUid = 100;
+        final TestActivityDisplay secondaryDisplay = TestActivityDisplay.create(mSupervisor, info);
+        mRootActivityContainer.addChild(secondaryDisplay, POSITION_TOP);
+
+        // Create an activity with specify the original launch pid / uid.
+        final ActivityRecord r = new ActivityBuilder(mService).setLaunchedFromPid(200)
+                .setLaunchedFromUid(200).build();
+
+        // Simulate ActivityStarter to find a launch stack for requesting the activity to launch
+        // on the secondary display with realCallerId.
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(secondaryDisplay.mDisplayId);
+        options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId,
+                300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info);
+        final ActivityStack result = mRootActivityContainer.getLaunchStack(r, options,
+                null /* task */, true /* onTop */, null, 300 /* test realCallerPid */,
+                300 /* test realCallerUid */);
+
+        // Assert that the stack is returned as expected.
+        assertNotNull(result);
+        assertEquals("The display ID of the stack should same as secondary display ",
+                secondaryDisplay.mDisplayId, result.mDisplayId);
+    }
+
+    /**
      * Mock {@link RootActivityContainer#resolveHomeActivity} for returning consistent activity
      * info for test cases (the original implementation will resolve from the real package manager).
      */
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 2fe2c41..5a4d399 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -231,7 +231,7 @@
                 new AMTestInjector(mContext, mHandlerThread), mHandlerThread);
         spyOn(mAmService);
         doReturn(mock(IPackageManager.class)).when(mAmService).getPackageManager();
-        doNothing().when(mAmService).grantEphemeralAccessLocked(
+        doNothing().when(mAmService).grantImplicitAccess(
                 anyInt(), any(), anyInt(), anyInt());
 
         // ActivityManagerInternal
diff --git a/startop/apps/test/src/SystemServerBenchmarkActivity.java b/startop/apps/test/src/SystemServerBenchmarkActivity.java
index 61d4322..ed3cbe9 100644
--- a/startop/apps/test/src/SystemServerBenchmarkActivity.java
+++ b/startop/apps/test/src/SystemServerBenchmarkActivity.java
@@ -17,8 +17,10 @@
 package com.android.startop.test;
 
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -139,6 +141,10 @@
                     throw new RuntimeException(e);
                 }
             });
+
+            new Benchmark(benchmarkList, "getPackagesForUid", () -> {
+                pm.getPackagesForUid(app.uid);
+            });
         } catch (NameNotFoundException e) {
             throw new RuntimeException(e);
         }
@@ -152,5 +158,45 @@
             }
         });
 
+        new Benchmark(benchmarkList, "getLaunchIntentForPackage", () -> {
+            pm.getLaunchIntentForPackage("com.android.startop.test");
+        });
+
+        new Benchmark(benchmarkList, "getPackageUid", () -> {
+            try {
+                pm.getPackageUid("com.android.startop.test", 0);
+            } catch (NameNotFoundException e) {
+                throw new RuntimeException(e);
+            }
+        });
+
+        new Benchmark(benchmarkList, "checkPermission", () -> {
+            // Check for the first permission I could find.
+            pm.checkPermission("android.permission.SEND_SMS", "com.android.startop.test");
+        });
+
+        new Benchmark(benchmarkList, "checkSignatures", () -> {
+            // Compare with settings, since settings is on both AOSP and Master builds
+            pm.checkSignatures("com.android.settings", "com.android.startop.test");
+        });
+
+        Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED);
+        new Benchmark(benchmarkList, "queryBroadcastReceivers", () -> {
+            pm.queryBroadcastReceivers(intent, 0);
+        });
+
+        new Benchmark(benchmarkList, "hasSystemFeature", () -> {
+            pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);
+        });
+
+        new Benchmark(benchmarkList, "resolveService", () -> {
+            pm.resolveService(intent, 0);
+        });
+
+        ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
+        new Benchmark(benchmarkList, "getRunningAppProcesses", () -> {
+            am.getRunningAppProcesses();
+        });
+
     }
 }
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 58f2858..f527bc3 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -578,7 +578,8 @@
         PackageManager packageManager = context.getPackageManager();
         PackageInfo packageInfo;
         try {
-            packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+            packageInfo = packageManager.getPackageInfo(packageName,
+                PackageManager.GET_SIGNING_CERTIFICATES);
         } catch (PackageManager.NameNotFoundException e) {
             Log.d("SubscriptionInfo", "canManageSubscription: Unknown package: " + packageName, e);
             return false;
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index d3cba2e..51de903 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2701,7 +2701,8 @@
         PackageManager packageManager = mContext.getPackageManager();
         PackageInfo packageInfo;
         try {
-            packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+            packageInfo = packageManager.getPackageInfo(packageName,
+                PackageManager.GET_SIGNING_CERTIFICATES);
         } catch (PackageManager.NameNotFoundException e) {
             logd("Unknown package: " + packageName);
             return false;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f25b012..b5dbbe7 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3251,6 +3251,31 @@
         }
     }
 
+
+    /**
+     * Returns true if the specified type of application (e.g. {@link #APPTYPE_CSIM} is present
+     * on the UICC card.
+     *
+     * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
+     *
+     * @param appType the uicc app type like {@link APPTYPE_CSIM}
+     * @return true if the specified type of application in UICC CARD or false if no uicc or error.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public boolean isApplicationOnUicc(@UiccAppType int appType) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.isApplicationOnUicc(getSubId(), appType);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#isApplicationOnUicc", e);
+        }
+        return false;
+    }
+
     /**
      * Returns a constant indicating the state of the device SIM card in a logical slot.
      *
diff --git a/telephony/java/android/telephony/UiccAccessRule.java b/telephony/java/android/telephony/UiccAccessRule.java
index 811722f..93ccba1 100644
--- a/telephony/java/android/telephony/UiccAccessRule.java
+++ b/telephony/java/android/telephony/UiccAccessRule.java
@@ -20,6 +20,7 @@
 import android.annotation.SystemApi;
 import android.content.pm.PackageInfo;
 import android.content.pm.Signature;
+import android.content.pm.SigningInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -169,17 +170,28 @@
      *
      * @param packageInfo package info fetched from
      *     {@link android.content.pm.PackageManager#getPackageInfo}.
-     *     {@link android.content.pm.PackageManager#GET_SIGNATURES} must have been passed in.
+     *     {@link android.content.pm.PackageManager#GET_SIGNING_CERTIFICATES} must have been
+     *         passed in.
      * @return either {@link TelephonyManager#CARRIER_PRIVILEGE_STATUS_HAS_ACCESS} or
      *     {@link TelephonyManager#CARRIER_PRIVILEGE_STATUS_NO_ACCESS}.
      */
     public int getCarrierPrivilegeStatus(PackageInfo packageInfo) {
-        if (packageInfo.signatures == null || packageInfo.signatures.length == 0) {
-            throw new IllegalArgumentException(
-                    "Must use GET_SIGNATURES when looking up package info");
+        Signature[] signatures = packageInfo.signatures;
+        SigningInfo sInfo = packageInfo.signingInfo;
+
+        if (sInfo != null) {
+            signatures = sInfo.getSigningCertificateHistory();
+            if (sInfo.hasMultipleSigners()) {
+                signatures = sInfo.getApkContentsSigners();
+            }
         }
 
-        for (Signature sig : packageInfo.signatures) {
+        if (signatures == null || signatures.length == 0) {
+            throw new IllegalArgumentException(
+                    "Must use GET_SIGNING_CERTIFICATES when looking up package info");
+        }
+
+        for (Signature sig : signatures) {
             int accessStatus = getCarrierPrivilegeStatus(sig, packageInfo.packageName);
             if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) {
                 return accessStatus;
diff --git a/telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl
index 606df15..6a35e33 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl
@@ -22,7 +22,6 @@
  */
 oneway interface IImsSmsListener {
     void onSendSmsResult(int token, int messageRef, int status, int reason);
-    void onSmsStatusReportReceived(int token, int messageRef, in String format,
-            in byte[] pdu);
+    void onSmsStatusReportReceived(int token, in String format, in byte[] pdu);
     void onSmsReceived(int token, in String format, in byte[] pdu);
-}
\ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
index 852c8e0..2e4bfb3 100644
--- a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
@@ -147,7 +147,7 @@
      *               {@link SmsMessage#FORMAT_3GPP2}.
      * @param smsc the Short Message Service Center address.
      * @param isRetry whether it is a retry of an already attempted message or not.
-     * @param pdu PDUs representing the contents of the message.
+     * @param pdu PDU representing the contents of the message.
      */
     public void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry,
             byte[] pdu) {
@@ -166,27 +166,29 @@
      * provider.
      *
      * @param token token provided in {@link #onSmsReceived(int, String, byte[])}
+     * @param messageRef the message reference
      * @param result result of delivering the message. Valid values are:
      *  {@link #DELIVER_STATUS_OK},
      *  {@link #DELIVER_STATUS_ERROR_GENERIC},
      *  {@link #DELIVER_STATUS_ERROR_NO_MEMORY},
      *  {@link #DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED}
-     * @param messageRef the message reference
      */
-    public void acknowledgeSms(int token, @DeliverStatusResult int messageRef, int result) {
+    public void acknowledgeSms(int token, int messageRef, @DeliverStatusResult int result) {
         Log.e(LOG_TAG, "acknowledgeSms() not implemented.");
     }
 
     /**
      * This method will be triggered by the platform after
-     * {@link #onSmsStatusReportReceived(int, int, String, byte[])} has been called to provide the
+     * {@link #onSmsStatusReportReceived(int, int, String, byte[])} or
+     * {@link #onSmsStatusReportReceived(int, String, byte[])} has been called to provide the
      * result to the IMS provider.
      *
-     * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])}
+     * @param token token provided in {@link #onSmsStatusReportReceived(int, int, String, byte[])}
+     *              or {@link #onSmsStatusReportReceived(int, String, byte[])}
+     * @param messageRef the message reference
      * @param result result of delivering the message. Valid values are:
      *  {@link #STATUS_REPORT_STATUS_OK},
      *  {@link #STATUS_REPORT_STATUS_ERROR}
-     * @param messageRef the message reference
      */
     public void acknowledgeSmsReport(int token, int messageRef, @StatusReportResult int result) {
         Log.e(LOG_TAG, "acknowledgeSmsReport() not implemented.");
@@ -204,7 +206,7 @@
      *              callbacks for this message.
      * @param format the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and
      * {@link SmsMessage#FORMAT_3GPP2}.
-     * @param pdu PDUs representing the contents of the message.
+     * @param pdu PDU representing the contents of the message.
      * @throws RuntimeException if called before {@link #onReady()} is triggered.
      */
     public final void onSmsReceived(int token, String format, byte[] pdu) throws RuntimeException {
@@ -285,23 +287,32 @@
     }
 
     /**
-     * Sets the status report of the sent message.
+     * This method should be triggered by the IMS providers when the status report of the sent
+     * message is received. The platform will handle the report and notify the IMS provider of the
+     * result by calling {@link #acknowledgeSmsReport(int, int, int)}.
      *
+     * This method must not be called before {@link #onReady()} is called or the call will fail. If
+     * the platform is not available, {@link #acknowledgeSmsReport(int, int, int)} will be called
+     * with the {@link #STATUS_REPORT_STATUS_ERROR} result code.
      * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])}
      * @param messageRef the message reference.
      * @param format the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and
-     * {@link SmsMessage#FORMAT_3GPP2}.
-     * @param pdu PDUs representing the content of the status report.
+     *               {@link SmsMessage#FORMAT_3GPP2}.
+     * @param pdu PDU representing the content of the status report.
      * @throws RuntimeException if called before {@link #onReady()} is triggered
+     *
+     * @deprecated Use {@link #onSmsStatusReportReceived(int, String, byte[])} instead without the
+     * message reference.
      */
+    @Deprecated
     public final void onSmsStatusReportReceived(int token, int messageRef, String format,
-            byte[] pdu) throws RuntimeException{
+            byte[] pdu) throws RuntimeException {
         synchronized (mLock) {
             if (mListener == null) {
                 throw new RuntimeException("Feature not ready.");
             }
             try {
-                mListener.onSmsStatusReportReceived(token, messageRef, format, pdu);
+                mListener.onSmsStatusReportReceived(token, format, pdu);
             } catch (RemoteException e) {
                 Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage());
                 acknowledgeSmsReport(token, messageRef, STATUS_REPORT_STATUS_ERROR);
@@ -310,6 +321,46 @@
     }
 
     /**
+     * This method should be triggered by the IMS providers when the status report of the sent
+     * message is received. The platform will handle the report and notify the IMS provider of the
+     * result by calling {@link #acknowledgeSmsReport(int, int, int)}.
+     *
+     * This method must not be called before {@link #onReady()} is called or the call will fail. If
+     * the platform is not available, {@link #acknowledgeSmsReport(int, int, int)} will be called
+     * with the {@link #STATUS_REPORT_STATUS_ERROR} result code.
+     * @param token unique token generated by IMS providers that the platform will use to trigger
+     *              callbacks for this message.
+     * @param format the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and
+     *               {@link SmsMessage#FORMAT_3GPP2}.
+     * @param pdu PDU representing the content of the status report.
+     * @throws RuntimeException if called before {@link #onReady()} is triggered
+     */
+    public final void onSmsStatusReportReceived(int token, String format, byte[] pdu)
+            throws RuntimeException {
+        synchronized (mLock) {
+            if (mListener == null) {
+                throw new RuntimeException("Feature not ready.");
+            }
+            try {
+                mListener.onSmsStatusReportReceived(token, format, pdu);
+            } catch (RemoteException e) {
+                Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage());
+                SmsMessage message = SmsMessage.createFromPdu(pdu, format);
+                if (message != null && message.mWrappedSmsMessage != null) {
+                    acknowledgeSmsReport(
+                            token,
+                            message.mWrappedSmsMessage.mMessageRef,
+                            STATUS_REPORT_STATUS_ERROR);
+                } else {
+                    Log.w(LOG_TAG,
+                            "onSmsStatusReportReceivedWithoutMessageRef: Invalid pdu entered.");
+                    acknowledgeSmsReport(token, 0, STATUS_REPORT_STATUS_ERROR);
+                }
+            }
+        }
+    }
+
+    /**
      * Returns the SMS format. Default is {@link SmsMessage#FORMAT_3GPP} unless overridden by IMS
      * Provider.
      *
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 9f1a2f7..866e936 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2012,6 +2012,13 @@
      */
     int getRadioHalVersion();
 
+    /**
+     * Returns true if the specified type of application (e.g. {@link #APPTYPE_CSIM} is present
+     * on the UICC card.
+     * @hide
+     */
+    boolean isApplicationOnUicc(int subId, int appType);
+
     boolean isModemEnabledForSlot(int slotIndex, String callingPackage);
 
     boolean isDataEnabledForApn(int apnType, int subId, String callingPackage);
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index ff4c970..79f5095 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -765,6 +765,45 @@
         assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_B);
     }
 
+    /**
+     * Test default monitoring duration is used when PackageWatchdog#startObservingHealth is offered
+     * an invalid durationMs.
+     */
+    @Test
+    public void testInvalidMonitoringDuration_beforeExpiry() {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observer = new TestObserver(OBSERVER_NAME_1);
+
+        watchdog.startObservingHealth(observer, Arrays.asList(APP_A), -1);
+        // Note: Don't move too close to the expiration time otherwise the handler will be thrashed
+        // by PackageWatchdog#scheduleNextSyncStateLocked which keeps posting runnables with very
+        // small timeouts.
+        moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_OBSERVING_DURATION_MS - 100);
+        raiseFatalFailureAndDispatch(watchdog,
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+
+        // We should receive APP_A since the observer hasn't expired
+        assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A);
+    }
+
+    /**
+     * Test default monitoring duration is used when PackageWatchdog#startObservingHealth is offered
+     * an invalid durationMs.
+     */
+    @Test
+    public void testInvalidMonitoringDuration_afterExpiry() {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observer = new TestObserver(OBSERVER_NAME_1);
+
+        watchdog.startObservingHealth(observer, Arrays.asList(APP_A), -1);
+        moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_OBSERVING_DURATION_MS + 1);
+        raiseFatalFailureAndDispatch(watchdog,
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+
+        // We should receive nothing since the observer has expired
+        assertThat(observer.mHealthCheckFailedPackages).isEmpty();
+    }
+
     /** Test we are notified when enough failures are triggered within any window. */
     @Test
     public void testFailureTriggerWindow() {
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 5e06818..e36668e 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -53,9 +53,9 @@
 using ::android::ResTable_config;
 using ::android::StringPiece;
 using ::android::base::ReadFileToString;
-using ::android::base::WriteStringToFile;
 using ::android::base::StringAppendF;
 using ::android::base::StringPrintf;
+using ::android::base::WriteStringToFile;
 
 namespace aapt {
 
@@ -300,29 +300,7 @@
   OptimizeContext* context_;
 };
 
-bool ExtractObfuscationWhitelistFromConfig(const std::string& path, OptimizeContext* context,
-                                           OptimizeOptions* options) {
-  std::string contents;
-  if (!ReadFileToString(path, &contents, true)) {
-    context->GetDiagnostics()->Error(DiagMessage()
-                                     << "failed to parse whitelist from config file: " << path);
-    return false;
-  }
-  for (StringPiece resource_name : util::Tokenize(contents, ',')) {
-    options->table_flattener_options.whitelisted_resources.insert(
-        resource_name.to_string());
-  }
-  return true;
-}
-
-bool ExtractConfig(const std::string& path, OptimizeContext* context,
-                                    OptimizeOptions* options) {
-  std::string content;
-  if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) {
-    context->GetDiagnostics()->Error(DiagMessage(path) << "failed reading whitelist");
-    return false;
-  }
-
+bool ParseConfig(const std::string& content, IAaptContext* context, OptimizeOptions* options) {
   size_t line_no = 0;
   for (StringPiece line : util::Tokenize(content, '\n')) {
     line_no++;
@@ -351,15 +329,24 @@
     for (StringPiece directive : util::Tokenize(directives, ',')) {
       if (directive == "remove") {
         options->resources_blacklist.insert(resource_name.ToResourceName());
-      } else if (directive == "no_obfuscate") {
-        options->table_flattener_options.whitelisted_resources.insert(
-            resource_name.entry.to_string());
+      } else if (directive == "no_collapse" || directive == "no_obfuscate") {
+        options->table_flattener_options.name_collapse_exemptions.insert(
+            resource_name.ToResourceName());
       }
     }
   }
   return true;
 }
 
+bool ExtractConfig(const std::string& path, IAaptContext* context, OptimizeOptions* options) {
+  std::string content;
+  if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) {
+    context->GetDiagnostics()->Error(DiagMessage(path) << "failed reading config file");
+    return false;
+  }
+  return ParseConfig(content, context, options);
+}
+
 bool ExtractAppDataFromManifest(OptimizeContext* context, const LoadedApk* apk,
                                 OptimizeOptions* out_options) {
   const xml::XmlResource* manifest = apk->GetManifest();
@@ -467,15 +454,6 @@
     }
   }
 
-  if (options_.table_flattener_options.collapse_key_stringpool) {
-    if (whitelist_path_) {
-      std::string& path = whitelist_path_.value();
-      if (!ExtractObfuscationWhitelistFromConfig(path, &context, &options_)) {
-        return 1;
-      }
-    }
-  }
-
   if (resources_config_path_) {
     std::string& path = resources_config_path_.value();
     if (!ExtractConfig(path, &context, &options_)) {
diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h
index ce3b2ad..5070ccc 100644
--- a/tools/aapt2/cmd/Optimize.h
+++ b/tools/aapt2/cmd/Optimize.h
@@ -78,10 +78,6 @@
             "All the resources that would be unused on devices of the given densities will be \n"
             "removed from the APK.",
         &target_densities_);
-    AddOptionalFlag("--whitelist-path",
-        "Path to the whitelist.cfg file containing whitelisted resources \n"
-            "whose names should not be altered in final resource tables.",
-        &whitelist_path_);
     AddOptionalFlag("--resources-config-path",
         "Path to the resources.cfg file containing the list of resources and \n"
             "directives to each resource. \n"
@@ -127,7 +123,6 @@
                                const std::string &file_path);
 
   Maybe<std::string> config_path_;
-  Maybe<std::string> whitelist_path_;
   Maybe<std::string> resources_config_path_;
   Maybe<std::string> target_densities_;
   std::vector<std::string> configs_;
diff --git a/tools/aapt2/cmd/Optimize_test.cpp b/tools/aapt2/cmd/Optimize_test.cpp
new file mode 100644
index 0000000..ac681e8
--- /dev/null
+++ b/tools/aapt2/cmd/Optimize_test.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Optimize.h"
+
+#include "AppInfo.h"
+#include "Diagnostics.h"
+#include "LoadedApk.h"
+#include "Resource.h"
+#include "test/Test.h"
+
+using testing::Contains;
+using testing::Eq;
+
+namespace aapt {
+
+bool ParseConfig(const std::string&, IAaptContext*, OptimizeOptions*);
+
+using OptimizeTest = CommandTestFixture;
+
+TEST_F(OptimizeTest, ParseConfigWithNoCollapseExemptions) {
+  const std::string& content = R"(
+string/foo#no_collapse
+dimen/bar#no_collapse
+)";
+  aapt::test::Context context;
+  OptimizeOptions options;
+  ParseConfig(content, &context, &options);
+
+  const std::set<ResourceName>& name_collapse_exemptions =
+      options.table_flattener_options.name_collapse_exemptions;
+
+  ASSERT_THAT(name_collapse_exemptions.size(), Eq(2));
+  EXPECT_THAT(name_collapse_exemptions, Contains(ResourceName({}, ResourceType::kString, "foo")));
+  EXPECT_THAT(name_collapse_exemptions, Contains(ResourceName({}, ResourceType::kDimen, "bar")));
+}
+
+TEST_F(OptimizeTest, ParseConfigWithNoObfuscateExemptions) {
+  const std::string& content = R"(
+string/foo#no_obfuscate
+dimen/bar#no_obfuscate
+)";
+  aapt::test::Context context;
+  OptimizeOptions options;
+  ParseConfig(content, &context, &options);
+
+  const std::set<ResourceName>& name_collapse_exemptions =
+      options.table_flattener_options.name_collapse_exemptions;
+
+  ASSERT_THAT(name_collapse_exemptions.size(), Eq(2));
+  EXPECT_THAT(name_collapse_exemptions, Contains(ResourceName({}, ResourceType::kString, "foo")));
+  EXPECT_THAT(name_collapse_exemptions, Contains(ResourceName({}, ResourceType::kDimen, "bar")));
+}
+
+}  // namespace aapt
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index b932117..58e232c 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -228,14 +228,15 @@
  public:
   PackageFlattener(IAaptContext* context, ResourceTablePackage* package,
                    const std::map<size_t, std::string>* shared_libs, bool use_sparse_entries,
-                   bool collapse_key_stringpool, const std::set<std::string>& whitelisted_resources)
+                   bool collapse_key_stringpool,
+                   const std::set<ResourceName>& name_collapse_exemptions)
       : context_(context),
         diag_(context->GetDiagnostics()),
         package_(package),
         shared_libs_(shared_libs),
         use_sparse_entries_(use_sparse_entries),
         collapse_key_stringpool_(collapse_key_stringpool),
-        whitelisted_resources_(whitelisted_resources) {
+        name_collapse_exemptions_(name_collapse_exemptions) {
   }
 
   bool FlattenPackage(BigBuffer* buffer) {
@@ -652,11 +653,12 @@
 
       for (ResourceEntry* entry : sorted_entries) {
         uint32_t local_key_index;
+        ResourceName resource_name({}, type->type, entry->name);
         if (!collapse_key_stringpool_ ||
-            whitelisted_resources_.find(entry->name) != whitelisted_resources_.end()) {
+            name_collapse_exemptions_.find(resource_name) != name_collapse_exemptions_.end()) {
           local_key_index = (uint32_t)key_pool_.MakeRef(entry->name).index();
         } else {
-          // resource isn't whitelisted, add it as obfuscated value
+          // resource isn't exempt from collapse, add it as obfuscated value
           local_key_index = (uint32_t)key_pool_.MakeRef(obfuscated_resource_name).index();
         }
         // Group values by configuration.
@@ -712,7 +714,7 @@
   StringPool type_pool_;
   StringPool key_pool_;
   bool collapse_key_stringpool_;
-  const std::set<std::string>& whitelisted_resources_;
+  const std::set<ResourceName>& name_collapse_exemptions_;
 };
 
 }  // namespace
@@ -760,7 +762,7 @@
 
     PackageFlattener flattener(context, package.get(), &table->included_packages_,
                                options_.use_sparse_entries, options_.collapse_key_stringpool,
-                               options_.whitelisted_resources);
+                               options_.name_collapse_exemptions);
     if (!flattener.FlattenPackage(&package_buffer)) {
       return false;
     }
diff --git a/tools/aapt2/format/binary/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h
index 73c1729..4360db1 100644
--- a/tools/aapt2/format/binary/TableFlattener.h
+++ b/tools/aapt2/format/binary/TableFlattener.h
@@ -19,6 +19,7 @@
 
 #include "android-base/macros.h"
 
+#include "Resource.h"
 #include "ResourceTable.h"
 #include "process/IResourceTableConsumer.h"
 #include "util/BigBuffer.h"
@@ -41,8 +42,8 @@
   // have name indices that point to this single value
   bool collapse_key_stringpool = false;
 
-  // Set of whitelisted resource names to avoid altering in key stringpool
-  std::set<std::string> whitelisted_resources;
+  // Set of resources to avoid collapsing to a single entry in key stringpool.
+  std::set<ResourceName> name_collapse_exemptions;
 
   // Map from original resource paths to shortened resource paths.
   std::map<std::string, std::string> shortened_path_map;
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index a940923..8fbdd7f 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -518,7 +518,7 @@
   ASSERT_FALSE(Flatten(context.get(), {}, table.get(), &result));
 }
 
-TEST_F(TableFlattenerTest, ObfuscatingResourceNamesNoWhitelistSucceeds) {
+TEST_F(TableFlattenerTest, ObfuscatingResourceNamesNoNameCollapseExemptionsSucceeds) {
   std::unique_ptr<ResourceTable> table =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.test", 0x7f)
@@ -572,7 +572,7 @@
                      ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u));
 }
 
-TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithWhitelistSucceeds) {
+TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithNameCollapseExemptionsSucceeds) {
   std::unique_ptr<ResourceTable> table =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.test", 0x7f)
@@ -591,21 +591,22 @@
 
   TableFlattenerOptions options;
   options.collapse_key_stringpool = true;
-  options.whitelisted_resources.insert("test");
-  options.whitelisted_resources.insert("three");
+  options.name_collapse_exemptions.insert(ResourceName({}, ResourceType::kId, "one"));
+  options.name_collapse_exemptions.insert(ResourceName({}, ResourceType::kString, "test"));
   ResTable res_table;
 
   ASSERT_TRUE(Flatten(context_.get(), options, table.get(), &res_table));
 
-  EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated",
+  EXPECT_TRUE(Exists(&res_table, "com.app.test:id/one",
                      ResourceId(0x7f020000), {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
 
   EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated",
                      ResourceId(0x7f020001), {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
 
-  EXPECT_TRUE(Exists(&res_table, "com.app.test:id/three", ResourceId(0x7f020002), {},
-                     Res_value::TYPE_REFERENCE, 0x7f020000u, 0u));
+  EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated",
+                     ResourceId(0x7f020002), {}, Res_value::TYPE_REFERENCE, 0x7f020000u, 0u));
 
+  // Note that this resource is also named "one", but it's a different type, so gets obfuscated.
   EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/0_resource_name_obfuscated",
                      ResourceId(0x7f030000), {}, Res_value::TYPE_INT_DEC, 1u,
                      ResTable_config::CONFIG_VERSION));