Merge "Replace com.android.internal.util.Preconditions.checkNotNull with java.util.Objects.requireNonNull"
diff --git a/Android.bp b/Android.bp
index 15188ec..bf901ec 100644
--- a/Android.bp
+++ b/Android.bp
@@ -245,7 +245,7 @@
         ":libcamera_client_framework_aidl",
         ":libupdate_engine_aidl",
         // TODO: this needs to be removed when statsd-framework.jar is separated out
-        ":statsd_aidl",
+        ":statsd_java_aidl",
         ":storaged_aidl",
         ":vold_aidl",
 
@@ -467,6 +467,7 @@
     installable: false, // this lib is a build-only library
     static_libs: [
         "framework-minus-apex",
+        "updatable_media_stubs",
         "framework-appsearch", // TODO(b/146218515): should be framework-appsearch-stubs
         "framework-sdkext-stubs-systemapi",
         // TODO(b/146167933): Use framework-statsd-stubs instead.
@@ -799,11 +800,7 @@
 filegroup {
     name: "incremental_aidl",
     srcs: [
-        "core/java/android/os/incremental/IIncrementalManagerNative.aidl",
-        "core/java/android/os/incremental/IIncrementalManager.aidl",
-        "core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl",
         "core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl",
-        "core/java/android/os/incremental/NamedParcelFileDescriptor.aidl",
     ],
     path: "core/java",
 }
@@ -811,7 +808,20 @@
 filegroup {
     name: "dataloader_aidl",
     srcs: [
+        "core/java/android/content/pm/DataLoaderParamsParcel.aidl",
+        "core/java/android/content/pm/FileSystemControlParcel.aidl",
         "core/java/android/content/pm/IDataLoaderStatusListener.aidl",
+        "core/java/android/content/pm/IPackageInstallerSessionFileSystemConnector.aidl",
+        "core/java/android/content/pm/NamedParcelFileDescriptor.aidl",
+    ],
+    path: "core/java",
+}
+
+filegroup {
+    name: "incremental_manager_aidl",
+    srcs: [
+        "core/java/android/os/incremental/IIncrementalManager.aidl",
+        "core/java/android/os/incremental/IIncrementalManagerNative.aidl",
     ],
     path: "core/java",
 }
@@ -821,9 +831,6 @@
     srcs: [
         ":incremental_aidl",
     ],
-    imports: [
-        "libdataloader_aidl",
-    ],
     backend: {
         java: {
             sdk_version: "28",
@@ -842,6 +849,9 @@
     srcs: [
         ":dataloader_aidl",
     ],
+    imports: [
+        "libincremental_aidl",
+    ],
     backend: {
         java: {
             sdk_version: "28",
@@ -850,8 +860,30 @@
             enabled: true,
         },
         ndk: {
+            enabled: false,
+        },
+    },
+}
+
+aidl_interface {
+    name: "libincremental_manager_aidl",
+    srcs: [
+        ":incremental_manager_aidl",
+    ],
+    imports: [
+        "libincremental_aidl",
+        "libdataloader_aidl",
+    ],
+    backend: {
+        java: {
+            sdk_version: "28",
+        },
+        cpp: {
             enabled: true,
         },
+        ndk: {
+            enabled: false,
+        },
     },
 }
 
@@ -935,6 +967,7 @@
         "core/java/android/os/RemoteException.java",
         "core/java/android/util/AndroidException.java",
     ],
+    libs: [ "unsupportedappusage" ],
 
     dxflags: ["--core-library"],
     installable: false,
diff --git a/CleanSpec.mk b/CleanSpec.mk
index f94de29..b84e715 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -257,6 +257,8 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java/com/google/android/mms)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/*-service.jar)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/service-statsd.jar)
+$(call add-clean-step, rm -rf $(SOONG_OUT_DIR)/.intermediates/frameworks/base/libincremental_aidl-cpp-source/)
+$(call add-clean-step, rm -rf $(SOONG_OUT_DIR)/.intermediates/frameworks/base/libincremental_manager_aidl-cpp-source/)
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
 # ******************************************************************
diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp
index e6ca544..aed6ad9 100644
--- a/apex/statsd/aidl/Android.bp
+++ b/apex/statsd/aidl/Android.bp
@@ -17,6 +17,18 @@
 // TODO(b/145815909): move StatsDimensionsValue.aidl and StatsLogEventWrapper.aidl here
 filegroup {
     name: "statsd_aidl",
+    srcs: [
+        "android/os/IPullAtomCallback.aidl",
+        "android/os/IPullAtomResultReceiver.aidl",
+        "android/os/IStatsCompanionService.aidl",
+        "android/os/IStatsd.aidl",
+        "android/os/IStatsPullerCallback.aidl",
+        "android/util/StatsEventParcel.aidl",
+    ],
+}
+
+filegroup {
+    name: "statsd_java_aidl",
     srcs: ["**/*.aidl"],
 }
 
diff --git a/apex/statsd/aidl/android/os/IStatsManagerService.aidl b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
new file mode 100644
index 0000000..45ba3a2
--- /dev/null
+++ b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.app.PendingIntent;
+
+/**
+  * Binder interface to communicate with the Java-based statistics service helper.
+  * Contains parcelable objects available only in Java.
+  * {@hide}
+  */
+interface IStatsManagerService {
+
+    /**
+     * Registers the given pending intent for this config key. This intent is invoked when the
+     * memory consumed by the metrics for this configuration approach the pre-defined limits. There
+     * can be at most one listener per config key.
+     *
+     * Requires Manifest.permission.DUMP.
+     */
+    void setDataFetchOperation(long configKey, in PendingIntent pendingIntent,
+        in String packageName);
+
+    /**
+     * Registers the given pending intent for this packagename. This intent is invoked when the
+     * active status of any of the configs sent by this package changes and will contain a list of
+     * config ids that are currently active. It also returns the list of configs that are currently
+     * active. There can be at most one active configs changed listener per package.
+     *
+     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+     */
+    long[] setActiveConfigsChangedOperation(in PendingIntent pendingIntent, in String packageName);
+
+    /**
+     * Set the PendingIntent to be used when broadcasting subscriber
+     * information to the given subscriberId within the given config.
+     *
+     * Suppose that the calling uid has added a config with key configKey, and that in this config
+     * it is specified that when a particular anomaly is detected, a broadcast should be sent to
+     * a BroadcastSubscriber with id subscriberId. This function links the given pendingIntent with
+     * that subscriberId (for that config), so that this pendingIntent is used to send the broadcast
+     * when the anomaly is detected.
+     *
+     * This function can only be called by the owner (uid) of the config. It must be called each
+     * time statsd starts. Later calls overwrite previous calls; only one PendingIntent is stored.
+     *
+     * Requires Manifest.permission.DUMP.
+     */
+    void setBroadcastSubscriber(long configKey, long subscriberId, in PendingIntent pendingIntent,
+                                in String packageName);
+}
\ No newline at end of file
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java
new file mode 100644
index 0000000..71b52e2
--- /dev/null
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.stats;
+
+import android.content.Context;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+
+/**
+ * @hide
+ */
+public class StatsCompanion {
+    private static final String TAG = "StatsCompanion";
+    private static final boolean DEBUG = false;
+
+    /**
+     * Lifecycle class for both {@link StatsCompanionService} and {@link StatsManagerService}.
+     */
+    public static final class Lifecycle extends SystemService {
+        private StatsCompanionService mStatsCompanionService;
+        private StatsManagerService mStatsManagerService;
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            mStatsCompanionService = new StatsCompanionService(getContext());
+            mStatsManagerService = new StatsManagerService(getContext());
+            mStatsCompanionService.setStatsManagerService(mStatsManagerService);
+            mStatsManagerService.setStatsCompanionService(mStatsCompanionService);
+
+            try {
+                publishBinderService(Context.STATS_COMPANION_SERVICE,
+                        mStatsCompanionService);
+                if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_COMPANION_SERVICE);
+                publishBinderService(Context.STATS_MANAGER_SERVICE,
+                        mStatsManagerService);
+                if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_MANAGER_SERVICE);
+            } catch (Exception e) {
+                Slog.e(TAG, "Failed to publishBinderService", e);
+            }
+        }
+
+        @Override
+        public void onBootPhase(int phase) {
+            super.onBootPhase(phase);
+            if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+                mStatsCompanionService.systemReady();
+                mStatsManagerService.systemReady();
+            }
+        }
+    }
+}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index bc7716e..7c25c6c 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -137,7 +137,6 @@
 import com.android.internal.util.DumpUtils;
 import com.android.server.BinderCallsStatsService;
 import com.android.server.LocalServices;
-import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
 import com.android.server.am.MemoryStatUtil.MemoryStat;
 import com.android.server.notification.NotificationManagerService;
@@ -173,6 +172,7 @@
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
@@ -278,6 +278,8 @@
     private final BroadcastReceiver mUserUpdateReceiver;
     private final ShutdownEventReceiver mShutdownEventReceiver;
 
+    private StatsManagerService mStatsManagerService;
+
     private static final class PullerKey {
         private final int mUid;
         private final int mAtomTag;
@@ -2135,8 +2137,8 @@
         pulledData.add(e);
     }
 
-    private void pullDangerousPermissionState(long elapsedNanos, final long wallClockNanos,
-            List<StatsLogEventWrapper> pulledData) {
+    private void pullDangerousPermissionState(int atomId, long elapsedNanos,
+            final long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
         long token = Binder.clearCallingIdentity();
         Set<Integer> reportedUids = new HashSet<>();
         try {
@@ -2165,6 +2167,11 @@
                     }
                     reportedUids.add(pkg.applicationInfo.uid);
 
+                    if (atomId == StatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED
+                            && ThreadLocalRandom.current().nextFloat() > 0.2f) {
+                        continue;
+                    }
+
                     int numPerms = pkg.requestedPermissions.length;
                     for (int permNum  = 0; permNum < numPerms; permNum++) {
                         String permName = pkg.requestedPermissions[permNum];
@@ -2174,7 +2181,7 @@
                         try {
                             permissionInfo = pm.getPermissionInfo(permName, 0);
                             permissionFlags =
-                                pm.getPermissionFlags(permName, pkg.packageName, user);
+                                    pm.getPermissionFlags(permName, pkg.packageName, user);
 
                         } catch (PackageManager.NameNotFoundException ignored) {
                             continue;
@@ -2185,11 +2192,13 @@
                         }
 
                         StatsLogEventWrapper e = new StatsLogEventWrapper(
-                                StatsLog.DANGEROUS_PERMISSION_STATE, elapsedNanos, wallClockNanos);
+                                atomId, elapsedNanos, wallClockNanos);
 
                         e.writeString(permName);
                         e.writeInt(pkg.applicationInfo.uid);
-                        e.writeString(null);
+                        if (atomId == StatsLog.DANGEROUS_PERMISSION_STATE) {
+                            e.writeString(null);
+                        }
                         e.writeBoolean((pkg.requestedPermissionsFlags[permNum]
                                 & REQUESTED_PERMISSION_GRANTED) != 0);
                         e.writeInt(permissionFlags);
@@ -2639,7 +2648,13 @@
                 break;
             }
             case StatsLog.DANGEROUS_PERMISSION_STATE: {
-                pullDangerousPermissionState(elapsedNanos, wallClockNanos, ret);
+                pullDangerousPermissionState(StatsLog.DANGEROUS_PERMISSION_STATE, elapsedNanos,
+                        wallClockNanos, ret);
+                break;
+            }
+            case StatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED: {
+                pullDangerousPermissionState(StatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED,
+                        elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.TIME_ZONE_DATA_INFO: {
@@ -2681,6 +2696,7 @@
             Slog.d(TAG, "learned that statsdReady");
         }
         sayHiToStatsd(); // tell statsd that we're ready too and link to it
+        mStatsManagerService.systemReady();
         mContext.sendBroadcastAsUser(new Intent(StatsManager.ACTION_STATSD_STARTED)
                         .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND),
                 UserHandle.SYSTEM, android.Manifest.permission.DUMP);
@@ -2736,7 +2752,7 @@
         }
     }
 
-    // Lifecycle and related code
+    // Statsd related code
 
     /**
      * Fetches the statsd IBinder service.
@@ -2747,42 +2763,18 @@
         return IStatsd.Stub.asInterface(ServiceManager.getService("stats"));
     }
 
-    public static final class Lifecycle extends SystemService {
-        private StatsCompanionService mStatsCompanionService;
-
-        public Lifecycle(Context context) {
-            super(context);
-        }
-
-        @Override
-        public void onStart() {
-            mStatsCompanionService = new StatsCompanionService(getContext());
-            try {
-                publishBinderService(Context.STATS_COMPANION_SERVICE,
-                        mStatsCompanionService);
-                if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_COMPANION_SERVICE);
-            } catch (Exception e) {
-                Slog.e(TAG, "Failed to publishBinderService", e);
-            }
-        }
-
-        @Override
-        public void onBootPhase(int phase) {
-            super.onBootPhase(phase);
-            if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
-                mStatsCompanionService.systemReady();
-            }
-        }
-    }
-
     /**
      * Now that the android system is ready, StatsCompanion is ready too, so inform statsd.
      */
-    private void systemReady() {
+    void systemReady() {
         if (DEBUG) Slog.d(TAG, "Learned that systemReady");
         sayHiToStatsd();
     }
 
+    void setStatsManagerService(StatsManagerService statsManagerService) {
+        mStatsManagerService = statsManagerService;
+    }
+
     /**
      * Tells statsd that statscompanion is ready. If the binder call returns, link to
      * statsd.
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
new file mode 100644
index 0000000..f3bf909
--- /dev/null
+++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
@@ -0,0 +1,108 @@
+/*
+ * 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.stats;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.IStatsManagerService;
+import android.os.IStatsd;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * @hide
+ */
+public class StatsManagerService extends IStatsManagerService.Stub {
+
+    private static final String TAG = "StatsManagerService";
+    private static final boolean DEBUG = false;
+
+    @GuardedBy("sStatsdLock")
+    private static IStatsd sStatsd;
+    private static final Object sStatsdLock = new Object();
+
+    private StatsCompanionService mStatsCompanionService;
+
+    public StatsManagerService(Context context) {
+        super();
+    }
+
+    @Override
+    public void setDataFetchOperation(long configKey, PendingIntent pendingIntent,
+            String packageName) {
+        // no-op
+        if (DEBUG) {
+            Slog.d(TAG, "setDataFetchOperation");
+        }
+    }
+
+    @Override
+    public long[] setActiveConfigsChangedOperation(PendingIntent pendingIntent,
+            String packageName) {
+        // no-op
+        if (DEBUG) {
+            Slog.d(TAG, "setActiveConfigsChangedOperation");
+        }
+        return new long[]{};
+    }
+
+    @Override
+    public void setBroadcastSubscriber(long configKey, long subscriberId,
+            PendingIntent pendingIntent, String packageName) {
+        //no-op
+        if (DEBUG) {
+            Slog.d(TAG, "setBroadcastSubscriber");
+        }
+    }
+
+    void setStatsCompanionService(StatsCompanionService statsCompanionService) {
+        mStatsCompanionService = statsCompanionService;
+    }
+
+    void systemReady() {
+        if (DEBUG) {
+            Slog.d(TAG, "statsdReady");
+        }
+        setupStatsManagerService();
+    }
+
+    private void setupStatsManagerService() {
+        synchronized (sStatsdLock) {
+            if (sStatsd != null) {
+                if (DEBUG) {
+                    Slog.e(TAG, "Trying to fetch statsd, but it was already fetched",
+                            new IllegalStateException(
+                                    "sStatsd is not null when being fetched"));
+                }
+                return;
+            }
+            sStatsd = IStatsd.Stub.asInterface(ServiceManager.getService("stats"));
+            // Assume statsd is ready since this is called form statscompanion, link to statsd.
+            try {
+                sStatsd.asBinder().linkToDeath((IBinder.DeathRecipient) () -> {
+                    sStatsd = null;
+                }, 0);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e);
+            }
+        }
+    }
+}
diff --git a/api/current.txt b/api/current.txt
index 52dd1a1..39d5263 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16934,7 +16934,7 @@
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Rational> CONTROL_AE_COMPENSATION_STEP;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> CONTROL_AE_LOCK_AVAILABLE;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AF_AVAILABLE_MODES;
-    field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.CapabilityAndMaxSize[]> CONTROL_AVAILABLE_BOKEH_CAPABILITIES;
+    field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.Capability[]> CONTROL_AVAILABLE_BOKEH_CAPABILITIES;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_EFFECTS;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_MODES;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_SCENE_MODES;
@@ -16945,6 +16945,7 @@
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AF;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AWB;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>> CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE;
+    field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Float>> CONTROL_ZOOM_RATIO_RANGE;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> DEPTH_DEPTH_IS_EXCLUSIVE;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> DISTORTION_CORRECTION_AVAILABLE_MODES;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> EDGE_AVAILABLE_EDGE_MODES;
@@ -17357,6 +17358,7 @@
     field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST;
     field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_SCENE_MODE;
     field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_VIDEO_STABILIZATION_MODE;
+    field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> CONTROL_ZOOM_RATIO;
     field @NonNull public static final android.os.Parcelable.Creator<android.hardware.camera2.CaptureRequest> CREATOR;
     field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> DISTORTION_CORRECTION_MODE;
     field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> EDGE_MODE;
@@ -17443,6 +17445,7 @@
     field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST;
     field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_SCENE_MODE;
     field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_VIDEO_STABILIZATION_MODE;
+    field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> CONTROL_ZOOM_RATIO;
     field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> DISTORTION_CORRECTION_MODE;
     field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> EDGE_MODE;
     field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> FLASH_MODE;
@@ -17532,9 +17535,10 @@
     field public static final int COUNT = 4; // 0x4
   }
 
-  public final class CapabilityAndMaxSize {
+  public final class Capability {
     method @NonNull public android.util.Size getMaxStreamingSize();
     method public int getMode();
+    method @NonNull public android.util.Range<java.lang.Float> getZoomRatioRange();
   }
 
   public final class ColorSpaceTransform {
@@ -27639,6 +27643,7 @@
     method @Nullable public android.app.PendingIntent getSessionActivity();
     method @NonNull public android.os.Bundle getSessionInfo();
     method @NonNull public android.media.session.MediaSession.Token getSessionToken();
+    method @NonNull public String getTag();
     method @NonNull public android.media.session.MediaController.TransportControls getTransportControls();
     method public void registerCallback(@NonNull android.media.session.MediaController.Callback);
     method public void registerCallback(@NonNull android.media.session.MediaController.Callback, @Nullable android.os.Handler);
@@ -30041,6 +30046,7 @@
   @Deprecated public static class WifiConfiguration.GroupCipher {
     field @Deprecated public static final int CCMP = 3; // 0x3
     field @Deprecated public static final int GCMP_256 = 5; // 0x5
+    field @Deprecated public static final int SMS4 = 6; // 0x6
     field @Deprecated public static final int TKIP = 2; // 0x2
     field @Deprecated public static final int WEP104 = 1; // 0x1
     field @Deprecated public static final int WEP40 = 0; // 0x0
@@ -30070,6 +30076,7 @@
     field @Deprecated public static final int CCMP = 2; // 0x2
     field @Deprecated public static final int GCMP_256 = 3; // 0x3
     field @Deprecated public static final int NONE = 0; // 0x0
+    field @Deprecated public static final int SMS4 = 4; // 0x4
     field @Deprecated public static final int TKIP = 1; // 0x1
     field @Deprecated public static final String[] strings;
     field @Deprecated public static final String varName = "pairwise";
@@ -30077,6 +30084,7 @@
 
   @Deprecated public static class WifiConfiguration.Protocol {
     field @Deprecated public static final int RSN = 1; // 0x1
+    field @Deprecated public static final int WAPI = 3; // 0x3
     field @Deprecated public static final int WPA = 0; // 0x0
     field @Deprecated public static final String[] strings;
     field @Deprecated public static final String varName = "proto";
@@ -30123,6 +30131,12 @@
     method @Deprecated public void setSubjectMatch(String);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiEnterpriseConfig> CREATOR;
+    field public static final String EXTRA_WAPI_AS_CERTIFICATE_DATA = "android.net.wifi.extra.WAPI_AS_CERTIFICATE_DATA";
+    field public static final String EXTRA_WAPI_AS_CERTIFICATE_NAME = "android.net.wifi.extra.WAPI_AS_CERTIFICATE_NAME";
+    field public static final String EXTRA_WAPI_USER_CERTIFICATE_DATA = "android.net.wifi.extra.WAPI_USER_CERTIFICATE_DATA";
+    field public static final String EXTRA_WAPI_USER_CERTIFICATE_NAME = "android.net.wifi.extra.WAPI_USER_CERTIFICATE_NAME";
+    field public static final String WAPI_AS_CERTIFICATE = "WAPIAS_";
+    field public static final String WAPI_USER_CERTIFICATE = "WAPIUSR_";
   }
 
   public static final class WifiEnterpriseConfig.Eap {
@@ -30135,6 +30149,7 @@
     field public static final int TLS = 1; // 0x1
     field public static final int TTLS = 2; // 0x2
     field public static final int UNAUTH_TLS = 7; // 0x7
+    field public static final int WAPI_CERT = 8; // 0x8
   }
 
   public static final class WifiEnterpriseConfig.Phase2 {
@@ -30206,6 +30221,7 @@
     method public boolean isPreferredNetworkOffloadSupported();
     method @Deprecated public boolean isScanAlwaysAvailable();
     method public boolean isTdlsSupported();
+    method public boolean isWapiSupported();
     method public boolean isWifiEnabled();
     method public boolean isWpa3SaeSupported();
     method public boolean isWpa3SuiteBSupported();
@@ -30362,6 +30378,8 @@
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPasspointConfig(@NonNull android.net.wifi.hotspot2.PasspointConfiguration);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSsid(@NonNull String);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiEnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiPassphrase(@NonNull String);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa2EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa2Passphrase(@NonNull String);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa3EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
@@ -30648,6 +30666,10 @@
     ctor public WifiP2pConfig();
     ctor public WifiP2pConfig(android.net.wifi.p2p.WifiP2pConfig);
     method public int describeContents();
+    method public int getGroupOwnerBand();
+    method public int getNetworkId();
+    method @Nullable public String getNetworkName();
+    method @Nullable public String getPassphrase();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pConfig> CREATOR;
     field public static final int GROUP_OWNER_BAND_2GHZ = 1; // 0x1
@@ -30721,6 +30743,8 @@
     method public boolean isGroupOwner();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pGroup> CREATOR;
+    field public static final int PERSISTENT_NET_ID = -2; // 0xfffffffe
+    field public static final int TEMPORARY_NET_ID = -1; // 0xffffffff
   }
 
   public class WifiP2pInfo implements android.os.Parcelable {
@@ -35753,7 +35777,7 @@
     method @Deprecated public void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
     method public static boolean supportsMultipleUsers();
     field public static final String ALLOW_PARENT_PROFILE_APP_LINKING = "allow_parent_profile_app_linking";
-    field public static final String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile";
+    field @Deprecated public static final String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile";
     field public static final String DISALLOW_ADD_USER = "no_add_user";
     field public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
     field public static final String DISALLOW_AIRPLANE_MODE = "no_airplane_mode";
@@ -35792,7 +35816,7 @@
     field public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
     field public static final String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
     field public static final String DISALLOW_PRINTING = "no_printing";
-    field public static final String DISALLOW_REMOVE_MANAGED_PROFILE = "no_remove_managed_profile";
+    field @Deprecated public static final String DISALLOW_REMOVE_MANAGED_PROFILE = "no_remove_managed_profile";
     field public static final String DISALLOW_REMOVE_USER = "no_remove_user";
     field public static final String DISALLOW_SAFE_BOOT = "no_safe_boot";
     field public static final String DISALLOW_SET_USER_ICON = "no_set_user_icon";
@@ -39139,6 +39163,7 @@
     field public static final String ACTION_APP_SEARCH_SETTINGS = "android.settings.APP_SEARCH_SETTINGS";
     field public static final String ACTION_APP_USAGE_SETTINGS = "android.settings.action.APP_USAGE_SETTINGS";
     field public static final String ACTION_BATTERY_SAVER_SETTINGS = "android.settings.BATTERY_SAVER_SETTINGS";
+    field public static final String ACTION_BIOMETRIC_ENROLL = "android.settings.BIOMETRIC_ENROLL";
     field public static final String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
     field public static final String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
     field public static final String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
@@ -39150,7 +39175,7 @@
     field public static final String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
     field public static final String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
     field public static final String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
-    field public static final String ACTION_FINGERPRINT_ENROLL = "android.settings.FINGERPRINT_ENROLL";
+    field @Deprecated public static final String ACTION_FINGERPRINT_ENROLL = "android.settings.FINGERPRINT_ENROLL";
     field public static final String ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS";
     field public static final String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS";
     field public static final String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS";
@@ -39213,6 +39238,7 @@
     field public static final String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
     field public static final String EXTRA_AUTHORITIES = "authorities";
     field public static final String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
+    field public static final String EXTRA_BIOMETRIC_MINIMUM_STRENGTH_REQUIRED = "android.provider.extra.BIOMETRIC_MINIMUM_STRENGTH_REQUIRED";
     field public static final String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
     field public static final String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
     field public static final String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
@@ -44364,19 +44390,27 @@
     field @Deprecated public static final String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
     field public static final String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED";
     field public static final String ACTION_PHONE_ACCOUNT_UNREGISTERED = "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED";
+    field public static final String ACTION_POST_CALL = "android.telecom.action.POST_CALL";
     field public static final String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
     field public static final String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
     field public static final String ACTION_SHOW_MISSED_CALLS_NOTIFICATION = "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION";
     field public static final String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
+    field public static final int DURATION_LONG = 3; // 0x3
+    field public static final int DURATION_MEDIUM = 2; // 0x2
+    field public static final int DURATION_SHORT = 1; // 0x1
+    field public static final int DURATION_VERY_SHORT = 0; // 0x0
     field public static final String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
     field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
     field public static final String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
+    field public static final String EXTRA_CALL_DURATION = "android.telecom.extra.CALL_DURATION";
     field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telecom.extra.CALL_NETWORK_TYPE";
     field public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
     field public static final String EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME = "android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME";
     field public static final String EXTRA_DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME = "android.telecom.extra.DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME";
+    field public static final String EXTRA_DISCONNECT_CAUSE = "android.telecom.extra.DISCONNECT_CAUSE";
+    field public static final String EXTRA_HANDLE = "android.telecom.extra.HANDLE";
     field public static final String EXTRA_INCOMING_CALL_ADDRESS = "android.telecom.extra.INCOMING_CALL_ADDRESS";
     field public static final String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS";
     field public static final String EXTRA_INCOMING_VIDEO_STATE = "android.telecom.extra.INCOMING_VIDEO_STATE";
diff --git a/api/system-current.txt b/api/system-current.txt
index 1108927..d67305d 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4652,12 +4652,20 @@
     ctor public LinkProperties(@Nullable android.net.LinkProperties);
     method public boolean addDnsServer(@NonNull java.net.InetAddress);
     method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
+    method public boolean addPcscfServer(@NonNull java.net.InetAddress);
+    method @NonNull public java.util.List<java.net.InetAddress> getAddresses();
+    method @NonNull public java.util.List<java.lang.String> getAllInterfaceNames();
+    method @NonNull public java.util.List<android.net.LinkAddress> getAllLinkAddresses();
+    method @NonNull public java.util.List<android.net.RouteInfo> getAllRoutes();
     method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
     method @Nullable public String getTcpBufferSizes();
     method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
     method public boolean hasGlobalIpv6Address();
     method public boolean hasIpv4Address();
+    method public boolean hasIpv4DefaultRoute();
+    method public boolean hasIpv4DnsServer();
     method public boolean hasIpv6DefaultRoute();
+    method public boolean hasIpv6DnsServer();
     method public boolean isIpv4Provisioned();
     method public boolean isIpv6Provisioned();
     method public boolean isProvisioned();
@@ -5542,6 +5550,11 @@
     field @Deprecated public byte id;
   }
 
+  public class ScanResult implements android.os.Parcelable {
+    field public static final int KEY_MGMT_WAPI_CERT = 14; // 0xe
+    field public static final int KEY_MGMT_WAPI_PSK = 13; // 0xd
+  }
+
   public final class SoftApConfiguration implements android.os.Parcelable {
     method public int describeContents();
     method public int getBand();
@@ -5552,9 +5565,10 @@
     method @Nullable public String getWpa2Passphrase();
     method public boolean isHiddenSsid();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int BAND_2GHZ = 0; // 0x0
-    field public static final int BAND_5GHZ = 1; // 0x1
-    field public static final int BAND_ANY = -1; // 0xffffffff
+    field public static final int BAND_2GHZ = 1; // 0x1
+    field public static final int BAND_5GHZ = 2; // 0x2
+    field public static final int BAND_6GHZ = 4; // 0x4
+    field public static final int BAND_ANY = 7; // 0x7
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApConfiguration> CREATOR;
     field public static final int SECURITY_TYPE_OPEN = 0; // 0x0
     field public static final int SECURITY_TYPE_WPA2_PSK = 1; // 0x1
@@ -5566,7 +5580,7 @@
     method @NonNull public android.net.wifi.SoftApConfiguration build();
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBand(int);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress);
-    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int);
+    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int, int);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setSsid(@Nullable String);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setWpa2Passphrase(@Nullable String);
@@ -5639,6 +5653,8 @@
   }
 
   @Deprecated public static class WifiConfiguration.KeyMgmt {
+    field @Deprecated public static final int WAPI_CERT = 14; // 0xe
+    field @Deprecated public static final int WAPI_PSK = 13; // 0xd
     field @Deprecated public static final int WPA2_PSK = 4; // 0x4
   }
 
@@ -5675,10 +5691,12 @@
     method @NonNull public String getCaPath();
     method @NonNull public String getClientCertificateAlias();
     method public int getOcsp();
+    method @Nullable public String getWapiCertSuite();
     method public void setCaCertificateAliases(@Nullable String[]);
     method public void setCaPath(@Nullable String);
     method public void setClientCertificateAlias(@Nullable String);
     method public void setOcsp(int);
+    method public void setWapiCertSuite(@Nullable String);
     field public static final int OCSP_NONE = 0; // 0x0
     field public static final int OCSP_REQUEST_CERT_STATUS = 1; // 0x1
     field public static final int OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS = 3; // 0x3
@@ -8722,6 +8740,13 @@
   public class CbGeoUtils {
   }
 
+  public static class CbGeoUtils.Circle implements android.telephony.CbGeoUtils.Geometry {
+    ctor public CbGeoUtils.Circle(@NonNull android.telephony.CbGeoUtils.LatLng, double);
+    method public boolean contains(@NonNull android.telephony.CbGeoUtils.LatLng);
+    method @NonNull public android.telephony.CbGeoUtils.LatLng getCenter();
+    method public double getRadius();
+  }
+
   public static interface CbGeoUtils.Geometry {
     method public boolean contains(@NonNull android.telephony.CbGeoUtils.LatLng);
   }
@@ -8734,6 +8759,12 @@
     field public final double lng;
   }
 
+  public static class CbGeoUtils.Polygon implements android.telephony.CbGeoUtils.Geometry {
+    ctor public CbGeoUtils.Polygon(@NonNull java.util.List<android.telephony.CbGeoUtils.LatLng>);
+    method public boolean contains(@NonNull android.telephony.CbGeoUtils.LatLng);
+    method @NonNull public java.util.List<android.telephony.CbGeoUtils.LatLng> getVertices();
+  }
+
   public class CellBroadcastIntents {
     method public static void sendOrderedBroadcastForBackgroundReceivers(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
   }
@@ -9735,6 +9766,7 @@
     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 isAnyRadioPoweredOn();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
     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 isDataEnabledForApn(int);
@@ -9788,6 +9820,10 @@
     method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String);
     field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED";
     field public static final String ACTION_EMERGENCY_ASSISTANCE = "android.telephony.action.EMERGENCY_ASSISTANCE";
+    field public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED = "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED";
+    field public static final String ACTION_EMERGENCY_CALL_STATE_CHANGED = "android.intent.action.EMERGENCY_CALL_STATE_CHANGED";
+    field public static final String ACTION_NETWORK_SET_TIME = "android.telephony.action.NETWORK_SET_TIME";
+    field public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS = "android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS";
     field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
     field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
     field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
diff --git a/api/test-current.txt b/api/test-current.txt
index 219258e..7deac26 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -12,6 +12,7 @@
     field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
     field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
     field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
+    field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES";
     field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
     field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
     field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
@@ -629,6 +630,9 @@
   public class StorageStatsManager {
     method public boolean isQuotaSupported(@NonNull java.util.UUID);
     method public boolean isReservedSupported(@NonNull java.util.UUID);
+    method @NonNull @WorkerThread public java.util.Collection<android.os.storage.CrateInfo> queryCratesForPackage(@NonNull java.util.UUID, @NonNull String, @NonNull android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull @WorkerThread public java.util.Collection<android.os.storage.CrateInfo> queryCratesForUid(@NonNull java.util.UUID, int) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_CRATES) @WorkerThread public java.util.Collection<android.os.storage.CrateInfo> queryCratesForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
   }
 
   public final class UsageStatsManager {
@@ -2314,6 +2318,17 @@
 
 package android.os.storage {
 
+  public final class CrateInfo implements android.os.Parcelable {
+    ctor public CrateInfo(@NonNull CharSequence, long);
+    ctor public CrateInfo(@NonNull CharSequence);
+    method @Nullable public static android.os.storage.CrateInfo copyFrom(int, @Nullable String, @Nullable String);
+    method public int describeContents();
+    method public long getExpirationMillis();
+    method @NonNull public CharSequence getLabel();
+    method public void writeToParcel(@Nullable android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.os.storage.CrateInfo> CREATOR;
+  }
+
   public class StorageManager {
     method public static boolean hasIsolatedStorage();
   }
diff --git a/cmds/incidentd/src/WorkDirectory.cpp b/cmds/incidentd/src/WorkDirectory.cpp
index 7e7c642..9963533 100644
--- a/cmds/incidentd/src/WorkDirectory.cpp
+++ b/cmds/incidentd/src/WorkDirectory.cpp
@@ -666,7 +666,7 @@
         clock_gettime(CLOCK_REALTIME, &spec);
         timestampNs = int64_t(spec.tv_sec) * 1000 + spec.tv_nsec;
     } while (file_exists_locked(timestampNs));
-    return timestampNs;
+    return (timestampNs >= 0)? timestampNs : -timestampNs;
 }
 
 /**
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index a20436d..a2cfff2 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -356,7 +356,7 @@
     }
 
     // Pulled events will start at field 10000.
-    // Next: 10067
+    // Next: 10068
     oneof pulled {
         WifiBytesTransfer wifi_bytes_transfer = 10000;
         WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -424,6 +424,7 @@
         ProcessMemorySnapshot process_memory_snapshot = 10064;
         VmsClientStats vms_client_stats = 10065;
         NotificationRemoteViews notification_remote_views = 10066;
+        DangerousPermissionStateSampled dangerous_permission_state_sampled = 10067;
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP.
@@ -6490,7 +6491,8 @@
 
 /**
  * State of a dangerous permission requested by a package
- */
+ * Pulled from: StatsCompanionService
+*/
 message DangerousPermissionState {
     // Name of the permission
     optional string permission_name = 1;
@@ -7541,3 +7543,22 @@
     optional int64 dropped_bytes = 9;
     optional int64 dropped_packets = 10;
 }
+
+/**
+ * State of a dangerous permission requested by a package - sampled
+ * Pulled from: StatsCompanionService.java with data obtained from PackageManager API
+*/
+message DangerousPermissionStateSampled {
+    // Name of the permission
+    optional string permission_name = 1;
+
+    // Uid of the package
+    optional int32 uid = 2 [(is_uid) = true];
+
+    // If the permission is granted to the uid
+    optional bool is_granted = 3;
+
+    // Permission flags as per android.content.pm.PermissionFlags
+    optional int32 permission_flags = 4;
+}
+
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 9ee627e..f913118 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -284,6 +284,10 @@
         // NotiifcationRemoteViews.
         {{.atomTag = android::util::NOTIFICATION_REMOTE_VIEWS},
          {.puller = new StatsCompanionServicePuller(android::util::NOTIFICATION_REMOTE_VIEWS)}},
+        // PermissionStateSampled.
+        {{.atomTag = android::util::DANGEROUS_PERMISSION_STATE_SAMPLED},
+         {.puller =
+               new StatsCompanionServicePuller(android::util::DANGEROUS_PERMISSION_STATE_SAMPLED)}},
 };
 
 StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 564b9ee..692d91e 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -181,6 +181,8 @@
 
     static const int64_t kInt64Max = 0x7fffffffffffffffLL;
 
+    static const int32_t kMaxLoggedBucketDropEvents = 10;
+
     /**
      * Report a new config has been received and report the static stats about the config.
      *
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 64344e8..4ab6ec3 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -52,8 +52,13 @@
 // for GaugeMetricDataWrapper
 const int FIELD_ID_DATA = 1;
 const int FIELD_ID_SKIPPED = 2;
+// for SkippedBuckets
 const int FIELD_ID_SKIPPED_START_MILLIS = 3;
 const int FIELD_ID_SKIPPED_END_MILLIS = 4;
+const int FIELD_ID_SKIPPED_DROP_EVENT = 5;
+// for DumpEvent Proto
+const int FIELD_ID_BUCKET_DROP_REASON = 1;
+const int FIELD_ID_DROP_TIME = 2;
 // for GaugeMetricData
 const int FIELD_ID_DIMENSION_IN_WHAT = 1;
 const int FIELD_ID_BUCKET_INFO = 3;
@@ -193,7 +198,7 @@
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
     protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_IS_ACTIVE, isActiveLocked());
 
-    if (mPastBuckets.empty()) {
+    if (mPastBuckets.empty() && mSkippedBuckets.empty()) {
         return;
     }
 
@@ -212,13 +217,21 @@
 
     uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_GAUGE_METRICS);
 
-    for (const auto& pair : mSkippedBuckets) {
+    for (const auto& skippedBucket : mSkippedBuckets) {
         uint64_t wrapperToken =
                 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SKIPPED);
         protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_START_MILLIS,
-                           (long long)(NanoToMillis(pair.first)));
+                           (long long)(NanoToMillis(skippedBucket.bucketStartTimeNs)));
         protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_END_MILLIS,
-                           (long long)(NanoToMillis(pair.second)));
+                           (long long)(NanoToMillis(skippedBucket.bucketEndTimeNs)));
+
+        for (const auto& dropEvent : skippedBucket.dropEvents) {
+            uint64_t dropEventToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+                                                         FIELD_ID_SKIPPED_DROP_EVENT);
+            protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_BUCKET_DROP_REASON, dropEvent.reason);
+            protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DROP_TIME, (long long) (NanoToMillis(dropEvent.dropTimeNs)));
+            protoOutput->end(dropEventToken);
+        }
         protoOutput->end(wrapperToken);
     }
 
@@ -545,7 +558,10 @@
         info.mBucketEndNs = fullBucketEndTimeNs;
     }
 
-    if (info.mBucketEndNs - mCurrentBucketStartTimeNs >= mMinBucketSizeNs) {
+    // Add bucket to mPastBuckets if bucket is large enough.
+    // Otherwise, drop the bucket data and add bucket metadata to mSkippedBuckets.
+    bool isBucketLargeEnough = info.mBucketEndNs - mCurrentBucketStartTimeNs >= mMinBucketSizeNs;
+    if (isBucketLargeEnough) {
         for (const auto& slice : *mCurrentSlicedBucket) {
             info.mGaugeAtoms = slice.second;
             auto& bucketList = mPastBuckets[slice.first];
@@ -554,7 +570,13 @@
                  slice.first.toString().c_str());
         }
     } else {
-        mSkippedBuckets.emplace_back(info.mBucketStartNs, info.mBucketEndNs);
+        mCurrentSkippedBucket.bucketStartTimeNs = mCurrentBucketStartTimeNs;
+        mCurrentSkippedBucket.bucketEndTimeNs = eventTimeNs;
+        if (!maxDropEventsReached()) {
+            mCurrentSkippedBucket.dropEvents.emplace_back(
+                    buildDropEvent(eventTimeNs, BucketDropReason::BUCKET_TOO_SMALL));
+        }
+        mSkippedBuckets.emplace_back(mCurrentSkippedBucket);
     }
 
     // If we have anomaly trackers, we need to update the partial bucket values.
@@ -573,6 +595,7 @@
     StatsdStats::getInstance().noteBucketCount(mMetricId);
     mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
     mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
+    mCurrentSkippedBucket.reset();
 }
 
 size_t GaugeMetricProducer::byteSizeLocked() const {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 640a02a..12dcaa4 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -158,9 +158,6 @@
     // this slice (ie, for partial buckets, we use the last partial bucket in this full bucket).
     std::shared_ptr<DimToValMap> mCurrentSlicedBucketForAnomaly;
 
-    // Pairs of (elapsed start, elapsed end) denoting buckets that were skipped.
-    std::list<std::pair<int64_t, int64_t>> mSkippedBuckets;
-
     const int64_t mMinBucketSizeNs;
 
     // Translate Atom based bucket to single numeric value bucket for anomaly and updates the map
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 2c8f0e3..cf1d2f3 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -19,6 +19,7 @@
 
 #include "MetricProducer.h"
 
+#include "../guardrail/StatsdStats.h"
 #include "state/StateTracker.h"
 
 using android::util::FIELD_COUNT_REPEATED;
@@ -289,6 +290,17 @@
     }
 }
 
+DropEvent MetricProducer::buildDropEvent(const int64_t dropTimeNs, const BucketDropReason reason) {
+    DropEvent event;
+    event.reason = reason;
+    event.dropTimeNs = dropTimeNs;
+    return event;
+}
+
+bool MetricProducer::maxDropEventsReached() {
+    return mCurrentSkippedBucket.dropEvents.size() >= StatsdStats::kMaxLoggedBucketDropEvents;
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 3512f18..30675fc 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -70,6 +70,22 @@
     NO_TIME_CONSTRAINTS = 2
 };
 
+// Keep this in sync with BucketDropReason enum in stats_log.proto
+enum BucketDropReason {
+    // For ValueMetric, a bucket is dropped during a dump report request iff
+    // current bucket should be included, a pull is needed (pulled metric and
+    // condition is true), and we are under fast time constraints.
+    DUMP_REPORT_REQUESTED = 1,
+    EVENT_IN_WRONG_BUCKET = 2,
+    CONDITION_UNKNOWN = 3,
+    PULL_FAILED = 4,
+    PULL_DELAYED = 5,
+    DIMENSION_GUARDRAIL_REACHED = 6,
+    MULTIPLE_BUCKETS_SKIPPED = 7,
+    // Not an invalid bucket case, but the bucket is dropped.
+    BUCKET_TOO_SMALL = 8
+};
+
 struct Activation {
     Activation(const ActivationType& activationType, const int64_t ttlNs)
         : ttl_ns(ttlNs),
@@ -83,6 +99,28 @@
     const ActivationType activationType;
 };
 
+struct DropEvent {
+    // Reason for dropping the bucket and/or marking the bucket invalid.
+    BucketDropReason reason;
+    // The timestamp of the drop event.
+    int64_t dropTimeNs;
+};
+
+struct SkippedBucket {
+    // Start time of the dropped bucket.
+    int64_t bucketStartTimeNs;
+    // End time of the dropped bucket.
+    int64_t bucketEndTimeNs;
+    // List of events that invalidated this bucket.
+    std::vector<DropEvent> dropEvents;
+
+    void reset() {
+        bucketStartTimeNs = 0;
+        bucketEndTimeNs = 0;
+        dropEvents.clear();
+    }
+};
+
 // A MetricProducer is responsible for compute one single metrics, creating stats log report, and
 // writing the report to dropbox. MetricProducers should respond to package changes as required in
 // PackageInfoListener, but if none of the metrics are slicing by package name, then the update can
@@ -342,6 +380,12 @@
     void getMappedStateValue(const int32_t atomId, const HashableDimensionKey& queryKey,
                              FieldValue* value);
 
+    DropEvent buildDropEvent(const int64_t dropTimeNs, const BucketDropReason reason);
+
+    // Returns true if the number of drop events in the current bucket has
+    // exceeded the maximum number allowed, which is currently capped at 10.
+    bool maxDropEventsReached();
+
     const int64_t mMetricId;
 
     const ConfigKey mConfigKey;
@@ -403,6 +447,10 @@
     // atom to fields in the "what" atom.
     std::vector<Metric2State> mMetric2StateLinks;
 
+    SkippedBucket mCurrentSkippedBucket;
+    // Buckets that were invalidated and had their data dropped.
+    std::vector<SkippedBucket> mSkippedBuckets;
+
     FRIEND_TEST(CountMetricE2eTest, TestSlicedState);
     FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap);
     FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 2c99911..d8f399f 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -55,8 +55,13 @@
 // for ValueMetricDataWrapper
 const int FIELD_ID_DATA = 1;
 const int FIELD_ID_SKIPPED = 2;
+// for SkippedBuckets
 const int FIELD_ID_SKIPPED_START_MILLIS = 3;
 const int FIELD_ID_SKIPPED_END_MILLIS = 4;
+const int FIELD_ID_SKIPPED_DROP_EVENT = 5;
+// for DumpEvent Proto
+const int FIELD_ID_BUCKET_DROP_REASON = 1;
+const int FIELD_ID_DROP_TIME = 2;
 // for ValueMetricData
 const int FIELD_ID_DIMENSION_IN_WHAT = 1;
 const int FIELD_ID_BUCKET_INFO = 3;
@@ -211,7 +216,7 @@
         if (pullNeeded) {
             switch (dumpLatency) {
                 case FAST:
-                    invalidateCurrentBucket();
+                    invalidateCurrentBucket(dumpTimeNs, BucketDropReason::DUMP_REPORT_REQUESTED);
                     break;
                 case NO_TIME_CONSTRAINTS:
                     pullAndMatchEventsLocked(dumpTimeNs);
@@ -240,13 +245,22 @@
 
     uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_VALUE_METRICS);
 
-    for (const auto& pair : mSkippedBuckets) {
+    for (const auto& skippedBucket : mSkippedBuckets) {
         uint64_t wrapperToken =
                 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SKIPPED);
         protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_START_MILLIS,
-                           (long long)(NanoToMillis(pair.first)));
+                           (long long)(NanoToMillis(skippedBucket.bucketStartTimeNs)));
         protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_END_MILLIS,
-                           (long long)(NanoToMillis(pair.second)));
+                           (long long)(NanoToMillis(skippedBucket.bucketEndTimeNs)));
+        for (const auto& dropEvent : skippedBucket.dropEvents) {
+            uint64_t dropEventToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+                                                         FIELD_ID_SKIPPED_DROP_EVENT);
+            protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_BUCKET_DROP_REASON, dropEvent.reason);
+            protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DROP_TIME,
+                               (long long)(NanoToMillis(dropEvent.dropTimeNs)));
+            ;
+            protoOutput->end(dropEventToken);
+        }
         protoOutput->end(wrapperToken);
     }
 
@@ -321,16 +335,25 @@
     }
 }
 
-void ValueMetricProducer::invalidateCurrentBucketWithoutResetBase() {
+void ValueMetricProducer::invalidateCurrentBucketWithoutResetBase(const int64_t dropTimeNs,
+                                                                  const BucketDropReason reason) {
     if (!mCurrentBucketIsInvalid) {
-        // Only report once per invalid bucket.
+        // Only report to StatsdStats once per invalid bucket.
         StatsdStats::getInstance().noteInvalidatedBucket(mMetricId);
+
+        mCurrentSkippedBucket.bucketStartTimeNs = mCurrentBucketStartTimeNs;
+        mCurrentSkippedBucket.bucketEndTimeNs = getCurrentBucketEndTimeNs();
+    }
+
+    if (!maxDropEventsReached()) {
+        mCurrentSkippedBucket.dropEvents.emplace_back(buildDropEvent(dropTimeNs, reason));
     }
     mCurrentBucketIsInvalid = true;
 }
 
-void ValueMetricProducer::invalidateCurrentBucket() {
-    invalidateCurrentBucketWithoutResetBase();
+void ValueMetricProducer::invalidateCurrentBucket(const int64_t dropTimeNs,
+                                                  const BucketDropReason reason) {
+    invalidateCurrentBucketWithoutResetBase(dropTimeNs, reason);
     resetBase();
 }
 
@@ -351,7 +374,8 @@
     bool isEventTooLate  = eventTimeNs < mCurrentBucketStartTimeNs;
     if (isEventTooLate) {
         // Drop bucket because event arrived too late, ie. we are missing data for this bucket.
-        invalidateCurrentBucket();
+        StatsdStats::getInstance().noteLateLogEventSkipped(mMetricId);
+        invalidateCurrentBucket(eventTimeNs, BucketDropReason::EVENT_IN_WRONG_BUCKET);
     }
 
     // Call parent method once we've verified the validity of current bucket.
@@ -394,8 +418,9 @@
     if (isEventTooLate) {
         VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
              (long long)mCurrentBucketStartTimeNs);
+        StatsdStats::getInstance().noteLateLogEventSkipped(mMetricId);
         StatsdStats::getInstance().noteConditionChangeInNextBucket(mMetricId);
-        invalidateCurrentBucket();
+        invalidateCurrentBucket(eventTimeNs, BucketDropReason::EVENT_IN_WRONG_BUCKET);
         mCondition = ConditionState::kUnknown;
         mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
         return;
@@ -408,7 +433,7 @@
     //
     // We still want to pull to set the base.
     if (mCondition == ConditionState::kUnknown) {
-        invalidateCurrentBucket();
+        invalidateCurrentBucket(eventTimeNs, BucketDropReason::CONDITION_UNKNOWN);
     }
 
     // Pull and match for the following condition change cases:
@@ -445,7 +470,7 @@
     vector<std::shared_ptr<LogEvent>> allData;
     if (!mPullerManager->Pull(mPullTagId, &allData)) {
         ALOGE("Stats puller failed for tag: %d at %lld", mPullTagId, (long long)timestampNs);
-        invalidateCurrentBucket();
+        invalidateCurrentBucket(timestampNs, BucketDropReason::PULL_FAILED);
         return;
     }
 
@@ -465,7 +490,7 @@
     if (mCondition == ConditionState::kTrue) {
         // If the pull failed, we won't be able to compute a diff.
         if (!pullSuccess) {
-            invalidateCurrentBucket();
+            invalidateCurrentBucket(originalPullTimeNs, BucketDropReason::PULL_FAILED);
         } else {
             bool isEventLate = originalPullTimeNs < getCurrentBucketEndTimeNs();
             if (isEventLate) {
@@ -502,11 +527,12 @@
         VLOG("Skip bucket end pull due to late arrival: %lld vs %lld",
              (long long)eventElapsedTimeNs, (long long)mCurrentBucketStartTimeNs);
         StatsdStats::getInstance().noteLateLogEventSkipped(mMetricId);
-        invalidateCurrentBucket();
+        invalidateCurrentBucket(eventElapsedTimeNs, BucketDropReason::EVENT_IN_WRONG_BUCKET);
         return;
     }
 
-    const int64_t pullDelayNs = getElapsedRealtimeNs() - originalPullTimeNs;
+    const int64_t elapsedRealtimeNs = getElapsedRealtimeNs();
+    const int64_t pullDelayNs = elapsedRealtimeNs - originalPullTimeNs;
     StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
     if (pullDelayNs > mMaxPullDelayNs) {
         ALOGE("Pull finish too late for atom %d, longer than %lld", mPullTagId,
@@ -514,7 +540,7 @@
         StatsdStats::getInstance().notePullExceedMaxDelay(mPullTagId);
         // We are missing one pull from the bucket which means we will not have a complete view of
         // what's going on.
-        invalidateCurrentBucket();
+        invalidateCurrentBucket(eventElapsedTimeNs, BucketDropReason::PULL_DELAYED);
         return;
     }
 
@@ -553,7 +579,7 @@
     // incorrectly compute the diff when mUseZeroDefaultBase is true since an existing key
     // might be missing from mCurrentSlicedBucket.
     if (hasReachedGuardRailLimit()) {
-        invalidateCurrentBucket();
+        invalidateCurrentBucket(eventElapsedTimeNs, BucketDropReason::DIMENSION_GUARDRAIL_REACHED);
         mCurrentSlicedBucket.clear();
     }
 }
@@ -839,7 +865,8 @@
         StatsdStats::getInstance().noteSkippedForwardBuckets(mMetricId);
         // Something went wrong. Maybe the device was sleeping for a long time. It is better
         // to mark the current bucket as invalid. The last pull might have been successful through.
-        invalidateCurrentBucketWithoutResetBase();
+        invalidateCurrentBucketWithoutResetBase(eventTimeNs,
+                                                BucketDropReason::MULTIPLE_BUCKETS_SKIPPED);
     }
 
     VLOG("finalizing bucket for %ld, dumping %d slices", (long)mCurrentBucketStartTimeNs,
@@ -849,6 +876,18 @@
     // Close the current bucket.
     int64_t conditionTrueDuration = mConditionTimer.newBucketStart(bucketEndTime);
     bool isBucketLargeEnough = bucketEndTime - mCurrentBucketStartTimeNs >= mMinBucketSizeNs;
+    if (!isBucketLargeEnough) {
+        // If the bucket is valid, this is the only drop reason and we need to
+        // set the skipped bucket start and end times.
+        if (!mCurrentBucketIsInvalid) {
+            mCurrentSkippedBucket.bucketStartTimeNs = mCurrentBucketStartTimeNs;
+            mCurrentSkippedBucket.bucketEndTimeNs = bucketEndTime;
+        }
+        if (!maxDropEventsReached()) {
+            mCurrentSkippedBucket.dropEvents.emplace_back(
+                    buildDropEvent(eventTimeNs, BucketDropReason::BUCKET_TOO_SMALL));
+        }
+    }
     if (isBucketLargeEnough && !mCurrentBucketIsInvalid) {
         // The current bucket is large enough to keep.
         for (const auto& slice : mCurrentSlicedBucket) {
@@ -861,7 +900,7 @@
             }
         }
     } else {
-        mSkippedBuckets.emplace_back(mCurrentBucketStartTimeNs, bucketEndTime);
+        mSkippedBuckets.emplace_back(mCurrentSkippedBucket);
     }
 
     appendToFullBucket(eventTimeNs, fullBucketEndTimeNs);
@@ -917,6 +956,8 @@
     }
 
     mCurrentBucketIsInvalid = false;
+    mCurrentSkippedBucket.reset();
+
     // If we do not have a global base when the condition is true,
     // we will have incomplete bucket for the next bucket.
     if (mUseDiff && !mHasGlobalBase && mCondition) {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 2033a2a..4eae99b 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -130,8 +130,9 @@
     int64_t calcBucketsForwardCount(const int64_t& eventTimeNs) const;
 
     // Mark the data as invalid.
-    void invalidateCurrentBucket();
-    void invalidateCurrentBucketWithoutResetBase();
+    void invalidateCurrentBucket(const int64_t dropTimeNs, const BucketDropReason reason);
+    void invalidateCurrentBucketWithoutResetBase(const int64_t dropTimeNs,
+                                                 const BucketDropReason reason);
 
     const int mWhatMatcherIndex;
 
@@ -177,9 +178,6 @@
     // Save the past buckets and we can clear when the StatsLogReport is dumped.
     std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>> mPastBuckets;
 
-    // Pairs of (elapsed start, elapsed end) denoting buckets that were skipped.
-    std::list<std::pair<int64_t, int64_t>> mSkippedBuckets;
-
     const int64_t mMinBucketSizeNs;
 
     // Util function to check whether the specified dimension hits the guardrail.
@@ -248,7 +246,6 @@
     FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition);
     FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition);
     FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2);
-    FRIEND_TEST(ValueMetricProducerTest, TestBucketIncludingUnknownConditionIsInvalid);
     FRIEND_TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet);
     FRIEND_TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime);
     FRIEND_TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged);
@@ -258,10 +255,6 @@
     FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition);
     FRIEND_TEST(ValueMetricProducerTest, TestFirstBucket);
     FRIEND_TEST(ValueMetricProducerTest, TestFullBucketResetWhenLastBucketInvalid);
-    FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit);
-    FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed);
-    FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed);
-    FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed);
     FRIEND_TEST(ValueMetricProducerTest, TestLateOnDataPulledWithDiff);
     FRIEND_TEST(ValueMetricProducerTest, TestLateOnDataPulledWithoutDiff);
     FRIEND_TEST(ValueMetricProducerTest, TestPartialBucketCreated);
@@ -295,6 +288,13 @@
     FRIEND_TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey);
     FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase);
     FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures);
+
+    FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed);
+    FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed);
+    FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed);
+    FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenGuardRailHit);
+    FRIEND_TEST(ValueMetricProducerTest_BucketDrop,
+                TestInvalidBucketWhenAccumulateEventWrongBucket);
     friend class ValueMetricProducerTestHelper;
 };
 
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index e45e24fe..8b4d781 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -191,11 +191,40 @@
 
   // Fields 2 and 3 are reserved.
 
+  // Keep this in sync with BucketDropReason enum in MetricProducer.h.
+  enum BucketDropReason {
+      // For ValueMetric, a bucket is dropped during a dump report request iff
+      // current bucket should be included, a pull is needed (pulled metric and
+      // condition is true), and we are under fast time constraints.
+      DUMP_REPORT_REQUESTED = 1;
+      EVENT_IN_WRONG_BUCKET = 2;
+      CONDITION_UNKNOWN = 3;
+      PULL_FAILED = 4;
+      PULL_DELAYED = 5;
+      DIMENSION_GUARDRAIL_REACHED = 6;
+      MULTIPLE_BUCKETS_SKIPPED = 7;
+      // Not an invalid bucket case, but the bucket is dropped.
+      BUCKET_TOO_SMALL = 8;
+  };
+
+  message DropEvent {
+      optional BucketDropReason drop_reason = 1;
+
+      optional int64 drop_time_millis = 2;
+  }
+
   message SkippedBuckets {
       optional int64 start_bucket_elapsed_nanos = 1;
+
       optional int64 end_bucket_elapsed_nanos = 2;
+
       optional int64 start_bucket_elapsed_millis = 3;
+
       optional int64 end_bucket_elapsed_millis = 4;
+
+      // The number of drop events is capped by StatsdStats::kMaxLoggedBucketDropEvents.
+      // The current maximum is 10 drop events.
+      repeated DropEvent drop_event = 5;
   }
 
   message EventMetricDataWrapper {
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index b027e8e..308c43d 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -12,19 +12,22 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/matchers/SimpleLogMatchingTracker.h"
 #include "src/metrics/GaugeMetricProducer.h"
-#include "src/stats_log_util.h"
-#include "logd/LogEvent.h"
-#include "metrics_test_helper.h"
-#include "tests/statsd_test_util.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <math.h>
 #include <stdio.h>
+
 #include <vector>
 
+#include "logd/LogEvent.h"
+#include "metrics_test_helper.h"
+#include "src/matchers/SimpleLogMatchingTracker.h"
+#include "src/metrics/MetricProducer.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
 using namespace testing;
 using android::sp;
 using std::set;
@@ -784,6 +787,70 @@
     EXPECT_EQ(6, bucketIt->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value);
 }
 
+/*
+ * Test that BUCKET_TOO_SMALL dump reason is logged when a flushed bucket size
+ * is smaller than the "min_bucket_size_nanos" specified in the metric config.
+ */
+TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(FIVE_MINUTES);
+    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
+    metric.set_min_bucket_size_nanos(10000000000);  // 10 seconds
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Bucket start.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+                event->write("field1");
+                event->write(10);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    int triggerId = 5;
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard,
+                                      tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
+                                      pullerManager);
+
+    LogEvent trigger(triggerId, bucketStartTimeNs + 3);
+    trigger.init();
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    gaugeProducer.onDumpReport(bucketStartTimeNs + 9000000, true /* include recent buckets */,
+                                true, FAST /* dump_latency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_gauge_metrics());
+    EXPECT_EQ(0, report.gauge_metrics().data_size());
+    EXPECT_EQ(1, report.gauge_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.gauge_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000),
+              report.gauge_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(1, report.gauge_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.gauge_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), dropEvent.drop_time_millis());
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 4b9d0c0..da0a672 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -12,21 +12,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/matchers/SimpleLogMatchingTracker.h"
 #include "src/metrics/ValueMetricProducer.h"
-#include "src/stats_log_util.h"
-#include "metrics_test_helper.h"
-#include "tests/statsd_test_util.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <math.h>
 #include <stdio.h>
+
 #include <vector>
 
+#include "metrics_test_helper.h"
+#include "src/matchers/SimpleLogMatchingTracker.h"
+#include "src/metrics/MetricProducer.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
 using namespace testing;
 using android::sp;
-using android::util::ProtoReader;
 using std::make_shared;
 using std::set;
 using std::shared_ptr;
@@ -128,6 +130,24 @@
         return valueProducer;
     }
 
+    static sp<ValueMetricProducer> createValueProducerWithNoInitialCondition(
+            sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric) {
+        UidMap uidMap;
+        SimpleAtomMatcher atomMatcher;
+        atomMatcher.set_atom_id(tagId);
+        sp<EventMatcherWizard> eventMatcherWizard =
+                new EventMatcherWizard({new SimpleLogMatchingTracker(
+                        atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+        sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+        EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+        EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+        sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
+                kConfigKey, metric, 1, wizard, logEventMatcherIndex, eventMatcherWizard, tagId,
+                bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+        return valueProducer;
+    }
+
     static ValueMetric createMetric() {
         ValueMetric metric;
         metric.set_id(metricId);
@@ -206,7 +226,7 @@
  * Tests pulled atoms with no conditions
  */
 TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -290,7 +310,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestPartialBucketCreated) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             // Initialize bucket.
@@ -347,7 +367,7 @@
  * Tests pulled atoms with filtering
  */
 TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -696,7 +716,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -1026,7 +1046,7 @@
 
 // Test value metric no condition, the pull on bucket boundary come in time and too late
 TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
     EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
     sp<ValueMetricProducer> valueProducer =
@@ -2104,7 +2124,10 @@
     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
 }
 
-TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed) {
+/*
+ * Tests that a bucket is marked invalid when a condition change pull fails.
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed) {
     ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -2162,9 +2185,33 @@
     EXPECT_EQ(140, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucket2StartTimeNs + 10, false /* include partial bucket */, true,
+                                FAST /* dumpLatency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    EXPECT_EQ(0, report.value_metrics().data_size());
+    EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
 }
 
-TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit) {
+/*
+ * Tests that a bucket is marked invalid when the guardrail is hit.
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenGuardRailHit) {
     ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.mutable_dimensions_in_what()->set_field(tagId);
     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
@@ -2191,9 +2238,47 @@
     valueProducer->onConditionChanged(true, bucketStartTimeNs + 2);
     EXPECT_EQ(true, valueProducer->mCurrentBucketIsInvalid);
     EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+    EXPECT_EQ(0UL, valueProducer->mSkippedBuckets.size());
+
+    // Bucket 2 start.
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+    event->write(1);
+    event->write(10);
+    event->init();
+    allData.push_back(event);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+    // First bucket added to mSkippedBuckets after flush.
+    EXPECT_EQ(1UL, valueProducer->mSkippedBuckets.size());
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
+                                true, FAST /* dumpLatency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    EXPECT_EQ(0, report.value_metrics().data_size());
+    EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::DIMENSION_GUARDRAIL_REACHED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
 }
 
-TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed) {
+/*
+ * Tests that a bucket is marked invalid when the bucket's initial pull fails.
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed) {
     ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -2257,9 +2342,34 @@
     EXPECT_EQ(140, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
+                                true, FAST /* dumpLatency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    EXPECT_EQ(0, report.value_metrics().data_size());
+    EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
 }
 
-TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed) {
+/*
+ * Tests that a bucket is marked invalid when the bucket's final pull fails
+ * (i.e. failed pull on bucket boundary).
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed) {
     ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -2300,8 +2410,6 @@
     allData.push_back(event);
     valueProducer->onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
 
-    // This will fail and should invalidate the whole bucket since we do not have all the data
-    // needed to compute the metric value when the screen was on.
     valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
     valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
 
@@ -2317,17 +2425,38 @@
     valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
 
     EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-    // Last pull failed so based has been reset.
+    // Last pull failed so base has been reset.
     EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval& curInterval =
             valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(false, curInterval.hasBase);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(false, valueProducer->mHasGlobalBase);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
+                                true, FAST /* dumpLatency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    EXPECT_EQ(0, report.value_metrics().data_size());
+    EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs), dropEvent.drop_time_millis());
 }
 
 TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             // Start bucket.
@@ -2520,48 +2649,6 @@
     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
 }
 
-TEST(ValueMetricProducerTest, TestBucketIncludingUnknownConditionIsInvalid) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    metric.mutable_dimensions_in_what()->set_field(tagId);
-    metric.mutable_dimensions_in_what()->add_child()->set_field(1);
-    metric.set_condition(StringToId("SCREEN_ON"));
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-            // Second onConditionChanged.
-            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
-                event->write(tagId);
-                event->write(2);
-                event->write(2);
-                event->init();
-                data->push_back(event);
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
-    valueProducer->mCondition = ConditionState::kUnknown;
-
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 10);
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 20);
-
-    // End of bucket
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-    event->write(4);
-    event->write(4);
-    event->init();
-    allData.push_back(event);
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    // Bucket is incomplete so it is mark as invalid, however the base is fine since the last pull
-    // succeeded.
-    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-}
-
 TEST(ValueMetricProducerTest, TestFullBucketResetWhenLastBucketInvalid) {
     ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
 
@@ -2750,6 +2837,7 @@
     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2}, {2});
 }
 
+// TODO: b/145705635 fix or delete this test
 TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) {
     ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
@@ -2797,25 +2885,8 @@
     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {});
 }
 
-static StatsLogReport outputStreamToProto(ProtoOutputStream* proto) {
-    vector<uint8_t> bytes;
-    bytes.resize(proto->size());
-    size_t pos = 0;
-    sp<ProtoReader> reader = proto->data();
-    while (reader->readBuffer() != NULL) {
-        size_t toRead = reader->currentToRead();
-        std::memcpy(&((bytes)[pos]), reader->readBuffer(), toRead);
-        pos += toRead;
-        reader->move(toRead);
-    }
-
-    StatsLogReport report;
-    report.ParseFromArray(bytes.data(), bytes.size());
-    return report;
-}
-
 TEST(ValueMetricProducerTest, TestPullNeededFastDump) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -2857,7 +2928,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -2910,7 +2981,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -3103,6 +3174,600 @@
     assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {});
 }
 
+/*
+ * Test that DUMP_REPORT_REQUESTED dump reason is logged.
+ *
+ * For the bucket to be marked invalid during a dump report requested,
+ * three things must be true:
+ * - we want to include the current partial bucket
+ * - we need a pull (metric is pulled and condition is true)
+ * - the dump latency must be FAST
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenDumpReportRequested) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Condition change to true.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
+                event->write("field1");
+                event->write(10);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+    // Condition change event.
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 20);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucketStartTimeNs + 40, true /* include recent buckets */, true,
+                                FAST /* dumpLatency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    EXPECT_EQ(0, report.value_metrics().data_size());
+    EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::DUMP_REPORT_REQUESTED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 40), dropEvent.drop_time_millis());
+}
+
+/*
+ * Test that EVENT_IN_WRONG_BUCKET dump reason is logged for a late condition
+ * change event (i.e. the condition change occurs in the wrong bucket).
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionEventWrongBucket) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Condition change to true.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 50);
+                event->write("field1");
+                event->write(10);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+    // Condition change event.
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
+
+    // Bucket boundary pull.
+    vector<shared_ptr<LogEvent>> allData;
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs);
+    event->write("field1");
+    event->write(15);
+    event->init();
+    allData.push_back(event);
+    valueProducer->onDataPulled(allData, /** succeeds */ true, bucket2StartTimeNs + 1);
+
+    // Late condition change event.
+    valueProducer->onConditionChanged(false, bucket2StartTimeNs - 100);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucket2StartTimeNs + 100, true /* include recent buckets */, true,
+                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    EXPECT_EQ(1, report.value_metrics().data_size());
+    EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucket3StartTimeNs),
+              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::EVENT_IN_WRONG_BUCKET, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs - 100), dropEvent.drop_time_millis());
+}
+
+/*
+ * Test that EVENT_IN_WRONG_BUCKET dump reason is logged for a late accumulate
+ * event (i.e. the accumulate events call occurs in the wrong bucket).
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenAccumulateEventWrongBucket) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Condition change to true.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 50);
+                event->write("field1");
+                event->write(10);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            // Dump report requested.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 100);
+                event->write("field1");
+                event->write(15);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+    // Condition change event.
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
+
+    // Bucket boundary pull.
+    vector<shared_ptr<LogEvent>> allData;
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs);
+    event->write("field1");
+    event->write(15);
+    event->init();
+    allData.push_back(event);
+    valueProducer->onDataPulled(allData, /** succeeds */ true, bucket2StartTimeNs + 1);
+
+    allData.clear();
+    event = make_shared<LogEvent>(tagId, bucket2StartTimeNs - 100);
+    event->write("field1");
+    event->write(20);
+    event->init();
+    allData.push_back(event);
+
+    // Late accumulateEvents event.
+    valueProducer->accumulateEvents(allData, bucket2StartTimeNs - 100, bucket2StartTimeNs - 100);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucket2StartTimeNs + 100, true /* include recent buckets */, true,
+                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    EXPECT_EQ(1, report.value_metrics().data_size());
+    EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucket3StartTimeNs),
+              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::EVENT_IN_WRONG_BUCKET, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs - 100), dropEvent.drop_time_millis());
+}
+
+/*
+ * Test that CONDITION_UNKNOWN dump reason is logged due to an unknown condition
+ * when a metric is initialized.
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionUnknown) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Condition change to true.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 50);
+                event->write("field1");
+                event->write(10);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            // Dump report requested.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 100);
+                event->write("field1");
+                event->write(15);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithNoInitialCondition(pullerManager,
+                                                                                     metric);
+
+    // Condition change event.
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucketStartTimeNs + 100, true /* include recent buckets */, true,
+                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    EXPECT_EQ(0, report.value_metrics().data_size());
+    EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 100), dropEvent.drop_time_millis());
+}
+
+/*
+ * Test that PULL_FAILED dump reason is logged due to a pull failure in
+ * #pullAndMatchEventsLocked.
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenPullFailed) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Condition change to true.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 50);
+                event->write("field1");
+                event->write(10);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            // Dump report requested, pull fails.
+            .WillOnce(Return(false));
+
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+    // Condition change event.
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucketStartTimeNs + 100, true /* include recent buckets */, true,
+                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    EXPECT_EQ(0, report.value_metrics().data_size());
+    EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 100), dropEvent.drop_time_millis());
+}
+
+/*
+ * Test that MULTIPLE_BUCKETS_SKIPPED dump reason is logged when a log event
+ * skips over more than one bucket.
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenMultipleBucketsSkipped) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Condition change to true.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                event->write("field1");
+                event->write(10);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            // Dump report requested.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event =
+                        make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1000);
+                event->write("field1");
+                event->write(15);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+    // Condition change event.
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
+
+    // Condition change event that skips forward by three buckets.
+    valueProducer->onConditionChanged(false, bucket4StartTimeNs + 10);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucket4StartTimeNs + 1000, true /* include recent buckets */, true,
+                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    EXPECT_EQ(0, report.value_metrics().data_size());
+    EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::MULTIPLE_BUCKETS_SKIPPED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucket4StartTimeNs + 10), dropEvent.drop_time_millis());
+}
+
+/*
+ * Test that BUCKET_TOO_SMALL dump reason is logged when a flushed bucket size
+ * is smaller than the "min_bucket_size_nanos" specified in the metric config.
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+    metric.set_min_bucket_size_nanos(10000000000);  // 10 seconds
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Condition change to true.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                event->write("field1");
+                event->write(10);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            // Dump report requested.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event =
+                        make_shared<LogEvent>(tagId, bucketStartTimeNs + 9000000);
+                event->write("field1");
+                event->write(15);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+    // Condition change event.
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucketStartTimeNs + 9000000, true /* include recent buckets */,
+                                true, NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    EXPECT_EQ(0, report.value_metrics().data_size());
+    EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000),
+              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), dropEvent.drop_time_millis());
+}
+
+/*
+ * Test multiple bucket drop events in the same bucket.
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestMultipleBucketDropEvents) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Condition change to true.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                event->write("field1");
+                event->write(10);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithNoInitialCondition(pullerManager,
+                                                                                     metric);
+
+    // Condition change event.
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucketStartTimeNs + 1000, true /* include recent buckets */, true,
+                                FAST /* dumpLatency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    EXPECT_EQ(0, report.value_metrics().data_size());
+    EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(2, report.value_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 10), dropEvent.drop_time_millis());
+
+    dropEvent = report.value_metrics().skipped(0).drop_event(1);
+    EXPECT_EQ(BucketDropReason::DUMP_REPORT_REQUESTED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 1000), dropEvent.drop_time_millis());
+}
+
+/*
+ * Test that the number of logged bucket drop events is capped at the maximum.
+ * The maximum is currently 10 and is set in MetricProducer::maxDropEventsReached().
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestMaxBucketDropEvents) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // First condition change event.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                for (int i = 0; i < 2000; i++) {
+                    shared_ptr<LogEvent> event =
+                            make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
+                    event->write(i);
+                    event->write(i);
+                    event->init();
+                    data->push_back(event);
+                }
+                return true;
+            }))
+            .WillOnce(Return(false))
+            .WillOnce(Return(false))
+            .WillOnce(Return(false))
+            .WillOnce(Return(false))
+            .WillOnce(Return(false))
+            .WillOnce(Return(false))
+            .WillOnce(Return(false))
+            .WillOnce(Return(false))
+            .WillOnce(Return(false))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 220);
+                event->write("field1");
+                event->write(10);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithNoInitialCondition(pullerManager,
+                                                                                     metric);
+
+    // First condition change event causes guardrail to be reached.
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
+
+    // 2-10 condition change events result in failed pulls.
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 30);
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 70);
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 90);
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 100);
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 150);
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 170);
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 190);
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 200);
+
+    // Condition change event 11
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 220);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    // Because we already have 10 dump events in the current bucket,
+    // this case should not be added to the list of dump events.
+    valueProducer->onDumpReport(bucketStartTimeNs + 1000, true /* include recent buckets */, true,
+                                FAST /* dumpLatency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    EXPECT_EQ(0, report.value_metrics().data_size());
+    EXPECT_EQ(1, report.value_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(10, report.value_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 10), dropEvent.drop_time_millis());
+
+    dropEvent = report.value_metrics().skipped(0).drop_event(1);
+    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 30), dropEvent.drop_time_millis());
+
+    dropEvent = report.value_metrics().skipped(0).drop_event(2);
+    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 50), dropEvent.drop_time_millis());
+
+    dropEvent = report.value_metrics().skipped(0).drop_event(3);
+    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 70), dropEvent.drop_time_millis());
+
+    dropEvent = report.value_metrics().skipped(0).drop_event(4);
+    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 90), dropEvent.drop_time_millis());
+
+    dropEvent = report.value_metrics().skipped(0).drop_event(5);
+    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 100), dropEvent.drop_time_millis());
+
+    dropEvent = report.value_metrics().skipped(0).drop_event(6);
+    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 150), dropEvent.drop_time_millis());
+
+    dropEvent = report.value_metrics().skipped(0).drop_event(7);
+    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 170), dropEvent.drop_time_millis());
+
+    dropEvent = report.value_metrics().skipped(0).drop_event(8);
+    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 190), dropEvent.drop_time_millis());
+
+    dropEvent = report.value_metrics().skipped(0).drop_event(9);
+    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 200), dropEvent.drop_time_millis());
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index d154b1b..7b651df 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -18,6 +18,23 @@
 namespace os {
 namespace statsd {
 
+StatsLogReport outputStreamToProto(ProtoOutputStream* proto) {
+    vector<uint8_t> bytes;
+    bytes.resize(proto->size());
+    size_t pos = 0;
+    sp<ProtoReader> reader = proto->data();
+
+    while (reader->readBuffer() != NULL) {
+        size_t toRead = reader->currentToRead();
+        std::memcpy(&((bytes)[pos]), reader->readBuffer(), toRead);
+        pos += toRead;
+        reader->move(toRead);
+    }
+
+    StatsLogReport report;
+    report.ParseFromArray(bytes.data(), bytes.size());
+    return report;
+}
 
 AtomMatcher CreateSimpleAtomMatcher(const string& name, int atomId) {
     AtomMatcher atom_matcher;
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index e1e134b..010c194 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -27,8 +27,12 @@
 namespace os {
 namespace statsd {
 
+using android::util::ProtoReader;
 using google::protobuf::RepeatedPtrField;
 
+// Converts a ProtoOutputStream to a StatsLogReport proto.
+StatsLogReport outputStreamToProto(ProtoOutputStream* proto);
+
 // Create AtomMatcher proto to simply match a specific atom type.
 AtomMatcher CreateSimpleAtomMatcher(const string& name, int atomId);
 
diff --git a/cmds/svc/src/com/android/commands/svc/DataCommand.java b/cmds/svc/src/com/android/commands/svc/DataCommand.java
index b4dbd1d..35510cf 100644
--- a/cmds/svc/src/com/android/commands/svc/DataCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/DataCommand.java
@@ -16,16 +16,12 @@
 
 package com.android.commands.svc;
 
-/**
- * @deprecated Please use adb shell cmd phone data enabled/disable instead.
- */
-@Deprecated
+import android.os.ServiceManager;
+import android.os.RemoteException;
+import android.content.Context;
+import com.android.internal.telephony.ITelephony;
+
 public class DataCommand extends Svc.Command {
-
-    private static final String DECPRECATED_MESSAGE =
-            "adb shell svc data enable/disable is deprecated;"
-            + "please use adb shell cmd phone data enable/disable instead.";
-
     public DataCommand() {
         super("data");
     }
@@ -37,10 +33,36 @@
     public String longHelp() {
         return shortHelp() + "\n"
                 + "\n"
-                + DECPRECATED_MESSAGE;
+                + "usage: svc data [enable|disable]\n"
+                + "         Turn mobile data on or off.\n\n";
     }
 
     public void run(String[] args) {
-        System.err.println(DECPRECATED_MESSAGE);
+        boolean validCommand = false;
+        if (args.length >= 2) {
+            boolean flag = false;
+            if ("enable".equals(args[1])) {
+                flag = true;
+                validCommand = true;
+            } else if ("disable".equals(args[1])) {
+                flag = false;
+                validCommand = true;
+            }
+            if (validCommand) {
+                ITelephony phoneMgr
+                        = ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
+                try {
+                    if (flag) {
+                        phoneMgr.enableDataConnectivity();
+                    } else
+                        phoneMgr.disableDataConnectivity();
+                }
+                catch (RemoteException e) {
+                    System.err.println("Mobile data operation failed: " + e);
+                }
+                return;
+            }
+        }
+        System.err.println(longHelp());
     }
 }
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 0f619c8..c0fee6e 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -21,8 +21,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Service;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 7fd01db..5e2c1fa 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -22,9 +22,9 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index c822d20..9a18880 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/accounts/AccountAndUser.java b/core/java/android/accounts/AccountAndUser.java
index b0d5343..fd67394 100644
--- a/core/java/android/accounts/AccountAndUser.java
+++ b/core/java/android/accounts/AccountAndUser.java
@@ -16,7 +16,7 @@
 
 package android.accounts;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * Used to store the Account and the UserId this account is associated with.
diff --git a/core/java/android/accounts/AccountAuthenticatorResponse.java b/core/java/android/accounts/AccountAuthenticatorResponse.java
index bb2e327..a2a5799 100644
--- a/core/java/android/accounts/AccountAuthenticatorResponse.java
+++ b/core/java/android/accounts/AccountAuthenticatorResponse.java
@@ -16,10 +16,10 @@
 
 package android.accounts;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Bundle;
-import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.util.Log;
 
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 0f10c39..8fe2f12 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -25,8 +25,8 @@
 import android.annotation.Size;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
diff --git a/core/java/android/accounts/AuthenticatorDescription.java b/core/java/android/accounts/AuthenticatorDescription.java
index 5556394..b7bf11d 100644
--- a/core/java/android/accounts/AuthenticatorDescription.java
+++ b/core/java/android/accounts/AuthenticatorDescription.java
@@ -16,10 +16,10 @@
 
 package android.accounts;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
-import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.Parcelable;
 
 /**
  * A {@link Parcelable} value type that contains information about an account authenticator.
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 17d54d2..3cdd691 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -17,7 +17,7 @@
 package android.animation;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.ConstantState;
 
diff --git a/core/java/android/animation/ArgbEvaluator.java b/core/java/android/animation/ArgbEvaluator.java
index 5b69d18..9519ddd 100644
--- a/core/java/android/animation/ArgbEvaluator.java
+++ b/core/java/android/animation/ArgbEvaluator.java
@@ -16,7 +16,7 @@
 
 package android.animation;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * This evaluator can be used to perform type interpolation between integer
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index c753710..21f0b6b 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -16,7 +16,7 @@
 
 package android.animation;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.view.View;
 import android.view.ViewGroup;
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 764e599..ca37e9b 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -19,7 +19,7 @@
 import android.annotation.CallSuper;
 import android.annotation.IntDef;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Looper;
 import android.os.Trace;
diff --git a/core/java/android/annotation/SystemApi.java b/core/java/android/annotation/SystemApi.java
index f589cc5..2cb93e4 100644
--- a/core/java/android/annotation/SystemApi.java
+++ b/core/java/android/annotation/SystemApi.java
@@ -44,9 +44,24 @@
     enum Client {
         /**
          * Specifies that the intended clients of a SystemApi are privileged apps.
-         * This is the default value for {@link #client}.
+         * This is the default value for {@link #client}. This implies
+         * MODULE_APPS and MODULE_LIBRARIES as well, which means that APIs will also
+         * be available to module apps and jars.
          */
         PRIVILEGED_APPS,
+
+        /**
+         * Specifies that the intended clients of a SystemApi are modules implemented
+         * as apps, like the NetworkStack app. This implies MODULE_LIBRARIES as well,
+         * which means that APIs will also be available to module jars.
+         */
+        MODULE_APPS,
+
+        /**
+         * Specifies that the intended clients of a SystemApi are modules implemented
+         * as libraries, like the conscrypt.jar in the conscrypt APEX.
+         */
+        MODULE_LIBRARIES
     }
 
     enum Process {
@@ -55,6 +70,11 @@
          * This is the default value for {@link #process}.
          */
         ALL,
+
+        /**
+         * Specifies that the SystemAPI is available only in the system server process.
+         */
+        SYSTEM_SERVER
     }
 
     /**
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index e573279..504364c 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -22,7 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 1e3b950..ff581c0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -33,10 +33,10 @@
 import android.annotation.StyleRes;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.VoiceInteractor.Request;
 import android.app.admin.DevicePolicyManager;
 import android.app.assist.AssistContent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
 import android.content.ContentResolver;
diff --git a/core/java/android/app/ActivityGroup.java b/core/java/android/app/ActivityGroup.java
index d4aa01b..cb06eea 100644
--- a/core/java/android/app/ActivityGroup.java
+++ b/core/java/android/app/ActivityGroup.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.os.Bundle;
 
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 795f51a..68bdfae 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -28,7 +28,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -1120,8 +1120,8 @@
         }
 
         /**
-         * Copies this the values from another TaskDescription, but preserves the hidden fields
-         * if they weren't set on {@code other}
+         * Copies values from another TaskDescription, but preserves the hidden fields if they
+         * weren't set on {@code other}. Public fields will be overwritten anyway.
          * @hide
          */
         public void copyFromPreserveHiddenFields(TaskDescription other) {
@@ -1130,6 +1130,7 @@
             mIconRes = other.mIconRes;
             mIconFilename = other.mIconFilename;
             mColorPrimary = other.mColorPrimary;
+
             if (other.mColorBackground != 0) {
                 mColorBackground = other.mColorBackground;
             }
@@ -1139,12 +1140,20 @@
             if (other.mNavigationBarColor != 0) {
                 mNavigationBarColor = other.mNavigationBarColor;
             }
+
             mEnsureStatusBarContrastWhenTransparent = other.mEnsureStatusBarContrastWhenTransparent;
             mEnsureNavigationBarContrastWhenTransparent =
                     other.mEnsureNavigationBarContrastWhenTransparent;
-            mResizeMode = other.mResizeMode;
-            mMinWidth = other.mMinWidth;
-            mMinHeight = other.mMinHeight;
+
+            if (other.mResizeMode != RESIZE_MODE_RESIZEABLE) {
+                mResizeMode = other.mResizeMode;
+            }
+            if (other.mMinWidth != -1) {
+                mMinWidth = other.mMinWidth;
+            }
+            if (other.mMinHeight != -1) {
+                mMinHeight = other.mMinHeight;
+            }
         }
 
         private TaskDescription(Parcel source) {
@@ -2097,6 +2106,113 @@
                 return new TaskSnapshot[size];
             }
         };
+
+        /** Builder for a {@link TaskSnapshot} object */
+        public static final class Builder {
+            private long mId;
+            private ComponentName mTopActivity;
+            private GraphicBuffer mSnapshot;
+            private ColorSpace mColorSpace;
+            private int mOrientation;
+            private Rect mContentInsets;
+            private boolean mReducedResolution;
+            private float mScaleFraction;
+            private boolean mIsRealSnapshot;
+            private int mWindowingMode;
+            private int mSystemUiVisibility;
+            private boolean mIsTranslucent;
+            private int mPixelFormat;
+
+            public Builder setId(long id) {
+                mId = id;
+                return this;
+            }
+
+            public Builder setTopActivityComponent(ComponentName name) {
+                mTopActivity = name;
+                return this;
+            }
+
+            public Builder setSnapshot(GraphicBuffer buffer) {
+                mSnapshot = buffer;
+                return this;
+            }
+
+            public Builder setColorSpace(ColorSpace colorSpace) {
+                mColorSpace = colorSpace;
+                return this;
+            }
+
+            public Builder setOrientation(int orientation) {
+                mOrientation = orientation;
+                return this;
+            }
+
+            public Builder setContentInsets(Rect contentInsets) {
+                mContentInsets = contentInsets;
+                return this;
+            }
+
+            public Builder setReducedResolution(boolean reducedResolution) {
+                mReducedResolution = reducedResolution;
+                return this;
+            }
+
+            public float getScaleFraction() {
+                return mScaleFraction;
+            }
+
+            public Builder setScaleFraction(float scaleFraction) {
+                mScaleFraction = scaleFraction;
+                return this;
+            }
+
+            public Builder setIsRealSnapshot(boolean realSnapshot) {
+                mIsRealSnapshot = realSnapshot;
+                return this;
+            }
+
+            public Builder setWindowingMode(int windowingMode) {
+                mWindowingMode = windowingMode;
+                return this;
+            }
+
+            public Builder setSystemUiVisibility(int systemUiVisibility) {
+                mSystemUiVisibility = systemUiVisibility;
+                return this;
+            }
+
+            public Builder setIsTranslucent(boolean isTranslucent) {
+                mIsTranslucent = isTranslucent;
+                return this;
+            }
+
+            public int getPixelFormat() {
+                return mPixelFormat;
+            }
+
+            public Builder setPixelFormat(int pixelFormat) {
+                mPixelFormat = pixelFormat;
+                return this;
+            }
+
+            public TaskSnapshot build() {
+                return new TaskSnapshot(
+                        mId,
+                        mTopActivity,
+                        mSnapshot,
+                        mColorSpace,
+                        mOrientation,
+                        mContentInsets,
+                        mReducedResolution,
+                        mScaleFraction,
+                        mIsRealSnapshot,
+                        mWindowingMode,
+                        mSystemUiVisibility,
+                        mIsTranslucent);
+
+            }
+        }
     }
 
     /** @hide */
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 607ef18..b9eb957 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -15,7 +15,7 @@
  */
 
 package android.app;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.os.IBinder;
 
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index f91453e..4aacf48 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -25,7 +25,7 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index ac8c9f4..122004c 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -19,7 +19,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5cdc505..be14556 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -32,7 +32,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.app.backup.BackupAgent;
@@ -46,6 +45,7 @@
 import android.app.servertransaction.PendingTransactionActions.StopInfo;
 import android.app.servertransaction.TransactionExecutor;
 import android.app.servertransaction.TransactionExecutorHelper;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.AutofillOptions;
 import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks2;
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index d8ddf218..c03413c 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -21,7 +21,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index bfc216a..4c34737 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -21,7 +21,7 @@
 import android.annotation.DrawableRes;
 import android.annotation.StringRes;
 import android.annotation.StyleRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.ResourceId;
diff --git a/core/java/android/app/AppGlobals.java b/core/java/android/app/AppGlobals.java
index 8312327..81e1565 100644
--- a/core/java/android/app/AppGlobals.java
+++ b/core/java/android/app/AppGlobals.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.IPackageManager;
 import android.permission.IPermissionManager;
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index f2fa4fd..4ce91a6 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -26,8 +26,8 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.usage.UsageStatsManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageManager;
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index e12942f..941467f 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -19,7 +19,7 @@
 import android.annotation.CallSuper;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentCallbacks;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index 2e59b90..bac432e 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.SharedLibraryInfo;
 import android.os.Build;
 import android.os.GraphicsEnvironment;
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 034826a..7f26565 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -20,9 +20,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
 import android.annotation.XmlRes;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
diff --git a/core/java/android/app/ContentProviderHolder.java b/core/java/android/app/ContentProviderHolder.java
index 004dca1a..3d74583 100644
--- a/core/java/android/app/ContentProviderHolder.java
+++ b/core/java/android/app/ContentProviderHolder.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentProviderNative;
 import android.content.IContentProvider;
 import android.content.pm.ProviderInfo;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 155e93f..bd87fcd 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -20,7 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.AutofillOptions;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 9d82ffa..195c3e1 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 39f1e95..5e05506 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -24,7 +24,7 @@
 import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.annotation.StyleRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ContextWrapper;
diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java
index bfc15c2..e4c84d7 100644
--- a/core/java/android/app/DialogFragment.java
+++ b/core/java/android/app/DialogFragment.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.os.Bundle;
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index eb50581..49c389a 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -22,7 +22,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.ContentUris;
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 4f121aa..c6a0de4 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -21,7 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/app/FragmentController.java b/core/java/android/app/FragmentController.java
index 9316be7..f021f76 100644
--- a/core/java/android/app/FragmentController.java
+++ b/core/java/android/app/FragmentController.java
@@ -17,7 +17,7 @@
 package android.app;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.os.Bundle;
diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java
index 26b4a11..9e887b8 100644
--- a/core/java/android/app/FragmentHostCallback.java
+++ b/core/java/android/app/FragmentHostCallback.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 68daf44..904c473 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -22,7 +22,7 @@
 import android.animation.AnimatorSet;
 import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 690e956..9e552e6 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -19,7 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
index 74fb99a..71b28fb 100644
--- a/core/java/android/app/IntentService.java
+++ b/core/java/android/app/IntentService.java
@@ -16,9 +16,9 @@
 
 package android.app;
 
-import android.annotation.UnsupportedAppUsage;
-import android.annotation.WorkerThread;
 import android.annotation.Nullable;
+import android.annotation.WorkerThread;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.os.Handler;
 import android.os.HandlerThread;
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index b1565ab..6518652 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -23,8 +23,8 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
 import android.app.trust.ITrustManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -118,6 +118,16 @@
     public static final int RESULT_ALTERNATE = 1;
 
     /**
+     *
+     * If this is set, check device policy for allowed biometrics when the user is authenticating.
+     * This should only be used in the context of managed profiles.
+     *
+     * @hide
+     */
+    public static final String EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS = "check_dpm";
+
+
+    /**
      * Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics
      * if enrolled) for the current user of the device. The caller is expected to launch this
      * activity using {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
@@ -166,6 +176,28 @@
 
     /**
      * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
+     * for the given user. The caller is expected to launch this activity using
+     * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
+     * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
+     *
+     * @param disallowBiometricsIfPolicyExists If true check if the Device Policy Manager has
+     * disabled biometrics on the device. If biometrics are disabled, fall back to PIN/pattern/pass.
+     *
+     * @return the intent for launching the activity or null if no password is required.
+     *
+     * @hide
+     */
+    public Intent createConfirmDeviceCredentialIntent(
+            CharSequence title, CharSequence description, int userId,
+            boolean disallowBiometricsIfPolicyExists) {
+        Intent intent = this.createConfirmDeviceCredentialIntent(title, description, userId);
+        intent.putExtra(EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS,
+                disallowBiometricsIfPolicyExists);
+        return intent;
+    }
+
+    /**
+     * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
      * for the previous owner of the device. The caller is expected to launch this activity using
      * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
      * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index e858e6a..453c600 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 87b064d..4033aea 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -16,9 +16,9 @@
 
 package android.app;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread.ActivityClientRecord;
 import android.app.servertransaction.PendingTransactionActions;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.os.Binder;
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index 25eb958..74bc9e2 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e307142..6f63eea 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -32,7 +32,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.LocusId;
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 1fc8a2b..3eee1ae 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -18,8 +18,8 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.NotificationManager.Importance;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index c4c1e4f..403fb3e 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -17,7 +17,7 @@
 
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 850645d..fdbb8bb 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -23,8 +23,8 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Notification.Builder;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/app/PackageDeleteObserver.java b/core/java/android/app/PackageDeleteObserver.java
index b7b0b19..d8803aa 100644
--- a/core/java/android/app/PackageDeleteObserver.java
+++ b/core/java/android/app/PackageDeleteObserver.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.content.pm.IPackageDeleteObserver2;
 
diff --git a/core/java/android/app/PackageInstallObserver.java b/core/java/android/app/PackageInstallObserver.java
index 50031e0..0820367 100644
--- a/core/java/android/app/PackageInstallObserver.java
+++ b/core/java/android/app/PackageInstallObserver.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.content.pm.IPackageInstallObserver2;
 import android.os.Bundle;
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 0407a8a..b8348c7 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -19,7 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java
index cb72d4d..f864fb5 100644
--- a/core/java/android/app/Presentation.java
+++ b/core/java/android/app/Presentation.java
@@ -20,24 +20,24 @@
 import static android.content.Context.WINDOW_SERVICE;
 import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.os.Binder;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Message;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
-import android.os.Handler;
-import android.os.Message;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.TypedValue;
 
 /**
  * Base class for presentations.
diff --git a/core/java/android/app/ProgressDialog.java b/core/java/android/app/ProgressDialog.java
index 3193eb8..432fae5 100644
--- a/core/java/android/app/ProgressDialog.java
+++ b/core/java/android/app/ProgressDialog.java
@@ -16,9 +16,7 @@
 
 package android.app;
 
-import com.android.internal.R;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
@@ -34,6 +32,8 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
+import com.android.internal.R;
+
 import java.text.NumberFormat;
 
 /**
diff --git a/core/java/android/app/QueuedWork.java b/core/java/android/app/QueuedWork.java
index 7626539..82cc2c4 100644
--- a/core/java/android/app/QueuedWork.java
+++ b/core/java/android/app/QueuedWork.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 08a28f5..aa11598 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -21,7 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.res.ApkAssets;
diff --git a/core/java/android/app/ResultInfo.java b/core/java/android/app/ResultInfo.java
index 9ee0f31..979d3db 100644
--- a/core/java/android/app/ResultInfo.java
+++ b/core/java/android/app/ResultInfo.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.os.Build;
 import android.os.Parcel;
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 8493fb2..9fe894b 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -17,7 +17,7 @@
 package android.app;
 
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index b10c3e2..95f55ab 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -19,7 +19,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.ContentResolver;
diff --git a/core/java/android/app/SearchableInfo.java b/core/java/android/app/SearchableInfo.java
index a01cec7..83eb2ee 100644
--- a/core/java/android/app/SearchableInfo.java
+++ b/core/java/android/app/SearchableInfo.java
@@ -16,17 +16,14 @@
 
 package android.app;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.annotation.StringRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ProviderInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ProviderInfo;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.os.Parcel;
@@ -38,6 +35,9 @@
 import android.util.Xml;
 import android.view.inputmethod.EditorInfo;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 import java.util.HashMap;
 
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 9b62e3b..dc8269f 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -21,7 +21,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
 import android.content.Context;
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index 9f865b4..abb0cfc 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -17,10 +17,10 @@
 package android.app;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.compat.Compatibility;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.SharedPreferences;
 import android.os.Build;
 import android.os.FileUtils;
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index f6e9569..cd855cf 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -27,6 +27,7 @@
 import android.os.IPullAtomCallback;
 import android.os.IPullAtomResultReceiver;
 import android.os.IStatsCompanionService;
+import android.os.IStatsManagerService;
 import android.os.IStatsPullerCallback;
 import android.os.IStatsd;
 import android.os.RemoteException;
@@ -61,6 +62,9 @@
     @GuardedBy("sLock")
     private IStatsCompanionService mStatsCompanion;
 
+    @GuardedBy("sLock")
+    private IStatsManagerService mStatsManagerService;
+
     /**
      * Long extra of uid that added the relevant stats config.
      */
@@ -686,6 +690,16 @@
         return mStatsCompanion;
     }
 
+    @GuardedBy("sLock")
+    private IStatsManagerService getIStatsManagerServiceLocked() {
+        if (mStatsManagerService != null) {
+            return mStatsManagerService;
+        }
+        mStatsManagerService = IStatsManagerService.Stub.asInterface(
+                ServiceManager.getService(Context.STATS_MANAGER_SERVICE));
+        return mStatsManagerService;
+    }
+
     /**
      * Exception thrown when communication with the stats service fails (eg if it is not available).
      * This might be thrown early during boot before the stats service has started or if it crashed.
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 28413be..a1765c8 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -23,7 +23,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index de64db9..fe9c640 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.res.Configuration;
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 40d10b7..343b386 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -16,8 +16,8 @@
 
 package android.app;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager.TaskSnapshot;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.os.Binder;
 import android.os.IBinder;
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index 1b281d5..c529297 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -17,7 +17,7 @@
 package android.app;
 
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 13d566c..18a3e6e 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -25,7 +25,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.Rect;
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 1e9bbae..82e9881 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -19,6 +19,7 @@
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.annotation.Nullable;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
@@ -40,8 +41,6 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.IAccessibilityManager;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
 import libcore.io.IoUtils;
 
 import java.io.FileInputStream;
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index d8c030d..3633064 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -23,7 +23,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.os.RemoteException;
diff --git a/core/java/android/app/UserSwitchObserver.java b/core/java/android/app/UserSwitchObserver.java
index 2f8ee744b..6abc4f0 100644
--- a/core/java/android/app/UserSwitchObserver.java
+++ b/core/java/android/app/UserSwitchObserver.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.IRemoteCallback;
 import android.os.RemoteException;
 
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
index c74f8c3..08a210b 100644
--- a/core/java/android/app/VrManager.java
+++ b/core/java/android/app/VrManager.java
@@ -6,7 +6,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.RemoteException;
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 41604ec..ac8b40c 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -26,7 +26,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index aa6492e..1e4f8f3 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -26,6 +26,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Parcel;
@@ -35,8 +36,6 @@
 import android.util.proto.WireTypeMismatchException;
 import android.view.DisplayInfo;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
 import java.io.IOException;
 
 /**
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 63bc40b..a2f4414 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -17,7 +17,7 @@
 package android.app.admin;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7332978..3ca8f49 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -33,13 +33,13 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.app.Activity;
 import android.app.IServiceConnection;
 import android.app.KeyguardManager;
 import android.app.admin.SecurityLog.SecurityEvent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 9727621..f0b87a8 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -18,7 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/app/assist/AssistContent.java b/core/java/android/app/assist/AssistContent.java
index db6ae4f..e5316bc0 100644
--- a/core/java/android/app/assist/AssistContent.java
+++ b/core/java/android/app/assist/AssistContent.java
@@ -1,6 +1,6 @@
 package android.app.assist;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ClipData;
 import android.content.Intent;
 import android.net.Uri;
diff --git a/core/java/android/app/backup/BackupDataInput.java b/core/java/android/app/backup/BackupDataInput.java
index 2a98ca7..d1383c8 100644
--- a/core/java/android/app/backup/BackupDataInput.java
+++ b/core/java/android/app/backup/BackupDataInput.java
@@ -17,7 +17,7 @@
 package android.app.backup;
 
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
diff --git a/core/java/android/app/backup/BackupDataInputStream.java b/core/java/android/app/backup/BackupDataInputStream.java
index 0888066..11a3d0c 100644
--- a/core/java/android/app/backup/BackupDataInputStream.java
+++ b/core/java/android/app/backup/BackupDataInputStream.java
@@ -16,9 +16,10 @@
 
 package android.app.backup;
 
-import android.annotation.UnsupportedAppUsage;
-import java.io.InputStream;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.io.IOException;
+import java.io.InputStream;
 
 /**
  * Provides an {@link java.io.InputStream}-like interface for accessing an
diff --git a/core/java/android/app/backup/BackupDataOutput.java b/core/java/android/app/backup/BackupDataOutput.java
index 01961e7..fb161d4 100644
--- a/core/java/android/app/backup/BackupDataOutput.java
+++ b/core/java/android/app/backup/BackupDataOutput.java
@@ -17,7 +17,7 @@
 package android.app.backup;
 
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.ParcelFileDescriptor;
 
 import java.io.FileDescriptor;
diff --git a/core/java/android/app/backup/BackupHelperDispatcher.java b/core/java/android/app/backup/BackupHelperDispatcher.java
index e9acdbf..6faa887 100644
--- a/core/java/android/app/backup/BackupHelperDispatcher.java
+++ b/core/java/android/app/backup/BackupHelperDispatcher.java
@@ -16,7 +16,7 @@
 
 package android.app.backup;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 93d1e71..beb4449 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -21,7 +21,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/app/backup/FileBackupHelperBase.java b/core/java/android/app/backup/FileBackupHelperBase.java
index 0caab98..5ad5d08 100644
--- a/core/java/android/app/backup/FileBackupHelperBase.java
+++ b/core/java/android/app/backup/FileBackupHelperBase.java
@@ -16,7 +16,7 @@
 
 package android.app.backup;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 9a595b2..587e883 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -16,7 +16,7 @@
 
 package android.app.backup;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.XmlResourceParser;
diff --git a/core/java/android/app/backup/FullBackupDataOutput.java b/core/java/android/app/backup/FullBackupDataOutput.java
index 0ce8653..d8fa0f5 100644
--- a/core/java/android/app/backup/FullBackupDataOutput.java
+++ b/core/java/android/app/backup/FullBackupDataOutput.java
@@ -1,6 +1,6 @@
 package android.app.backup;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.ParcelFileDescriptor;
 
 /**
diff --git a/core/java/android/app/role/RoleControllerService.java b/core/java/android/app/role/RoleControllerService.java
index 06623f9..d92c956 100644
--- a/core/java/android/app/role/RoleControllerService.java
+++ b/core/java/android/app/role/RoleControllerService.java
@@ -35,6 +35,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.pooled.PooledLambda;
 
+import java.util.Objects;
 import java.util.concurrent.Executor;
 
 /**
@@ -82,7 +83,7 @@
             public void grantDefaultRoles(RemoteCallback callback) {
                 enforceCallerSystemUid("grantDefaultRoles");
 
-                Preconditions.checkNotNull(callback, "callback cannot be null");
+                Objects.requireNonNull(callback, "callback cannot be null");
 
                 mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
                         RoleControllerService::grantDefaultRoles, RoleControllerService.this,
@@ -97,7 +98,7 @@
                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
                 Preconditions.checkStringNotEmpty(packageName,
                         "packageName cannot be null or empty");
-                Preconditions.checkNotNull(callback, "callback cannot be null");
+                Objects.requireNonNull(callback, "callback cannot be null");
 
                 mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
                         RoleControllerService::onAddRoleHolder, RoleControllerService.this,
@@ -112,7 +113,7 @@
                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
                 Preconditions.checkStringNotEmpty(packageName,
                         "packageName cannot be null or empty");
-                Preconditions.checkNotNull(callback, "callback cannot be null");
+                Objects.requireNonNull(callback, "callback cannot be null");
 
                 mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
                         RoleControllerService::onRemoveRoleHolder, RoleControllerService.this,
@@ -124,7 +125,7 @@
                 enforceCallerSystemUid("onClearRoleHolders");
 
                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
-                Preconditions.checkNotNull(callback, "callback cannot be null");
+                Objects.requireNonNull(callback, "callback cannot be null");
 
                 mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
                         RoleControllerService::onClearRoleHolders, RoleControllerService.this,
@@ -146,7 +147,7 @@
                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
                 Preconditions.checkStringNotEmpty(packageName,
                         "packageName cannot be null or empty");
-                Preconditions.checkNotNull(callback, "callback cannot be null");
+                Objects.requireNonNull(callback, "callback cannot be null");
 
                 boolean qualified = onIsApplicationQualifiedForRole(roleName, packageName);
                 callback.sendResult(qualified ? Bundle.EMPTY : null);
@@ -160,7 +161,7 @@
                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
                 Preconditions.checkStringNotEmpty(packageName,
                         "packageName cannot be null or empty");
-                Preconditions.checkNotNull(callback, "callback cannot be null");
+                Objects.requireNonNull(callback, "callback cannot be null");
 
                 boolean visible = onIsApplicationVisibleForRole(roleName, packageName);
                 callback.sendResult(visible ? Bundle.EMPTY : null);
@@ -171,7 +172,7 @@
                 enforceCallingPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, null);
 
                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
-                Preconditions.checkNotNull(callback, "callback cannot be null");
+                Objects.requireNonNull(callback, "callback cannot be null");
 
                 boolean visible = onIsRoleVisible(roleName);
                 callback.sendResult(visible ? Bundle.EMPTY : null);
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index bb04a2e..61eeacc 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -42,6 +42,7 @@
 import com.android.internal.util.function.pooled.PooledLambda;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
@@ -284,7 +285,7 @@
     @TestApi
     public List<String> getRoleHoldersAsUser(@NonNull String roleName, @NonNull UserHandle user) {
         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
-        Preconditions.checkNotNull(user, "user cannot be null");
+        Objects.requireNonNull(user, "user cannot be null");
         try {
             return mService.getRoleHoldersAsUser(roleName, user.getIdentifier());
         } catch (RemoteException e) {
@@ -321,9 +322,9 @@
             @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
-        Preconditions.checkNotNull(user, "user cannot be null");
-        Preconditions.checkNotNull(executor, "executor cannot be null");
-        Preconditions.checkNotNull(callback, "callback cannot be null");
+        Objects.requireNonNull(user, "user cannot be null");
+        Objects.requireNonNull(executor, "executor cannot be null");
+        Objects.requireNonNull(callback, "callback cannot be null");
         try {
             mService.addRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
                     createRemoteCallback(executor, callback));
@@ -360,9 +361,9 @@
             @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
-        Preconditions.checkNotNull(user, "user cannot be null");
-        Preconditions.checkNotNull(executor, "executor cannot be null");
-        Preconditions.checkNotNull(callback, "callback cannot be null");
+        Objects.requireNonNull(user, "user cannot be null");
+        Objects.requireNonNull(executor, "executor cannot be null");
+        Objects.requireNonNull(callback, "callback cannot be null");
         try {
             mService.removeRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
                     createRemoteCallback(executor, callback));
@@ -397,9 +398,9 @@
             @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor,
             @NonNull Consumer<Boolean> callback) {
         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
-        Preconditions.checkNotNull(user, "user cannot be null");
-        Preconditions.checkNotNull(executor, "executor cannot be null");
-        Preconditions.checkNotNull(callback, "callback cannot be null");
+        Objects.requireNonNull(user, "user cannot be null");
+        Objects.requireNonNull(executor, "executor cannot be null");
+        Objects.requireNonNull(callback, "callback cannot be null");
         try {
             mService.clearRoleHoldersAsUser(roleName, flags, user.getIdentifier(),
                     createRemoteCallback(executor, callback));
@@ -442,9 +443,9 @@
     @TestApi
     public void addOnRoleHoldersChangedListenerAsUser(@CallbackExecutor @NonNull Executor executor,
             @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user) {
-        Preconditions.checkNotNull(executor, "executor cannot be null");
-        Preconditions.checkNotNull(listener, "listener cannot be null");
-        Preconditions.checkNotNull(user, "user cannot be null");
+        Objects.requireNonNull(executor, "executor cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
+        Objects.requireNonNull(user, "user cannot be null");
         int userId = user.getIdentifier();
         synchronized (mListenersLock) {
             ArrayMap<OnRoleHoldersChangedListener, OnRoleHoldersChangedListenerDelegate> listeners =
@@ -488,8 +489,8 @@
     @TestApi
     public void removeOnRoleHoldersChangedListenerAsUser(
             @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
-        Preconditions.checkNotNull(user, "user cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
+        Objects.requireNonNull(user, "user cannot be null");
         int userId = user.getIdentifier();
         synchronized (mListenersLock) {
             ArrayMap<OnRoleHoldersChangedListener, OnRoleHoldersChangedListenerDelegate> listeners =
@@ -529,7 +530,7 @@
     @SystemApi
     @TestApi
     public void setRoleNamesFromController(@NonNull List<String> roleNames) {
-        Preconditions.checkNotNull(roleNames, "roleNames cannot be null");
+        Objects.requireNonNull(roleNames, "roleNames cannot be null");
         try {
             mService.setRoleNamesFromController(roleNames);
         } catch (RemoteException e) {
diff --git a/core/java/android/app/servertransaction/ActivityResultItem.java b/core/java/android/app/servertransaction/ActivityResultItem.java
index 52ec3e6..4e743ca 100644
--- a/core/java/android/app/servertransaction/ActivityResultItem.java
+++ b/core/java/android/app/servertransaction/ActivityResultItem.java
@@ -18,9 +18,9 @@
 
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.ClientTransactionHandler;
 import android.app.ResultInfo;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java
index b08e5973..4d2e9a5 100644
--- a/core/java/android/app/servertransaction/ClientTransaction.java
+++ b/core/java/android/app/servertransaction/ClientTransaction.java
@@ -17,9 +17,9 @@
 package android.app.servertransaction;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ClientTransactionHandler;
 import android.app.IApplicationThread;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 1236e0a..6d674ae 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -18,11 +18,11 @@
 
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread.ActivityClientRecord;
 import android.app.ClientTransactionHandler;
 import android.app.ProfilerInfo;
 import android.app.ResultInfo;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.res.CompatibilityInfo;
diff --git a/core/java/android/app/servertransaction/NewIntentItem.java b/core/java/android/app/servertransaction/NewIntentItem.java
index bb775fc..6a4996d 100644
--- a/core/java/android/app/servertransaction/NewIntentItem.java
+++ b/core/java/android/app/servertransaction/NewIntentItem.java
@@ -19,8 +19,8 @@
 import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME;
 import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.ClientTransactionHandler;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 27abdcf..65b2775 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -19,7 +19,7 @@
 import android.Manifest;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.hardware.biometrics.BiometricSourceType;
 import android.os.Handler;
diff --git a/core/java/android/app/usage/ConfigurationStats.java b/core/java/android/app/usage/ConfigurationStats.java
index da3b769..8a7107d 100644
--- a/core/java/android/app/usage/ConfigurationStats.java
+++ b/core/java/android/app/usage/ConfigurationStats.java
@@ -15,7 +15,7 @@
  */
 package android.app.usage;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.Configuration;
 import android.os.Build;
 import android.os.Parcel;
diff --git a/core/java/android/app/usage/IStorageStatsManager.aidl b/core/java/android/app/usage/IStorageStatsManager.aidl
index 7eacc89..b5036da 100644
--- a/core/java/android/app/usage/IStorageStatsManager.aidl
+++ b/core/java/android/app/usage/IStorageStatsManager.aidl
@@ -18,6 +18,8 @@
 
 import android.app.usage.StorageStats;
 import android.app.usage.ExternalStorageStats;
+import android.content.pm.ParceledListSlice;
+import android.os.storage.CrateInfo;
 
 /** {@hide} */
 interface IStorageStatsManager {
@@ -31,4 +33,10 @@
     StorageStats queryStatsForUid(String volumeUuid, int uid, String callingPackage);
     StorageStats queryStatsForUser(String volumeUuid, int userId, String callingPackage);
     ExternalStorageStats queryExternalStatsForUser(String volumeUuid, int userId, String callingPackage);
+    ParceledListSlice /* CrateInfo */ queryCratesForPackage(String volumeUuid, String packageName,
+            int userId, String callingPackage);
+    ParceledListSlice /* CrateInfo */ queryCratesForUid(String volumeUuid, int uid,
+            String callingPackage);
+    ParceledListSlice /* CrateInfo */ queryCratesForUser(String volumeUuid, int userId,
+            String callingPackage);
 }
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 6bade90..7412970 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -21,8 +21,8 @@
 import android.annotation.Nullable;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.usage.NetworkStats.Bucket;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.DataUsageRequest;
diff --git a/core/java/android/app/usage/StorageStatsManager.java b/core/java/android/app/usage/StorageStatsManager.java
index a86c27a..eecf092 100644
--- a/core/java/android/app/usage/StorageStatsManager.java
+++ b/core/java/android/app/usage/StorageStatsManager.java
@@ -20,6 +20,7 @@
 
 import android.annotation.BytesLong;
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.annotation.WorkerThread;
@@ -27,15 +28,19 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
 import android.os.ParcelableException;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.storage.CrateInfo;
 import android.os.storage.StorageManager;
 
 import com.android.internal.util.Preconditions;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Collection;
+import java.util.Objects;
 import java.util.UUID;
 
 /**
@@ -347,4 +352,100 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Return all of crate information for the specified storageUuid, packageName, and
+     * userHandle.
+     *
+     * @param storageUuid the UUID of the storage volume you're interested in,
+     *            such as {@link StorageManager#UUID_DEFAULT}.
+     * @param uid the uid you're interested in.
+     * @return the collection of crate information.
+     * @throws PackageManager.NameNotFoundException when the package name is not found.
+     * @throws IOException cause by IO, not support, or the other reasons.
+     * @hide
+     */
+    @TestApi
+    @WorkerThread
+    @NonNull
+    public Collection<CrateInfo> queryCratesForUid(@NonNull UUID storageUuid,
+            int uid) throws IOException, PackageManager.NameNotFoundException {
+        try {
+            ParceledListSlice<CrateInfo> crateInfoList =
+                    mService.queryCratesForUid(convert(storageUuid), uid,
+                            mContext.getOpPackageName());
+            return Objects.requireNonNull(crateInfoList).getList();
+        } catch (ParcelableException e) {
+            e.maybeRethrow(PackageManager.NameNotFoundException.class);
+            e.maybeRethrow(IOException.class);
+            throw new RuntimeException(e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return all of crates information for the specified storageUuid, packageName, and
+     * userHandle.
+     *
+     * @param storageUuid the UUID of the storage volume you're interested in,
+     *            such as {@link StorageManager#UUID_DEFAULT}.
+     * @param packageName the package name you're interested in.
+     * @param user the user you're interested in.
+     * @return the collection of crate information.
+     * @throws PackageManager.NameNotFoundException when the package name is not found.
+     * @throws IOException cause by IO, not support, or the other reasons.
+     * @hide
+     */
+    @WorkerThread
+    @TestApi
+    @NonNull
+    public Collection<CrateInfo> queryCratesForPackage(@NonNull UUID storageUuid,
+            @NonNull String packageName, @NonNull UserHandle user)
+            throws PackageManager.NameNotFoundException, IOException {
+        try {
+            ParceledListSlice<CrateInfo> crateInfoList =
+                    mService.queryCratesForPackage(convert(storageUuid), packageName,
+                            user.getIdentifier(), mContext.getOpPackageName());
+            return Objects.requireNonNull(crateInfoList).getList();
+        } catch (ParcelableException e) {
+            e.maybeRethrow(PackageManager.NameNotFoundException.class);
+            e.maybeRethrow(IOException.class);
+            throw new RuntimeException(e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return all of crate information for the specified storageUuid, packageName, and
+     * userHandle.
+     *
+     * @param storageUuid the UUID of the storage volume you're interested in,
+     *            such as {@link StorageManager#UUID_DEFAULT}.
+     * @param user the user you're interested in.
+     * @return the collection of crate information.
+     * @throws PackageManager.NameNotFoundException when the package name is not found.
+     * @throws IOException cause by IO, not support, or the other reasons.
+     * @hide
+     */
+    @WorkerThread
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_CRATES)
+    @NonNull
+    public Collection<CrateInfo> queryCratesForUser(@NonNull UUID storageUuid,
+            @NonNull UserHandle user) throws PackageManager.NameNotFoundException, IOException {
+        try {
+            ParceledListSlice<CrateInfo> crateInfoList =
+                    mService.queryCratesForUser(convert(storageUuid), user.getIdentifier(),
+                            mContext.getOpPackageName());
+            return Objects.requireNonNull(crateInfoList).getList();
+        } catch (ParcelableException e) {
+            e.maybeRethrow(PackageManager.NameNotFoundException.class);
+            e.maybeRethrow(IOException.class);
+            throw new RuntimeException(e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 4bf9c04..d840c1c 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -18,7 +18,7 @@
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.Configuration;
 import android.os.Build;
 import android.os.Parcel;
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 9d43dd3..d06baed 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -29,7 +29,7 @@
 import static android.app.usage.UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE;
 
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 419377c..176a181 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -23,9 +23,9 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
 import android.os.Build;
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index c20cb25..467b2fb 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -18,8 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.IntentSender;
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 85f0e23..09d56ec 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -16,9 +16,9 @@
 
 package android.appwidget;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.ActivityOptions;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ContextWrapper;
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index dbc1c19..6dea1c6 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -23,9 +23,9 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
 import android.app.IServiceConnection;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 2faa900..130a20d 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -18,8 +18,8 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 64df0e8..d8c653c6 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -24,7 +24,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
 import android.os.Build;
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
index c6957e1..8993de0 100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -21,7 +21,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 8404705..b1b6f0d 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -25,7 +25,6 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
 import android.bluetooth.BluetoothProfile.ConnectionPolicy;
 import android.bluetooth.le.BluetoothLeAdvertiser;
@@ -36,6 +35,7 @@
 import android.bluetooth.le.ScanRecord;
 import android.bluetooth.le.ScanResult;
 import android.bluetooth.le.ScanSettings;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.BatteryStats;
 import android.os.Binder;
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index 260e2fb..905b0cee 100755
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -17,7 +17,7 @@
 package android.bluetooth;
 
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
index 08d0797..93e76fa 100644
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -19,7 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 323c7d1..9fe4dd6 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -24,7 +24,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Parcel;
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index d616b8f..f877f04 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -16,7 +16,7 @@
 
 package android.bluetooth;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Handler;
 import android.os.ParcelUuid;
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
index edacf3e..7066f47 100644
--- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
@@ -15,7 +15,7 @@
  */
 package android.bluetooth;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.ParcelUuid;
 import android.os.Parcelable;
diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java
index 0783cd2..7cc2d6b 100644
--- a/core/java/android/bluetooth/BluetoothGattDescriptor.java
+++ b/core/java/android/bluetooth/BluetoothGattDescriptor.java
@@ -16,7 +16,7 @@
 
 package android.bluetooth;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.ParcelUuid;
 import android.os.Parcelable;
diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java
index c20faf9..13d6d70 100644
--- a/core/java/android/bluetooth/BluetoothGattService.java
+++ b/core/java/android/bluetooth/BluetoothGattService.java
@@ -15,7 +15,7 @@
  */
 package android.bluetooth;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.ParcelUuid;
 import android.os.Parcelable;
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 0955b10..1ba2bb5 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -23,7 +23,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Binder;
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index 7ee29ff..6de1ffb 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -19,7 +19,7 @@
 import android.Manifest;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
 import android.os.Bundle;
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
index 7165dd5..d1a096e 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
@@ -16,7 +16,7 @@
 
 package android.bluetooth;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index b4521c6..83eaa72 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -23,7 +23,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index 979dfd4..917e7fa 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -19,7 +19,7 @@
 import android.Manifest;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index 0ec473c..0aa5aac 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -19,8 +19,8 @@
 import android.Manifest;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Binder;
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 4e97627..42f27f2 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -23,7 +23,7 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index df02896..c579fdf 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -20,7 +20,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 097a367..638e6de 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -22,7 +22,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
index 9b4dabc..8bf1b58 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -19,7 +19,7 @@
 import android.Manifest;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 3a23808..88c186c 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -16,7 +16,7 @@
 
 package android.bluetooth;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Handler;
 import android.os.ParcelUuid;
 import android.util.Log;
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 760166b..f774369 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -16,7 +16,7 @@
 
 package android.bluetooth;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.net.LocalSocket;
 import android.os.ParcelFileDescriptor;
 import android.os.ParcelUuid;
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 7e96c23..e274af1 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.ParcelUuid;
 
 import java.nio.ByteBuffer;
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
index 97e3f52..c0c1aa1 100644
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ b/core/java/android/bluetooth/le/ScanRecord.java
@@ -18,8 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.bluetooth.BluetoothUuid;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.ParcelUuid;
 import android.util.ArrayMap;
 import android.util.Log;
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index ac40150..1f57c7d 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.provider.OneTimeUseBuilder;
diff --git a/core/java/android/companion/BluetoothDeviceFilter.java b/core/java/android/companion/BluetoothDeviceFilter.java
index fe0123c..2649fbe 100644
--- a/core/java/android/companion/BluetoothDeviceFilter.java
+++ b/core/java/android/companion/BluetoothDeviceFilter.java
@@ -25,8 +25,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.bluetooth.BluetoothDevice;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.ParcelUuid;
 import android.provider.OneTimeUseBuilder;
diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java
index 0f67f6b..24be45c 100644
--- a/core/java/android/companion/BluetoothDeviceFilterUtils.java
+++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java
@@ -21,9 +21,9 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.le.ScanFilter;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.net.wifi.ScanResult;
 import android.os.ParcelUuid;
 import android.os.Parcelable;
diff --git a/core/java/android/companion/BluetoothLeDeviceFilter.java b/core/java/android/companion/BluetoothLeDeviceFilter.java
index 2701619..730bc60 100644
--- a/core/java/android/companion/BluetoothLeDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLeDeviceFilter.java
@@ -25,11 +25,11 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.le.ScanFilter;
 import android.bluetooth.le.ScanRecord;
 import android.bluetooth.le.ScanResult;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.provider.OneTimeUseBuilder;
 import android.text.TextUtils;
diff --git a/core/java/android/companion/DeviceFilter.java b/core/java/android/companion/DeviceFilter.java
index dc7cf82..c9cb072 100644
--- a/core/java/android/companion/DeviceFilter.java
+++ b/core/java/android/companion/DeviceFilter.java
@@ -19,7 +19,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcelable;
 
 import java.lang.annotation.Retention;
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index bb7d5e4..14c3387 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -16,7 +16,7 @@
 
 package android.content;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.OperationCanceledException;
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index f73a376..1d4d30d 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -18,11 +18,11 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.IActivityManager;
 import android.app.QueuedWork;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 999ec37..9c806fa 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -21,7 +21,7 @@
 import static android.content.ContentResolver.SCHEME_CONTENT;
 import static android.content.ContentResolver.SCHEME_FILE;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.AssetFileDescriptor;
 import android.graphics.Bitmap;
 import android.net.Uri;
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index dc1c700..dec9589 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
diff --git a/core/java/android/content/ComponentName.java b/core/java/android/content/ComponentName.java
index 33216d7..27960b0 100644
--- a/core/java/android/content/ComponentName.java
+++ b/core/java/android/content/ComponentName.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 2240823..393d488 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -27,8 +27,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AppOpsManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.PackageManager;
 import android.content.pm.PathPermission;
 import android.content.pm.ProviderInfo;
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index bb65aa0..4008f2b 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -22,7 +22,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.AssetFileDescriptor;
 import android.database.CrossProcessCursorWrapper;
 import android.database.Cursor;
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index dfa71f8..45ace40 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -17,7 +17,7 @@
 package android.content;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.AssetFileDescriptor;
 import android.database.BulkCursorDescriptor;
 import android.database.BulkCursorToCursorAdaptor;
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index d4280f8..ede668a 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -25,12 +25,12 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.app.UriGrantsManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.AssetFileDescriptor;
diff --git a/core/java/android/content/ContentValues.java b/core/java/android/content/ContentValues.java
index bdd1f4c..f9f4c5d 100644
--- a/core/java/android/content/ContentValues.java
+++ b/core/java/android/content/ContentValues.java
@@ -16,9 +16,8 @@
 
 package android.content;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArrayMap;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 24b5061..66abf5d 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -32,12 +32,12 @@
 import android.annotation.StyleableRes;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
 import android.app.VrManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
@@ -4828,6 +4828,12 @@
     public static final String INCIDENT_COMPANION_SERVICE = "incidentcompanion";
 
     /**
+     * Service to assist {@link android.app.StatsManager} that lives in system server.
+     * @hide
+     */
+    public static final String STATS_MANAGER_SERVICE = "statsmanager";
+
+    /**
      * Service to assist statsd in obtaining general stats.
      * @hide
      */
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index d1b5135..6fe1187 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -21,9 +21,9 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
diff --git a/core/java/android/content/CursorEntityIterator.java b/core/java/android/content/CursorEntityIterator.java
index 2c630d2..952366d 100644
--- a/core/java/android/content/CursorEntityIterator.java
+++ b/core/java/android/content/CursorEntityIterator.java
@@ -16,7 +16,7 @@
 
 package android.content;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.database.Cursor;
 import android.os.RemoteException;
 
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index 4ccafab..4ff5cca 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -16,7 +16,7 @@
 
 package android.content;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.CancellationSignal;
diff --git a/core/java/android/content/Entity.java b/core/java/android/content/Entity.java
index ff4f150..13137c4 100644
--- a/core/java/android/content/Entity.java
+++ b/core/java/android/content/Entity.java
@@ -16,7 +16,7 @@
 
 package android.content;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.net.Uri;
 import android.os.Build;
 
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 1fb2958..6f477ff 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -17,7 +17,7 @@
 package android.content;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 47fb375..c5a147a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -28,8 +28,8 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AppGlobals;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 93390bd..73c1e2f 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -18,7 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Parcel;
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index ec0bac4..f40dc29 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -16,14 +16,14 @@
 
 package android.content;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.AndroidException;
 
diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java
index bbdab04..885eb70 100644
--- a/core/java/android/content/RestrictionsManager.java
+++ b/core/java/android/content/RestrictionsManager.java
@@ -17,9 +17,9 @@
 package android.content;
 
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.admin.DevicePolicyManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
diff --git a/core/java/android/content/SearchRecentSuggestionsProvider.java b/core/java/android/content/SearchRecentSuggestionsProvider.java
index 8ee7b9e..fc3ddf6 100644
--- a/core/java/android/content/SearchRecentSuggestionsProvider.java
+++ b/core/java/android/content/SearchRecentSuggestionsProvider.java
@@ -16,8 +16,8 @@
 
 package android.content;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.SearchManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java
index 8c8fe5a..7bcdbfd 100644
--- a/core/java/android/content/SyncAdapterType.java
+++ b/core/java/android/content/SyncAdapterType.java
@@ -17,11 +17,11 @@
 package android.content;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
-import android.text.TextUtils;
-import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
 
 /**
  * Value type that represents a SyncAdapterType. This object overrides {@link #equals} and
diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java
index d4e5217..58445a7 100644
--- a/core/java/android/content/SyncAdaptersCache.java
+++ b/core/java/android/content/SyncAdaptersCache.java
@@ -16,7 +16,7 @@
 
 package android.content;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.RegisteredServicesCache;
 import android.content.pm.XmlSerializerAndParser;
 import android.content.res.Resources;
@@ -29,8 +29,8 @@
 import com.android.internal.annotations.GuardedBy;
 
 import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
 import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.util.ArrayList;
diff --git a/core/java/android/content/SyncContext.java b/core/java/android/content/SyncContext.java
index 50d1dc9..4a9f66c 100644
--- a/core/java/android/content/SyncContext.java
+++ b/core/java/android/content/SyncContext.java
@@ -16,10 +16,10 @@
 
 package android.content;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.IBinder;
 
 public class SyncContext {
     private ISyncContext mSyncContext;
diff --git a/core/java/android/content/SyncInfo.java b/core/java/android/content/SyncInfo.java
index d3f2eed..017a92b 100644
--- a/core/java/android/content/SyncInfo.java
+++ b/core/java/android/content/SyncInfo.java
@@ -17,7 +17,7 @@
 package android.content;
 
 import android.accounts.Account;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index 5f1f180..9e568a4 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -17,7 +17,7 @@
 package android.content;
 
 import android.accounts.Account;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java
index 0eea47a..b72eb04 100644
--- a/core/java/android/content/SyncStatusInfo.java
+++ b/core/java/android/content/SyncStatusInfo.java
@@ -16,7 +16,7 @@
 
 package android.content;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
diff --git a/core/java/android/content/UndoManager.java b/core/java/android/content/UndoManager.java
index f9c58d6..ed9cd86 100644
--- a/core/java/android/content/UndoManager.java
+++ b/core/java/android/content/UndoManager.java
@@ -16,7 +16,7 @@
 
 package android.content;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.text.TextUtils;
 import android.util.ArrayMap;
diff --git a/core/java/android/content/UndoOperation.java b/core/java/android/content/UndoOperation.java
index a425486..235d721 100644
--- a/core/java/android/content/UndoOperation.java
+++ b/core/java/android/content/UndoOperation.java
@@ -16,7 +16,7 @@
 
 package android.content;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/core/java/android/content/UriMatcher.java b/core/java/android/content/UriMatcher.java
index 208bc01..7fa48f0 100644
--- a/core/java/android/content/UriMatcher.java
+++ b/core/java/android/content/UriMatcher.java
@@ -16,7 +16,7 @@
 
 package android.content;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.net.Uri;
 
 import java.util.ArrayList;
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index 1a78f79..a3487be 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -20,8 +20,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 26193f6..5b1f926 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -18,7 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.res.Configuration;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 552c8ac..1aed977 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -22,7 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
diff --git a/core/java/android/content/pm/BaseParceledListSlice.java b/core/java/android/content/pm/BaseParceledListSlice.java
index ffbca16..bd847bf 100644
--- a/core/java/android/content/pm/BaseParceledListSlice.java
+++ b/core/java/android/content/pm/BaseParceledListSlice.java
@@ -16,7 +16,7 @@
 
 package android.content.pm;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Parcel;
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index 10f0df7..8b41c04 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -16,7 +16,7 @@
 
 package android.content.pm;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
diff --git a/core/java/android/os/incremental/IncrementalDataLoaderParams.java b/core/java/android/content/pm/DataLoaderParams.java
similarity index 82%
rename from core/java/android/os/incremental/IncrementalDataLoaderParams.java
rename to core/java/android/content/pm/DataLoaderParams.java
index 701f1cc..b163861 100644
--- a/core/java/android/os/incremental/IncrementalDataLoaderParams.java
+++ b/core/java/android/content/pm/DataLoaderParams.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.os.incremental;
+package android.content.pm;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -29,12 +29,12 @@
  * Hide for now.
  * @hide
  */
-public class IncrementalDataLoaderParams {
-    @NonNull private final IncrementalDataLoaderParamsParcel mData;
+public class DataLoaderParams {
+    @NonNull private final DataLoaderParamsParcel mData;
 
-    public IncrementalDataLoaderParams(@NonNull String url, @NonNull String packageName,
+    public DataLoaderParams(@NonNull String url, @NonNull String packageName,
             @Nullable Map<String, ParcelFileDescriptor> namedFds) {
-        IncrementalDataLoaderParamsParcel data = new IncrementalDataLoaderParamsParcel();
+        DataLoaderParamsParcel data = new DataLoaderParamsParcel();
         data.staticArgs = url;
         data.packageName = packageName;
         if (namedFds == null || namedFds.isEmpty()) {
@@ -52,7 +52,7 @@
         mData = data;
     }
 
-    public IncrementalDataLoaderParams(@NonNull IncrementalDataLoaderParamsParcel data) {
+    public DataLoaderParams(@NonNull DataLoaderParamsParcel data) {
         mData = data;
     }
 
@@ -70,7 +70,7 @@
         return mData.packageName;
     }
 
-    public final @NonNull IncrementalDataLoaderParamsParcel getData() {
+    public final @NonNull DataLoaderParamsParcel getData() {
         return mData;
     }
 
diff --git a/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl b/core/java/android/content/pm/DataLoaderParamsParcel.aidl
similarity index 85%
rename from core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl
rename to core/java/android/content/pm/DataLoaderParamsParcel.aidl
index cd988dc..3316398 100644
--- a/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl
+++ b/core/java/android/content/pm/DataLoaderParamsParcel.aidl
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-package android.os.incremental;
+package android.content.pm;
 
-import android.os.incremental.NamedParcelFileDescriptor;
+import android.content.pm.NamedParcelFileDescriptor;
 
 /**
  * Class for holding data loader configuration parameters.
  * @hide
  */
-parcelable IncrementalDataLoaderParamsParcel {
+parcelable DataLoaderParamsParcel {
     @utf8InCpp String packageName;
     @utf8InCpp String staticArgs;
     NamedParcelFileDescriptor[] dynamicArgs;
diff --git a/core/java/android/content/pm/FileSystemControlParcel.aidl b/core/java/android/content/pm/FileSystemControlParcel.aidl
new file mode 100644
index 0000000..f00feae
--- /dev/null
+++ b/core/java/android/content/pm/FileSystemControlParcel.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.content.pm.IPackageInstallerSessionFileSystemConnector;
+import android.os.incremental.IncrementalFileSystemControlParcel;
+
+/**
+ * Wraps info needed for DataLoader to provide data.
+ * @hide
+ */
+parcelable FileSystemControlParcel {
+    // Incremental FS control descriptors.
+    @nullable IncrementalFileSystemControlParcel incremental;
+    // Callback-based installation connector.
+    @nullable IPackageInstallerSessionFileSystemConnector callback;
+}
diff --git a/core/java/android/content/pm/IDataLoader.aidl b/core/java/android/content/pm/IDataLoader.aidl
index 60cc9ba9..c65bd6a 100644
--- a/core/java/android/content/pm/IDataLoader.aidl
+++ b/core/java/android/content/pm/IDataLoader.aidl
@@ -30,5 +30,4 @@
    void start(in List<InstallationFile> fileInfos);
    void stop();
    void destroy();
-   void onFileCreated(long inode, in byte[] metadata);
 }
diff --git a/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl b/core/java/android/content/pm/IPackageInstallerSessionFileSystemConnector.aidl
similarity index 76%
copy from core/java/android/os/incremental/NamedParcelFileDescriptor.aidl
copy to core/java/android/content/pm/IPackageInstallerSessionFileSystemConnector.aidl
index 038ced1..4b2f29e 100644
--- a/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSessionFileSystemConnector.aidl
@@ -14,15 +14,11 @@
  * limitations under the License.
  */
 
-package android.os.incremental;
+package android.content.pm;
 
 import android.os.ParcelFileDescriptor;
 
-/**
- * A named ParcelFileDescriptor.
- * @hide
- */
-parcelable NamedParcelFileDescriptor {
-    @utf8InCpp String name;
-    ParcelFileDescriptor fd;
+/** {@hide} */
+interface IPackageInstallerSessionFileSystemConnector {
+    void writeData(String name, long offsetBytes, long lengthBytes, in ParcelFileDescriptor fd);
 }
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index 1451431..67deb82 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -16,7 +16,7 @@
 
 package android.content.pm;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index d2a4030..94a5375 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -25,10 +25,10 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
diff --git a/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl b/core/java/android/content/pm/NamedParcelFileDescriptor.aidl
similarity index 95%
rename from core/java/android/os/incremental/NamedParcelFileDescriptor.aidl
rename to core/java/android/content/pm/NamedParcelFileDescriptor.aidl
index 038ced1..68dd5f5 100644
--- a/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl
+++ b/core/java/android/content/pm/NamedParcelFileDescriptor.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.os.incremental;
+package android.content.pm;
 
 import android.os.ParcelFileDescriptor;
 
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index aa0002d..36fa572 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -17,7 +17,7 @@
 package android.content.pm;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java
index f5442ec..6743a3f 100644
--- a/core/java/android/content/pm/PackageInfoLite.java
+++ b/core/java/android/content/pm/PackageInfoLite.java
@@ -16,7 +16,7 @@
 
 package android.content.pm;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 898631e..5386422 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -26,9 +26,9 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
 import android.content.Intent;
@@ -50,8 +50,6 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.os.incremental.IncrementalDataLoaderParams;
-import android.os.incremental.IncrementalDataLoaderParamsParcel;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.util.ArraySet;
@@ -1459,7 +1457,7 @@
         /** {@hide} */
         public long requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
         /** {@hide} */
-        public IncrementalDataLoaderParams incrementalParams;
+        public DataLoaderParams incrementalParams;
         /** TODO(b/146080380): add a class name to make it fully compatible with ComponentName.
          * {@hide} */
         public String dataLoaderPackageName;
@@ -1496,10 +1494,10 @@
             isMultiPackage = source.readBoolean();
             isStaged = source.readBoolean();
             requiredInstalledVersionCode = source.readLong();
-            IncrementalDataLoaderParamsParcel dataLoaderParamsParcel = source.readParcelable(
-                    IncrementalDataLoaderParamsParcel.class.getClassLoader());
+            DataLoaderParamsParcel dataLoaderParamsParcel = source.readParcelable(
+                    DataLoaderParamsParcel.class.getClassLoader());
             if (dataLoaderParamsParcel != null) {
-                incrementalParams = new IncrementalDataLoaderParams(
+                incrementalParams = new DataLoaderParams(
                         dataLoaderParamsParcel);
             }
             dataLoaderPackageName = source.readString();
@@ -1863,7 +1861,7 @@
          * {@hide}
          */
         @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
-        public void setIncrementalParams(@NonNull IncrementalDataLoaderParams incrementalParams) {
+        public void setIncrementalParams(@NonNull DataLoaderParams incrementalParams) {
             this.incrementalParams = incrementalParams;
         }
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0d1f404..21c9739 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -29,7 +29,6 @@
 import android.annotation.StringRes;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
 import android.annotation.XmlRes;
 import android.app.ActivityManager;
@@ -40,6 +39,7 @@
 import android.app.usage.StorageStatsManager;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.Disabled;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 65ee1e5..47edf2e 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -47,11 +47,11 @@
 import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.apex.ApexInfo;
 import android.app.ActivityTaskManager;
 import android.app.ActivityThread;
 import android.app.ResourcesManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
diff --git a/core/java/android/content/pm/PackageStats.java b/core/java/android/content/pm/PackageStats.java
index b0fecfa..7c12527 100644
--- a/core/java/android/content/pm/PackageStats.java
+++ b/core/java/android/content/pm/PackageStats.java
@@ -16,8 +16,8 @@
 
 package android.content.pm;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.usage.StorageStatsManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 55574c3..f0f6753 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -27,7 +27,7 @@
 import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.parsing.ComponentParseUtils;
 import android.os.BaseBundle;
 import android.os.Debug;
diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java
index dccc524..73119e0 100644
--- a/core/java/android/content/pm/ParceledListSlice.java
+++ b/core/java/android/content/pm/ParceledListSlice.java
@@ -16,7 +16,7 @@
 
 package android.content.pm;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index c77c53f..89a1c6a 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -22,7 +22,7 @@
 import android.annotation.StringRes;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 23fbefb..bd909c7 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -17,7 +17,7 @@
 package android.content.pm;
 
 import android.Manifest;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -43,11 +43,11 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 
+import libcore.io.IoUtils;
+
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
-import libcore.io.IoUtils;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index 4d3e1f7..55846ad 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -17,7 +17,7 @@
 package android.content.pm;
 
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.IntentFilter;
 import android.graphics.drawable.Drawable;
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 5a80079..2c4ccbf 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -20,11 +20,11 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
 import android.app.Notification;
 import android.app.Person;
 import android.app.TaskStackBuilder;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index f851799..dde8865 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -22,9 +22,9 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
 import android.app.usage.UsageStatsManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java
index 25a4dca..3b84ae7 100644
--- a/core/java/android/content/pm/Signature.java
+++ b/core/java/android/content/pm/Signature.java
@@ -16,7 +16,7 @@
 
 package android.content.pm;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index fff9cf3..008cfa5 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -18,8 +18,8 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
diff --git a/core/java/android/content/pm/VerifierInfo.java b/core/java/android/content/pm/VerifierInfo.java
index 224ca62..5f88555 100644
--- a/core/java/android/content/pm/VerifierInfo.java
+++ b/core/java/android/content/pm/VerifierInfo.java
@@ -16,7 +16,7 @@
 
 package android.content.pm;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/core/java/android/content/pm/XmlSerializerAndParser.java b/core/java/android/content/pm/XmlSerializerAndParser.java
index 6d24800..5dce839 100644
--- a/core/java/android/content/pm/XmlSerializerAndParser.java
+++ b/core/java/android/content/pm/XmlSerializerAndParser.java
@@ -16,11 +16,12 @@
 
 package android.content.pm;
 
-import org.xmlpull.v1.XmlSerializer;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
 
-import android.annotation.UnsupportedAppUsage;
 import java.io.IOException;
 
 /** @hide */
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
index ad37555..0e4a8e6 100644
--- a/core/java/android/content/res/ApkAssets.java
+++ b/core/java/android/content/res/ApkAssets.java
@@ -17,7 +17,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.om.OverlayableInfo;
 import android.content.res.loader.ResourcesProvider;
 import android.text.TextUtils;
diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java
index 2ba5579..e93ec00 100644
--- a/core/java/android/content/res/AssetFileDescriptor.java
+++ b/core/java/android/content/res/AssetFileDescriptor.java
@@ -16,7 +16,7 @@
 
 package android.content.res;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 168eae6..d20dca1 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -24,7 +24,7 @@
 import android.annotation.StringRes;
 import android.annotation.StyleRes;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration.NativeConfig;
 import android.content.res.loader.ResourceLoader;
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index b5b097b..f23c802 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -19,9 +19,18 @@
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.Resources.Theme;
 import android.graphics.Color;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.MathUtils;
+import android.util.SparseArray;
+import android.util.StateSet;
+import android.util.Xml;
 
 import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
@@ -30,16 +39,6 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.annotation.UnsupportedAppUsage;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.MathUtils;
-import android.util.SparseArray;
-import android.util.StateSet;
-import android.util.Xml;
-import android.os.Parcel;
-import android.os.Parcelable;
-
 import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.util.Arrays;
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index f3b7553..c66c70a2 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -16,7 +16,7 @@
 
 package android.content.res;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ApplicationInfo;
 import android.graphics.Canvas;
 import android.graphics.PointF;
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index fa5ad39..8c358cc 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -45,8 +45,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.WindowConfiguration;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.LocaleProto;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.Config;
diff --git a/core/java/android/content/res/ConfigurationBoundResourceCache.java b/core/java/android/content/res/ConfigurationBoundResourceCache.java
index 848790f..5e10a57 100644
--- a/core/java/android/content/res/ConfigurationBoundResourceCache.java
+++ b/core/java/android/content/res/ConfigurationBoundResourceCache.java
@@ -16,7 +16,7 @@
 
 package android.content.res;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
 
 /**
diff --git a/core/java/android/content/res/DrawableCache.java b/core/java/android/content/res/DrawableCache.java
index 90604b8..5497e61 100644
--- a/core/java/android/content/res/DrawableCache.java
+++ b/core/java/android/content/res/DrawableCache.java
@@ -16,7 +16,7 @@
 
 package android.content.res;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.drawable.Drawable;
 
 /**
diff --git a/core/java/android/content/res/ObbInfo.java b/core/java/android/content/res/ObbInfo.java
index 8af27ca..c477abc 100644
--- a/core/java/android/content/res/ObbInfo.java
+++ b/core/java/android/content/res/ObbInfo.java
@@ -16,7 +16,7 @@
 
 package android.content.res;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index c698267..4725e0a 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -40,9 +40,9 @@
 import android.annotation.StringRes;
 import android.annotation.StyleRes;
 import android.annotation.StyleableRes;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.XmlRes;
 import android.app.ResourcesManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.loader.ResourceLoader;
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index e4a4a1a..acdd47a 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -27,7 +27,7 @@
 import android.annotation.RawRes;
 import android.annotation.StyleRes;
 import android.annotation.StyleableRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.AssetManager.AssetInputStream;
diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java
index 1db2dd8..a29fea0 100644
--- a/core/java/android/content/res/ResourcesKey.java
+++ b/core/java/android/content/res/ResourcesKey.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.text.TextUtils;
 
 import java.util.Arrays;
diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java
index d43bd36..8f3f77b 100644
--- a/core/java/android/content/res/StringBlock.java
+++ b/core/java/android/content/res/StringBlock.java
@@ -16,7 +16,7 @@
 
 package android.content.res;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Rect;
diff --git a/core/java/android/content/res/ThemedResourceCache.java b/core/java/android/content/res/ThemedResourceCache.java
index 968ab40..3270944 100644
--- a/core/java/android/content/res/ThemedResourceCache.java
+++ b/core/java/android/content/res/ThemedResourceCache.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.Resources.Theme;
 import android.content.res.Resources.ThemeKey;
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 38df3175..29c5c93 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -20,7 +20,7 @@
 import android.annotation.ColorInt;
 import android.annotation.Nullable;
 import android.annotation.StyleableRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.Config;
 import android.graphics.Typeface;
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index 626bf77..cb93cbf 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -20,7 +20,7 @@
 
 import android.annotation.AnyRes;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.TypedValue;
 
 import com.android.internal.util.XmlUtils;
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 6f9c9e6..cb8fc8b 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -87,6 +87,11 @@
      * @hide
      */
     public static final String KEY_AUTHENTICATORS_ALLOWED = "authenticators_allowed";
+    /**
+     * If this is set, check the Device Policy Manager for allowed biometrics.
+     * @hide
+     */
+    public static final String EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS = "check_dpm";
 
     /**
      * Error/help message will show for this amount of time.
@@ -326,6 +331,20 @@
         }
 
         /**
+         * If set check the Device Policy Manager for disabled biometrics.
+         *
+         * @param checkDevicePolicyManager
+         * @return This builder.
+         * @hide
+         */
+        @NonNull
+        public Builder setDisallowBiometricsIfPolicyExists(boolean checkDevicePolicyManager) {
+            mBundle.putBoolean(EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS,
+                    checkDevicePolicyManager);
+            return this;
+        }
+
+        /**
          * Creates a {@link BiometricPrompt}.
          *
          * @return An instance of {@link BiometricPrompt}.
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index c84c4a7..b605866 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1125,8 +1125,8 @@
             new Key<android.util.Range<Integer>>("android.control.postRawSensitivityBoostRange", new TypeReference<android.util.Range<Integer>>() {{ }});
 
     /**
-     * <p>The list of bokeh modes that are supported by this camera device, and each bokeh mode's
-     * maximum streaming (non-stall) size with bokeh effect.</p>
+     * <p>The list of bokeh modes for {@link CaptureRequest#CONTROL_BOKEH_MODE android.control.bokehMode} that are supported by this camera
+     * device, and each bokeh mode's maximum streaming (non-stall) size with bokeh effect.</p>
      * <p>For OFF mode, the camera behaves normally with no bokeh effect.</p>
      * <p>For STILL_CAPTURE mode, the maximum streaming dimension specifies the limit under which
      * bokeh is effective when capture intent is PREVIEW. Note that when capture intent is
@@ -1148,12 +1148,86 @@
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
+     * @see CaptureRequest#CONTROL_BOKEH_MODE
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @hide
+     */
+    public static final Key<int[]> CONTROL_AVAILABLE_BOKEH_MAX_SIZES =
+            new Key<int[]>("android.control.availableBokehMaxSizes", int[].class);
+
+    /**
+     * <p>The ranges of supported zoom ratio for non-OFF {@link CaptureRequest#CONTROL_BOKEH_MODE android.control.bokehMode}.</p>
+     * <p>When bokeh mode is enabled, the camera device may have limited range of zoom ratios
+     * compared to when bokeh mode is disabled. This tag lists the zoom ratio ranges for all
+     * supported non-OFF bokeh modes, in the same order as in
+     * {@link CameraCharacteristics#CONTROL_AVAILABLE_BOKEH_CAPABILITIES android.control.availableBokehCapabilities}.</p>
+     * <p>Range [1.0, 1.0] means that no zoom (optical or digital) is supported.</p>
+     * <p><b>Units</b>: (minZoom, maxZoom)</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#CONTROL_AVAILABLE_BOKEH_CAPABILITIES
+     * @see CaptureRequest#CONTROL_BOKEH_MODE
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @hide
+     */
+    public static final Key<float[]> CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES =
+            new Key<float[]>("android.control.availableBokehZoomRatioRanges", float[].class);
+
+    /**
+     * <p>The list of bokeh modes for {@link CaptureRequest#CONTROL_BOKEH_MODE android.control.bokehMode} that are supported by
+     * this camera device, and each bokeh mode's capabilities such as maximum streaming size
+     * with bokeh effect, and supported zoom ratio ranges.</p>
+     * <p>For OFF mode, the camera behaves normally with no bokeh effect.</p>
+     * <p>For STILL_CAPTURE mode, the maximum streaming dimension specifies the limit under which
+     * bokeh is effective when capture intent is PREVIEW. Note that when capture intent is
+     * PREVIEW, the bokeh effect may not be as high quality compared to STILL_CAPTURE intent
+     * in order to maintain reasonable frame rate. The maximum streaming dimension must be one
+     * of the YUV_420_888 or PRIVATE resolutions in availableStreamConfigurations, or (0, 0)
+     * if preview bokeh is not supported. If the application configures a stream larger than
+     * the maximum streaming dimension, bokeh effect may not be applied for this stream for
+     * PREVIEW intent.</p>
+     * <p>For CONTINUOUS mode, the maximum streaming dimension specifies the limit under which
+     * bokeh is effective. This dimension must be one of the YUV_420_888 or PRIVATE resolutions
+     * in availableStreamConfigurations, and if the sensor maximum resolution is larger than or
+     * equal to 1080p, the maximum streaming dimension must be at least 1080p. If the
+     * application configures a stream with larger dimension, the stream may not have bokeh
+     * effect applied.</p>
+     * <p>When bokeh mode is enabled, the camera device may have limited range of zoom ratios
+     * compared to when bokeh mode is disabled. availableBokehCapabilities lists the zoom
+     * ranges for all supported bokeh modes. A range of (1.0, 1.0) means that no zoom
+     * (optical or digital) is supported.</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#CONTROL_BOKEH_MODE
+     */
+    @PublicKey
+    @NonNull
+    @SyntheticKey
+    public static final Key<android.hardware.camera2.params.Capability[]> CONTROL_AVAILABLE_BOKEH_CAPABILITIES =
+            new Key<android.hardware.camera2.params.Capability[]>("android.control.availableBokehCapabilities", android.hardware.camera2.params.Capability[].class);
+
+    /**
+     * <p>Minimum and maximum zoom ratios supported by this camera device.</p>
+     * <p>If the camera device supports zoom-out from 1x zoom, minZoom will be less than 1.0, and
+     * setting android.control.zoomRation to values less than 1.0 increases the camera's field
+     * of view.</p>
+     * <p><b>Units</b>: A pair of zoom ratio in floating points: (minZoom, maxZoom)</p>
+     * <p><b>Range of valid values:</b><br></p>
+     * <p>maxZoom &gt;= 1.0 &gt;= minZoom</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      */
     @PublicKey
     @NonNull
-    public static final Key<android.hardware.camera2.params.CapabilityAndMaxSize[]> CONTROL_AVAILABLE_BOKEH_CAPABILITIES =
-            new Key<android.hardware.camera2.params.CapabilityAndMaxSize[]>("android.control.availableBokehCapabilities", android.hardware.camera2.params.CapabilityAndMaxSize[].class);
+    public static final Key<android.util.Range<Float>> CONTROL_ZOOM_RATIO_RANGE =
+            new Key<android.util.Range<Float>>("android.control.zoomRatioRange", new TypeReference<android.util.Range<Float>>() {{ }});
 
     /**
      * <p>List of edge enhancement modes for {@link CaptureRequest#EDGE_MODE android.edge.mode} that are supported by this camera
@@ -2215,11 +2289,16 @@
      * <p>Crop regions that have a width or height that is smaller
      * than this ratio allows will be rounded up to the minimum
      * allowed size by the camera device.</p>
+     * <p>Starting from API level 30, when using {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} to zoom in or out,
+     * the application must use {@link CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE android.control.zoomRatioRange} to query both the minimum and
+     * maximum zoom ratio.</p>
      * <p><b>Units</b>: Zoom scale factor</p>
      * <p><b>Range of valid values:</b><br>
      * &gt;=1</p>
      * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
+     * @see CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE
      * @see CaptureRequest#SCALER_CROP_REGION
      */
     @PublicKey
@@ -2667,6 +2746,21 @@
      * <p>Camera devices that support FREEFORM cropping will support any crop region that
      * is inside of the active array. The camera device will apply the same crop region and
      * return the final used crop region in capture result metadata {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}.</p>
+     * <p>Starting from API level 30,</p>
+     * <ul>
+     * <li>If the camera device supports FREEFORM cropping, in order to do FREEFORM cropping, the
+     * application must set {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} to 1.0, and use {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}
+     * for zoom.</li>
+     * <li>To do CENTER_ONLY zoom, the application has below 2 options:<ol>
+     * <li>Set {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} to 1.0; adjust zoom by {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}.</li>
+     * <li>Adjust zoom by {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}; use {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to crop
+     * the field of view vertically (letterboxing) or horizontally (pillarboxing), but not
+     * windowboxing.</li>
+     * </ol>
+     * </li>
+     * <li>Setting {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} to values different than 1.0 and
+     * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to be windowboxing at the same time is undefined behavior.</li>
+     * </ul>
      * <p>LEGACY capability devices will only support CENTER_ONLY cropping.</p>
      * <p><b>Possible values:</b>
      * <ul>
@@ -2675,6 +2769,7 @@
      * </ul></p>
      * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      * @see #SCALER_CROPPING_TYPE_CENTER_ONLY
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index f2a7abd..8e0a46d 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -764,6 +764,7 @@
      * <li>{@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions}</li>
      * <li>{@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}</li>
      * <li>{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}</li>
+     * <li>{@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}</li>
      * </ul>
      * <p>Outside of android.control.*, the following controls will work:</p>
      * <ul>
@@ -812,6 +813,7 @@
      * @see CaptureRequest#CONTROL_AWB_REGIONS
      * @see CaptureRequest#CONTROL_EFFECT_MODE
      * @see CaptureRequest#CONTROL_MODE
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#FLASH_MODE
      * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
@@ -2316,6 +2318,7 @@
      * <li>{@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions}</li>
      * <li>{@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}</li>
      * <li>{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}</li>
+     * <li>{@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}</li>
      * </ul>
      * <p>Outside of android.control.*, the following controls will work:</p>
      * <ul>
@@ -2362,6 +2365,7 @@
      * @see CaptureRequest#CONTROL_AWB_REGIONS
      * @see CaptureRequest#CONTROL_EFFECT_MODE
      * @see CaptureRequest#CONTROL_MODE
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#FLASH_MODE
      * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 5c76dff..6bf5783 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1376,6 +1376,16 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata.  If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
+     * <p>Starting from API level 30, the coordinate system of activeArraySize or
+     * preCorrectionActiveArraySize is used to represent post-zoomRatio field of view, not
+     * pre-zoom field of view. This means that the same aeRegions values at different
+     * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} represent different parts of the scene. The aeRegions
+     * coordinates are relative to the activeArray/preCorrectionActiveArray representing the
+     * zoomed field of view. If {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is set to 1.0 (default), the same
+     * aeRegions at different {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} still represent the same parts of the
+     * scene as they do before. See {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details. Whether to use
+     * activeArraySize or preCorrectionActiveArraySize still depends on distortion correction
+     * mode.</p>
      * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
      * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
      * distortion correction capability and mode</p>
@@ -1386,6 +1396,7 @@
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AE
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -1575,6 +1586,16 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata. If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
+     * <p>Starting from API level 30, the coordinate system of activeArraySize or
+     * preCorrectionActiveArraySize is used to represent post-zoomRatio field of view, not
+     * pre-zoom field of view. This means that the same afRegions values at different
+     * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} represent different parts of the scene. The afRegions
+     * coordinates are relative to the activeArray/preCorrectionActiveArray representing the
+     * zoomed field of view. If {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is set to 1.0 (default), the same
+     * afRegions at different {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} still represent the same parts of the
+     * scene as they do before. See {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details. Whether to use
+     * activeArraySize or preCorrectionActiveArraySize still depends on distortion correction
+     * mode.</p>
      * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
      * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
      * distortion correction capability and mode</p>
@@ -1585,6 +1606,7 @@
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AF
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -1767,6 +1789,16 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata.  If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
+     * <p>Starting from API level 30, the coordinate system of activeArraySize or
+     * preCorrectionActiveArraySize is used to represent post-zoomRatio field of view, not
+     * pre-zoom field of view. This means that the same awbRegions values at different
+     * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} represent different parts of the scene. The awbRegions
+     * coordinates are relative to the activeArray/preCorrectionActiveArray representing the
+     * zoomed field of view. If {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is set to 1.0 (default), the same
+     * awbRegions at different {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} still represent the same parts of
+     * the scene as they do before. See {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details. Whether to use
+     * activeArraySize or preCorrectionActiveArraySize still depends on distortion correction
+     * mode.</p>
      * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
      * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
      * distortion correction capability and mode</p>
@@ -1777,6 +1809,7 @@
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AWB
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -2140,6 +2173,56 @@
             new Key<Integer>("android.control.bokehMode", int.class);
 
     /**
+     * <p>The desired zoom ratio</p>
+     * <p>Instead of using {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} with dual purposes of crop and zoom, the
+     * application can now choose to use this tag to specify the desired zoom level. The
+     * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} can still be used to specify the horizontal or vertical
+     * crop to achieve aspect ratios different than the native camera sensor.</p>
+     * <p>By using this control, the application gains a simpler way to control zoom, which can
+     * be a combination of optical and digital zoom. More specifically, for a logical
+     * multi-camera with more than one focal length, using a floating point zoom ratio offers
+     * more zoom precision when a telephoto lens is used, as well as allowing zoom ratio of
+     * less than 1.0 to zoom out to a wide field of view.</p>
+     * <p>Note that the coordinate system of cropRegion, AE/AWB/AF regions, and faces now changes
+     * to the effective after-zoom field-of-view represented by rectangle of (0, 0,
+     * activeArrayWidth, activeArrayHeight).</p>
+     * <p>For example, if {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} is 4032*3024, and the preview stream
+     * is configured to the same 4:3 aspect ratio, the application can achieve 2.0x zoom in
+     * one of two ways:</p>
+     * <ul>
+     * <li>zoomRatio = 2.0, scaler.cropRegion = (0, 0, 4032, 3024)</li>
+     * <li>zoomRatio = 1.0 (default), scaler.cropRegion = (1008, 756, 3024, 2268)</li>
+     * </ul>
+     * <p>If the application intends to set aeRegions to be top-left quarter of the preview
+     * field-of-view, the {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions} should be set to (0, 0, 2016, 1512) with
+     * zoomRatio set to 2.0. Alternatively, the application can set aeRegions to the equivalent
+     * region of (1008, 756, 2016, 1512) for zoomRatio of 1.0. If the application doesn't
+     * explicitly set {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, its value defaults to 1.0.</p>
+     * <p>This coordinate system change isn't applicable to RAW capture and its related metadata
+     * such as intrinsicCalibration and lensShadingMap.</p>
+     * <p>One limitation of controlling zoom using zoomRatio is that the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}
+     * must only be used for letterboxing or pillarboxing of the sensor active array, and no
+     * FREEFORM cropping can be used with {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} other than 1.0.</p>
+     * <p><b>Range of valid values:</b><br>
+     * {@link CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE android.control.zoomRatioRange}</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_REGIONS
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
+     * @see CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CaptureRequest#SCALER_CROP_REGION
+     * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     */
+    @PublicKey
+    @NonNull
+    public static final Key<Float> CONTROL_ZOOM_RATIO =
+            new Key<Float>("android.control.zoomRatio", float.class);
+
+    /**
      * <p>Operation mode for edge
      * enhancement.</p>
      * <p>Edge enhancement improves sharpness and details in the captured image. OFF means
@@ -2697,12 +2780,21 @@
      * for rounding and other hardware requirements; the final
      * crop region used will be included in the output capture
      * result.</p>
+     * <p>Starting from API level 30, it's strongly recommended to use {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}
+     * to take advantage of better support for zoom with logical multi-camera. The benefits
+     * include better precision with optical-digital zoom combination, and ability to do
+     * zoom-out from 1.0x. When using {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for zoom, the crop region in
+     * the capture request must be either letterboxing or pillarboxing (but not both). The
+     * coordinate system is post-zoom, meaning that the activeArraySize or
+     * preCorrectionActiveArraySize covers the camera device's field of view "after" zoom.
+     * See {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details.</p>
      * <p><b>Units</b>: Pixel coordinates relative to
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
      * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on distortion correction
      * capability and mode</p>
      * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 2d0ec6d..c995623 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -780,6 +780,16 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata.  If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
+     * <p>Starting from API level 30, the coordinate system of activeArraySize or
+     * preCorrectionActiveArraySize is used to represent post-zoomRatio field of view, not
+     * pre-zoom field of view. This means that the same aeRegions values at different
+     * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} represent different parts of the scene. The aeRegions
+     * coordinates are relative to the activeArray/preCorrectionActiveArray representing the
+     * zoomed field of view. If {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is set to 1.0 (default), the same
+     * aeRegions at different {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} still represent the same parts of the
+     * scene as they do before. See {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details. Whether to use
+     * activeArraySize or preCorrectionActiveArraySize still depends on distortion correction
+     * mode.</p>
      * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
      * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
      * distortion correction capability and mode</p>
@@ -790,6 +800,7 @@
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AE
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -1228,6 +1239,16 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata. If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
+     * <p>Starting from API level 30, the coordinate system of activeArraySize or
+     * preCorrectionActiveArraySize is used to represent post-zoomRatio field of view, not
+     * pre-zoom field of view. This means that the same afRegions values at different
+     * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} represent different parts of the scene. The afRegions
+     * coordinates are relative to the activeArray/preCorrectionActiveArray representing the
+     * zoomed field of view. If {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is set to 1.0 (default), the same
+     * afRegions at different {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} still represent the same parts of the
+     * scene as they do before. See {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details. Whether to use
+     * activeArraySize or preCorrectionActiveArraySize still depends on distortion correction
+     * mode.</p>
      * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
      * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
      * distortion correction capability and mode</p>
@@ -1238,6 +1259,7 @@
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AF
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -1830,6 +1852,16 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata.  If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
+     * <p>Starting from API level 30, the coordinate system of activeArraySize or
+     * preCorrectionActiveArraySize is used to represent post-zoomRatio field of view, not
+     * pre-zoom field of view. This means that the same awbRegions values at different
+     * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} represent different parts of the scene. The awbRegions
+     * coordinates are relative to the activeArray/preCorrectionActiveArray representing the
+     * zoomed field of view. If {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is set to 1.0 (default), the same
+     * awbRegions at different {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} still represent the same parts of
+     * the scene as they do before. See {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details. Whether to use
+     * activeArraySize or preCorrectionActiveArraySize still depends on distortion correction
+     * mode.</p>
      * <p><b>Units</b>: Pixel coordinates within {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
      * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on
      * distortion correction capability and mode</p>
@@ -1840,6 +1872,7 @@
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AWB
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -2370,6 +2403,56 @@
             new Key<Integer>("android.control.bokehMode", int.class);
 
     /**
+     * <p>The desired zoom ratio</p>
+     * <p>Instead of using {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} with dual purposes of crop and zoom, the
+     * application can now choose to use this tag to specify the desired zoom level. The
+     * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} can still be used to specify the horizontal or vertical
+     * crop to achieve aspect ratios different than the native camera sensor.</p>
+     * <p>By using this control, the application gains a simpler way to control zoom, which can
+     * be a combination of optical and digital zoom. More specifically, for a logical
+     * multi-camera with more than one focal length, using a floating point zoom ratio offers
+     * more zoom precision when a telephoto lens is used, as well as allowing zoom ratio of
+     * less than 1.0 to zoom out to a wide field of view.</p>
+     * <p>Note that the coordinate system of cropRegion, AE/AWB/AF regions, and faces now changes
+     * to the effective after-zoom field-of-view represented by rectangle of (0, 0,
+     * activeArrayWidth, activeArrayHeight).</p>
+     * <p>For example, if {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} is 4032*3024, and the preview stream
+     * is configured to the same 4:3 aspect ratio, the application can achieve 2.0x zoom in
+     * one of two ways:</p>
+     * <ul>
+     * <li>zoomRatio = 2.0, scaler.cropRegion = (0, 0, 4032, 3024)</li>
+     * <li>zoomRatio = 1.0 (default), scaler.cropRegion = (1008, 756, 3024, 2268)</li>
+     * </ul>
+     * <p>If the application intends to set aeRegions to be top-left quarter of the preview
+     * field-of-view, the {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions} should be set to (0, 0, 2016, 1512) with
+     * zoomRatio set to 2.0. Alternatively, the application can set aeRegions to the equivalent
+     * region of (1008, 756, 2016, 1512) for zoomRatio of 1.0. If the application doesn't
+     * explicitly set {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, its value defaults to 1.0.</p>
+     * <p>This coordinate system change isn't applicable to RAW capture and its related metadata
+     * such as intrinsicCalibration and lensShadingMap.</p>
+     * <p>One limitation of controlling zoom using zoomRatio is that the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}
+     * must only be used for letterboxing or pillarboxing of the sensor active array, and no
+     * FREEFORM cropping can be used with {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} other than 1.0.</p>
+     * <p><b>Range of valid values:</b><br>
+     * {@link CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE android.control.zoomRatioRange}</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_REGIONS
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
+     * @see CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CaptureRequest#SCALER_CROP_REGION
+     * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     */
+    @PublicKey
+    @NonNull
+    public static final Key<Float> CONTROL_ZOOM_RATIO =
+            new Key<Float>("android.control.zoomRatio", float.class);
+
+    /**
      * <p>Operation mode for edge
      * enhancement.</p>
      * <p>Edge enhancement improves sharpness and details in the captured image. OFF means
@@ -3336,12 +3419,21 @@
      * for rounding and other hardware requirements; the final
      * crop region used will be included in the output capture
      * result.</p>
+     * <p>Starting from API level 30, it's strongly recommended to use {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}
+     * to take advantage of better support for zoom with logical multi-camera. The benefits
+     * include better precision with optical-digital zoom combination, and ability to do
+     * zoom-out from 1.0x. When using {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for zoom, the crop region in
+     * the capture request must be either letterboxing or pillarboxing (but not both). The
+     * coordinate system is post-zoom, meaning that the activeArraySize or
+     * preCorrectionActiveArraySize covers the camera device's field of view "after" zoom.
+     * See {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details.</p>
      * <p><b>Units</b>: Pixel coordinates relative to
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
      * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on distortion correction
      * capability and mode</p>
      * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#DISTORTION_CORRECTION_MODE
      * @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -3877,10 +3969,21 @@
      * When the distortion correction mode is not OFF, the coordinate system follows
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
      * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
-     * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} == FULL
-     * This key is available on all devices.</p>
+     * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} == FULL.</p>
+     * <p>Starting from API level 30, the coordinate system of activeArraySize or
+     * preCorrectionActiveArraySize is used to represent post-zoomRatio field of view, not
+     * pre-zoomRatio field of view. This means that if the relative position of faces and
+     * the camera device doesn't change, when zooming in by increasing
+     * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, the face landmarks move farther away from the center of the
+     * activeArray or preCorrectionActiveArray. If {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is set to 1.0
+     * (default), the face landmarks coordinates won't change as {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}
+     * changes. See {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details. Whether to use activeArraySize or
+     * preCorrectionActiveArraySize still depends on distortion correction mode.</p>
+     * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#DISTORTION_CORRECTION_MODE
+     * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
@@ -3903,10 +4006,21 @@
      * When the distortion correction mode is not OFF, the coordinate system follows
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
      * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
-     * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} != OFF
-     * This key is available on all devices.</p>
+     * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} != OFF.</p>
+     * <p>Starting from API level 30, the coordinate system of activeArraySize or
+     * preCorrectionActiveArraySize is used to represent post-zoomRatio field of view, not
+     * pre-zoomRatio field of view. This means that if the relative position of faces and
+     * the camera device doesn't change, when zooming in by increasing
+     * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, the face rectangles grow larger and move farther away from
+     * the center of the activeArray or preCorrectionActiveArray. If {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}
+     * is set to 1.0 (default), the face rectangles won't change as {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}
+     * changes. See {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details. Whether to use activeArraySize or
+     * preCorrectionActiveArraySize still depends on distortion correction mode.</p>
+     * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#CONTROL_ZOOM_RATIO
      * @see CaptureRequest#DISTORTION_CORRECTION_MODE
+     * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 7c1ddad..c3ebe43 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -30,7 +30,6 @@
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.impl.MarshalQueryableArray;
 import android.hardware.camera2.marshal.impl.MarshalQueryableBlackLevelPattern;
-import android.hardware.camera2.marshal.impl.MarshalQueryableCapabilityAndMaxSize;
 import android.hardware.camera2.marshal.impl.MarshalQueryableBoolean;
 import android.hardware.camera2.marshal.impl.MarshalQueryableColorSpaceTransform;
 import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
@@ -50,7 +49,7 @@
 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
 import android.hardware.camera2.marshal.impl.MarshalQueryableString;
-import android.hardware.camera2.params.CapabilityAndMaxSize;
+import android.hardware.camera2.params.Capability;
 import android.hardware.camera2.params.Face;
 import android.hardware.camera2.params.HighSpeedVideoConfiguration;
 import android.hardware.camera2.params.LensShadingMap;
@@ -71,6 +70,7 @@
 import android.os.Parcelable;
 import android.os.ServiceSpecificException;
 import android.util.Log;
+import android.util.Range;
 import android.util.Size;
 
 import com.android.internal.util.Preconditions;
@@ -1385,22 +1385,57 @@
         return samples;
     }
 
-    private CapabilityAndMaxSize[] getBokehCapabilities() {
-        CapabilityAndMaxSize[] bcs = getBase(
-                CameraCharacteristics.CONTROL_AVAILABLE_BOKEH_CAPABILITIES);
+    private Capability[] getBokehCapabilities() {
+        int[] bokehMaxSizes = getBase(CameraCharacteristics.CONTROL_AVAILABLE_BOKEH_MAX_SIZES);
+        float[] bokehZoomRanges = getBase(
+                CameraCharacteristics.CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES);
+        Range<Float> zoomRange = getBase(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE);
+        float maxDigitalZoom = getBase(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
 
-        if (bcs != null) {
-            for (CapabilityAndMaxSize bc : bcs) {
-                if (bc.getMode() < CameraMetadata.CONTROL_BOKEH_MODE_OFF ||
-                        bc.getMode() > CameraMetadata.CONTROL_BOKEH_MODE_CONTINUOUS) {
-                    throw new AssertionError(String.format(
-                            "bokehMode %d is out of valid range [%d, %d]", bc.getMode(),
-                            CameraMetadata.CONTROL_BOKEH_MODE_OFF,
-                            CameraMetadata.CONTROL_BOKEH_MODE_CONTINUOUS));
-                }
+        if (bokehMaxSizes == null) {
+            return null;
+        }
+        if (bokehMaxSizes.length % 3 != 0) {
+            throw new AssertionError("availableBokehMaxSizes must be tuples of " +
+                    "[mode, width, height]");
+        }
+        int numBokehModes = bokehMaxSizes.length / 3;
+        int numBokehZoomRanges = 0;
+        if (bokehZoomRanges != null) {
+            if (bokehZoomRanges.length % 2 != 0) {
+                throw new AssertionError("availableBokehZoomRanges must be tuples of " +
+                        "[minZoom, maxZoom]");
+            }
+            numBokehZoomRanges = bokehZoomRanges.length / 2;
+            if (numBokehModes - numBokehZoomRanges != 1) {
+                throw new AssertionError("Number of bokeh zoom ranges must be 1 less than " +
+                        "number of supported bokeh modes");
             }
         }
-        return bcs;
+
+        float bokehOffMinZoomRatio = 1.0f;
+        float bokehOffMaxZoomRatio = maxDigitalZoom;
+        if (zoomRange != null) {
+            bokehOffMinZoomRatio = zoomRange.getLower();
+            bokehOffMaxZoomRatio = zoomRange.getUpper();
+        }
+
+        Capability[] capabilities = new Capability[numBokehModes];
+        for (int i = 0, j = 0; i < numBokehModes; i++) {
+            int mode = bokehMaxSizes[3 * i];
+            int width = bokehMaxSizes[3 * i + 1];
+            int height = bokehMaxSizes[3 * i + 2];
+            if (mode != CameraMetadata.CONTROL_BOKEH_MODE_OFF && j < numBokehZoomRanges) {
+                capabilities[i] = new Capability(mode, width, height, bokehZoomRanges[2 * j],
+                        bokehZoomRanges[2 * j + 1]);
+                j++;
+            } else {
+                capabilities[i] = new Capability(mode, width, height, bokehOffMinZoomRatio,
+                        bokehOffMaxZoomRatio);
+            }
+        }
+
+        return capabilities;
     }
 
     private <T> void setBase(CameraCharacteristics.Key<T> key, T value) {
@@ -1780,7 +1815,6 @@
                 new MarshalQueryableBlackLevelPattern(),
                 new MarshalQueryableHighSpeedVideoConfiguration(),
                 new MarshalQueryableRecommendedStreamConfiguration(),
-                new MarshalQueryableCapabilityAndMaxSize(),
 
                 // generic parcelable marshaler (MUST BE LAST since it has lowest priority)
                 new MarshalQueryableParcelable(),
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableCapabilityAndMaxSize.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableCapabilityAndMaxSize.java
deleted file mode 100644
index 5c1f301..0000000
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableCapabilityAndMaxSize.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2.marshal.impl;
-
-import android.hardware.camera2.marshal.MarshalQueryable;
-import android.hardware.camera2.marshal.Marshaler;
-import android.hardware.camera2.params.CapabilityAndMaxSize;
-import android.hardware.camera2.utils.TypeReference;
-import android.util.Size;
-
-import java.nio.ByteBuffer;
-
-import static android.hardware.camera2.impl.CameraMetadataNative.TYPE_INT32;
-import static android.hardware.camera2.marshal.MarshalHelpers.SIZEOF_INT32;
-
-/**
- * Marshal {@link CapabilityAndMaxSize} to/from {@link #TYPE_INT32} {@code x CapabilityAndMaxSize.COUNT}
- */
-public class MarshalQueryableCapabilityAndMaxSize implements MarshalQueryable<CapabilityAndMaxSize> {
-    private static final int SIZE = SIZEOF_INT32 * CapabilityAndMaxSize.COUNT;
-
-    private class MarshalerCapabilityAndMaxSize extends Marshaler<CapabilityAndMaxSize> {
-        protected MarshalerCapabilityAndMaxSize(TypeReference<CapabilityAndMaxSize> typeReference,
-                                               int nativeType) {
-            super(MarshalQueryableCapabilityAndMaxSize.this, typeReference, nativeType);
-        }
-
-        @Override
-        public void marshal(CapabilityAndMaxSize value, ByteBuffer buffer) {
-            Size maxStreamingSize = value.getMaxStreamingSize();
-
-            buffer.putInt(value.getMode());
-            buffer.putInt(maxStreamingSize.getWidth());
-            buffer.putInt(maxStreamingSize.getHeight());
-        }
-
-        @Override
-        public CapabilityAndMaxSize unmarshal(ByteBuffer buffer) {
-            int mode = buffer.getInt();
-            int maxWidth = buffer.getInt();
-            int maxHeight = buffer.getInt();
-
-            return new CapabilityAndMaxSize(mode, maxWidth, maxHeight);
-        }
-
-        @Override
-        public int getNativeSize() {
-            return SIZE;
-        }
-    }
-
-    @Override
-    public Marshaler<CapabilityAndMaxSize> createMarshaler(
-            TypeReference<CapabilityAndMaxSize> managedType, int nativeType) {
-        return new MarshalerCapabilityAndMaxSize(managedType, nativeType);
-    }
-
-    @Override
-    public boolean isTypeMappingSupported(
-            TypeReference<CapabilityAndMaxSize> managedType, int nativeType) {
-        return nativeType == TYPE_INT32 &&
-                (CapabilityAndMaxSize.class.equals(managedType.getType()));
-    }
-}
diff --git a/core/java/android/hardware/camera2/params/CapabilityAndMaxSize.java b/core/java/android/hardware/camera2/params/Capability.java
similarity index 61%
rename from core/java/android/hardware/camera2/params/CapabilityAndMaxSize.java
rename to core/java/android/hardware/camera2/params/Capability.java
index be08299..367690c 100644
--- a/core/java/android/hardware/camera2/params/CapabilityAndMaxSize.java
+++ b/core/java/android/hardware/camera2/params/Capability.java
@@ -23,16 +23,17 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.utils.HashCodeHelpers;
+import android.util.Range;
 import android.util.Size;
 
 /**
- * Immutable class to store the available camera capability and its
- * corresponding maximum streaming dimensions.
+ * Immutable class to store the camera capability, its corresponding maximum
+ * streaming dimension and zoom range.
  *
  * @see CameraCharacteristics#CONTROL_AVAILABLE_BOKEH_CAPABILITIES
  */
 
-public final class CapabilityAndMaxSize {
+public final class Capability {
     /**
      * @hide
      */
@@ -41,22 +42,31 @@
     private final int mMode;
     private final int mMaxStreamingWidth;
     private final int mMaxStreamingHeight;
+    private final float mMinZoomRatio;
+    private final float mMaxZoomRatio;
 
     /**
-     * Create a new CapabilityAndMaxSize object.
+     * Create a new Capability object.
      *
      * @param mode supported mode for a camera capability.
-     * @param maxStreamingWidth width >= 0
-     * @param maxStreamingHeight height >= 0
+     * @param maxStreamingWidth The width of the maximum streaming size for this mode
+     * @param maxStreamingHeight The height of the maximum streaming size for this mode
+     * @param minZoomRatio the minimum zoom ratio this mode supports
+     * @param maxZoomRatio the maximum zoom ratio this mode supports
      *
+     * @throws IllegalArgumentException if any of the argument is not valid
      * @hide
      */
-    public CapabilityAndMaxSize(int mode, int maxStreamingWidth, int maxStreamingHeight) {
+    public Capability(int mode, int maxStreamingWidth, int maxStreamingHeight,
+            float minZoomRatio, float maxZoomRatio) {
         mMode = mode;
         mMaxStreamingWidth = checkArgumentNonnegative(maxStreamingWidth,
                 "maxStreamingWidth must be nonnegative");
         mMaxStreamingHeight = checkArgumentNonnegative(maxStreamingHeight,
                 "maxStreamingHeight must be nonnegative");
+        mMinZoomRatio = checkArgumentInRange(minZoomRatio, 0.0f, 1.0f,
+                "minZoomRatio must be between 0.0f and 1.0f");
+        mMaxZoomRatio = maxZoomRatio;
     }
 
     /**
@@ -81,11 +91,22 @@
     }
 
     /**
-     * Compare two CapabilityAndMaxSize objects to see if they are equal.
+     * Return the zoom ratio range of this capability.
      *
-     * @param obj Another CapabilityAndMaxSize object
+     * @return The supported zoom ratio range supported by this capability
+     */
+    public @NonNull Range<Float> getZoomRatioRange() {
+        return new Range<Float>(mMinZoomRatio, mMaxZoomRatio);
+    }
+
+
+    /**
+     * Compare two Capability objects to see if they are equal.
      *
-     * @return {@code true} if the mode and max size are equal, {@code false} otherwise
+     * @param obj Another Capability object
+     *
+     * @return {@code true} if the mode, max size and zoom ratio range are equal,
+     *         {@code false} otherwise
      */
     @Override
     public boolean equals(final Object obj) {
@@ -95,11 +116,13 @@
         if (this == obj) {
             return true;
         }
-        if (obj instanceof CapabilityAndMaxSize) {
-            final CapabilityAndMaxSize other = (CapabilityAndMaxSize) obj;
+        if (obj instanceof Capability) {
+            final Capability other = (Capability) obj;
             return (mMode == other.mMode
                     && mMaxStreamingWidth == other.mMaxStreamingWidth
-                    && mMaxStreamingHeight == other.mMaxStreamingHeight);
+                    && mMaxStreamingHeight == other.mMaxStreamingHeight
+                    && mMinZoomRatio == other.mMinZoomRatio
+                    && mMaxZoomRatio == other.mMaxZoomRatio);
         }
         return false;
     }
@@ -109,18 +132,20 @@
      */
     @Override
     public int hashCode() {
-        return HashCodeHelpers.hashCode(mMode, mMaxStreamingWidth, mMaxStreamingHeight);
+        return HashCodeHelpers.hashCode(mMode, mMaxStreamingWidth, mMaxStreamingHeight,
+                mMinZoomRatio, mMaxZoomRatio);
     }
 
     /**
-     * Return the CapabilityAndMaxSize as a string representation
-     * {@code "(mode:%d, maxStreamingSize:%d x %d)"}.
+     * Return the Capability as a string representation
+     * {@code "(mode:%d, maxStreamingSize:%d x %d, zoomRatio: %f-%f)"}.
      *
      * @return string representation of the capability and max streaming size.
      */
     @Override
     public String toString() {
-        return String.format("(mode:%d, maxStreamingSize:%d x %d)",
-                mMode, mMaxStreamingWidth, mMaxStreamingHeight);
+        return String.format("(mode:%d, maxStreamingSize:%d x %d, zoomRatio: %f-%f)",
+                mMode, mMaxStreamingWidth, mMaxStreamingHeight, mMinZoomRatio,
+                mMaxZoomRatio);
     }
 }
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 8e18341..ed509cb 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -74,6 +74,8 @@
     private static final int MIN_MTU_V6 = 1280;
     private static final int MAX_MTU    = 10000;
 
+    private static final int INET6_ADDR_LENGTH = 16;
+
     // Stores the properties of links that are "stacked" above this link.
     // Indexed by interface name to allow modification and to prevent duplicates being added.
     private Hashtable<String, LinkProperties> mStackedLinks = new Hashtable<>();
@@ -227,7 +229,7 @@
     /**
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public @NonNull List<String> getAllInterfaceNames() {
         List<String> interfaceNames = new ArrayList<>(mStackedLinks.size() + 1);
         if (mIfaceName != null) interfaceNames.add(mIfaceName);
@@ -247,7 +249,7 @@
      * @return An unmodifiable {@link List} of {@link InetAddress} for this link.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public @NonNull List<InetAddress> getAddresses() {
         final List<InetAddress> addresses = new ArrayList<>();
         for (LinkAddress linkAddress : mLinkAddresses) {
@@ -342,8 +344,8 @@
      * Returns all the addresses on this link and all the links stacked above it.
      * @hide
      */
-    @UnsupportedAppUsage
-    public List<LinkAddress> getAllLinkAddresses() {
+    @SystemApi
+    public @NonNull List<LinkAddress> getAllLinkAddresses() {
         List<LinkAddress> addresses = new ArrayList<>(mLinkAddresses);
         for (LinkProperties stacked: mStackedLinks.values()) {
             addresses.addAll(stacked.getAllLinkAddresses());
@@ -542,6 +544,7 @@
      * @return true if the PCSCF server was added, false otherwise.
      * @hide
      */
+    @SystemApi
     public boolean addPcscfServer(@NonNull InetAddress pcscfServer) {
         if (pcscfServer != null && !mPcscfs.contains(pcscfServer)) {
             mPcscfs.add(pcscfServer);
@@ -729,7 +732,7 @@
      * Returns all the routes on this link and all the links stacked above it.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public @NonNull List<RouteInfo> getAllRoutes() {
         List<RouteInfo> routes = new ArrayList<>(mRoutes);
         for (LinkProperties stacked: mStackedLinks.values()) {
@@ -1025,7 +1028,7 @@
      * @return {@code true} if there is an IPv4 default route, {@code false} otherwise.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public boolean hasIpv4DefaultRoute() {
         for (RouteInfo r : mRoutes) {
             if (r.isIPv4Default()) {
@@ -1082,7 +1085,7 @@
      * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public boolean hasIpv4DnsServer() {
         for (InetAddress ia : mDnses) {
             if (ia instanceof Inet4Address) {
@@ -1110,7 +1113,7 @@
      * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public boolean hasIpv6DnsServer() {
         for (InetAddress ia : mDnses) {
             if (ia instanceof Inet6Address) {
@@ -1626,20 +1629,11 @@
             dest.writeParcelable(linkAddress, flags);
         }
 
-        dest.writeInt(mDnses.size());
-        for (InetAddress d : mDnses) {
-            dest.writeByteArray(d.getAddress());
-        }
-        dest.writeInt(mValidatedPrivateDnses.size());
-        for (InetAddress d : mValidatedPrivateDnses) {
-            dest.writeByteArray(d.getAddress());
-        }
+        writeAddresses(dest, mDnses);
+        writeAddresses(dest, mValidatedPrivateDnses);
         dest.writeBoolean(mUsePrivateDns);
         dest.writeString(mPrivateDnsServerName);
-        dest.writeInt(mPcscfs.size());
-        for (InetAddress d : mPcscfs) {
-            dest.writeByteArray(d.getAddress());
-        }
+        writeAddresses(dest, mPcscfs);
         dest.writeString(mDomains);
         dest.writeInt(mMtu);
         dest.writeString(mTcpBufferSizes);
@@ -1662,6 +1656,35 @@
         dest.writeBoolean(mWakeOnLanSupported);
     }
 
+    private static void writeAddresses(@NonNull Parcel dest, @NonNull List<InetAddress> list) {
+        dest.writeInt(list.size());
+        for (InetAddress d : list) {
+            writeAddress(dest, d);
+        }
+    }
+
+    private static void writeAddress(@NonNull Parcel dest, @NonNull InetAddress addr) {
+        dest.writeByteArray(addr.getAddress());
+        if (addr instanceof Inet6Address) {
+            final Inet6Address v6Addr = (Inet6Address) addr;
+            final boolean hasScopeId = v6Addr.getScopeId() != 0;
+            dest.writeBoolean(hasScopeId);
+            if (hasScopeId) dest.writeInt(v6Addr.getScopeId());
+        }
+    }
+
+    @NonNull
+    private static InetAddress readAddress(@NonNull Parcel p) throws UnknownHostException {
+        final byte[] addr = p.createByteArray();
+        if (addr.length == INET6_ADDR_LENGTH) {
+            final boolean hasScopeId = p.readBoolean();
+            final int scopeId = hasScopeId ? p.readInt() : 0;
+            return Inet6Address.getByAddress(null /* host */, addr, scopeId);
+        }
+
+        return InetAddress.getByAddress(addr);
+    }
+
     /**
      * Implement the Parcelable interface.
      */
@@ -1681,14 +1704,13 @@
                 addressCount = in.readInt();
                 for (int i = 0; i < addressCount; i++) {
                     try {
-                        netProp.addDnsServer(InetAddress.getByAddress(in.createByteArray()));
+                        netProp.addDnsServer(readAddress(in));
                     } catch (UnknownHostException e) { }
                 }
                 addressCount = in.readInt();
                 for (int i = 0; i < addressCount; i++) {
                     try {
-                        netProp.addValidatedPrivateDnsServer(
-                                InetAddress.getByAddress(in.createByteArray()));
+                        netProp.addValidatedPrivateDnsServer(readAddress(in));
                     } catch (UnknownHostException e) { }
                 }
                 netProp.setUsePrivateDns(in.readBoolean());
@@ -1696,7 +1718,7 @@
                 addressCount = in.readInt();
                 for (int i = 0; i < addressCount; i++) {
                     try {
-                        netProp.addPcscfServer(InetAddress.getByAddress(in.createByteArray()));
+                        netProp.addPcscfServer(readAddress(in));
                     } catch (UnknownHostException e) { }
                 }
                 netProp.setDomains(in.readString());
diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java
index 459b140..0946499 100644
--- a/core/java/android/net/nsd/NsdServiceInfo.java
+++ b/core/java/android/net/nsd/NsdServiceInfo.java
@@ -17,13 +17,13 @@
 package android.net.nsd;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
-import android.os.Parcelable;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
+import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Base64;
 import android.util.Log;
-import android.util.ArrayMap;
 
 import java.io.UnsupportedEncodingException;
 import java.net.InetAddress;
diff --git a/core/java/android/nfc/ErrorCodes.java b/core/java/android/nfc/ErrorCodes.java
index 98e31ad..d2c81cd 100644
--- a/core/java/android/nfc/ErrorCodes.java
+++ b/core/java/android/nfc/ErrorCodes.java
@@ -16,7 +16,7 @@
 
 package android.nfc;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * This class defines all the error codes that can be returned by the service
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 5044a86..fe316c4 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -16,7 +16,7 @@
 
 package android.nfc;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Parcel;
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index abfa133..935374d1 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -16,9 +16,9 @@
 
 package android.nfc;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.Application;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentProvider;
 import android.content.Intent;
 import android.net.Uri;
@@ -26,7 +26,6 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.util.Log;
 
 import java.util.ArrayList;
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 875d17a..5715c9a 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -21,11 +21,11 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.ActivityThread;
 import android.app.OnActivityPausedListener;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.IntentFilter;
 import android.content.pm.IPackageManager;
diff --git a/core/java/android/nfc/NfcManager.java b/core/java/android/nfc/NfcManager.java
index 030066e..644e312 100644
--- a/core/java/android/nfc/NfcManager.java
+++ b/core/java/android/nfc/NfcManager.java
@@ -17,7 +17,7 @@
 package android.nfc;
 
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Build;
 
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 5a4c465..8bb2df0 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -16,7 +16,7 @@
 
 package android.nfc;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.nfc.tech.IsoDep;
 import android.nfc.tech.MifareClassic;
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
index 77b5552..c4f5e0b 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -16,18 +16,18 @@
 
 package android.nfc.cardemulation;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
-import android.annotation.UnsupportedAppUsage;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * The AidGroup class represents a group of Application Identifiers (AIDs).
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index d9000e4..8da9db1 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -16,7 +16,7 @@
 
 package android.nfc.cardemulation;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
diff --git a/core/java/android/os/AsyncResult.java b/core/java/android/os/AsyncResult.java
index 58a2701..e80528b 100644
--- a/core/java/android/os/AsyncResult.java
+++ b/core/java/android/os/AsyncResult.java
@@ -16,8 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
-import android.os.Message;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /** @hide */
 public class AsyncResult
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index b37e176..e1dabd3 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -18,8 +18,8 @@
 
 import android.annotation.MainThread;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.WorkerThread;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import java.util.ArrayDeque;
 import java.util.concurrent.Callable;
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 9d9c683..6453af8 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.MathUtils;
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 5ced86c..12ec0a0 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -21,7 +21,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.hardware.health.V1_0.Constants;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 53ea936..fbe6a50 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -21,9 +21,9 @@
 import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES;
 
 import android.annotation.IntDef;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.job.JobParameters;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.os.BatteryStatsManager.WifiState;
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index a9c5a91..a90ab85 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -19,8 +19,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AppOpsManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.ExceptionUtils;
 import android.util.Log;
 import android.util.Slog;
diff --git a/core/java/android/os/Broadcaster.java b/core/java/android/os/Broadcaster.java
index 6ac7f1a..d1a953f 100644
--- a/core/java/android/os/Broadcaster.java
+++ b/core/java/android/os/Broadcaster.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /** @hide */
 public class Broadcaster
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 6eaea99..a291734 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -22,9 +22,9 @@
 import android.annotation.SuppressAutoDoc;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
 import android.app.Application;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.sysprop.TelephonyProperties;
 import android.text.TextUtils;
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index c5b4222..f8f8bf7 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -17,7 +17,7 @@
 package android.os;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.ArrayMap;
 import android.util.Size;
 import android.util.SizeF;
diff --git a/core/java/android/os/CancellationSignal.java b/core/java/android/os/CancellationSignal.java
index 99fb998..260f7ad 100644
--- a/core/java/android/os/CancellationSignal.java
+++ b/core/java/android/os/CancellationSignal.java
@@ -16,9 +16,7 @@
 
 package android.os;
 
-import android.os.ICancellationSignal;
-
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * Provides the ability to cancel an operation in progress.
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 5634929..1c4ef38 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -18,8 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AppGlobals;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.util.Log;
 
@@ -1938,8 +1938,14 @@
     public static final int MEMINFO_PAGE_TABLES = 13;
     /** @hide */
     public static final int MEMINFO_KERNEL_STACK = 14;
+    /**
+     * Note: MEMINFO_KRECLAIMABLE includes MEMINFO_SLAB_RECLAIMABLE (see KReclaimable field
+     * description in kernel documentation).
+     * @hide
+     */
+    public static final int MEMINFO_KRECLAIMABLE = 15;
     /** @hide */
-    public static final int MEMINFO_COUNT = 15;
+    public static final int MEMINFO_COUNT = 16;
 
     /**
      * Retrieves /proc/meminfo.  outSizes is filled with fields
@@ -2561,4 +2567,27 @@
      * @hide
      */
     public static native long getZramFreeKb();
+
+    /**
+     * Return memory size in kilobytes allocated for ION heaps.
+     *
+     * @hide
+     */
+    public static native long getIonHeapsSizeKb();
+
+    /**
+     * Return memory size in kilobytes allocated for ION pools.
+     *
+     * @hide
+     */
+    public static native long getIonPoolsSizeKb();
+
+    /**
+     * Return ION memory mapped by processes in kB.
+     * Notes:
+     *  * Warning: Might impact performance as it reads /proc/<pid>/maps files for each process.
+     *
+     * @hide
+     */
+    public static native long getIonMappedSizeKb();
 }
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index b7cccc6..18ba5a8 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -24,7 +24,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.util.Log;
 
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 61da5e6..44f12a6 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -20,10 +20,10 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.admin.DevicePolicyManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index 5b715c0..ca303d9 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -19,7 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Log;
 
 import java.io.File;
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 2ac3def..a47fbba 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -40,7 +40,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.provider.DocumentsContract.Document;
 import android.system.ErrnoException;
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 928df3c..af776d1 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Log;
 import android.util.Printer;
 
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index 09afdc7..7c42c36 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -18,7 +18,7 @@
 
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import libcore.util.NativeAllocationRegistry;
 
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index 9786f16..fb36e6f 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -21,7 +21,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import dalvik.annotation.optimization.FastNative;
 
diff --git a/core/java/android/os/HwRemoteBinder.java b/core/java/android/os/HwRemoteBinder.java
index 72ec958..756202e 100644
--- a/core/java/android/os/HwRemoteBinder.java
+++ b/core/java/android/os/HwRemoteBinder.java
@@ -16,7 +16,8 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import libcore.util.NativeAllocationRegistry;
 
 /** @hide */
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index ed980f3..f336fda 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import java.io.FileDescriptor;
 
diff --git a/core/java/android/os/LocaleList.java b/core/java/android/os/LocaleList.java
index 0de09ef..0bf387e 100644
--- a/core/java/android/os/LocaleList.java
+++ b/core/java/android/os/LocaleList.java
@@ -20,7 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Size;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.icu.util.ULocale;
 
 import com.android.internal.annotations.GuardedBy;
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index df16ffe..b478dbe 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Log;
 import android.util.Printer;
 import android.util.Slog;
diff --git a/core/java/android/os/MemoryFile.java b/core/java/android/os/MemoryFile.java
index 5a1e3d4..f84f9f05 100644
--- a/core/java/android/os/MemoryFile.java
+++ b/core/java/android/os/MemoryFile.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.system.ErrnoException;
 
 import java.io.FileDescriptor;
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 9d101e5..c62df40 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index b5f4bc6..a72795d 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -19,8 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
-import android.os.MessageQueueProto;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Log;
 import android.util.Printer;
 import android.util.SparseArray;
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 339397b..c9ebed3 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -19,8 +19,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AppOpsManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index fdb44e7..983053b 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -32,7 +32,7 @@
 import static android.system.OsConstants.S_IWOTH;
 
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
diff --git a/core/java/android/os/ParcelUuid.java b/core/java/android/os/ParcelUuid.java
index cc50c89..0b52c75 100644
--- a/core/java/android/os/ParcelUuid.java
+++ b/core/java/android/os/ParcelUuid.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import java.util.UUID;
 
diff --git a/core/java/android/os/ParcelableParcel.java b/core/java/android/os/ParcelableParcel.java
index 61f3968..38d980e 100644
--- a/core/java/android/os/ParcelableParcel.java
+++ b/core/java/android/os/ParcelableParcel.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.MathUtils;
 
 /**
diff --git a/core/java/android/os/PerformanceCollector.java b/core/java/android/os/PerformanceCollector.java
index 33c86b8..27de48d 100644
--- a/core/java/android/os/PerformanceCollector.java
+++ b/core/java/android/os/PerformanceCollector.java
@@ -17,7 +17,8 @@
 package android.os;
 
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.util.ArrayList;
 
 /**
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 5e478b5..2f8e30e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -25,7 +25,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.service.dreams.Sandman;
 import android.util.ArrayMap;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index ebb2071..94623bc 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -19,13 +19,16 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.system.Os;
 import android.system.OsConstants;
+import android.util.Pair;
 import android.webkit.WebViewZygote;
 
 import dalvik.system.VMRuntime;
 
+import java.util.Map;
+
 /**
  * Tools for managing OS processes.
  */
@@ -521,6 +524,8 @@
      * @param isTopApp whether the process starts for high priority application.
      * @param disabledCompatChanges null-ok list of disabled compat changes for the process being
      *                             started.
+     * @param pkgDataInfoMap Map from related package names to private data directory
+     *                       volume UUID and inode number.
      * @param zygoteArgs Additional arguments to supply to the zygote process.
      * @return An object that describes the result of the attempt to start the process.
      * @throws RuntimeException on fatal start failure
@@ -541,11 +546,14 @@
                                            @Nullable String packageName,
                                            boolean isTopApp,
                                            @Nullable long[] disabledCompatChanges,
+                                           @Nullable Map<String, Pair<String, Long>>
+                                                   pkgDataInfoMap,
                                            @Nullable String[] zygoteArgs) {
         return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                     abi, instructionSet, appDataDir, invokeWith, packageName,
-                    /*useUsapPool=*/ true, isTopApp, disabledCompatChanges, zygoteArgs);
+                    /*useUsapPool=*/ true, isTopApp, disabledCompatChanges,
+                    pkgDataInfoMap, zygoteArgs);
     }
 
     /** @hide */
@@ -563,10 +571,13 @@
                                                   @Nullable String packageName,
                                                   @Nullable long[] disabledCompatChanges,
                                                   @Nullable String[] zygoteArgs) {
+        // Webview zygote can't access app private data files, so doesn't need to know its data
+        // info.
         return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids,
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                     abi, instructionSet, appDataDir, invokeWith, packageName,
-                    /*useUsapPool=*/ false, /*isTopApp=*/ false, disabledCompatChanges, zygoteArgs);
+                    /*useUsapPool=*/ false, /*isTopApp=*/ false, disabledCompatChanges,
+                    /* pkgDataInfoMap */ null, zygoteArgs);
     }
 
     /**
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index e3f6e12..1901820 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -22,8 +22,8 @@
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
diff --git a/core/java/android/os/Registrant.java b/core/java/android/os/Registrant.java
index 572b975..d6afd04 100644
--- a/core/java/android/os/Registrant.java
+++ b/core/java/android/os/Registrant.java
@@ -16,9 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
-import android.os.Handler;
-import android.os.Message;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import java.lang.ref.WeakReference;
 
diff --git a/core/java/android/os/RegistrantList.java b/core/java/android/os/RegistrantList.java
index 9c017df..98f949b 100644
--- a/core/java/android/os/RegistrantList.java
+++ b/core/java/android/os/RegistrantList.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import java.util.ArrayList;
 
diff --git a/core/java/android/os/RemoteCallback.java b/core/java/android/os/RemoteCallback.java
index da58d0f..373060f 100644
--- a/core/java/android/os/RemoteCallback.java
+++ b/core/java/android/os/RemoteCallback.java
@@ -20,8 +20,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * @hide
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 6165146..df4ade0 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.ArrayMap;
 import android.util.Slog;
 
diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java
index 34809e7..f64a811 100644
--- a/core/java/android/os/SELinux.java
+++ b/core/java/android/os/SELinux.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Slog;
 
 import java.io.File;
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 3c0997b..74ff310 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.ArrayMap;
 import android.util.Log;
 
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index 124b6c6..ba4042d 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * Native implementation of the service manager.  Most clients will only
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
index 57a8801..26d9c7d 100644
--- a/core/java/android/os/SharedMemory.java
+++ b/core/java/android/os/SharedMemory.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java
index f3a6869..0be3d68 100644
--- a/core/java/android/os/ShellCommand.java
+++ b/core/java/android/os/ShellCommand.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Slog;
 
 import com.android.internal.util.FastPrintWriter;
diff --git a/core/java/android/os/StatFs.java b/core/java/android/os/StatFs.java
index 881d0b4..6d1a116 100644
--- a/core/java/android/os/StatFs.java
+++ b/core/java/android/os/StatFs.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.StructStatVfs;
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 0bf634e..3faaff7 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -20,10 +20,10 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.IActivityManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index c104abd..fd68c2b 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -17,8 +17,8 @@
 package android.os;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
 import android.app.IAlarmManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.location.ILocationManager;
 import android.location.LocationTime;
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index e7a271c..c5e5cc4 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -20,7 +20,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Log;
 import android.util.MutableInt;
 
diff --git a/core/java/android/os/SystemService.java b/core/java/android/os/SystemService.java
index 968c761..5871d2d 100644
--- a/core/java/android/os/SystemService.java
+++ b/core/java/android/os/SystemService.java
@@ -16,9 +16,10 @@
 
 package android.os;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
 import com.google.android.collect.Maps;
 
-import android.annotation.UnsupportedAppUsage;
 import java.util.HashMap;
 import java.util.concurrent.TimeoutException;
 
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index fbd11ca..f585c75 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.media.AudioAttributes;
 import android.util.Log;
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index e132c11..25584f1 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -17,9 +17,7 @@
 package android.os;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
-
-import com.android.internal.os.Zygote;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
diff --git a/core/java/android/os/UEventObserver.java b/core/java/android/os/UEventObserver.java
index dc98c42..fa30e50 100644
--- a/core/java/android/os/UEventObserver.java
+++ b/core/java/android/os/UEventObserver.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Log;
 
 import java.util.ArrayList;
diff --git a/core/java/android/os/UpdateLock.java b/core/java/android/os/UpdateLock.java
index ea273ce..036d095 100644
--- a/core/java/android/os/UpdateLock.java
+++ b/core/java/android/os/UpdateLock.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.util.Log;
 
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 62e83aa..b92fb47 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -20,8 +20,8 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import java.io.PrintWriter;
 
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index d099629..7efe0b7 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -28,12 +28,12 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.admin.DevicePolicyManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -442,7 +442,13 @@
      * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
      * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
+     * @deprecated As the ability to have a managed profile on a fully-managed device has been
+     * removed from the platform, this restriction will be silently ignored when applied by the
+     * device owner.
+     * When the device is provisioned with a managed profile on an organization-owned device,
+     * the managed profile could not be removed anyway.
      */
+    @Deprecated
     public static final String DISALLOW_REMOVE_MANAGED_PROFILE = "no_remove_managed_profile";
 
     /**
@@ -589,7 +595,11 @@
      * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
      * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
+     * @deprecated As the ability to have a managed profile on a fully-managed device has been
+     * removed from the platform, this restriction will be silently ignored when applied by the
+     * device owner.
      */
+    @Deprecated
     public static final String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile";
 
     /**
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 5769c34..75b4724 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.hardware.vibrator.V1_0.EffectStrength;
@@ -27,8 +28,6 @@
 import android.net.Uri;
 import android.util.MathUtils;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 6456d72..ccbb0f1 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -20,8 +20,8 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.media.AudioAttributes;
 import android.util.Log;
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index 397c2a9..7161b07 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -4,9 +4,8 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.os.WorkSourceProto;
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.util.Log;
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index d17a5e0..62b8953 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -18,11 +18,12 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ApplicationInfo;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -39,6 +40,7 @@
 import java.util.Base64;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 
 /*package*/ class ZygoteStartFailedEx extends Exception {
@@ -310,6 +312,8 @@
      *                             started.
      * @param zygoteArgs Additional arguments to supply to the zygote process.
      * @param isTopApp Whether the process starts for high priority application.
+     * @param pkgDataInfoMap Map from related package names to private data directory
+     *                       volume UUID and inode number.
      *
      * @return An object that describes the result of the attempt to start the process.
      * @throws RuntimeException on fatal start failure
@@ -328,6 +332,8 @@
                                                   boolean useUsapPool,
                                                   boolean isTopApp,
                                                   @Nullable long[] disabledCompatChanges,
+                                                  @Nullable Map<String, Pair<String, Long>>
+                                                          pkgDataInfoMap,
                                                   @Nullable String[] zygoteArgs) {
         // TODO (chriswailes): Is there a better place to check this value?
         if (fetchUsapPoolEnabledPropWithMinInterval()) {
@@ -338,7 +344,8 @@
             return startViaZygote(processClass, niceName, uid, gid, gids,
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                     abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
-                    packageName, useUsapPool, isTopApp, disabledCompatChanges, zygoteArgs);
+                    packageName, useUsapPool, isTopApp, disabledCompatChanges,
+                    pkgDataInfoMap, zygoteArgs);
         } catch (ZygoteStartFailedEx ex) {
             Log.e(LOG_TAG,
                     "Starting VM process through Zygote failed");
@@ -539,6 +546,8 @@
      * @param packageName null-ok the name of the package this process belongs to.
      * @param isTopApp Whether the process starts for high priority application.
      * @param disabledCompatChanges a list of disabled compat changes for the process being started.
+     * @param pkgDataInfoMap Map from related package names to private data directory volume UUID
+     *                       and inode number.
      * @param extraArgs Additional arguments to supply to the zygote process.
      * @return An object that describes the result of the attempt to start the process.
      * @throws ZygoteStartFailedEx if process start failed for any reason
@@ -559,6 +568,8 @@
                                                       boolean useUsapPool,
                                                       boolean isTopApp,
                                                       @Nullable long[] disabledCompatChanges,
+                                                      @Nullable Map<String, Pair<String, Long>>
+                                                              pkgDataInfoMap,
                                                       @Nullable String[] extraArgs)
                                                       throws ZygoteStartFailedEx {
         ArrayList<String> argsForZygote = new ArrayList<>();
@@ -635,6 +646,24 @@
         if (isTopApp) {
             argsForZygote.add(Zygote.START_AS_TOP_APP_ARG);
         }
+        if (pkgDataInfoMap != null && pkgDataInfoMap.size() > 0) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(Zygote.PKG_DATA_INFO_MAP);
+            sb.append("=");
+            boolean started = false;
+            for (Map.Entry<String, Pair<String, Long>> entry : pkgDataInfoMap.entrySet()) {
+                if (started) {
+                    sb.append(',');
+                }
+                started = true;
+                sb.append(entry.getKey());
+                sb.append(',');
+                sb.append(entry.getValue().first);
+                sb.append(',');
+                sb.append(entry.getValue().second);
+            }
+            argsForZygote.add(sb.toString());
+        }
 
         if (disabledCompatChanges != null && disabledCompatChanges.length > 0) {
             StringBuilder sb = new StringBuilder();
@@ -1182,12 +1211,14 @@
 
         Process.ProcessStartResult result;
         try {
+            // As app zygote is for generating isolated process, at the end it can't access
+            // apps data, so doesn't need to its data info.
             result = startViaZygote(processClass, niceName, uid, gid,
                     gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
                     abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
                     true /* startChildZygote */, null /* packageName */,
                     false /* useUsapPool */, false /* isTopApp */,
-                    null /* disabledCompatChanges */, extraArgs);
+                    null /* disabledCompatChanges */, null /* pkgDataInfoMap */, extraArgs);
         } catch (ZygoteStartFailedEx ex) {
             throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
         }
diff --git a/core/java/android/os/health/HealthStatsParceler.java b/core/java/android/os/health/HealthStatsParceler.java
index 384342c..f28a974 100644
--- a/core/java/android/os/health/HealthStatsParceler.java
+++ b/core/java/android/os/health/HealthStatsParceler.java
@@ -17,11 +17,10 @@
 package android.os.health;
 
 import android.annotation.TestApi;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
 /**
  * Class to allow sending the HealthStats through aidl generated glue.
  *
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
index a92e28a..6e259ea 100644
--- a/core/java/android/os/health/SystemHealthManager.java
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -17,14 +17,13 @@
 package android.os.health;
 
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.BatteryStats;
 import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.ServiceManager.ServiceNotFoundException;
 
 import com.android.internal.app.IBatteryStats;
 
diff --git a/core/java/android/os/incremental/IIncrementalManager.aidl b/core/java/android/os/incremental/IIncrementalManager.aidl
index f84d7ef..17a310a 100644
--- a/core/java/android/os/incremental/IIncrementalManager.aidl
+++ b/core/java/android/os/incremental/IIncrementalManager.aidl
@@ -16,8 +16,8 @@
 
 package android.os.incremental;
 
-import android.os.incremental.IncrementalFileSystemControlParcel;
-import android.os.incremental.IncrementalDataLoaderParamsParcel;
+import android.content.pm.FileSystemControlParcel;
+import android.content.pm.DataLoaderParamsParcel;
 import android.content.pm.IDataLoaderStatusListener;
 
 /**
@@ -27,8 +27,8 @@
  */
 interface IIncrementalManager {
     boolean prepareDataLoader(int mountId,
-        in IncrementalFileSystemControlParcel control,
-        in IncrementalDataLoaderParamsParcel params,
+        in FileSystemControlParcel control,
+        in DataLoaderParamsParcel params,
         in IDataLoaderStatusListener listener);
     boolean startDataLoader(int mountId);
     void showHealthBlockedUI(int mountId);
diff --git a/core/java/android/os/incremental/IIncrementalManagerNative.aidl b/core/java/android/os/incremental/IIncrementalManagerNative.aidl
index d9c7c6b..14215b1 100644
--- a/core/java/android/os/incremental/IIncrementalManagerNative.aidl
+++ b/core/java/android/os/incremental/IIncrementalManagerNative.aidl
@@ -16,7 +16,7 @@
 
 package android.os.incremental;
 
-import android.os.incremental.IncrementalDataLoaderParamsParcel;
+import android.content.pm.DataLoaderParamsParcel;
 
 /** @hide */
 interface IIncrementalManagerNative {
@@ -32,7 +32,7 @@
      * Opens or creates a storage given a target path and data loader params. Returns the storage ID.
      */
     int openStorage(in @utf8InCpp String path);
-    int createStorage(in @utf8InCpp String path, in IncrementalDataLoaderParamsParcel params, int createMode);
+    int createStorage(in @utf8InCpp String path, in DataLoaderParamsParcel params, int createMode);
     int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode);
 
     /**
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 5bd0748..fb94fc9 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -35,6 +35,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.DataLoaderParams;
 import android.content.pm.InstallationFile;
 import android.os.IVold;
 import android.os.RemoteException;
@@ -82,12 +83,12 @@
     public IncrementalFileStorages(@NonNull String packageName,
             @NonNull File stageDir,
             @NonNull IncrementalManager incrementalManager,
-            @NonNull IncrementalDataLoaderParams incrementalDataLoaderParams) {
+            @NonNull DataLoaderParams dataLoaderParams) {
         mPackageName = packageName;
         mStageDir = stageDir;
         mIncrementalManager = incrementalManager;
-        if (incrementalDataLoaderParams.getPackageName().equals("local")) {
-            final String incrementalPath = incrementalDataLoaderParams.getStaticArgs();
+        if (dataLoaderParams.getPackageName().equals("local")) {
+            final String incrementalPath = dataLoaderParams.getStaticArgs();
             mDefaultStorage = mIncrementalManager.openStorage(incrementalPath);
             mDefaultDir = incrementalPath;
             return;
@@ -97,7 +98,7 @@
             return;
         }
         mDefaultStorage = mIncrementalManager.createStorage(mDefaultDir,
-                incrementalDataLoaderParams,
+                dataLoaderParams,
                 IncrementalManager.CREATE_MODE_CREATE
                         | IncrementalManager.CREATE_MODE_TEMPORARY_BIND, false);
     }
@@ -265,7 +266,7 @@
     }
 
     private String getTempDir() {
-        final String tmpDirRoot = "/data/tmp";
+        final String tmpDirRoot = "/data/incremental/tmp";
         final Random random = new Random();
         final Path tmpDir =
                 Paths.get(tmpDirRoot, String.valueOf(random.nextInt(Integer.MAX_VALUE - 1)));
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index c30f558..c722287 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemService;
 import android.content.Context;
+import android.content.pm.DataLoaderParams;
 import android.os.RemoteException;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -104,7 +105,7 @@
      */
     @Nullable
     public IncrementalStorage createStorage(@NonNull String path,
-            @NonNull IncrementalDataLoaderParams params, @CreateMode int createMode,
+            @NonNull DataLoaderParams params, @CreateMode int createMode,
             boolean autoStartDataLoader) {
         try {
             final int id = mNativeService.createStorage(path, params.getData(), createMode);
diff --git a/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl b/core/java/android/os/storage/CrateInfo.aidl
similarity index 75%
copy from core/java/android/os/incremental/NamedParcelFileDescriptor.aidl
copy to core/java/android/os/storage/CrateInfo.aidl
index 038ced1..dd91053 100644
--- a/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl
+++ b/core/java/android/os/storage/CrateInfo.aidl
@@ -13,16 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.os.incremental;
-
-import android.os.ParcelFileDescriptor;
+package android.os.storage;
 
 /**
- * A named ParcelFileDescriptor.
  * @hide
  */
-parcelable NamedParcelFileDescriptor {
-    @utf8InCpp String name;
-    ParcelFileDescriptor fd;
-}
+parcelable CrateInfo;
diff --git a/core/java/android/os/storage/CrateInfo.java b/core/java/android/os/storage/CrateInfo.java
new file mode 100644
index 0000000..418d39e
--- /dev/null
+++ b/core/java/android/os/storage/CrateInfo.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.app.usage.StorageStatsManager;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+import android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.UUID;
+
+/**
+ * The CrateInfo describe the crate information.
+ * <p>
+ *      It describe the following items.
+ *      <ul>
+ *          <li>The crate id that is the name of the child directory in
+ *          {@link Context#getCrateDir(String)}</li>
+ *          <li>Label to provide human readable text for the users.</li>
+ *          <li>Expiration information. When the crate is expired and the run .</li>
+ *
+ *      </ul>for the directory
+ * </p>
+ * @hide
+ */
+@TestApi
+public final class CrateInfo implements Parcelable {
+    private static final String TAG = "CrateInfo";
+
+    /**
+     * The following member fields whose value are set by apps and retrieved by system_server.
+     */
+    private CharSequence mLabel;
+    @CurrentTimeMillisLong
+    private long mExpiration;
+
+    /**
+     * The following member fields whose value are retrieved by installd.
+     * <p>{@link android.app.usage.StorageStatsManager#queryCratesForUser(UUID, UserHandle)} query
+     * all of crates for the specified UserHandle. That means the return crate list whose elements
+     * may have the same userId but different package name. Each crate needs the information to tell
+     * the caller from where package comes.
+     * </p>
+     */
+    private int mUid;
+
+    /**
+     * The following member fields whose value are retrieved by installd.
+     * <p>Both {@link StorageStatsManager#queryCratesForUid(UUID, int)} and
+     * {@link android.app.usage.StorageStatsManager#queryCratesForUser(UUID, UserHandle)} query
+     * all of crates for the specified uid or userId. That means the return crate list whose
+     * elements may have the same uid or userId but different package name. Each crate needs the
+     * information to tell the caller from where package comes.
+     * </p>
+     */
+    @Nullable
+    private String mPackageName;
+
+    /**
+     * The following member fields whose value are retrieved by system_server.
+     * <p>
+     *     The child directories in {@link Context#getCrateDir(String)} are crates. Each directories
+     *     is a crate. The folder name is the crate id.
+     * </p><p>
+     *     Can't apply check if the path is validated or not because it need pass through the
+     *     parcel.
+     * </p>
+     */
+    @Nullable
+    private String mId;
+
+    private CrateInfo() {
+        mExpiration = 0;
+    }
+
+    /**
+     * To create the crateInfo by passing validated label.
+     * @param label a display name for the crate
+     * @param expiration It's positive integer. if current time is larger than the expiration, the
+     *                  files under this crate will be considered to be deleted. Default value is 0.
+     * @throws IllegalArgumentException cause IllegalArgumentException when label is null
+     *      or empty string
+     */
+    public CrateInfo(@NonNull CharSequence label, @CurrentTimeMillisLong long expiration) {
+        Preconditions.checkStringNotEmpty(label,
+                "Label should not be either null or empty string");
+        Preconditions.checkArgumentNonnegative(expiration,
+                "Expiration should be non negative number");
+
+        mLabel = label;
+        mExpiration = expiration;
+    }
+
+    /**
+     * To create the crateInfo by passing validated label.
+     * @param label a display name for the crate
+     * @throws IllegalArgumentException cause IllegalArgumentException when label is null
+     *      or empty string
+     */
+    public CrateInfo(@NonNull CharSequence label) {
+        this(label, 0);
+    }
+
+    /**
+     * To get the meaningful text of the crate for the users.
+     * @return the meaningful text
+     */
+    @NonNull
+    public CharSequence getLabel() {
+        if (TextUtils.isEmpty(mLabel)) {
+            return mId;
+        }
+        return mLabel;
+    }
+
+
+    /**
+     * To return the expiration time.
+     * <p>
+     *     If the current time is larger than expiration time, the crate files are considered to be
+     *     deleted.
+     * </p>
+     * @return the expiration time
+     */
+    @CurrentTimeMillisLong
+    public long getExpirationMillis() {
+        return mExpiration;
+    }
+
+    /**
+     * To set the expiration time.
+     * @param expiration the expiration time
+     * @hide
+     */
+    public void setExpiration(@CurrentTimeMillisLong long expiration) {
+        Preconditions.checkArgumentNonnegative(expiration);
+        mExpiration = expiration;
+    }
+
+    @Override
+    public int hashCode() {
+        return super.hashCode();
+    }
+
+    /**
+     * To compare with crateinfo when selves' mId is validated.
+     * <p>The validated crateinfo.mId must be validated the following items.
+     * <ul>
+     *     <li>mId is not null</li>
+     *     <li>mId is not empty string</li>
+     * </ul>
+     * </p>
+     * @param   obj   the reference object with which to compare.
+     * @return true when selves's mId is validated and equal to crateinfo.mId.
+     */
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (obj == null) {
+            return false;
+        }
+
+        if (obj instanceof CrateInfo) {
+            CrateInfo crateInfo = (CrateInfo) obj;
+            if (!TextUtils.isEmpty(mId)
+                    && TextUtils.equals(mId, crateInfo.mId)) {
+                return true;
+            }
+        }
+
+        return super.equals(obj);
+    }
+
+
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@Nullable Parcel dest, int flags) {
+        if (dest == null) {
+            return;
+        }
+
+        dest.writeCharSequence(mLabel);
+        dest.writeLong(mExpiration);
+
+        dest.writeInt(mUid);
+        dest.writeString(mPackageName);
+        dest.writeString(mId);
+    }
+
+    /**
+     * To read the data from parcel.
+     * <p>
+     *     It's called by StorageStatsService.
+     * </p>
+     * @hide
+     */
+    public void readFromParcel(@Nullable Parcel in) {
+        if (in == null) {
+            return;
+        }
+
+        mLabel = in.readCharSequence();
+        mExpiration = in.readLong();
+
+        mUid = in.readInt();
+        mPackageName = in.readString();
+        mId = in.readString();
+    }
+
+    @NonNull
+    public static final Creator<CrateInfo> CREATOR = new Creator<CrateInfo>() {
+        @NonNull
+        @Override
+        public CrateInfo createFromParcel(@NonNull Parcel in) {
+            CrateInfo crateInfo = new CrateInfo();
+            crateInfo.readFromParcel(in);
+            return crateInfo;
+        }
+
+        @NonNull
+        @Override
+        public CrateInfo[] newArray(int size) {
+            return new CrateInfo[size];
+        }
+    };
+
+    /**
+     * To copy the information from service into crateinfo.
+     * <p>
+     * This function is called in system_server. The copied information includes
+     *     <ul>
+     *         <li>uid</li>
+     *         <li>package name</li>
+     *         <li>crate id</li>
+     *     </ul>
+     * </p>
+     * @param uid the uid that the crate belong to
+     * @param packageName the package name that the crate belong to
+     * @param id the crate dir
+     * @return the CrateInfo instance
+     * @hide
+     */
+    @TestApi
+    @Nullable
+    public static CrateInfo copyFrom(int uid, @Nullable String packageName, @Nullable String id) {
+        if (!UserHandle.isApp(uid) || TextUtils.isEmpty(packageName) || TextUtils.isEmpty(id)) {
+            return null;
+        }
+
+        CrateInfo crateInfo = new CrateInfo(id /* default label = id */, 0);
+        crateInfo.mUid = uid;
+        crateInfo.mPackageName = packageName;
+        crateInfo.mId = id;
+        return crateInfo;
+    }
+}
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index b797324..df3c4d5 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.Resources;
 import android.os.Build;
 import android.os.Parcel;
diff --git a/core/java/android/os/storage/StorageEventListener.java b/core/java/android/os/storage/StorageEventListener.java
index 39d5b45..9fd9e4e 100644
--- a/core/java/android/os/storage/StorageEventListener.java
+++ b/core/java/android/os/storage/StorageEventListener.java
@@ -16,7 +16,7 @@
 
 package android.os.storage;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * Used for receiving notifications from the StorageManager
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 2e9f27e..8959fcf 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -40,12 +40,12 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.WorkerThread;
 import android.app.Activity;
 import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 560d617..2ab226f 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index d6ec52f..fb90655 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
diff --git a/core/java/android/os/storage/VolumeRecord.java b/core/java/android/os/storage/VolumeRecord.java
index 99b45d6..60df981 100644
--- a/core/java/android/os/storage/VolumeRecord.java
+++ b/core/java/android/os/storage/VolumeRecord.java
@@ -16,7 +16,7 @@
 
 package android.os.storage;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Environment;
 import android.os.Parcel;
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index 32511e9..dfdb57c4 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -21,9 +21,9 @@
 import android.annotation.DrawableRes;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AlertDialog;
 import android.app.Dialog;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.SharedPreferences;
diff --git a/core/java/android/preference/EditTextPreference.java b/core/java/android/preference/EditTextPreference.java
index 74c5e3e..af6f184 100644
--- a/core/java/android/preference/EditTextPreference.java
+++ b/core/java/android/preference/EditTextPreference.java
@@ -17,7 +17,7 @@
 package android.preference;
 
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.res.TypedArray;
diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java
index 830de525..0b64809 100644
--- a/core/java/android/preference/ListPreference.java
+++ b/core/java/android/preference/ListPreference.java
@@ -17,8 +17,8 @@
 package android.preference;
 
 import android.annotation.ArrayRes;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AlertDialog.Builder;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.TypedArray;
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index e82e60d..f508dda 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -21,7 +21,7 @@
 import android.annotation.LayoutRes;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 4750971..ae4a626 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -19,13 +19,13 @@
 import android.animation.LayoutTransition;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.XmlRes;
 import android.app.Fragment;
 import android.app.FragmentBreadCrumbs;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
 import android.app.ListActivity;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java
index d6c069f0..3f6e505 100644
--- a/core/java/android/preference/PreferenceFragment.java
+++ b/core/java/android/preference/PreferenceFragment.java
@@ -17,10 +17,10 @@
 package android.preference;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.XmlRes;
 import android.app.Activity;
 import android.app.Fragment;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.res.TypedArray;
diff --git a/core/java/android/preference/PreferenceGroupAdapter.java b/core/java/android/preference/PreferenceGroupAdapter.java
index dcc5d4c..b263f50 100644
--- a/core/java/android/preference/PreferenceGroupAdapter.java
+++ b/core/java/android/preference/PreferenceGroupAdapter.java
@@ -16,7 +16,7 @@
 
 package android.preference;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.preference.Preference.OnPreferenceChangeInternalListener;
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index f741bd6..9d3f349 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -18,9 +18,9 @@
 
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.XmlRes;
 import android.app.Activity;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
diff --git a/core/java/android/preference/PreferenceScreen.java b/core/java/android/preference/PreferenceScreen.java
index a353dbc..01fe2f3 100644
--- a/core/java/android/preference/PreferenceScreen.java
+++ b/core/java/android/preference/PreferenceScreen.java
@@ -16,8 +16,8 @@
 
 package android.preference;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.Dialog;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.TypedArray;
diff --git a/core/java/android/preference/RingtonePreference.java b/core/java/android/preference/RingtonePreference.java
index 025aad0..c6d8c08 100644
--- a/core/java/android/preference/RingtonePreference.java
+++ b/core/java/android/preference/RingtonePreference.java
@@ -16,7 +16,7 @@
 
 package android.preference;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
diff --git a/core/java/android/preference/SeekBarDialogPreference.java b/core/java/android/preference/SeekBarDialogPreference.java
index 32ef821..46be122 100644
--- a/core/java/android/preference/SeekBarDialogPreference.java
+++ b/core/java/android/preference/SeekBarDialogPreference.java
@@ -16,7 +16,7 @@
 
 package android.preference;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
diff --git a/core/java/android/preference/SeekBarPreference.java b/core/java/android/preference/SeekBarPreference.java
index 99ab9db..a2852bc 100644
--- a/core/java/android/preference/SeekBarPreference.java
+++ b/core/java/android/preference/SeekBarPreference.java
@@ -16,7 +16,7 @@
 
 package android.preference;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.os.Parcel;
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 4dd9bab..0cdad9f 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -17,8 +17,8 @@
 package android.preference;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
 import android.app.NotificationManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/preference/SwitchPreference.java b/core/java/android/preference/SwitchPreference.java
index 9dea1c8..baa023e 100644
--- a/core/java/android/preference/SwitchPreference.java
+++ b/core/java/android/preference/SwitchPreference.java
@@ -17,7 +17,7 @@
 package android.preference;
 
 import android.annotation.StringRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
diff --git a/core/java/android/preference/TwoStatePreference.java b/core/java/android/preference/TwoStatePreference.java
index bb771d7..5eb5d17 100644
--- a/core/java/android/preference/TwoStatePreference.java
+++ b/core/java/android/preference/TwoStatePreference.java
@@ -17,7 +17,7 @@
 package android.preference;
 
 import android.annotation.StringRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.res.TypedArray;
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index a2d5a23..6eb524a 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -16,8 +16,8 @@
 
 package android.preference;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.Dialog;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.os.Parcel;
diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java
index d1b6efc..7ea5655 100644
--- a/core/java/android/print/PrintDocumentAdapter.java
+++ b/core/java/android/print/PrintDocumentAdapter.java
@@ -16,7 +16,7 @@
 
 package android.print;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 25f383c..63f38f8 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -23,7 +23,7 @@
 import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.os.Bundle;
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index e1ede93..9abce5d 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -22,9 +22,9 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.Application.ActivityLifecycleCallbacks;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.IntentSender;
diff --git a/core/java/android/print/PrinterId.java b/core/java/android/print/PrinterId.java
index 42570c6..75ca750 100644
--- a/core/java/android/print/PrinterId.java
+++ b/core/java/android/print/PrinterId.java
@@ -17,7 +17,7 @@
 package android.print;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 30021b4..afa7b80 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -16,10 +16,8 @@
 
 package android.provider;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.database.Cursor;
@@ -30,8 +28,6 @@
 import android.provider.BrowserContract.Bookmarks;
 import android.provider.BrowserContract.Combined;
 import android.provider.BrowserContract.History;
-import android.provider.BrowserContract.Searches;
-import android.util.Log;
 import android.webkit.WebIconDatabase;
 
 public class Browser {
diff --git a/core/java/android/provider/BrowserContract.java b/core/java/android/provider/BrowserContract.java
index 57dde66..5083b8b2 100644
--- a/core/java/android/provider/BrowserContract.java
+++ b/core/java/android/provider/BrowserContract.java
@@ -17,7 +17,7 @@
 package android.provider;
 
 import android.accounts.Account;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentProviderClient;
 import android.content.ContentProviderOperation;
 import android.content.ContentResolver;
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 7285166..9c6c92a 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -20,11 +20,11 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 30db638..a0e92b3 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -17,7 +17,7 @@
 
 package android.provider;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.ContentValues;
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index c86c83c..e383a37 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -23,8 +23,8 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentProviderClient;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f4e2329..503d6db 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -568,16 +568,47 @@
     /**
      * Activity Action: Show settings to enroll fingerprints, and setup PIN/Pattern/Pass if
      * necessary.
+     * @deprecated See {@link #ACTION_BIOMETRIC_ENROLL}.
      * <p>
      * Input: Nothing.
      * <p>
      * Output: Nothing.
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_FINGERPRINT_ENROLL =
             "android.settings.FINGERPRINT_ENROLL";
 
     /**
+     * Activity Action: Show settings to enroll biometrics, and setup PIN/Pattern/Pass if
+     * necessary. By default, this prompts the user to enroll biometrics with strength
+     * Weak or above, as defined by the CDD. Only biometrics that meet or exceed Strong, as defined
+     * in the CDD are allowed to participate in Keystore operations.
+     * <p>
+     * Input: extras {@link #EXTRA_BIOMETRIC_MINIMUM_STRENGTH_REQUIRED} as an integer, with
+     * constants defined in {@link android.hardware.biometrics.BiometricManager.Authenticators},
+     * e.g. {@link android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_STRONG}.
+     * If not specified, the default behavior is
+     * {@link android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_WEAK}.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_BIOMETRIC_ENROLL =
+            "android.settings.BIOMETRIC_ENROLL";
+
+    /**
+     * Activity Extra: The minimum strength to request enrollment for.
+     * <p>
+     * This can be passed as an extra field to the {@link #ACTION_BIOMETRIC_ENROLL} intent to
+     * indicate that only enrollment for sensors that meet this strength should be shown. The
+     * value should be one of the biometric strength constants defined in
+     * {@link android.hardware.biometrics.BiometricManager.Authenticators}.
+     */
+    public static final String EXTRA_BIOMETRIC_MINIMUM_STRENGTH_REQUIRED =
+            "android.provider.extra.BIOMETRIC_MINIMUM_STRENGTH_REQUIRED";
+
+    /**
      * Activity Action: Show settings to allow configuration of cast endpoints.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index 00060ab..d646e23 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -22,11 +22,14 @@
 
 package android.se.omapi;
 
+import android.app.ActivityThread;
 import android.annotation.NonNull;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -140,6 +143,10 @@
             throw new NullPointerException("Arguments must not be null");
         }
 
+        if (!hasOMAPIReaders()) {
+            throw new UnsupportedOperationException("Device does not support any OMAPI reader");
+        }
+
         mContext = context;
         mSEListener.mListener = listener;
         mSEListener.mExecutor = executor;
@@ -270,4 +277,23 @@
             throw new IllegalStateException(e.getMessage());
         }
     }
+
+    /**
+     * Helper to check if this device support any OMAPI readers
+     */
+    private static boolean hasOMAPIReaders() {
+        IPackageManager pm = ActivityThread.getPackageManager();
+        if (pm == null) {
+            Log.e(TAG, "Cannot get package manager, assuming OMAPI readers supported");
+            return true;
+        }
+        try {
+            return pm.hasSystemFeature(PackageManager.FEATURE_SE_OMAPI_UICC, 0)
+                || pm.hasSystemFeature(PackageManager.FEATURE_SE_OMAPI_ESE, 0)
+                || pm.hasSystemFeature(PackageManager.FEATURE_SE_OMAPI_SD, 0);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Package manager query failed, assuming OMAPI readers supported", e);
+            return true;
+        }
+    }
 }
diff --git a/core/java/android/service/controls/ControlState.java b/core/java/android/service/controls/ControlState.java
index f2410a8..1477f9f4 100644
--- a/core/java/android/service/controls/ControlState.java
+++ b/core/java/android/service/controls/ControlState.java
@@ -213,6 +213,8 @@
         if (mAppIntent != null) {
             dest.writeByte((byte) 1);
             mAppIntent.writeToParcel(dest, flags);
+        } else {
+            dest.writeByte((byte) 0);
         }
         if (mIcon != null) {
             dest.writeByte((byte) 1);
diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java
new file mode 100644
index 0000000..193b2bc
--- /dev/null
+++ b/core/java/android/service/controls/ControlsProviderService.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.controls;
+
+import android.annotation.NonNull;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+
+import java.util.List;
+
+/**
+ * Service implementation allowing applications to contribute controls to the
+ * System UI.
+ * @hide
+ */
+public abstract class ControlsProviderService extends Service {
+
+    @SdkConstant(SdkConstantType.SERVICE_ACTION)
+    public static final String CONTROLS_ACTION = "android.service.controls.ControlsProviderService";
+
+    private IControlsProviderCallback mCallback;
+    private RequestHandler mHandler;
+
+    /**
+     * Signal to retrieve all Controls. When complete, call
+     * {@link IControlsProviderCallback#onLoad} to inform the caller.
+     */
+    public abstract void load();
+
+    /**
+     * Informs the service that the caller is listening for updates to the given controlIds.
+     * {@link IControlsProviderCallback#onRefreshState} should be called any time
+     * there are Control updates to render.
+     */
+    public abstract void subscribe(@NonNull List<String> controlIds);
+
+    /**
+     * Informs the service that the caller is done listening for updates,
+     * and any calls to {@link IControlsProviderCallback#onRefreshState} will be ignored.
+     */
+    public abstract void unsubscribe();
+
+    /**
+     * The user has interacted with a Control. The action is dictated by the type of
+     * {@link ControlAction} that was sent.
+     */
+    public abstract void onAction(@NonNull String controlId, @NonNull ControlAction action);
+
+    protected IControlsProviderCallback getControlsProviderCallback() {
+        return mCallback;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        mHandler = new RequestHandler(Looper.getMainLooper());
+
+        Bundle bundle = intent.getBundleExtra("CALLBACK_BUNDLE");
+        IBinder callbackBinder = bundle.getBinder("CALLBACK_BINDER");
+        mCallback = IControlsProviderCallback.Stub.asInterface(callbackBinder);
+
+        return new IControlsProvider.Stub() {
+            public void load() {
+                mHandler.sendEmptyMessage(RequestHandler.MSG_LOAD);
+            }
+
+            public void subscribe(List<String> ids) {
+                mHandler.obtainMessage(RequestHandler.MSG_SUBSCRIBE, ids).sendToTarget();
+            }
+
+            public void unsubscribe() {
+                mHandler.sendEmptyMessage(RequestHandler.MSG_UNSUBSCRIBE);
+            }
+
+            public void onAction(String id, ControlAction action) {
+                ActionMessage msg = new ActionMessage(id, action);
+                mHandler.obtainMessage(RequestHandler.MSG_SUBSCRIBE, msg).sendToTarget();
+            }
+        };
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        mCallback = null;
+        mHandler = null;
+        return true;
+    }
+
+    private class RequestHandler extends Handler {
+        private static final int MSG_LOAD = 1;
+        private static final int MSG_SUBSCRIBE = 2;
+        private static final int MSG_UNSUBSCRIBE = 3;
+        private static final int MSG_ON_ACTION = 4;
+
+        RequestHandler(Looper looper) {
+            super(looper);
+        }
+
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case MSG_LOAD:
+                    ControlsProviderService.this.load();
+                    break;
+                case MSG_SUBSCRIBE:
+                    List<String> ids = (List<String>) msg.obj;
+                    ControlsProviderService.this.subscribe(ids);
+                    break;
+                case MSG_UNSUBSCRIBE:
+                    ControlsProviderService.this.unsubscribe();
+                    break;
+                case MSG_ON_ACTION:
+                    ActionMessage aMsg = (ActionMessage) msg.obj;
+                    ControlsProviderService.this.onAction(aMsg.mId, aMsg.mAction);
+                    break;
+            }
+        }
+    }
+
+    private class ActionMessage {
+        final String mId;
+        final ControlAction mAction;
+
+        ActionMessage(String id, ControlAction action) {
+            this.mId = id;
+            this.mAction = action;
+        }
+    }
+}
diff --git a/core/java/android/service/dataloader/DataLoaderService.java b/core/java/android/service/dataloader/DataLoaderService.java
new file mode 100644
index 0000000..373e1e5
--- /dev/null
+++ b/core/java/android/service/dataloader/DataLoaderService.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.dataloader;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Service;
+import android.content.Intent;
+import android.content.pm.DataLoaderParams;
+import android.content.pm.DataLoaderParamsParcel;
+import android.content.pm.FileSystemControlParcel;
+import android.content.pm.IDataLoader;
+import android.content.pm.IDataLoaderStatusListener;
+import android.content.pm.IPackageInstallerSessionFileSystemConnector;
+import android.content.pm.InstallationFile;
+import android.content.pm.NamedParcelFileDescriptor;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.ExceptionUtils;
+import android.util.Slog;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * The base class for implementing data loader service to control data loaders. Expecting
+ * Incremental Service to bind to a children class of this.
+ *
+ * @hide
+ *
+ * Hide for now, should be @SystemApi
+ * TODO(b/136132412): update with latest API design
+ */
+public abstract class DataLoaderService extends Service {
+    private static final String TAG = "IncrementalDataLoaderService";
+    private final DataLoaderBinderService mBinder = new DataLoaderBinderService();
+
+    public static final int DATA_LOADER_READY =
+            IDataLoaderStatusListener.DATA_LOADER_READY;
+    public static final int DATA_LOADER_NOT_READY =
+            IDataLoaderStatusListener.DATA_LOADER_NOT_READY;
+    public static final int DATA_LOADER_RUNNING =
+            IDataLoaderStatusListener.DATA_LOADER_RUNNING;
+    public static final int DATA_LOADER_STOPPED =
+            IDataLoaderStatusListener.DATA_LOADER_STOPPED;
+    public static final int DATA_LOADER_SLOW_CONNECTION =
+            IDataLoaderStatusListener.DATA_LOADER_SLOW_CONNECTION;
+    public static final int DATA_LOADER_NO_CONNECTION =
+            IDataLoaderStatusListener.DATA_LOADER_NO_CONNECTION;
+    public static final int DATA_LOADER_CONNECTION_OK =
+            IDataLoaderStatusListener.DATA_LOADER_CONNECTION_OK;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"DATA_LOADER_"}, value = {
+            DATA_LOADER_READY,
+            DATA_LOADER_NOT_READY,
+            DATA_LOADER_RUNNING,
+            DATA_LOADER_STOPPED,
+            DATA_LOADER_SLOW_CONNECTION,
+            DATA_LOADER_NO_CONNECTION,
+            DATA_LOADER_CONNECTION_OK
+    })
+    public @interface DataLoaderStatus {
+    }
+
+    /**
+     * Managed DataLoader interface. Each instance corresponds to a single Incremental File System
+     * instance.
+     */
+    public abstract static class DataLoader {
+        /**
+         * A virtual constructor used to do simple initialization. Not ready to serve any data yet.
+         * All heavy-lifting has to be done in onStart.
+         *
+         * @param params    Data loader configuration parameters.
+         * @param connector IncFS API wrapper.
+         * @param listener  Used for reporting internal state to IncrementalService.
+         * @return True if initialization of a Data Loader was successful. False will be reported to
+         * IncrementalService and can cause an unmount of an IFS instance.
+         */
+        public abstract boolean onCreate(@NonNull DataLoaderParams params,
+                @NonNull FileSystemConnector connector,
+                @NonNull StatusListener listener);
+
+        /**
+         * Start the data loader. After this method returns data loader is considered to be ready to
+         * receive callbacks from IFS, supply data via connector and send status updates via
+         * callbacks.
+         *
+         * @return True if Data Loader was able to start. False will be reported to
+         * IncrementalService and can cause an unmount of an IFS instance.
+         */
+        public abstract boolean onStart();
+
+        /**
+         * Stop the data loader. Use to stop any additional threads and free up resources. Data
+         * loader is not longer responsible for supplying data. Start/Stop pair can be called
+         * multiple times e.g. if IFS detects corruption and data needs to be re-loaded.
+         */
+        public abstract void onStop();
+
+        /**
+         * Virtual destructor. Use to cleanup all internal state. After this method returns, the
+         * data loader can no longer use connector or callbacks. For any additional operations with
+         * this instance of IFS a new DataLoader will be created using createDataLoader method.
+         */
+        public abstract void onDestroy();
+    }
+
+    /**
+     * DataLoader factory method.
+     *
+     * @return An instance of a DataLoader.
+     */
+    public abstract @Nullable DataLoader onCreateDataLoader();
+
+    /**
+     * @hide
+     */
+    public final @NonNull IBinder onBind(@NonNull Intent intent) {
+        return (IBinder) mBinder;
+    }
+
+    private class DataLoaderBinderService extends IDataLoader.Stub {
+        private int mId;
+
+        @Override
+        public void create(int id, @NonNull Bundle options,
+                @NonNull IDataLoaderStatusListener listener)
+                    throws IllegalArgumentException, RuntimeException {
+            mId = id;
+            final DataLoaderParamsParcel params =  options.getParcelable("params");
+            if (params == null) {
+                throw new IllegalArgumentException("Must specify Incremental data loader params");
+            }
+            final FileSystemControlParcel control =
+                    options.getParcelable("control");
+            if (control == null) {
+                throw new IllegalArgumentException("Must specify Incremental control parcel");
+            }
+            mStatusListener = listener;
+            try {
+                if (!nativeCreateDataLoader(id, control, params, listener)) {
+                    Slog.e(TAG, "Failed to create native loader for " + mId);
+                }
+            } catch (Exception ex) {
+                destroy();
+                throw new RuntimeException(ex);
+            } finally {
+                // Closing FDs.
+                if (control.incremental.cmd != null) {
+                    try {
+                        control.incremental.cmd.close();
+                    } catch (IOException e) {
+                        Slog.e(TAG, "Failed to close IncFs CMD file descriptor " + e);
+                    }
+                }
+                if (control.incremental.log != null) {
+                    try {
+                        control.incremental.log.close();
+                    } catch (IOException e) {
+                        Slog.e(TAG, "Failed to close IncFs LOG file descriptor " + e);
+                    }
+                }
+                NamedParcelFileDescriptor[] fds = params.dynamicArgs;
+                for (NamedParcelFileDescriptor nfd : fds) {
+                    try {
+                        nfd.fd.close();
+                    } catch (IOException e) {
+                        Slog.e(TAG,
+                                "Failed to close DynamicArgs parcel file descriptor " + e);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void start(List<InstallationFile> fileInfos) {
+            if (!nativeStartDataLoader(mId)) {
+                Slog.e(TAG, "Failed to start loader: loader not found for " + mId);
+            }
+        }
+
+        @Override
+        public void stop() {
+            if (!nativeStopDataLoader(mId)) {
+                Slog.w(TAG, "Failed to stop loader: loader not found for " + mId);
+            }
+        }
+
+        @Override
+        public void destroy() {
+            if (!nativeDestroyDataLoader(mId)) {
+                Slog.w(TAG, "Failed to destroy loader: loader not found for " + mId);
+            }
+        }
+    }
+
+    /**
+     *
+     * Used by the DataLoaderService implementations.
+     *
+     * @hide
+     *
+     * TODO(b/136132412) Should be @SystemApi
+     */
+    public static final class FileSystemConnector {
+        /**
+         * Creates a wrapper for an installation session connector.
+         * @hide
+         */
+        FileSystemConnector(IPackageInstallerSessionFileSystemConnector connector) {
+            mConnector = connector;
+        }
+
+        /**
+         * Write data to an installation file from an arbitrary FD.
+         *
+         * @param name name of file previously added to the installation session.
+         * @param offsetBytes offset into the file to begin writing at, or 0 to
+         *            start at the beginning of the file.
+         * @param lengthBytes total size of the file being written, used to
+         *            preallocate the underlying disk space, or -1 if unknown.
+         *            The system may clear various caches as needed to allocate
+         *            this space.
+         * @param incomingFd FD to read bytes from.
+         * @throws IOException if trouble opening the file for writing, such as
+         *             lack of disk space or unavailable media.
+         */
+        public void writeData(String name, long offsetBytes, long lengthBytes,
+                ParcelFileDescriptor incomingFd) throws IOException {
+            try {
+                mConnector.writeData(name, offsetBytes, lengthBytes, incomingFd);
+            } catch (RuntimeException e) {
+                ExceptionUtils.maybeUnwrapIOException(e);
+                throw e;
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        private final IPackageInstallerSessionFileSystemConnector mConnector;
+    }
+
+    /**
+     * Wrapper for native reporting DataLoader statuses.
+     * @hide
+     * TODO(b/136132412) Should be @SystemApi
+     */
+    public static final class StatusListener {
+        /**
+         * Creates a wrapper for a native instance.
+         * @hide
+         */
+        StatusListener(long nativeInstance) {
+            mNativeInstance = nativeInstance;
+        }
+
+        /**
+         * Report the status of DataLoader. Used for system-wide notifications e.g., disabling
+         * applications which rely on this data loader to function properly.
+         *
+         * @param status status to report.
+         * @return True if status was reported successfully.
+         */
+        public boolean onStatusChanged(@DataLoaderStatus int status) {
+            return nativeReportStatus(mNativeInstance, status);
+        }
+
+        private final long mNativeInstance;
+    }
+
+    private IDataLoaderStatusListener mStatusListener = null;
+
+    /* Native methods */
+    private native boolean nativeCreateDataLoader(int storageId,
+            @NonNull FileSystemControlParcel control,
+            @NonNull DataLoaderParamsParcel params,
+            IDataLoaderStatusListener listener);
+
+    private native boolean nativeStartDataLoader(int storageId);
+
+    private native boolean nativeStopDataLoader(int storageId);
+
+    private native boolean nativeDestroyDataLoader(int storageId);
+
+    private static native boolean nativeReportStatus(long nativeInstance, int status);
+}
diff --git a/core/java/android/service/incremental/IncrementalDataLoaderService.java b/core/java/android/service/incremental/IncrementalDataLoaderService.java
deleted file mode 100644
index c4a06c8..0000000
--- a/core/java/android/service/incremental/IncrementalDataLoaderService.java
+++ /dev/null
@@ -1,563 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.incremental;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Service;
-import android.content.Intent;
-import android.content.pm.IDataLoader;
-import android.content.pm.IDataLoaderStatusListener;
-import android.content.pm.InstallationFile;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.incremental.IncrementalDataLoaderParams;
-import android.os.incremental.IncrementalDataLoaderParamsParcel;
-import android.os.incremental.IncrementalFileSystemControlParcel;
-import android.os.incremental.NamedParcelFileDescriptor;
-import android.util.Slog;
-
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Collection;
-import java.util.List;
-
-
-/**
- * The base class for implementing data loader service to control data loaders. Expecting
- * Incremental Service to bind to a children class of this.
- *
- * @hide
- *
- * Hide for now, should be @SystemApi
- * TODO(b/136132412): update with latest API design
- */
-public abstract class IncrementalDataLoaderService extends Service {
-    private static final String TAG = "IncrementalDataLoaderService";
-    private final DataLoaderBinderService mBinder = new DataLoaderBinderService();
-
-    public static final int DATA_LOADER_READY =
-            IDataLoaderStatusListener.DATA_LOADER_READY;
-    public static final int DATA_LOADER_NOT_READY =
-            IDataLoaderStatusListener.DATA_LOADER_NOT_READY;
-    public static final int DATA_LOADER_RUNNING =
-            IDataLoaderStatusListener.DATA_LOADER_RUNNING;
-    public static final int DATA_LOADER_STOPPED =
-            IDataLoaderStatusListener.DATA_LOADER_STOPPED;
-    public static final int DATA_LOADER_SLOW_CONNECTION =
-            IDataLoaderStatusListener.DATA_LOADER_SLOW_CONNECTION;
-    public static final int DATA_LOADER_NO_CONNECTION =
-            IDataLoaderStatusListener.DATA_LOADER_NO_CONNECTION;
-    public static final int DATA_LOADER_CONNECTION_OK =
-            IDataLoaderStatusListener.DATA_LOADER_CONNECTION_OK;
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"DATA_LOADER_"}, value = {
-            DATA_LOADER_READY,
-            DATA_LOADER_NOT_READY,
-            DATA_LOADER_RUNNING,
-            DATA_LOADER_STOPPED,
-            DATA_LOADER_SLOW_CONNECTION,
-            DATA_LOADER_NO_CONNECTION,
-            DATA_LOADER_CONNECTION_OK
-    })
-    public @interface DataLoaderStatus {
-    }
-
-    /**
-     * Incremental FileSystem block size.
-     **/
-    public static final int BLOCK_SIZE = 4096;
-
-    /**
-     * Data compression types
-     */
-    public static final int COMPRESSION_NONE = 0;
-    public static final int COMPRESSION_LZ4 = 1;
-
-    /**
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({COMPRESSION_NONE, COMPRESSION_LZ4})
-    public @interface CompressionType {
-    }
-
-    /**
-     * Managed DataLoader interface. Each instance corresponds to a single Incremental File System
-     * instance.
-     */
-    public abstract static class DataLoader {
-        /**
-         * A virtual constructor used to do simple initialization. Not ready to serve any data yet.
-         * All heavy-lifting has to be done in onStart.
-         *
-         * @param params    Data loader configuration parameters.
-         * @param connector IncFS API wrapper.
-         * @param listener  Used for reporting internal state to IncrementalService.
-         * @return True if initialization of a Data Loader was successful. False will be reported to
-         * IncrementalService and can cause an unmount of an IFS instance.
-         */
-        public abstract boolean onCreate(@NonNull IncrementalDataLoaderParams params,
-                @NonNull FileSystemConnector connector,
-                @NonNull StatusListener listener);
-
-        /**
-         * Start the data loader. After this method returns data loader is considered to be ready to
-         * receive callbacks from IFS, supply data via connector and send status updates via
-         * callbacks.
-         *
-         * @return True if Data Loader was able to start. False will be reported to
-         * IncrementalService and can cause an unmount of an IFS instance.
-         */
-        public abstract boolean onStart();
-
-        /**
-         * Stop the data loader. Use to stop any additional threads and free up resources. Data
-         * loader is not longer responsible for supplying data. Start/Stop pair can be called
-         * multiple times e.g. if IFS detects corruption and data needs to be re-loaded.
-         */
-        public abstract void onStop();
-
-        /**
-         * Virtual destructor. Use to cleanup all internal state. After this method returns, the
-         * data loader can no longer use connector or callbacks. For any additional operations with
-         * this instance of IFS a new DataLoader will be created using createDataLoader method.
-         */
-        public abstract void onDestroy();
-
-        /**
-         * IFS reports a pending read each time the page needs to be loaded, e.g. missing.
-         *
-         * @param pendingReads array of blocks to load.
-         *
-         * TODO(b/136132412): avoid using collections
-         */
-        public abstract void onPendingReads(
-                @NonNull Collection<FileSystemConnector.PendingReadInfo> pendingReads);
-
-        /**
-         * IFS tracks all reads and reports them using onPageReads.
-         *
-         * @param reads array of blocks.
-         *
-         * TODO(b/136132412): avoid using collections
-         */
-        public abstract void onPageReads(@NonNull Collection<FileSystemConnector.ReadInfo> reads);
-
-        /**
-         * IFS informs data loader that a new file has been created.
-         * <p>
-         * This can be used to prepare the data loader before it starts loading data. For example,
-         * the data loader can keep a list of newly created files, so that it knows what files to
-         * download from the server.
-         *
-         * @param inode    The inode value of the new file.
-         * @param metadata The metadata of the new file.
-         */
-        public abstract void onFileCreated(long inode, byte[] metadata);
-    }
-
-    /**
-     * DataLoader factory method.
-     *
-     * @return An instance of a DataLoader.
-     */
-    public abstract @Nullable DataLoader onCreateDataLoader();
-
-    /**
-     * @hide
-     */
-    public final @NonNull IBinder onBind(@NonNull Intent intent) {
-        return (IBinder) mBinder;
-    }
-
-    private class DataLoaderBinderService extends IDataLoader.Stub {
-        private int mId;
-
-        @Override
-        public void create(int id, @NonNull Bundle options,
-                @NonNull IDataLoaderStatusListener listener)
-                    throws IllegalArgumentException, RuntimeException {
-            mId = id;
-            final IncrementalDataLoaderParamsParcel params =  options.getParcelable("params");
-            if (params == null) {
-                throw new IllegalArgumentException("Must specify Incremental data loader params");
-            }
-            final IncrementalFileSystemControlParcel control =
-                    options.getParcelable("control");
-            if (control == null) {
-                throw new IllegalArgumentException("Must specify Incremental control parcel");
-            }
-            mStatusListener = listener;
-            try {
-                if (!nativeCreateDataLoader(id, control, params, listener)) {
-                    Slog.e(TAG, "Failed to create native loader for " + mId);
-                }
-            } catch (Exception ex) {
-                destroy();
-                throw new RuntimeException(ex);
-            } finally {
-                // Closing FDs.
-                if (control.cmd != null) {
-                    try {
-                        control.cmd.close();
-                    } catch (IOException e) {
-                        Slog.e(TAG, "Failed to close IncFs CMD file descriptor " + e);
-                    }
-                }
-                if (control.log != null) {
-                    try {
-                        control.log.close();
-                    } catch (IOException e) {
-                        Slog.e(TAG, "Failed to close IncFs LOG file descriptor " + e);
-                    }
-                }
-                NamedParcelFileDescriptor[] fds = params.dynamicArgs;
-                for (NamedParcelFileDescriptor nfd : fds) {
-                    try {
-                        nfd.fd.close();
-                    } catch (IOException e) {
-                        Slog.e(TAG,
-                                "Failed to close DynamicArgs parcel file descriptor " + e);
-                    }
-                }
-            }
-        }
-
-        @Override
-        public void start(List<InstallationFile> fileInfos) {
-            if (!nativeStartDataLoader(mId)) {
-                Slog.e(TAG, "Failed to start loader: loader not found for " + mId);
-            }
-        }
-
-        @Override
-        public void stop() {
-            if (!nativeStopDataLoader(mId)) {
-                Slog.w(TAG, "Failed to stop loader: loader not found for " + mId);
-            }
-        }
-
-        @Override
-        public void destroy() {
-            if (!nativeDestroyDataLoader(mId)) {
-                Slog.w(TAG, "Failed to destroy loader: loader not found for " + mId);
-            }
-        }
-
-        @Override
-        // TODO(b/136132412): remove this
-        public void onFileCreated(long inode, byte[] metadata) {
-            if (!nativeOnFileCreated(mId, inode, metadata)) {
-                Slog.w(TAG, "Failed to handle onFileCreated for storage:" + mId
-                        + " inode:" + inode);
-            }
-        }
-    }
-
-    /**
-     * IncFs API wrapper for writing pages and getting page missing info. Non-hidden methods are
-     * expected to be called by the IncrementalDataLoaderService implemented by developers.
-     *
-     * @hide
-     *
-     * TODO(b/136132412) Should be @SystemApi
-     */
-    public static final class FileSystemConnector {
-        /**
-         * Defines a block address. A block is the unit of data chunk that IncFs operates with.
-         *
-         * @hide
-         */
-        public static class BlockAddress {
-            /**
-             * Linux inode uniquely identifies file within a single IFS instance.
-             */
-            private final long mFileIno;
-            /**
-             * Index of a 4K block within a file.
-             */
-            private final int mBlockIndex;
-
-            public BlockAddress(long fileIno, int blockIndex) {
-                this.mFileIno = fileIno;
-                this.mBlockIndex = blockIndex;
-            }
-
-            public long getFileIno() {
-                return mFileIno;
-            }
-
-            public int getBlockIndex() {
-                return mBlockIndex;
-            }
-        }
-
-        /**
-         * A block is the unit of data chunk that IncFs operates with.
-         *
-         * @hide
-         */
-        public static class Block extends BlockAddress {
-            /**
-             * Data content of the block.
-             */
-            private final @NonNull byte[] mDataBytes;
-
-            public Block(long fileIno, int blockIndex, @NonNull byte[] dataBytes) {
-                super(fileIno, blockIndex);
-                this.mDataBytes = dataBytes;
-            }
-        }
-
-        /**
-         * Defines a page/block inside a file.
-         */
-        public static class DataBlock extends Block {
-            /**
-             * Compression type of the data block.
-             */
-            private final @CompressionType int mCompressionType;
-
-            public DataBlock(long fileIno, int blockIndex, @NonNull byte[] dataBytes,
-                    @CompressionType int compressionType) {
-                super(fileIno, blockIndex, dataBytes);
-                this.mCompressionType = compressionType;
-            }
-        }
-
-        /**
-         * Defines a hash block for a certain file. A hash block index is the index in an array of
-         * hashes which is the 1-d representation of the hash tree. One DataBlock might be
-         * associated with multiple HashBlocks.
-         */
-        public static class HashBlock extends Block {
-            public HashBlock(long fileIno, int blockIndex, @NonNull byte[] dataBytes) {
-                super(fileIno, blockIndex, dataBytes);
-            }
-        }
-
-        /**
-         * Information about a page that is pending to be read.
-         */
-        public static class PendingReadInfo extends BlockAddress {
-            PendingReadInfo(long fileIno, int blockIndex) {
-                super(fileIno, blockIndex);
-            }
-        }
-
-        /**
-         * Information about a page that is read.
-         */
-        public static class ReadInfo extends BlockAddress {
-            /**
-             * A monotonically increasing read timestamp.
-             */
-            private final long mTimePoint;
-            /**
-             * Number of blocks read starting from blockIndex.
-             */
-            private final int mBlockCount;
-
-            ReadInfo(long timePoint, long fileIno, int firstBlockIndex, int blockCount) {
-                super(fileIno, firstBlockIndex);
-                this.mTimePoint = timePoint;
-                this.mBlockCount = blockCount;
-            }
-
-            public long getTimePoint() {
-                return mTimePoint;
-            }
-
-            public int getBlockCount() {
-                return mBlockCount;
-            }
-        }
-
-        /**
-         * Defines the dynamic information about an IncFs file.
-         */
-        public static class FileInfo {
-            /**
-             * BitSet to show if any block is available at each block index.
-             */
-            private final @NonNull
-            byte[] mBlockBitmap;
-
-            /**
-             * @hide
-             */
-            public FileInfo(@NonNull byte[] blockBitmap) {
-                this.mBlockBitmap = blockBitmap;
-            }
-        }
-
-        /**
-         * Creates a wrapper for a native instance.
-         */
-        FileSystemConnector(long nativeInstance) {
-            mNativeInstance = nativeInstance;
-        }
-
-        /**
-         * Checks whether a range in a file if loaded.
-         *
-         * @param node  inode of the file.
-         * @param start The starting offset of the range.
-         * @param end   The ending offset of the range.
-         * @return True if the file is fully loaded.
-         */
-        public boolean isFileRangeLoaded(long node, long start, long end) {
-            return nativeIsFileRangeLoadedNode(mNativeInstance, node, start, end);
-        }
-
-        /**
-         * Gets the metadata of a file.
-         *
-         * @param node inode of the file.
-         * @return The metadata object.
-         */
-        @NonNull
-        public byte[] getFileMetadata(long node) throws IOException {
-            final byte[] metadata = nativeGetFileMetadataNode(mNativeInstance, node);
-            if (metadata == null || metadata.length == 0) {
-                throw new IOException(
-                        "IncrementalFileSystem failed to obtain metadata for node: " + node);
-            }
-            return metadata;
-        }
-
-        /**
-         * Gets the dynamic information of a file, such as page bitmaps. Can be used to get missing
-         * page indices by the FileSystemConnector.
-         *
-         * @param node inode of the file.
-         * @return Dynamic file info.
-         */
-        @NonNull
-        public FileInfo getDynamicFileInfo(long node) throws IOException {
-            final byte[] blockBitmap = nativeGetFileInfoNode(mNativeInstance, node);
-            if (blockBitmap == null || blockBitmap.length == 0) {
-                throw new IOException(
-                        "IncrementalFileSystem failed to obtain dynamic file info for node: "
-                                + node);
-            }
-            return new FileInfo(blockBitmap);
-        }
-
-        /**
-         * Writes a page's data and/or hashes.
-         *
-         * @param dataBlocks the DataBlock objects that contain data block index and data bytes.
-         * @param hashBlocks the HashBlock objects that contain hash indices and hash bytes.
-         *
-         * TODO(b/136132412): change API to avoid dynamic allocation of data block objects
-         */
-        public void writeMissingData(@NonNull DataBlock[] dataBlocks,
-                @Nullable HashBlock[] hashBlocks) throws IOException {
-            if (!nativeWriteMissingData(mNativeInstance, dataBlocks, hashBlocks)) {
-                throw new IOException("IncrementalFileSystem failed to write missing data.");
-            }
-        }
-
-        /**
-         * Writes the signer block of a file. Expecting the connector to call this when it got
-         * signing data from data loader.
-         *
-         * @param node       the file to be written to.
-         * @param signerData the raw signer data byte array.
-         */
-        public void writeSignerData(long node, @NonNull byte[] signerData)
-                throws IOException {
-            if (!nativeWriteSignerDataNode(mNativeInstance, node, signerData)) {
-                throw new IOException(
-                        "IncrementalFileSystem failed to write signer data of node " + node);
-            }
-        }
-
-        private final long mNativeInstance;
-    }
-
-    /**
-     * Wrapper for native reporting DataLoader statuses.
-     *
-     * @hide
-     *
-     * TODO(b/136132412) Should be @SystemApi
-     */
-    public static final class StatusListener {
-        /**
-         * Creates a wrapper for a native instance.
-         *
-         * @hide
-         */
-        StatusListener(long nativeInstance) {
-            mNativeInstance = nativeInstance;
-        }
-
-        /**
-         * Report the status of DataLoader. Used for system-wide notifications e.g., disabling
-         * applications which rely on this data loader to function properly.
-         *
-         * @param status status to report.
-         * @return True if status was reported successfully.
-         */
-        public boolean onStatusChanged(@DataLoaderStatus int status) {
-            return nativeReportStatus(mNativeInstance, status);
-        }
-
-        private final long mNativeInstance;
-    }
-
-    private IDataLoaderStatusListener mStatusListener = null;
-
-    /* Native methods */
-    private native boolean nativeCreateDataLoader(int storageId,
-            @NonNull IncrementalFileSystemControlParcel control,
-            @NonNull IncrementalDataLoaderParamsParcel params,
-            IDataLoaderStatusListener listener);
-
-    private native boolean nativeStartDataLoader(int storageId);
-
-    private native boolean nativeStopDataLoader(int storageId);
-
-    private native boolean nativeDestroyDataLoader(int storageId);
-
-    private static native boolean nativeOnFileCreated(int storageId,
-            long inode, byte[] metadata);
-
-    private static native boolean nativeIsFileRangeLoadedNode(
-            long nativeInstance, long node, long start, long end);
-
-    private static native boolean nativeWriteMissingData(
-            long nativeInstance, FileSystemConnector.DataBlock[] dataBlocks,
-            FileSystemConnector.HashBlock[] hashBlocks);
-
-    private static native boolean nativeWriteSignerDataNode(
-            long nativeInstance, long node, byte[] signerData);
-
-    private static native byte[] nativeGetFileMetadataNode(
-            long nativeInstance, long node);
-
-    private static native byte[] nativeGetFileInfoNode(
-            long nativeInstance, long node);
-
-    private static native boolean nativeReportStatus(long nativeInstance, int status);
-}
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 44446ad0..172495f 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -1771,7 +1771,7 @@
      *
      * @param text The text that should be synthesized. No longer than
      *            {@link #getMaxSpeechInputLength()} characters.
-     * @param params Parameters for the request. Can be null.
+     * @param params Parameters for the request.
      *            Engine specific parameters may be passed in but the parameter keys
      *            must be prefixed by the name of the engine they are intended for. For example
      *            the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the engine
@@ -1798,7 +1798,7 @@
      *
      * @param text The text that should be synthesized. No longer than
      *            {@link #getMaxSpeechInputLength()} characters.
-     * @param params Parameters for the request. Can be null.
+     * @param params Parameters for the request. Cannot be null.
      *            Engine specific parameters may be passed in but the parameter keys
      *            must be prefixed by the name of the engine they are intended for. For example
      *            the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
@@ -1842,7 +1842,7 @@
      *
      * @param text The text that should be synthesized. No longer than
      *            {@link #getMaxSpeechInputLength()} characters.
-     * @param params Parameters for the request. Can be null.
+     * @param params Parameters for the request. Cannot be null.
      *            Supported parameter names:
      *            {@link Engine#KEY_PARAM_UTTERANCE_ID}.
      *            Engine specific parameters may be passed in but the parameter keys
diff --git a/core/java/android/util/CloseGuard.java b/core/java/android/util/CloseGuard.java
index c39a6c9..6ac7696 100644
--- a/core/java/android/util/CloseGuard.java
+++ b/core/java/android/util/CloseGuard.java
@@ -38,6 +38,11 @@
  *       public void cleanup() {
  *          guard.close();
  *          ...;
+ *          if (Build.VERSION.SDK_INT >= 28) {
+ *              Reference.reachabilityFence(this);
+ *          }
+ *          // For full correctness in the absence of a close() call, other methods may also need
+ *          // reachabilityFence() calls.
  *       }
  *
  *       protected void finalize() throws Throwable {
@@ -75,7 +80,9 @@
  *       public void cleanup() {
  *          guard.close();
  *          ...;
- *          Reference.reachabilityFence(this);
+ *          if (Build.VERSION.SDK_INT >= 28) {
+ *              Reference.reachabilityFence(this);
+ *          }
  *          // For full correctness in the absence of a close() call, other methods may also need
  *          // reachabilityFence() calls.
  *       }
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 71ac578..987edf7 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -20,7 +20,7 @@
 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER;
 
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.FrameInfo;
 import android.graphics.Insets;
 import android.hardware.display.DisplayManagerGlobal;
diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java
index 696e048..876331b 100644
--- a/core/java/android/view/ContextThemeWrapper.java
+++ b/core/java/android/view/ContextThemeWrapper.java
@@ -18,7 +18,7 @@
 
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.res.AssetManager;
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index ba25093..1a6ec4e 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -22,8 +22,8 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.KeyguardManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java
index da4d92fa..834dd7b 100644
--- a/core/java/android/view/DisplayAdjustments.java
+++ b/core/java/android/view/DisplayAdjustments.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 91acc46..eaf297c 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.util.Log;
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 04e82c7..8a5385d 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -24,7 +24,7 @@
 import static android.view.DisplayInfoProto.NAME;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java
index 8e6e99a..6035cbe 100644
--- a/core/java/android/view/DisplayListCanvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.BaseRecordingCanvas;
 import android.graphics.CanvasProperty;
 import android.graphics.Paint;
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 2a43bcc..35af0f2 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.os.Parcel;
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index ea66656..054dff7 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -17,7 +17,7 @@
 package android.view;
 
 import android.annotation.IntDef;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/view/FrameMetricsObserver.java b/core/java/android/view/FrameMetricsObserver.java
index 0f38e84..41bc9a7 100644
--- a/core/java/android/view/FrameMetricsObserver.java
+++ b/core/java/android/view/FrameMetricsObserver.java
@@ -17,11 +17,8 @@
 package android.view;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
-import android.os.Looper;
-import android.os.MessageQueue;
-
-import com.android.internal.util.VirtualRefBasePtr;
+import android.graphics.HardwareRendererObserver;
+import android.os.Handler;
 
 import java.lang.ref.WeakReference;
 
@@ -31,47 +28,39 @@
  *
  * @hide
  */
-public class FrameMetricsObserver {
-    @UnsupportedAppUsage
-    private MessageQueue mMessageQueue;
-
-    private WeakReference<Window> mWindow;
-
-    @UnsupportedAppUsage
-    private FrameMetrics mFrameMetrics;
-
-    /* pacage */ Window.OnFrameMetricsAvailableListener mListener;
-    /** @hide */
-    public VirtualRefBasePtr mNative;
+public class FrameMetricsObserver
+        implements HardwareRendererObserver.OnFrameMetricsAvailableListener {
+    private final WeakReference<Window> mWindow;
+    private final FrameMetrics mFrameMetrics;
+    private final HardwareRendererObserver mObserver;
+    /*package*/ final Window.OnFrameMetricsAvailableListener mListener;
 
     /**
      * Creates a FrameMetricsObserver
      *
-     * @param looper the looper to use when invoking callbacks
+     * @param handler the Handler to use when invoking callbacks
      */
-    FrameMetricsObserver(@NonNull Window window, @NonNull Looper looper,
+    FrameMetricsObserver(@NonNull Window window, @NonNull Handler handler,
             @NonNull Window.OnFrameMetricsAvailableListener listener) {
-        if (looper == null) {
-            throw new NullPointerException("looper cannot be null");
-        }
-
-        mMessageQueue = looper.getQueue();
-        if (mMessageQueue == null) {
-            throw new IllegalStateException("invalid looper, null message queue\n");
-        }
-
-        mFrameMetrics = new FrameMetrics();
         mWindow = new WeakReference<>(window);
         mListener = listener;
+        mFrameMetrics = new FrameMetrics();
+        mObserver = new HardwareRendererObserver(this,  mFrameMetrics.mTimingData, handler);
     }
 
-    // Called by native on the provided Handler
-    @SuppressWarnings("unused")
-    @UnsupportedAppUsage
-    private void notifyDataAvailable(int dropCount) {
-        final Window window = mWindow.get();
-        if (window != null) {
-            mListener.onFrameMetricsAvailable(window, mFrameMetrics, dropCount);
+    /**
+     * Implementation of OnFrameMetricsAvailableListener
+     * @param dropCountSinceLastInvocation the number of reports dropped since the last time
+     * @Override
+     */
+    public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
+        if (mWindow.get() != null) {
+            mListener.onFrameMetricsAvailable(mWindow.get(), mFrameMetrics,
+                    dropCountSinceLastInvocation);
         }
     }
+
+    /*package*/ HardwareRendererObserver getRendererObserver() {
+        return mObserver;
+    }
 }
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index d59ee92..4d71136 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -23,7 +23,7 @@
 import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP;
 import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Build;
 import android.os.Handler;
diff --git a/core/java/android/view/GhostView.java b/core/java/android/view/GhostView.java
index 3286bd6..a728327 100644
--- a/core/java/android/view/GhostView.java
+++ b/core/java/android/view/GhostView.java
@@ -15,7 +15,7 @@
  */
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.RecordingCanvas;
diff --git a/core/java/android/view/InputChannel.java b/core/java/android/view/InputChannel.java
index 5d0d5bd..5a64b13 100644
--- a/core/java/android/view/InputChannel.java
+++ b/core/java/android/view/InputChannel.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index e723f91..360dedd 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -18,7 +18,7 @@
 
 import android.annotation.RequiresPermission;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java
index 4b88a6a..5f9c480 100644
--- a/core/java/android/view/InputEvent.java
+++ b/core/java/android/view/InputEvent.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/core/java/android/view/InputEventConsistencyVerifier.java b/core/java/android/view/InputEventConsistencyVerifier.java
index e4b1a8d..c0a3cec 100644
--- a/core/java/android/view/InputEventConsistencyVerifier.java
+++ b/core/java/android/view/InputEventConsistencyVerifier.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.util.Log;
 
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index 3080b42..5674de8 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.MessageQueue;
diff --git a/core/java/android/view/InputEventSender.java b/core/java/android/view/InputEventSender.java
index c5f4c23..86a309e 100644
--- a/core/java/android/view/InputEventSender.java
+++ b/core/java/android/view/InputEventSender.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.util.Log;
diff --git a/core/java/android/view/InputFilter.java b/core/java/android/view/InputFilter.java
index 3aaf31e..36d5586 100644
--- a/core/java/android/view/InputFilter.java
+++ b/core/java/android/view/InputFilter.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
diff --git a/core/java/android/view/InputQueue.java b/core/java/android/view/InputQueue.java
index 69ebc46..74ce6ac 100644
--- a/core/java/android/view/InputQueue.java
+++ b/core/java/android/view/InputQueue.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.util.LongSparseArray;
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index bd03348..90e0f3f 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.hardware.input.InputManager;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 60db6a5..c638717 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -20,7 +20,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 75862e0..1afe11e 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -21,7 +21,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.res.Resources;
@@ -31,10 +31,7 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
-import android.os.SystemProperties;
 import android.os.Trace;
-import android.provider.DeviceConfig;
-import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.TypedValue;
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 1c94e02..c3c7b95 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -22,7 +22,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Matrix;
 import android.os.Build;
 import android.os.Parcel;
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index d54e9d5..8ec5df8 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -17,9 +17,9 @@
 package android.view;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AppOpsManager;
 import android.app.Notification;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index dfe34c8..18d0d7b 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -17,8 +17,8 @@
 package android.view;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.XmlRes;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java
index c686440..166d3ba 100644
--- a/core/java/android/view/RemoteAnimationAdapter.java
+++ b/core/java/android/view/RemoteAnimationAdapter.java
@@ -16,8 +16,8 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityOptions;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java
index da599ef..c9bd92a 100644
--- a/core/java/android/view/RemoteAnimationDefinition.java
+++ b/core/java/android/view/RemoteAnimationDefinition.java
@@ -19,9 +19,9 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.WindowConfiguration;
 import android.app.WindowConfiguration.ActivityType;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArraySet;
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index b873482..b04372a 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -30,8 +30,8 @@
 import static android.view.RemoteAnimationTargetProto.WINDOW_CONFIGURATION;
 
 import android.annotation.IntDef;
-import android.annotation.UnsupportedAppUsage;
 import android.app.WindowConfiguration;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Parcel;
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 93f52a0..06cb519 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -19,7 +19,7 @@
 import android.animation.Animator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.CanvasProperty;
 import android.graphics.Paint;
 import android.graphics.RecordingCanvas;
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 1d72151..346f76c 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Build;
 import android.os.Handler;
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index dac6282..7707ad1 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -18,7 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.CompatibilityInfo.Translator;
 import android.graphics.Canvas;
 import android.graphics.ColorSpace;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 87628da..93cc626 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -32,7 +32,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Size;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Bitmap;
 import android.graphics.ColorSpace;
 import android.graphics.GraphicBuffer;
@@ -2092,6 +2092,13 @@
         Runnable mFreeNativeResources;
 
         /**
+         * @hide
+         */
+        protected void checkPreconditions(SurfaceControl sc) {
+            sc.checkNotReleased();
+        }
+
+        /**
          * Open a new transaction object. The transaction may be filed with commands to
          * manipulate {@link SurfaceControl} instances, and then applied atomically with
          * {@link #apply}. Eventually the user should invoke {@link #close}, when the object
@@ -2155,7 +2162,7 @@
          */
         @NonNull
         public Transaction setVisibility(@NonNull SurfaceControl sc, boolean visible) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             if (visible) {
                 return show(sc);
             } else {
@@ -2172,7 +2179,7 @@
          */
         @UnsupportedAppUsage
         public Transaction show(SurfaceControl sc) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
             return this;
         }
@@ -2186,7 +2193,7 @@
          */
         @UnsupportedAppUsage
         public Transaction hide(SurfaceControl sc) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
             return this;
         }
@@ -2196,7 +2203,7 @@
          */
         @UnsupportedAppUsage
         public Transaction setPosition(SurfaceControl sc, float x, float y) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetPosition(mNativeObject, sc.mNativeObject, x, y);
             return this;
         }
@@ -2213,7 +2220,7 @@
         @NonNull
         public Transaction setBufferSize(@NonNull SurfaceControl sc,
                 @IntRange(from = 0) int w, @IntRange(from = 0) int h) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             mResizedSurfaces.put(sc, new Point(w, h));
             nativeSetSize(mNativeObject, sc.mNativeObject, w, h);
             return this;
@@ -2231,7 +2238,7 @@
         @NonNull
         public Transaction setLayer(@NonNull SurfaceControl sc,
                 @IntRange(from = Integer.MIN_VALUE, to = Integer.MAX_VALUE) int z) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetLayer(mNativeObject, sc.mNativeObject, z);
             return this;
         }
@@ -2240,7 +2247,7 @@
          * @hide
          */
         public Transaction setRelativeLayer(SurfaceControl sc, SurfaceControl relativeTo, int z) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetRelativeLayer(mNativeObject, sc.mNativeObject, relativeTo.mNativeObject, z);
             return this;
         }
@@ -2249,7 +2256,7 @@
          * @hide
          */
         public Transaction setTransparentRegionHint(SurfaceControl sc, Region transparentRegion) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetTransparentRegionHint(mNativeObject,
                     sc.mNativeObject, transparentRegion);
             return this;
@@ -2265,7 +2272,7 @@
         @NonNull
         public Transaction setAlpha(@NonNull SurfaceControl sc,
                 @FloatRange(from = 0.0, to = 1.0) float alpha) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetAlpha(mNativeObject, sc.mNativeObject, alpha);
             return this;
         }
@@ -2274,7 +2281,7 @@
          * @hide
          */
         public Transaction setInputWindowInfo(SurfaceControl sc, InputWindowHandle handle) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetInputWindowInfo(mNativeObject, sc.mNativeObject, handle);
             return this;
         }
@@ -2304,7 +2311,7 @@
         @NonNull
         public Transaction setGeometry(@NonNull SurfaceControl sc, @Nullable Rect sourceCrop,
                 @Nullable Rect destFrame, @Surface.Rotation int orientation) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetGeometry(mNativeObject, sc.mNativeObject, sourceCrop, destFrame, orientation);
             return this;
         }
@@ -2315,7 +2322,7 @@
         @UnsupportedAppUsage
         public Transaction setMatrix(SurfaceControl sc,
                 float dsdx, float dtdx, float dtdy, float dsdy) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetMatrix(mNativeObject, sc.mNativeObject,
                     dsdx, dtdx, dtdy, dsdy);
             return this;
@@ -2349,7 +2356,7 @@
          */
         public Transaction setColorTransform(SurfaceControl sc, @Size(9) float[] matrix,
                 @Size(3) float[] translation) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetColorTransform(mNativeObject, sc.mNativeObject, matrix, translation);
             return this;
         }
@@ -2361,7 +2368,7 @@
          * @hide
          */
         public Transaction setColorSpaceAgnostic(SurfaceControl sc, boolean agnostic) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetColorSpaceAgnostic(mNativeObject, sc.mNativeObject, agnostic);
             return this;
         }
@@ -2378,7 +2385,7 @@
          */
         @UnsupportedAppUsage
         public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             if (crop != null) {
                 nativeSetWindowCrop(mNativeObject, sc.mNativeObject,
                         crop.left, crop.top, crop.right, crop.bottom);
@@ -2399,7 +2406,7 @@
          * @hide
          */
         public Transaction setWindowCrop(SurfaceControl sc, int width, int height) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetWindowCrop(mNativeObject, sc.mNativeObject, 0, 0, width, height);
             return this;
         }
@@ -2413,7 +2420,7 @@
          */
         @UnsupportedAppUsage
         public Transaction setCornerRadius(SurfaceControl sc, float cornerRadius) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetCornerRadius(mNativeObject, sc.mNativeObject, cornerRadius);
 
             return this;
@@ -2424,7 +2431,7 @@
          */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O)
         public Transaction setLayerStack(SurfaceControl sc, int layerStack) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetLayerStack(mNativeObject, sc.mNativeObject, layerStack);
             return this;
         }
@@ -2438,7 +2445,7 @@
             if (frameNumber < 0) {
                 return this;
             }
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeDeferTransactionUntil(mNativeObject, sc.mNativeObject, barrier.mNativeObject,
                     frameNumber);
             return this;
@@ -2453,7 +2460,7 @@
             if (frameNumber < 0) {
                 return this;
             }
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeDeferTransactionUntilSurface(mNativeObject, sc.mNativeObject,
                     barrierSurface.mNativeObject, frameNumber);
             return this;
@@ -2463,7 +2470,7 @@
          * @hide
          */
         public Transaction reparentChildren(SurfaceControl sc, SurfaceControl newParent) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeReparentChildren(mNativeObject, sc.mNativeObject, newParent.mNativeObject);
             return this;
         }
@@ -2480,7 +2487,7 @@
         @NonNull
         public Transaction reparent(@NonNull SurfaceControl sc,
                 @Nullable SurfaceControl newParent) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             long otherObject = 0;
             if (newParent != null) {
                 newParent.checkNotReleased();
@@ -2494,7 +2501,7 @@
          * @hide
          */
         public Transaction detachChildren(SurfaceControl sc) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSeverChildren(mNativeObject, sc.mNativeObject);
             return this;
         }
@@ -2503,7 +2510,7 @@
          * @hide
          */
         public Transaction setOverrideScalingMode(SurfaceControl sc, int overrideScalingMode) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetOverrideScalingMode(mNativeObject, sc.mNativeObject,
                     overrideScalingMode);
             return this;
@@ -2516,7 +2523,7 @@
          */
         @UnsupportedAppUsage
         public Transaction setColor(SurfaceControl sc, @Size(3) float[] color) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetColor(mNativeObject, sc.mNativeObject, color);
             return this;
         }
@@ -2527,7 +2534,7 @@
          * @hide
          */
         public Transaction setSecure(SurfaceControl sc, boolean isSecure) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             if (isSecure) {
                 nativeSetFlags(mNativeObject, sc.mNativeObject, SECURE, SECURE);
             } else {
@@ -2542,7 +2549,7 @@
          * @hide
          */
         public Transaction setOpaque(SurfaceControl sc, boolean isOpaque) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             if (isOpaque) {
                 nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_OPAQUE, SURFACE_OPAQUE);
             } else {
@@ -2657,7 +2664,7 @@
          * @hide
          */
         public Transaction setMetadata(SurfaceControl sc, int key, Parcel data) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetMetadata(mNativeObject, sc.mNativeObject, key, data);
             return this;
         }
@@ -2680,7 +2687,7 @@
           * @hide
           */
         public Transaction setShadowRadius(SurfaceControl sc, float shadowRadius) {
-            sc.checkNotReleased();
+            checkPreconditions(sc);
             nativeSetShadowRadius(mNativeObject, sc.mNativeObject, shadowRadius);
             return this;
         }
@@ -2763,4 +2770,27 @@
                     }
                 };
     }
+
+    /**
+     * A debugging utility subclass of SurfaceControl.Transaction. At construction
+     * you can pass in a monitor object, and all the other methods will throw an exception
+     * if the monitor is not held when they are called.
+     * @hide
+     */
+    public static class LockDebuggingTransaction extends SurfaceControl.Transaction {
+        Object mMonitor;
+
+        public LockDebuggingTransaction(Object o) {
+            mMonitor = o;
+        }
+
+        @Override
+        protected void checkPreconditions(SurfaceControl sc) {
+            super.checkPreconditions(sc);
+            if (!Thread.holdsLock(mMonitor)) {
+                throw new RuntimeException(
+                        "Unlocked access to synchronized SurfaceControl.Transaction");
+            }
+        }
+    }
 }
diff --git a/core/java/android/view/SurfaceSession.java b/core/java/android/view/SurfaceSession.java
index 361ac93..0f851c1 100644
--- a/core/java/android/view/SurfaceSession.java
+++ b/core/java/android/view/SurfaceSession.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * An instance of this class represents a connection to the surface
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 0b5af2d..95a75eb 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -22,7 +22,7 @@
 
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.CompatibilityInfo.Translator;
 import android.graphics.BlendMode;
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 5876b03..277b872 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
diff --git a/core/java/android/view/TouchDelegate.java b/core/java/android/view/TouchDelegate.java
index 2ea95e9..de0f9e5 100644
--- a/core/java/android/view/TouchDelegate.java
+++ b/core/java/android/view/TouchDelegate.java
@@ -17,7 +17,7 @@
 package android.view;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.util.ArrayMap;
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index 7154f2b..a56633e 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Pools.SynchronizedPool;
 
 /**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 44f211a..1a5b3e5 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -43,7 +43,7 @@
 import android.annotation.StyleRes;
 import android.annotation.TestApi;
 import android.annotation.UiThread;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.AutofillOptions;
 import android.content.ClipData;
 import android.content.Context;
@@ -7147,10 +7147,9 @@
                     mFrameMetricsObservers = new ArrayList<>();
                 }
 
-                FrameMetricsObserver fmo = new FrameMetricsObserver(window,
-                        handler.getLooper(), listener);
+                FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener);
                 mFrameMetricsObservers.add(fmo);
-                mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo);
+                mAttachInfo.mThreadedRenderer.addObserver(fmo.getRendererObserver());
             } else {
                 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats");
             }
@@ -7159,8 +7158,7 @@
                 mFrameMetricsObservers = new ArrayList<>();
             }
 
-            FrameMetricsObserver fmo = new FrameMetricsObserver(window,
-                    handler.getLooper(), listener);
+            FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener);
             mFrameMetricsObservers.add(fmo);
         }
     }
@@ -7182,7 +7180,7 @@
         if (mFrameMetricsObservers != null) {
             mFrameMetricsObservers.remove(fmo);
             if (renderer != null) {
-                renderer.removeFrameMetricsObserver(fmo);
+                renderer.removeObserver(fmo.getRendererObserver());
             }
         }
     }
@@ -7192,7 +7190,7 @@
             ThreadedRenderer renderer = getThreadedRenderer();
             if (renderer != null) {
                 for (FrameMetricsObserver fmo : mFrameMetricsObservers) {
-                    renderer.addFrameMetricsObserver(fmo);
+                    renderer.addObserver(fmo.getRendererObserver());
                 }
             } else {
                 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats");
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 9e914d4..774a2de 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -18,8 +18,8 @@
 
 import android.annotation.FloatRange;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AppGlobals;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index a62ba63..2f44fe0 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4334bb5..21e9e31 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -24,7 +24,7 @@
 import android.annotation.NonNull;
 import android.annotation.TestApi;
 import android.annotation.UiThread;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ClipData;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/view/ViewHierarchyEncoder.java b/core/java/android/view/ViewHierarchyEncoder.java
index d5716bf..b0e0524 100644
--- a/core/java/android/view/ViewHierarchyEncoder.java
+++ b/core/java/android/view/ViewHierarchyEncoder.java
@@ -2,7 +2,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java
index e23c687..7830c57 100644
--- a/core/java/android/view/ViewOverlay.java
+++ b/core/java/android/view/ViewOverlay.java
@@ -17,7 +17,7 @@
 
 import android.animation.LayoutTransition;
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e3f0da1..3bab9eb 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -49,10 +49,10 @@
 import android.annotation.AnyThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.ResourcesManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.Context;
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index c72baca..d7b0afc 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.Region;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index ff31115..0776469 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -26,8 +26,8 @@
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.WindowConfiguration;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
diff --git a/core/java/android/view/WindowAnimationFrameStats.java b/core/java/android/view/WindowAnimationFrameStats.java
index 399dfba..dfc4f0c 100644
--- a/core/java/android/view/WindowAnimationFrameStats.java
+++ b/core/java/android/view/WindowAnimationFrameStats.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/core/java/android/view/WindowContentFrameStats.java b/core/java/android/view/WindowContentFrameStats.java
index 9fa5a00..217197c 100644
--- a/core/java/android/view/WindowContentFrameStats.java
+++ b/core/java/android/view/WindowContentFrameStats.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 2404c84..a9cc50f 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -34,7 +34,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.graphics.Insets;
 import android.graphics.Rect;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 3b6c55b..fc12639 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -66,9 +66,9 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.KeyguardManager;
 import android.app.Presentation;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.graphics.PixelFormat;
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 55b2a2a..9578002 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -18,8 +18,8 @@
 
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index c349443..cdeeaa4 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -17,7 +17,7 @@
 package android.view;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.graphics.Region;
 import android.os.Bundle;
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 34654ed..3b83683 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -18,7 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 3866517..914ff18 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -17,7 +17,7 @@
 package android.view.accessibility;
 
 import android.accessibilityservice.IAccessibilityServiceConnection;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 843f8e3..ff31bcc 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -30,8 +30,8 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index f2f84cd..92aa7d5 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -26,7 +26,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Build;
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index 4f6c9ef..c3a4d32 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -20,7 +20,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcelable;
 import android.view.View;
 
diff --git a/core/java/android/view/accessibility/CaptioningManager.java b/core/java/android/view/accessibility/CaptioningManager.java
index c42e9fe..3d68692 100644
--- a/core/java/android/view/accessibility/CaptioningManager.java
+++ b/core/java/android/view/accessibility/CaptioningManager.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index b03732a..b1d618e 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -19,7 +19,7 @@
 import android.annotation.AnimRes;
 import android.annotation.ColorInt;
 import android.annotation.InterpolatorRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.RectF;
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index f5b0746..7ce0f45 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -19,7 +19,7 @@
 import android.annotation.AnimRes;
 import android.annotation.InterpolatorRes;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java
index 58da04d..cfc6e39 100644
--- a/core/java/android/view/animation/Transformation.java
+++ b/core/java/android/view/animation/Transformation.java
@@ -17,7 +17,7 @@
 package android.view.animation;
 
 import android.annotation.FloatRange;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 
diff --git a/core/java/android/view/animation/TranslateAnimation.java b/core/java/android/view/animation/TranslateAnimation.java
index 6c040d4..ec55a02 100644
--- a/core/java/android/view/animation/TranslateAnimation.java
+++ b/core/java/android/view/animation/TranslateAnimation.java
@@ -16,7 +16,7 @@
 
 package android.view.animation;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
diff --git a/core/java/android/view/animation/TranslateYAnimation.java b/core/java/android/view/animation/TranslateYAnimation.java
index a6e0ccb..1a1dfbf 100644
--- a/core/java/android/view/animation/TranslateYAnimation.java
+++ b/core/java/android/view/animation/TranslateYAnimation.java
@@ -16,7 +16,7 @@
 
 package android.view.animation;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Matrix;
 
 /**
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index fe07fee..34005ac 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -17,7 +17,7 @@
 package android.view.inputmethod;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 2650a67..67ce8d2 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -26,9 +26,9 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
 import android.app.ActivityThread;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -2863,7 +2863,7 @@
     }
 
     /**
-     * This is kept due to {@link android.annotation.UnsupportedAppUsage}.
+     * This is kept due to {@link android.compat.annotation.UnsupportedAppUsage}.
      *
      * <p>TODO(Bug 113914148): Check if we can remove this.  We have accidentally exposed
      * WindowManagerInternal#getInputMethodWindowVisibleHeight to app developers and some of them
diff --git a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
index 8dd0dcd..50e95c8 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
@@ -16,7 +16,7 @@
 
 package android.view.inputmethod;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.util.Slog;
 
diff --git a/core/java/android/view/textclassifier/ConversationAction.java b/core/java/android/view/textclassifier/ConversationAction.java
index 6070b53..e633404 100644
--- a/core/java/android/view/textclassifier/ConversationAction.java
+++ b/core/java/android/view/textclassifier/ConversationAction.java
@@ -26,9 +26,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.util.Preconditions;
-
 import java.lang.annotation.Retention;
+import java.util.Objects;
 
 /** Represents the action suggested by a {@link TextClassifier} on a given conversation. */
 public final class ConversationAction implements Parcelable {
@@ -133,11 +132,11 @@
             @Nullable CharSequence textReply,
             float score,
             @NonNull Bundle extras) {
-        mType = Preconditions.checkNotNull(type);
+        mType = Objects.requireNonNull(type);
         mAction = action;
         mTextReply = textReply;
         mScore = score;
-        mExtras = Preconditions.checkNotNull(extras);
+        mExtras = Objects.requireNonNull(extras);
     }
 
     private ConversationAction(Parcel in) {
@@ -221,7 +220,7 @@
         private Bundle mExtras;
 
         public Builder(@NonNull @ActionType String actionType) {
-            mType = Preconditions.checkNotNull(actionType);
+            mType = Objects.requireNonNull(actionType);
         }
 
         /**
diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java
index f7f503a..80027b1e 100644
--- a/core/java/android/view/textclassifier/ConversationActions.java
+++ b/core/java/android/view/textclassifier/ConversationActions.java
@@ -38,6 +38,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Represents a list of actions suggested by a {@link TextClassifier} on a given conversation.
@@ -66,7 +67,7 @@
     public ConversationActions(
             @NonNull List<ConversationAction> conversationActions, @Nullable String id) {
         mConversationActions =
-                Collections.unmodifiableList(Preconditions.checkNotNull(conversationActions));
+                Collections.unmodifiableList(Objects.requireNonNull(conversationActions));
         mId = id;
     }
 
@@ -149,7 +150,7 @@
             mAuthor = author;
             mReferenceTime = referenceTime;
             mText = text;
-            mExtras = Preconditions.checkNotNull(bundle);
+            mExtras = Objects.requireNonNull(bundle);
         }
 
         private Message(Parcel in) {
@@ -243,7 +244,7 @@
              *               {@link #PERSON_USER_OTHERS} to represent a remote user.
              */
             public Builder(@NonNull Person author) {
-                mAuthor = Preconditions.checkNotNull(author);
+                mAuthor = Objects.requireNonNull(author);
             }
 
             /** Sets the text of this message. */
@@ -329,8 +330,8 @@
                 int maxSuggestions,
                 @Nullable @Hint List<String> hints,
                 @NonNull Bundle extras) {
-            mConversation = Preconditions.checkNotNull(conversation);
-            mTypeConfig = Preconditions.checkNotNull(typeConfig);
+            mConversation = Objects.requireNonNull(conversation);
+            mTypeConfig = Objects.requireNonNull(typeConfig);
             mMaxSuggestions = maxSuggestions;
             mHints = hints;
             mExtras = extras;
@@ -483,7 +484,7 @@
              *     actions for.
              */
             public Builder(@NonNull List<Message> conversation) {
-                mConversation = Preconditions.checkNotNull(conversation);
+                mConversation = Objects.requireNonNull(conversation);
             }
 
             /**
diff --git a/core/java/android/view/textclassifier/EntityConfidence.java b/core/java/android/view/textclassifier/EntityConfidence.java
index 3c51c38..4c12dda 100644
--- a/core/java/android/view/textclassifier/EntityConfidence.java
+++ b/core/java/android/view/textclassifier/EntityConfidence.java
@@ -22,12 +22,11 @@
 import android.os.Parcelable;
 import android.util.ArrayMap;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Helper object for setting and getting entity scores for classified text.
@@ -42,7 +41,7 @@
     EntityConfidence() {}
 
     EntityConfidence(@NonNull EntityConfidence source) {
-        Preconditions.checkNotNull(source);
+        Objects.requireNonNull(source);
         mEntityConfidence.putAll(source.mEntityConfidence);
         mSortedEntities.addAll(source.mSortedEntities);
     }
@@ -56,7 +55,7 @@
      *               1 (high confidence).
      */
     EntityConfidence(@NonNull Map<String, Float> source) {
-        Preconditions.checkNotNull(source);
+        Objects.requireNonNull(source);
 
         // Prune non-existent entities and clamp to 1.
         mEntityConfidence.ensureCapacity(source.size());
diff --git a/core/java/android/view/textclassifier/GenerateLinksLogger.java b/core/java/android/view/textclassifier/GenerateLinksLogger.java
index 3996b27..17ec73a 100644
--- a/core/java/android/view/textclassifier/GenerateLinksLogger.java
+++ b/core/java/android/view/textclassifier/GenerateLinksLogger.java
@@ -23,7 +23,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.util.Preconditions;
 
 import java.util.Locale;
 import java.util.Map;
@@ -66,9 +65,9 @@
     /** Logs statistics about a call to generateLinks. */
     public void logGenerateLinks(CharSequence text, TextLinks links, String callingPackageName,
             long latencyMs) {
-        Preconditions.checkNotNull(text);
-        Preconditions.checkNotNull(links);
-        Preconditions.checkNotNull(callingPackageName);
+        Objects.requireNonNull(text);
+        Objects.requireNonNull(links);
+        Objects.requireNonNull(callingPackageName);
         if (!shouldLog()) {
             return;
         }
diff --git a/core/java/android/view/textclassifier/ModelFileManager.java b/core/java/android/view/textclassifier/ModelFileManager.java
index e04285d..0a4ff5d 100644
--- a/core/java/android/view/textclassifier/ModelFileManager.java
+++ b/core/java/android/view/textclassifier/ModelFileManager.java
@@ -23,7 +23,6 @@
 import android.text.TextUtils;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -51,7 +50,7 @@
     private List<ModelFile> mModelFiles;
 
     public ModelFileManager(Supplier<List<ModelFile>> modelFileSupplier) {
-        mModelFileSupplier = Preconditions.checkNotNull(modelFileSupplier);
+        mModelFileSupplier = Objects.requireNonNull(modelFileSupplier);
     }
 
     /**
@@ -106,12 +105,12 @@
                 File updatedModelFile,
                 Function<Integer, Integer> versionSupplier,
                 Function<Integer, String> supportedLocalesSupplier) {
-            mUpdatedModelFile = Preconditions.checkNotNull(updatedModelFile);
-            mFactoryModelDir = Preconditions.checkNotNull(factoryModelDir);
+            mUpdatedModelFile = Objects.requireNonNull(updatedModelFile);
+            mFactoryModelDir = Objects.requireNonNull(factoryModelDir);
             mModelFilenamePattern = Pattern.compile(
-                    Preconditions.checkNotNull(factoryModelFileNameRegex));
-            mVersionSupplier = Preconditions.checkNotNull(versionSupplier);
-            mSupportedLocalesSupplier = Preconditions.checkNotNull(supportedLocalesSupplier);
+                    Objects.requireNonNull(factoryModelFileNameRegex));
+            mVersionSupplier = Objects.requireNonNull(versionSupplier);
+            mSupportedLocalesSupplier = Objects.requireNonNull(supportedLocalesSupplier);
         }
 
         @Override
@@ -208,10 +207,10 @@
         public ModelFile(File file, int version, List<Locale> supportedLocales,
                 String supportedLocalesStr,
                 boolean languageIndependent) {
-            mFile = Preconditions.checkNotNull(file);
+            mFile = Objects.requireNonNull(file);
             mVersion = version;
-            mSupportedLocales = Preconditions.checkNotNull(supportedLocales);
-            mSupportedLocalesStr = Preconditions.checkNotNull(supportedLocalesStr);
+            mSupportedLocales = Objects.requireNonNull(supportedLocales);
+            mSupportedLocalesStr = Objects.requireNonNull(supportedLocalesStr);
             mLanguageIndependent = languageIndependent;
         }
 
@@ -232,7 +231,7 @@
 
         /** Returns whether the language supports any language in the given ranges. */
         public boolean isAnyLanguageSupported(List<Locale.LanguageRange> languageRanges) {
-            Preconditions.checkNotNull(languageRanges);
+            Objects.requireNonNull(languageRanges);
             return mLanguageIndependent || Locale.lookup(languageRanges, mSupportedLocales) != null;
         }
 
diff --git a/core/java/android/view/textclassifier/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
index 7d1077e..09cb7a0 100644
--- a/core/java/android/view/textclassifier/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -149,7 +149,7 @@
         mAbsoluteStart = start;
         mAbsoluteEnd = end;
         mEventType = eventType;
-        mEntityType = Preconditions.checkNotNull(entityType);
+        mEntityType = Objects.requireNonNull(entityType);
         mResultId = resultId;
         mInvocationMethod = invocationMethod;
     }
@@ -257,7 +257,7 @@
     public static SelectionEvent createSelectionModifiedEvent(
             int start, int end, @NonNull TextClassification classification) {
         Preconditions.checkArgument(end >= start, "end cannot be less than start");
-        Preconditions.checkNotNull(classification);
+        Objects.requireNonNull(classification);
         final String entityType = classification.getEntityCount() > 0
                 ? classification.getEntity(0)
                 : TextClassifier.TYPE_UNKNOWN;
@@ -281,7 +281,7 @@
     public static SelectionEvent createSelectionModifiedEvent(
             int start, int end, @NonNull TextSelection selection) {
         Preconditions.checkArgument(end >= start, "end cannot be less than start");
-        Preconditions.checkNotNull(selection);
+        Objects.requireNonNull(selection);
         final String entityType = selection.getEntityCount() > 0
                 ? selection.getEntity(0)
                 : TextClassifier.TYPE_UNKNOWN;
@@ -329,7 +329,7 @@
             int start, int end, @SelectionEvent.ActionType int actionType,
             @NonNull TextClassification classification) {
         Preconditions.checkArgument(end >= start, "end cannot be less than start");
-        Preconditions.checkNotNull(classification);
+        Objects.requireNonNull(classification);
         checkActionType(actionType);
         final String entityType = classification.getEntityCount() > 0
                 ? classification.getEntity(0)
@@ -398,7 +398,7 @@
     }
 
     void setEntityType(@EntityType String entityType) {
-        mEntityType = Preconditions.checkNotNull(entityType);
+        mEntityType = Objects.requireNonNull(entityType);
     }
 
     /**
diff --git a/core/java/android/view/textclassifier/SelectionSessionLogger.java b/core/java/android/view/textclassifier/SelectionSessionLogger.java
index 20cc944..9c9b2d0 100644
--- a/core/java/android/view/textclassifier/SelectionSessionLogger.java
+++ b/core/java/android/view/textclassifier/SelectionSessionLogger.java
@@ -24,7 +24,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.util.Preconditions;
 
 import java.text.BreakIterator;
 import java.util.List;
@@ -65,12 +64,12 @@
 
     @VisibleForTesting
     public SelectionSessionLogger(@NonNull MetricsLogger metricsLogger) {
-        mMetricsLogger = Preconditions.checkNotNull(metricsLogger);
+        mMetricsLogger = Objects.requireNonNull(metricsLogger);
     }
 
     /** Emits a selection event to the logs. */
     public void writeEvent(@NonNull SelectionEvent event) {
-        Preconditions.checkNotNull(event);
+        Objects.requireNonNull(event);
         final LogMaker log = new LogMaker(MetricsEvent.TEXT_SELECTION_SESSION)
                 .setType(getLogType(event))
                 .setSubtype(getLogSubType(event))
@@ -240,7 +239,7 @@
      * Returns a token iterator for tokenizing text for logging purposes.
      */
     public static BreakIterator getTokenIterator(@NonNull Locale locale) {
-        return BreakIterator.getWordInstance(Preconditions.checkNotNull(locale));
+        return BreakIterator.getWordInstance(Objects.requireNonNull(locale));
     }
 
     /**
@@ -249,9 +248,9 @@
     public static String createId(
             String text, int start, int end, Context context, int modelVersion,
             List<Locale> locales) {
-        Preconditions.checkNotNull(text);
-        Preconditions.checkNotNull(context);
-        Preconditions.checkNotNull(locales);
+        Objects.requireNonNull(text);
+        Objects.requireNonNull(context);
+        Objects.requireNonNull(locales);
         final StringJoiner localesJoiner = new StringJoiner(",");
         for (Locale locale : locales) {
             localesJoiner.add(locale.toLanguageTag());
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index 66f7504..138d25d 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -33,8 +33,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.annotations.VisibleForTesting.Visibility;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Preconditions;
 
+import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -61,10 +61,10 @@
                 throws ServiceManager.ServiceNotFoundException {
         mManagerService = ITextClassifierService.Stub.asInterface(
                 ServiceManager.getServiceOrThrow(Context.TEXT_CLASSIFICATION_SERVICE));
-        mSettings = Preconditions.checkNotNull(settings);
+        mSettings = Objects.requireNonNull(settings);
         mFallback = context.getSystemService(TextClassificationManager.class)
                 .getTextClassifier(TextClassifier.LOCAL);
-        mPackageName = Preconditions.checkNotNull(context.getOpPackageName());
+        mPackageName = Objects.requireNonNull(context.getOpPackageName());
         mUserId = context.getUserId();
     }
 
@@ -74,7 +74,7 @@
     @Override
     @WorkerThread
     public TextSelection suggestSelection(TextSelection.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkMainThread();
         try {
             request.setCallingPackageName(mPackageName);
@@ -98,7 +98,7 @@
     @Override
     @WorkerThread
     public TextClassification classifyText(TextClassification.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkMainThread();
         try {
             request.setCallingPackageName(mPackageName);
@@ -122,7 +122,7 @@
     @Override
     @WorkerThread
     public TextLinks generateLinks(@NonNull TextLinks.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkMainThread();
 
         if (!mSettings.isSmartLinkifyEnabled() && request.isLegacyFallback()) {
@@ -147,7 +147,7 @@
 
     @Override
     public void onSelectionEvent(SelectionEvent event) {
-        Preconditions.checkNotNull(event);
+        Objects.requireNonNull(event);
         Utils.checkMainThread();
 
         try {
@@ -160,7 +160,7 @@
 
     @Override
     public void onTextClassifierEvent(@NonNull TextClassifierEvent event) {
-        Preconditions.checkNotNull(event);
+        Objects.requireNonNull(event);
         Utils.checkMainThread();
 
         try {
@@ -178,7 +178,7 @@
 
     @Override
     public TextLanguage detectLanguage(TextLanguage.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkMainThread();
 
         try {
@@ -199,7 +199,7 @@
 
     @Override
     public ConversationActions suggestConversationActions(ConversationActions.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkMainThread();
 
         try {
@@ -260,7 +260,7 @@
     void initializeRemoteSession(
             @NonNull TextClassificationContext classificationContext,
             @NonNull TextClassificationSessionId sessionId) {
-        mSessionId = Preconditions.checkNotNull(sessionId);
+        mSessionId = Objects.requireNonNull(sessionId);
         try {
             classificationContext.setUserId(mUserId);
             mManagerService.onCreateTextClassificationSession(classificationContext, mSessionId);
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 93f7103..3628d2d4 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -150,7 +150,7 @@
         mLegacyIntent = legacyIntent;
         mLegacyOnClickListener = legacyOnClickListener;
         mActions = Collections.unmodifiableList(actions);
-        mEntityConfidence = Preconditions.checkNotNull(entityConfidence);
+        mEntityConfidence = Objects.requireNonNull(entityConfidence);
         mId = id;
         mExtras = extras;
     }
@@ -287,7 +287,7 @@
      * @hide
      */
     public static OnClickListener createIntentOnClickListener(@NonNull final PendingIntent intent) {
-        Preconditions.checkNotNull(intent);
+        Objects.requireNonNull(intent);
         return v -> {
             try {
                 intent.send();
diff --git a/core/java/android/view/textclassifier/TextClassificationContext.java b/core/java/android/view/textclassifier/TextClassificationContext.java
index e4baaac..930765b 100644
--- a/core/java/android/view/textclassifier/TextClassificationContext.java
+++ b/core/java/android/view/textclassifier/TextClassificationContext.java
@@ -24,9 +24,8 @@
 import android.os.UserHandle;
 import android.view.textclassifier.TextClassifier.WidgetType;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.Locale;
+import java.util.Objects;
 
 /**
  * A representation of the context in which text classification would be performed.
@@ -44,8 +43,8 @@
             String packageName,
             String widgetType,
             String widgetVersion) {
-        mPackageName = Preconditions.checkNotNull(packageName);
-        mWidgetType = Preconditions.checkNotNull(widgetType);
+        mPackageName = Objects.requireNonNull(packageName);
+        mWidgetType = Objects.requireNonNull(widgetType);
         mWidgetVersion = widgetVersion;
     }
 
@@ -121,8 +120,8 @@
          * @return this builder
          */
         public Builder(@NonNull String packageName, @NonNull @WidgetType String widgetType) {
-            mPackageName = Preconditions.checkNotNull(packageName);
-            mWidgetType = Preconditions.checkNotNull(widgetType);
+            mPackageName = Objects.requireNonNull(packageName);
+            mWidgetType = Objects.requireNonNull(widgetType);
         }
 
         /**
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index 7c25bf0..bb96d55 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -19,8 +19,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.ServiceManager;
 import android.provider.DeviceConfig;
@@ -31,9 +31,9 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Preconditions;
 
 import java.lang.ref.WeakReference;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -71,7 +71,7 @@
 
     /** @hide */
     public TextClassificationManager(Context context) {
-        mContext = Preconditions.checkNotNull(context);
+        mContext = Objects.requireNonNull(context);
         mSessionFactory = mDefaultSessionFactory;
         mSettingsObserver = new SettingsObserver(this);
     }
@@ -157,10 +157,10 @@
     @NonNull
     public TextClassifier createTextClassificationSession(
             @NonNull TextClassificationContext classificationContext) {
-        Preconditions.checkNotNull(classificationContext);
+        Objects.requireNonNull(classificationContext);
         final TextClassifier textClassifier =
                 mSessionFactory.createTextClassificationSession(classificationContext);
-        Preconditions.checkNotNull(textClassifier, "Session Factory should never return null");
+        Objects.requireNonNull(textClassifier, "Session Factory should never return null");
         return textClassifier;
     }
 
@@ -170,8 +170,8 @@
      */
     public TextClassifier createTextClassificationSession(
             TextClassificationContext classificationContext, TextClassifier textClassifier) {
-        Preconditions.checkNotNull(classificationContext);
-        Preconditions.checkNotNull(textClassifier);
+        Objects.requireNonNull(classificationContext);
+        Objects.requireNonNull(textClassifier);
         return new TextClassificationSession(classificationContext, textClassifier);
     }
 
@@ -280,7 +280,7 @@
 
     /** @hide */
     public static TextClassificationConstants getSettings(Context context) {
-        Preconditions.checkNotNull(context);
+        Objects.requireNonNull(context);
         final TextClassificationManager tcm =
                 context.getSystemService(TextClassificationManager.class);
         if (tcm != null) {
diff --git a/core/java/android/view/textclassifier/TextClassificationSession.java b/core/java/android/view/textclassifier/TextClassificationSession.java
index 6a706f5..abfbc6c 100644
--- a/core/java/android/view/textclassifier/TextClassificationSession.java
+++ b/core/java/android/view/textclassifier/TextClassificationSession.java
@@ -20,6 +20,7 @@
 import android.view.textclassifier.SelectionEvent.InvocationMethod;
 
 import com.android.internal.util.Preconditions;
+import java.util.Objects;
 
 /**
  * Session-aware TextClassifier.
@@ -37,8 +38,8 @@
     private boolean mDestroyed;
 
     TextClassificationSession(TextClassificationContext context, TextClassifier delegate) {
-        mClassificationContext = Preconditions.checkNotNull(context);
-        mDelegate = Preconditions.checkNotNull(delegate);
+        mClassificationContext = Objects.requireNonNull(context);
+        mDelegate = Objects.requireNonNull(delegate);
         mSessionId = new TextClassificationSessionId();
         mEventHelper = new SelectionEventHelper(mSessionId, mClassificationContext);
         initializeRemoteSession();
@@ -149,8 +150,8 @@
 
         SelectionEventHelper(
                 TextClassificationSessionId sessionId, TextClassificationContext context) {
-            mSessionId = Preconditions.checkNotNull(sessionId);
-            mContext = Preconditions.checkNotNull(context);
+            mSessionId = Objects.requireNonNull(sessionId);
+            mContext = Objects.requireNonNull(context);
         }
 
         /**
diff --git a/core/java/android/view/textclassifier/TextClassificationSessionId.java b/core/java/android/view/textclassifier/TextClassificationSessionId.java
index 8b68e17..f90e6b2 100644
--- a/core/java/android/view/textclassifier/TextClassificationSessionId.java
+++ b/core/java/android/view/textclassifier/TextClassificationSessionId.java
@@ -20,9 +20,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.Locale;
+import java.util.Objects;
 import java.util.UUID;
 
 /**
@@ -118,7 +117,7 @@
                 @Override
                 public TextClassificationSessionId createFromParcel(Parcel parcel) {
                     return new TextClassificationSessionId(
-                            Preconditions.checkNotNull(parcel.readString()));
+                            Objects.requireNonNull(parcel.readString()));
                 }
 
                 @Override
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index ac8a429..9b33693 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -46,6 +46,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -193,7 +194,7 @@
     @WorkerThread
     @NonNull
     default TextSelection suggestSelection(@NonNull TextSelection.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkMainThread();
         return new TextSelection.Builder(request.getStartIndex(), request.getEndIndex()).build();
     }
@@ -252,7 +253,7 @@
     @WorkerThread
     @NonNull
     default TextClassification classifyText(@NonNull TextClassification.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkMainThread();
         return TextClassification.EMPTY;
     }
@@ -313,7 +314,7 @@
     @WorkerThread
     @NonNull
     default TextLinks generateLinks(@NonNull TextLinks.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkMainThread();
         return new TextLinks.Builder(request.getText().toString()).build();
     }
@@ -346,7 +347,7 @@
     @WorkerThread
     @NonNull
     default TextLanguage detectLanguage(@NonNull TextLanguage.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkMainThread();
         return TextLanguage.EMPTY;
     }
@@ -358,7 +359,7 @@
     @NonNull
     default ConversationActions suggestConversationActions(
             @NonNull ConversationActions.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkMainThread();
         return new ConversationActions(Collections.emptyList(), null);
     }
@@ -427,9 +428,9 @@
                 List<String> excludedEntityTypes,
                 List<String> hints,
                 boolean includeTypesFromTextClassifier) {
-            mIncludedTypes = Preconditions.checkNotNull(includedEntityTypes);
-            mExcludedTypes = Preconditions.checkNotNull(excludedEntityTypes);
-            mHints = Preconditions.checkNotNull(hints);
+            mIncludedTypes = Objects.requireNonNull(includedEntityTypes);
+            mExcludedTypes = Objects.requireNonNull(excludedEntityTypes);
+            mHints = Objects.requireNonNull(hints);
             mIncludeTypesFromTextClassifier = includeTypesFromTextClassifier;
         }
 
diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java
index eb6aec0..db88011 100644
--- a/core/java/android/view/textclassifier/TextClassifierEvent.java
+++ b/core/java/android/view/textclassifier/TextClassifierEvent.java
@@ -25,11 +25,11 @@
 import android.os.Parcelable;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * This class represents events that are sent by components to the {@link TextClassifier} to report
@@ -549,7 +549,7 @@
          */
         @NonNull
         public T setEntityTypes(@NonNull String... entityTypes) {
-            Preconditions.checkNotNull(entityTypes);
+            Objects.requireNonNull(entityTypes);
             mEntityTypes = new String[entityTypes.length];
             System.arraycopy(entityTypes, 0, mEntityTypes, 0, entityTypes.length);
             return self();
@@ -587,7 +587,7 @@
          */
         @NonNull
         public T setScores(@NonNull float... scores) {
-            Preconditions.checkNotNull(scores);
+            Objects.requireNonNull(scores);
             mScores = new float[scores.length];
             System.arraycopy(scores, 0, mScores, 0, scores.length);
             return self();
@@ -652,7 +652,7 @@
          */
         @NonNull
         public T setExtras(@NonNull Bundle extras) {
-            mExtras = Preconditions.checkNotNull(extras);
+            mExtras = Objects.requireNonNull(extras);
             return self();
         }
 
diff --git a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
index 3e088b8..8162699 100644
--- a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
+++ b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
@@ -29,7 +29,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
 
 
 /**
@@ -50,12 +50,12 @@
 
     @VisibleForTesting
     public TextClassifierEventTronLogger(MetricsLogger metricsLogger) {
-        mMetricsLogger = Preconditions.checkNotNull(metricsLogger);
+        mMetricsLogger = Objects.requireNonNull(metricsLogger);
     }
 
     /** Emits a text classifier event to the logs. */
     public void writeEvent(TextClassifierEvent event) {
-        Preconditions.checkNotNull(event);
+        Objects.requireNonNull(event);
 
         int category = getCategory(event);
         if (category == -1) {
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 024c379..61bd7c7 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -130,9 +130,9 @@
 
     public TextClassifierImpl(
             Context context, TextClassificationConstants settings, TextClassifier fallback) {
-        mContext = Preconditions.checkNotNull(context);
-        mFallback = Preconditions.checkNotNull(fallback);
-        mSettings = Preconditions.checkNotNull(settings);
+        mContext = Objects.requireNonNull(context);
+        mFallback = Objects.requireNonNull(fallback);
+        mSettings = Objects.requireNonNull(settings);
         mGenerateLinksLogger = new GenerateLinksLogger(mSettings.getGenerateLinksLogSampleRate());
         mAnnotatorModelFileManager = new ModelFileManager(
                 new ModelFileManager.ModelFileSupplierImpl(
@@ -180,7 +180,7 @@
     @Override
     @WorkerThread
     public TextSelection suggestSelection(TextSelection.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkMainThread();
         try {
             final int rangeLength = request.getEndIndex() - request.getStartIndex();
@@ -245,7 +245,7 @@
     @Override
     @WorkerThread
     public TextClassification classifyText(TextClassification.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkMainThread();
         try {
             final int rangeLength = request.getEndIndex() - request.getStartIndex();
@@ -285,7 +285,7 @@
     @Override
     @WorkerThread
     public TextLinks generateLinks(@NonNull TextLinks.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkTextLength(request.getText(), getMaxGenerateLinksTextLength());
         Utils.checkMainThread();
 
@@ -399,7 +399,7 @@
     /** @inheritDoc */
     @Override
     public TextLanguage detectLanguage(@NonNull TextLanguage.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkMainThread();
         try {
             final TextLanguage.Builder builder = new TextLanguage.Builder();
@@ -420,7 +420,7 @@
 
     @Override
     public ConversationActions suggestConversationActions(ConversationActions.Request request) {
-        Preconditions.checkNotNull(request);
+        Objects.requireNonNull(request);
         Utils.checkMainThread();
         try {
             ActionsSuggestionsModel actionsImpl = getActionsImpl();
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index bbb7f07..237d1a9 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -48,6 +48,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.function.Function;
 
 /**
@@ -155,7 +156,7 @@
             @NonNull Spannable text,
             @ApplyStrategy int applyStrategy,
             @Nullable Function<TextLink, TextLinkSpan> spanFactory) {
-        Preconditions.checkNotNull(text);
+        Objects.requireNonNull(text);
         return new TextLinksParams.Builder()
                 .setApplyStrategy(applyStrategy)
                 .setSpanFactory(spanFactory)
@@ -223,10 +224,10 @@
          */
         private TextLink(int start, int end, @NonNull EntityConfidence entityConfidence,
                 @NonNull Bundle extras, @Nullable URLSpan urlSpan) {
-            Preconditions.checkNotNull(entityConfidence);
+            Objects.requireNonNull(entityConfidence);
             Preconditions.checkArgument(!entityConfidence.getEntities().isEmpty());
             Preconditions.checkArgument(start <= end);
-            Preconditions.checkNotNull(extras);
+            Objects.requireNonNull(extras);
             mStart = start;
             mEnd = end;
             mEntityScores = entityConfidence;
@@ -455,7 +456,7 @@
             @Nullable private Bundle mExtras;
 
             public Builder(@NonNull CharSequence text) {
-                mText = Preconditions.checkNotNull(text);
+                mText = Objects.requireNonNull(text);
             }
 
             /**
@@ -654,7 +655,7 @@
          * @param fullText The full text to annotate with links
          */
         public Builder(@NonNull String fullText) {
-            mFullText = Preconditions.checkNotNull(fullText);
+            mFullText = Objects.requireNonNull(fullText);
             mLinks = new ArrayList<>();
         }
 
diff --git a/core/java/android/view/textclassifier/TextLinksParams.java b/core/java/android/view/textclassifier/TextLinksParams.java
index 8af4233..b7d63bf 100644
--- a/core/java/android/view/textclassifier/TextLinksParams.java
+++ b/core/java/android/view/textclassifier/TextLinksParams.java
@@ -25,10 +25,9 @@
 import android.view.textclassifier.TextLinks.TextLink;
 import android.view.textclassifier.TextLinks.TextLinkSpan;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.function.Function;
 
 /**
@@ -103,8 +102,8 @@
      */
     @TextLinks.Status
     public int apply(@NonNull Spannable text, @NonNull TextLinks textLinks) {
-        Preconditions.checkNotNull(text);
-        Preconditions.checkNotNull(textLinks);
+        Objects.requireNonNull(text);
+        Objects.requireNonNull(textLinks);
 
         final String textString = text.toString();
 
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 0c89749..4a36cbf 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -36,6 +36,7 @@
 
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Information about where text selection should be.
@@ -165,7 +166,7 @@
         public Builder setEntityType(
                 @NonNull @EntityType String type,
                 @FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
-            Preconditions.checkNotNull(type);
+            Objects.requireNonNull(type);
             mEntityConfidence.put(type, confidenceScore);
             return this;
         }
diff --git a/core/java/android/view/textclassifier/intent/LabeledIntent.java b/core/java/android/view/textclassifier/intent/LabeledIntent.java
index 30fc20e..cbd9d1a 100644
--- a/core/java/android/view/textclassifier/intent/LabeledIntent.java
+++ b/core/java/android/view/textclassifier/intent/LabeledIntent.java
@@ -32,7 +32,8 @@
 import android.view.textclassifier.TextClassifier;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
 
 /**
  * Helper class to store the information from which RemoteActions are built.
@@ -86,9 +87,9 @@
         }
         this.titleWithoutEntity = titleWithoutEntity;
         this.titleWithEntity = titleWithEntity;
-        this.description = Preconditions.checkNotNull(description);
+        this.description = Objects.requireNonNull(description);
         this.descriptionWithAppName = descriptionWithAppName;
-        this.intent = Preconditions.checkNotNull(intent);
+        this.intent = Objects.requireNonNull(intent);
         this.requestCode = requestCode;
     }
 
@@ -198,8 +199,8 @@
         public final RemoteAction remoteAction;
 
         public Result(Intent resolvedIntent, RemoteAction remoteAction) {
-            this.resolvedIntent = Preconditions.checkNotNull(resolvedIntent);
-            this.remoteAction = Preconditions.checkNotNull(remoteAction);
+            this.resolvedIntent = Objects.requireNonNull(resolvedIntent);
+            this.remoteAction = Objects.requireNonNull(remoteAction);
         }
     }
 
diff --git a/core/java/android/view/textclassifier/intent/TemplateClassificationIntentFactory.java b/core/java/android/view/textclassifier/intent/TemplateClassificationIntentFactory.java
index 111fc6a..aef4bd6 100644
--- a/core/java/android/view/textclassifier/intent/TemplateClassificationIntentFactory.java
+++ b/core/java/android/view/textclassifier/intent/TemplateClassificationIntentFactory.java
@@ -30,6 +30,7 @@
 import java.time.Instant;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Creates intents based on {@link RemoteActionTemplate} objects for a ClassificationResult.
@@ -44,8 +45,8 @@
 
     public TemplateClassificationIntentFactory(TemplateIntentFactory templateIntentFactory,
             ClassificationIntentFactory fallback) {
-        mTemplateIntentFactory = Preconditions.checkNotNull(templateIntentFactory);
-        mFallback = Preconditions.checkNotNull(fallback);
+        mTemplateIntentFactory = Objects.requireNonNull(templateIntentFactory);
+        mFallback = Objects.requireNonNull(fallback);
     }
 
     /**
diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
index 157c435..7dbcbf9 100644
--- a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
+++ b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
@@ -19,7 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.metrics.LogMaker;
 import android.util.Log;
@@ -105,14 +105,14 @@
     public SmartSelectionEventTracker(@NonNull Context context, @WidgetType int widgetType) {
         mWidgetType = widgetType;
         mWidgetVersion = null;
-        mContext = Preconditions.checkNotNull(context);
+        mContext = Objects.requireNonNull(context);
     }
 
     public SmartSelectionEventTracker(
             @NonNull Context context, @WidgetType int widgetType, @Nullable String widgetVersion) {
         mWidgetType = widgetType;
         mWidgetVersion = widgetVersion;
-        mContext = Preconditions.checkNotNull(context);
+        mContext = Objects.requireNonNull(context);
     }
 
     /**
@@ -122,7 +122,7 @@
      */
     @UnsupportedAppUsage(trackingBug = 136637107)
     public void logEvent(@NonNull SelectionEvent event) {
-        Preconditions.checkNotNull(event);
+        Objects.requireNonNull(event);
 
         if (event.mEventType != SelectionEvent.EventType.SELECTION_STARTED && mSessionId == null
                 && DEBUG_LOG_ENABLED) {
@@ -435,8 +435,8 @@
             mStart = start;
             mEnd = end;
             mEventType = eventType;
-            mEntityType = Preconditions.checkNotNull(entityType);
-            mVersionTag = Preconditions.checkNotNull(versionTag);
+            mEntityType = Objects.requireNonNull(entityType);
+            mVersionTag = Objects.requireNonNull(versionTag);
         }
 
         /**
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index f553ca5..afddaa2 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -16,7 +16,7 @@
 
 package android.view.textservice;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index 9ff64d9..acb35d6 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -18,8 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.RemoteException;
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 7e06719..fafe813 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -17,7 +17,7 @@
 package android.webkit;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/core/java/android/webkit/ConsoleMessage.java b/core/java/android/webkit/ConsoleMessage.java
index e548497..5474557 100644
--- a/core/java/android/webkit/ConsoleMessage.java
+++ b/core/java/android/webkit/ConsoleMessage.java
@@ -16,7 +16,7 @@
 
 package android.webkit;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 
 /**
diff --git a/core/java/android/webkit/JsResult.java b/core/java/android/webkit/JsResult.java
index 5bf6aab..448db58e 100644
--- a/core/java/android/webkit/JsResult.java
+++ b/core/java/android/webkit/JsResult.java
@@ -17,7 +17,7 @@
 package android.webkit;
 
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * An instance of this class is passed as a parameter in various {@link WebChromeClient} action
diff --git a/core/java/android/webkit/PluginData.java b/core/java/android/webkit/PluginData.java
index 8aeeb1c..c9a1960 100644
--- a/core/java/android/webkit/PluginData.java
+++ b/core/java/android/webkit/PluginData.java
@@ -16,7 +16,8 @@
 
 package android.webkit;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.io.InputStream;
 import java.util.Map;
 
diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
index 5d704cb0..844b156 100644
--- a/core/java/android/webkit/URLUtil.java
+++ b/core/java/android/webkit/URLUtil.java
@@ -17,7 +17,7 @@
 package android.webkit;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.net.ParseException;
 import android.net.Uri;
 import android.net.WebAddress;
diff --git a/core/java/android/webkit/UrlInterceptHandler.java b/core/java/android/webkit/UrlInterceptHandler.java
index f23aae6..a48e107 100644
--- a/core/java/android/webkit/UrlInterceptHandler.java
+++ b/core/java/android/webkit/UrlInterceptHandler.java
@@ -17,9 +17,8 @@
 package android.webkit;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.webkit.CacheManager.CacheResult;
-import android.webkit.PluginData;
 
 import java.util.Map;
 
diff --git a/core/java/android/webkit/UrlInterceptRegistry.java b/core/java/android/webkit/UrlInterceptRegistry.java
index eeb28d7..c9dee00 100644
--- a/core/java/android/webkit/UrlInterceptRegistry.java
+++ b/core/java/android/webkit/UrlInterceptRegistry.java
@@ -17,10 +17,8 @@
 package android.webkit;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.webkit.CacheManager.CacheResult;
-import android.webkit.PluginData;
-import android.webkit.UrlInterceptHandler;
 
 import java.util.Iterator;
 import java.util.LinkedList;
diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java
index 7c8f33e..219523b 100644
--- a/core/java/android/webkit/WebResourceResponse.java
+++ b/core/java/android/webkit/WebResourceResponse.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import java.io.InputStream;
 import java.io.StringBufferInputStream;
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 2895621..2d27a78 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -19,7 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 
 import java.lang.annotation.ElementType;
diff --git a/core/java/android/webkit/WebSyncManager.java b/core/java/android/webkit/WebSyncManager.java
index e44d6eb..7046c51 100644
--- a/core/java/android/webkit/WebSyncManager.java
+++ b/core/java/android/webkit/WebSyncManager.java
@@ -16,7 +16,7 @@
 
 package android.webkit;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 
 /**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4b47927..f9a713a 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -21,8 +21,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.Widget;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index f5657df..df86926 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -19,10 +19,10 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
 import android.app.Application;
 import android.app.ResourcesManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.res.Resources;
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 678a252..941af6e 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -17,10 +17,10 @@
 package android.webkit;
 
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.Application;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java
index 7e00cde..6629fdc4 100644
--- a/core/java/android/webkit/WebViewProviderInfo.java
+++ b/core/java/android/webkit/WebViewProviderInfo.java
@@ -17,7 +17,7 @@
 package android.webkit;
 
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.Signature;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/webkit/WebViewProviderResponse.java b/core/java/android/webkit/WebViewProviderResponse.java
index 5622abe..b58cc4bb 100644
--- a/core/java/android/webkit/WebViewProviderResponse.java
+++ b/core/java/android/webkit/WebViewProviderResponse.java
@@ -16,7 +16,7 @@
 
 package android.webkit;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.PackageInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/webkit/WebViewUpdateService.java b/core/java/android/webkit/WebViewUpdateService.java
index 12d3221..9152b43 100644
--- a/core/java/android/webkit/WebViewUpdateService.java
+++ b/core/java/android/webkit/WebViewUpdateService.java
@@ -17,7 +17,7 @@
 package android.webkit;
 
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.RemoteException;
 
 /**
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 6d60366..4752ead 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -20,7 +20,7 @@
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index bbcba2e..11a6acf 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index cfb93ec..aa3590a 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -22,7 +22,7 @@
 import android.animation.PropertyValuesHolder;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 7e58622..3a74356 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -18,7 +18,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.drawable.Drawable;
diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java
index f5bf759..d87bdf4 100644
--- a/core/java/android/widget/ActivityChooserModel.java
+++ b/core/java/android/widget/ActivityChooserModel.java
@@ -16,8 +16,8 @@
 
 package android.widget;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 89ea074..aa18d57 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -17,7 +17,7 @@
 package android.widget;
 
 import android.annotation.StringRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index c55f7d6..5265840 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.database.DataSetObserver;
 import android.os.Build;
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 67a70b4..d165bd0 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -16,7 +16,7 @@
 
 package android.widget;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index f7225d0..de9f76d 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -21,7 +21,7 @@
 import android.annotation.LayoutRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.util.Log;
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 8785251..8d9ae58 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -18,7 +18,7 @@
 
 import android.annotation.DrawableRes;
 import android.annotation.IntDef;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/BaseAdapter.java b/core/java/android/widget/BaseAdapter.java
index 7b9365b..27cf9a6 100644
--- a/core/java/android/widget/BaseAdapter.java
+++ b/core/java/android/widget/BaseAdapter.java
@@ -17,7 +17,7 @@
 package android.widget;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.database.DataSetObservable;
 import android.database.DataSetObserver;
 import android.view.View;
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index b552aa6..4b2f738 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -23,8 +23,8 @@
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.Widget;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 8b70f41..422d2d3 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -19,7 +19,7 @@
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index ac2336c..fbd29ba 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -309,6 +309,9 @@
 
         // Refresh display with current params
         refreshDrawableState();
+        // Default state is derived from on/off-text, so state has to be updated when on/off-text
+        // are updated.
+        setDefaultStateDescritption();
         setChecked(isChecked());
     }
 
diff --git a/core/java/android/widget/ToggleButton.java b/core/java/android/widget/ToggleButton.java
index d47405b..59e0c16 100644
--- a/core/java/android/widget/ToggleButton.java
+++ b/core/java/android/widget/ToggleButton.java
@@ -58,6 +58,9 @@
         mTextOff = a.getText(com.android.internal.R.styleable.ToggleButton_textOff);
         mDisabledAlpha = a.getFloat(com.android.internal.R.styleable.ToggleButton_disabledAlpha, 0.5f);
         syncTextState();
+        // Default state is derived from on/off-text, so state has to be updated when on/off-text
+        // are updated.
+        setDefaultStateDescritption();
         a.recycle();
     }
 
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index c64b705..08022e9 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 package com.android.internal.app;
+
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -23,10 +24,10 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.PagerAdapter;
-
-import com.android.internal.util.Preconditions;
 import com.android.internal.widget.ViewPager;
 
+import java.util.Objects;
+
 /**
  * Skeletal {@link PagerAdapter} implementation of a work or personal profile page for
  * intent resolution (including share sheet).
@@ -42,7 +43,7 @@
     private int mCurrentPage;
 
     AbstractMultiProfilePagerAdapter(Context context, int currentPage) {
-        mContext = Preconditions.checkNotNull(context);
+        mContext = Objects.requireNonNull(context);
         mCurrentPage = currentPage;
     }
 
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index f361784..48853bf 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -859,14 +859,21 @@
         return new PackageMonitor() {
             @Override
             public void onSomePackagesChanged() {
-                // TODO(arangelov): Dispatch this to all adapters when we have the helper methods
-                // in a follow-up CL
-                mChooserMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();
-                updateProfileViewButton();
+                handlePackagesChanged();
             }
         };
     }
 
+    /**
+     * Update UI to reflect changes in data.
+     */
+    public void handlePackagesChanged() {
+        // TODO(arangelov): Dispatch this to all adapters when we have the helper methods
+        // in a follow-up CL
+        mChooserMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();
+        updateProfileViewButton();
+    }
+
     private void onCopyButtonClicked(View v) {
         Intent targetIntent = getTargetIntent();
         if (targetIntent == null) {
diff --git a/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java b/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java
index bdbe210..21efc78 100644
--- a/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java
+++ b/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java
@@ -116,7 +116,7 @@
                 pinComponent(mTargetInfos.get(which).getResolvedComponentName());
             }
             // Force the chooser to requery and resort things
-            getActivity().recreate();
+            ((ChooserActivity) getActivity()).handlePackagesChanged();
         } else {
             // Last item in dialog is App Info
             Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index 6e9c4c3..6b76a0f 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -28,9 +28,9 @@
 import android.util.Slog;
 
 import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.Preconditions;
 
 import java.util.HashSet;
+import java.util.Objects;
 
 /**
  * Helper class for monitoring the state of packages: adding, removing,
@@ -93,7 +93,7 @@
             throw new IllegalStateException("Already registered");
         }
         mRegisteredContext = context;
-        mRegisteredHandler = Preconditions.checkNotNull(handler);
+        mRegisteredHandler = Objects.requireNonNull(handler);
         if (user != null) {
             context.registerReceiverAsUser(this, user, sPackageFilt, null, mRegisteredHandler);
             context.registerReceiverAsUser(this, user, sNonDataFilt, null, mRegisteredHandler);
diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java
index 98d679e..857377a 100644
--- a/core/java/com/android/internal/infra/ServiceConnector.java
+++ b/core/java/com/android/internal/infra/ServiceConnector.java
@@ -32,7 +32,6 @@
 import android.util.DebugUtils;
 import android.util.Log;
 
-import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.pooled.PooledLambda;
 
 import java.io.PrintWriter;
@@ -40,6 +39,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 import java.util.Queue;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionStage;
@@ -352,7 +352,7 @@
         @Override
         public <R> CompletionAwareJob<I, R> postForResult(@NonNull Job<I, R> job) {
             CompletionAwareJob<I, R> task = new CompletionAwareJob<>();
-            task.mDelegate = Preconditions.checkNotNull(job);
+            task.mDelegate = Objects.requireNonNull(job);
             enqueue(task);
             return task;
         }
@@ -360,7 +360,7 @@
         @Override
         public <R> AndroidFuture<R> postAsync(@NonNull Job<I, CompletableFuture<R>> job) {
             CompletionAwareJob<I, R> task = new CompletionAwareJob<>();
-            task.mDelegate = Preconditions.checkNotNull((Job) job);
+            task.mDelegate = Objects.requireNonNull((Job) job);
             task.mAsync = true;
             enqueue(task);
             return task;
diff --git a/core/java/com/android/internal/infra/WhitelistHelper.java b/core/java/com/android/internal/infra/WhitelistHelper.java
index 9d653ba..b1d85f7 100644
--- a/core/java/com/android/internal/infra/WhitelistHelper.java
+++ b/core/java/com/android/internal/infra/WhitelistHelper.java
@@ -23,10 +23,9 @@
 import android.util.ArraySet;
 import android.util.Log;
 
-import com.android.internal.util.Preconditions;
-
 import java.io.PrintWriter;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Helper class for keeping track of whitelisted packages/activities.
@@ -107,7 +106,7 @@
      * Returns {@code true} if the entire package is whitelisted.
      */
     public boolean isWhitelisted(@NonNull String packageName) {
-        Preconditions.checkNotNull(packageName);
+        Objects.requireNonNull(packageName);
 
         if (mWhitelistedPackages == null) return false;
 
@@ -119,7 +118,7 @@
      * Returns {@code true} if the specified activity is whitelisted.
      */
     public boolean isWhitelisted(@NonNull ComponentName componentName) {
-        Preconditions.checkNotNull(componentName);
+        Objects.requireNonNull(componentName);
 
         final String packageName = componentName.getPackageName();
         final ArraySet<ComponentName> whitelistedComponents = getWhitelistedComponents(packageName);
@@ -136,7 +135,7 @@
      */
     @Nullable
     public ArraySet<ComponentName> getWhitelistedComponents(@NonNull String packageName) {
-        Preconditions.checkNotNull(packageName);
+        Objects.requireNonNull(packageName);
 
         return mWhitelistedPackages == null ? null : mWhitelistedPackages.get(packageName);
     }
diff --git a/core/java/com/android/internal/os/FuseAppLoop.java b/core/java/com/android/internal/os/FuseAppLoop.java
index d08930b..a22615b 100644
--- a/core/java/com/android/internal/os/FuseAppLoop.java
+++ b/core/java/com/android/internal/os/FuseAppLoop.java
@@ -32,6 +32,7 @@
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.ThreadFactory;
 
 public class FuseAppLoop implements Handler.Callback {
@@ -92,8 +93,8 @@
     public int registerCallback(@NonNull ProxyFileDescriptorCallback callback,
             @NonNull Handler handler) throws FuseUnavailableMountException {
         synchronized (mLock) {
-            Preconditions.checkNotNull(callback);
-            Preconditions.checkNotNull(handler);
+            Objects.requireNonNull(callback);
+            Objects.requireNonNull(handler);
             Preconditions.checkState(
                     mCallbackMap.size() < Integer.MAX_VALUE - MIN_INODE, "Too many opened files.");
             Preconditions.checkArgument(
@@ -333,8 +334,8 @@
         boolean opened;
 
         CallbackEntry(ProxyFileDescriptorCallback callback, Handler handler) {
-            this.callback = Preconditions.checkNotNull(callback);
-            this.handler = Preconditions.checkNotNull(handler);
+            this.callback = Objects.requireNonNull(callback);
+            this.handler = Objects.requireNonNull(handler);
         }
 
         long getThreadId() {
@@ -368,7 +369,7 @@
 
         void stopUsing(long threadId) {
             final BytesMapEntry entry = mEntries.get(threadId);
-            Preconditions.checkNotNull(entry);
+            Objects.requireNonNull(entry);
             entry.counter--;
             if (entry.counter <= 0) {
                 mEntries.remove(threadId);
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 2b988c1..c390a51 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -151,6 +151,9 @@
     /** Make the new process have top application priority. */
     public static final String START_AS_TOP_APP_ARG = "--is-top-app";
 
+    /** List of packages with the same uid, and its app data info: volume uuid and inode. */
+    public static final String PKG_DATA_INFO_MAP = "--pkg-data-info-map";
+
     /**
      * An extraArg passed when a zygote process is forking a child-zygote, specifying a name
      * in the abstract socket namespace. This socket name is what the new child zygote
@@ -254,6 +257,8 @@
      * @param instructionSet null-ok the instruction set to use.
      * @param appDataDir null-ok the data directory of the app.
      * @param isTopApp true if the process is for top (high priority) application.
+     * @param pkgDataInfoList A list that stores related packages and its app data
+     * info: volume uuid and inode.
      *
      * @return 0 if this is the child, pid of the child
      * if this is the parent, or -1 on error.
@@ -261,12 +266,13 @@
     static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
             int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
             int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
-            int targetSdkVersion, boolean isTopApp) {
+            int targetSdkVersion, boolean isTopApp, String[] pkgDataInfoList) {
         ZygoteHooks.preFork();
 
         int pid = nativeForkAndSpecialize(
                 uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
-                fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp);
+                fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp,
+                pkgDataInfoList);
         // Enable tracing as soon as possible for the child process.
         if (pid == 0) {
             Zygote.disableExecuteOnly(targetSdkVersion);
@@ -286,7 +292,7 @@
     private static native int nativeForkAndSpecialize(int uid, int gid, int[] gids,
             int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
             int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
-            String appDataDir, boolean isTopApp);
+            String appDataDir, boolean isTopApp, String[] pkgDataInfoList);
 
     /**
      * Specialize an unspecialized app process.  The current VM must have been started
@@ -309,12 +315,16 @@
      * @param instructionSet null-ok  The instruction set to use.
      * @param appDataDir null-ok  The data directory of the app.
      * @param isTopApp  True if the process is for top (high priority) application.
+     * @param pkgDataInfoList A list that stores related packages and its app data
+     * info: volume uuid and inode.
      */
     private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags,
             int[][] rlimits, int mountExternal, String seInfo, String niceName,
-            boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp) {
+            boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
+            String[] pkgDataInfoList) {
         nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
-                niceName, startChildZygote, instructionSet, appDataDir, isTopApp);
+                niceName, startChildZygote, instructionSet, appDataDir, isTopApp,
+                pkgDataInfoList);
 
         // Enable tracing as soon as possible for the child process.
         Trace.setTracingEnabled(true, runtimeFlags);
@@ -336,7 +346,8 @@
 
     private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids,
             int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
-            boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp);
+            boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
+            String[] pkgDataInfoList);
 
     /**
      * Called to do any initialization before starting an application.
@@ -665,7 +676,8 @@
             specializeAppProcess(args.mUid, args.mGid, args.mGids,
                                  args.mRuntimeFlags, rlimits, args.mMountExternal,
                                  args.mSeInfo, args.mNiceName, args.mStartChildZygote,
-                                 args.mInstructionSet, args.mAppDataDir, args.mIsTopApp);
+                                 args.mInstructionSet, args.mAppDataDir, args.mIsTopApp,
+                                 args.mPkgDataInfoList);
 
             disableExecuteOnly(args.mTargetSdkVersion);
 
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 54b2a20..d349954 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -221,6 +221,12 @@
     long[] mDisabledCompatChanges = null;
 
     /**
+     * A list that stores all related packages and its data info: volume uuid and inode.
+     * Null if it does need to do app data isolation.
+     */
+    String[] mPkgDataInfoList;
+
+    /**
      * Constructs instance and parses args
      *
      * @param args zygote command-line args
@@ -437,6 +443,8 @@
                 for (int i = 0; i < length; i++) {
                     mDisabledCompatChanges[i] = Long.parseLong(params[i]);
                 }
+            } else if (arg.startsWith(Zygote.PKG_DATA_INFO_MAP)) {
+                mPkgDataInfoList = getAssignmentList(arg);
             } else {
                 break;
             }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 3111b6f..9c6a288 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -258,7 +258,7 @@
                 parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
                 parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
                 parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion,
-                parsedArgs.mIsTopApp);
+                parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList);
 
         try {
             if (pid == 0) {
diff --git a/core/java/com/android/internal/util/FileRotator.java b/core/java/com/android/internal/util/FileRotator.java
index f8885a2..3ca3320 100644
--- a/core/java/com/android/internal/util/FileRotator.java
+++ b/core/java/com/android/internal/util/FileRotator.java
@@ -27,6 +27,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.Objects;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
@@ -96,8 +97,8 @@
      *            may be deleted.
      */
     public FileRotator(File basePath, String prefix, long rotateAgeMillis, long deleteAgeMillis) {
-        mBasePath = Preconditions.checkNotNull(basePath);
-        mPrefix = Preconditions.checkNotNull(prefix);
+        mBasePath = Objects.requireNonNull(basePath);
+        mPrefix = Objects.requireNonNull(prefix);
         mRotateAgeMillis = rotateAgeMillis;
         mDeleteAgeMillis = deleteAgeMillis;
 
@@ -406,7 +407,7 @@
         public long endMillis;
 
         public FileInfo(String prefix) {
-            this.prefix = Preconditions.checkNotNull(prefix);
+            this.prefix = Objects.requireNonNull(prefix);
         }
 
         /**
diff --git a/core/java/com/android/internal/util/ObjectUtils.java b/core/java/com/android/internal/util/ObjectUtils.java
index a477688..5568d91 100644
--- a/core/java/com/android/internal/util/ObjectUtils.java
+++ b/core/java/com/android/internal/util/ObjectUtils.java
@@ -19,6 +19,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import java.util.Objects;
 
 /** @hide */
 public class ObjectUtils {
@@ -32,7 +33,7 @@
      */
     @NonNull
     public static <T> T firstNotNull(@Nullable T a, @NonNull T b) {
-        return a != null ? a : Preconditions.checkNotNull(b);
+        return a != null ? a : Objects.requireNonNull(b);
     }
 
     /**
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
index c7502ef..8446bbd 100755
--- a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
@@ -25,7 +25,6 @@
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.BitUtils;
-import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.DecConsumer;
 import com.android.internal.util.function.DecFunction;
 import com.android.internal.util.function.DecPredicate;
@@ -545,7 +544,7 @@
                             + ", k = " + k
                             + ")");
         }
-        r.mFunc = Preconditions.checkNotNull(func);
+        r.mFunc = Objects.requireNonNull(func);
         r.setFlags(MASK_FUNC_TYPE, LambdaType.encode(fNumArgs, fReturnType));
         r.setFlags(MASK_EXPOSED_AS, LambdaType.encode(numPlaceholders, fReturnType));
         if (ArrayUtils.size(r.mArgs) < fNumArgs) r.mArgs = new Object[fNumArgs];
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 54dede6..f9e98e7 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -33,11 +33,11 @@
 
 import android.widget.PopupWindow;
 import com.android.internal.R;
-import com.android.internal.util.Preconditions;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.widget.FloatingToolbar;
 
 import java.util.Arrays;
+import java.util.Objects;
 
 public final class FloatingActionMode extends ActionMode {
 
@@ -84,8 +84,8 @@
     public FloatingActionMode(
             Context context, ActionMode.Callback2 callback,
             View originatingView, FloatingToolbar floatingToolbar) {
-        mContext = Preconditions.checkNotNull(context);
-        mCallback = Preconditions.checkNotNull(callback);
+        mContext = Objects.requireNonNull(context);
+        mCallback = Objects.requireNonNull(callback);
         mMenu = new MenuBuilder(context).setDefaultShowAsAction(
                 MenuItem.SHOW_AS_ACTION_IF_ROOM);
         setType(ActionMode.TYPE_FLOATING);
@@ -107,14 +107,14 @@
         mViewRectOnScreen = new Rect();
         mPreviousViewRectOnScreen = new Rect();
         mScreenRect = new Rect();
-        mOriginatingView = Preconditions.checkNotNull(originatingView);
+        mOriginatingView = Objects.requireNonNull(originatingView);
         mOriginatingView.getLocationOnScreen(mViewPositionOnScreen);
         // Allow the content rect to overshoot a little bit beyond the
         // bottom view bound if necessary.
         mBottomAllowance = context.getResources()
                 .getDimensionPixelSize(R.dimen.content_rect_bottom_clip_allowance);
         mDisplaySize = new Point();
-        setFloatingToolbar(Preconditions.checkNotNull(floatingToolbar));
+        setFloatingToolbar(Objects.requireNonNull(floatingToolbar));
     }
 
     private void setFloatingToolbar(FloatingToolbar floatingToolbar) {
@@ -328,7 +328,7 @@
         private long mLastShowTime;
 
         public FloatingToolbarVisibilityHelper(FloatingToolbar toolbar) {
-            mToolbar = Preconditions.checkNotNull(toolbar);
+            mToolbar = Objects.requireNonNull(toolbar);
         }
 
         public void activate() {
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index d618f67..1979e4f 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -35,7 +35,7 @@
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.PopupWindow.OnDismissListener;
 
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
 
 /**
  * A standard menu popup in which when a submenu is opened, it replaces its parent menu in the
@@ -113,7 +113,7 @@
 
     public StandardMenuPopup(Context context, MenuBuilder menu, View anchorView, int popupStyleAttr,
             int popupStyleRes, boolean overflowOnly) {
-        mContext = Preconditions.checkNotNull(context);
+        mContext = Objects.requireNonNull(context);
         mMenu = menu;
         mOverflowOnly = overflowOnly;
         final LayoutInflater inflater = LayoutInflater.from(context);
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index bb7423a..d7611dc 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -155,7 +155,7 @@
         // TODO(b/65172902): Pass context in constructor when DecorView (and other callers)
         // supports multi-display.
         mContext = applyDefaultTheme(window.getContext());
-        mWindow = Preconditions.checkNotNull(window);
+        mWindow = Objects.requireNonNull(window);
         mPopup = new FloatingToolbarPopup(mContext, window.getDecorView());
     }
 
@@ -165,7 +165,7 @@
      * toolbar.
      */
     public FloatingToolbar setMenu(Menu menu) {
-        mMenu = Preconditions.checkNotNull(menu);
+        mMenu = Objects.requireNonNull(menu);
         return this;
     }
 
@@ -189,7 +189,7 @@
      * toolbar.
      */
     public FloatingToolbar setContentRect(Rect rect) {
-        mContentRect.set(Preconditions.checkNotNull(rect));
+        mContentRect.set(Objects.requireNonNull(rect));
         return this;
     }
 
@@ -457,8 +457,8 @@
          *      from.
          */
         public FloatingToolbarPopup(Context context, View parent) {
-            mParent = Preconditions.checkNotNull(parent);
-            mContext = Preconditions.checkNotNull(context);
+            mParent = Objects.requireNonNull(parent);
+            mContext = Objects.requireNonNull(context);
             mContentContainer = createContentContainer(context);
             mPopupWindow = createPopupWindow(mContentContainer);
             mMarginHorizontal = parent.getResources()
@@ -578,7 +578,7 @@
          * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
          */
         public void show(Rect contentRectOnScreen) {
-            Preconditions.checkNotNull(contentRectOnScreen);
+            Objects.requireNonNull(contentRectOnScreen);
 
             if (isShowing()) {
                 return;
@@ -650,7 +650,7 @@
          * This is a no-op if this popup is not showing.
          */
         public void updateCoordinates(Rect contentRectOnScreen) {
-            Preconditions.checkNotNull(contentRectOnScreen);
+            Objects.requireNonNull(contentRectOnScreen);
 
             if (!isShowing() || !mPopupWindow.isShowing()) {
                 return;
@@ -1134,11 +1134,11 @@
          * Sets the touchable region of this popup to be the area occupied by its content.
          */
         private void setContentAreaAsTouchableSurface() {
-            Preconditions.checkNotNull(mMainPanelSize);
+            Objects.requireNonNull(mMainPanelSize);
             final int width;
             final int height;
             if (mIsOverflowOpen) {
-                Preconditions.checkNotNull(mOverflowPanelSize);
+                Objects.requireNonNull(mOverflowPanelSize);
                 width = mOverflowPanelSize.getWidth();
                 height = mOverflowPanelSize.getHeight();
             } else {
@@ -1183,7 +1183,7 @@
          */
         public List<MenuItem> layoutMainPanelItems(
                 List<MenuItem> menuItems, final int toolbarWidth) {
-            Preconditions.checkNotNull(menuItems);
+            Objects.requireNonNull(menuItems);
 
             int availableWidth = toolbarWidth;
 
@@ -1555,7 +1555,7 @@
             private final FloatingToolbarPopup mPopup;
 
             OverflowPanel(FloatingToolbarPopup popup) {
-                super(Preconditions.checkNotNull(popup).mContext);
+                super(Objects.requireNonNull(popup).mContext);
                 this.mPopup = popup;
                 setScrollBarDefaultDelayBeforeFade(ViewConfiguration.getScrollDefaultDelay() * 3);
                 setScrollIndicators(View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM);
@@ -1616,7 +1616,7 @@
             private final Context mContext;
 
             public OverflowPanelViewHelper(Context context, int iconTextSpacing) {
-                mContext = Preconditions.checkNotNull(context);
+                mContext = Objects.requireNonNull(context);
                 mIconTextSpacing = iconTextSpacing;
                 mSidePadding = context.getResources()
                         .getDimensionPixelSize(R.dimen.floating_toolbar_overflow_side_padding);
@@ -1624,7 +1624,7 @@
             }
 
             public View getView(MenuItem menuItem, int minimumWidth, View convertView) {
-                Preconditions.checkNotNull(menuItem);
+                Objects.requireNonNull(menuItem);
                 if (convertView != null) {
                     updateMenuItemButton(
                             convertView, menuItem, mIconTextSpacing, shouldShowIcon(menuItem));
diff --git a/core/java/com/android/internal/widget/LockscreenCredential.java b/core/java/com/android/internal/widget/LockscreenCredential.java
index f456349..9b87dd2 100644
--- a/core/java/com/android/internal/widget/LockscreenCredential.java
+++ b/core/java/com/android/internal/widget/LockscreenCredential.java
@@ -33,6 +33,7 @@
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * A class representing a lockscreen credential. It can be either an empty password, a pattern
@@ -67,7 +68,7 @@
      * minimize the number of extra copies introduced.
      */
     private LockscreenCredential(int type, byte[] credential) {
-        Preconditions.checkNotNull(credential);
+        Objects.requireNonNull(credential);
         if (type == CREDENTIAL_TYPE_NONE) {
             Preconditions.checkArgument(credential.length == 0);
         } else {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index a2f6a62..7cd18a2 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -110,7 +110,6 @@
                 "android_view_InputEventReceiver.cpp",
                 "android_view_InputEventSender.cpp",
                 "android_view_InputQueue.cpp",
-                "android_view_FrameMetricsObserver.cpp",
                 "android_view_KeyCharacterMap.cpp",
                 "android_view_KeyEvent.cpp",
                 "android_view_MotionEvent.cpp",
@@ -208,6 +207,7 @@
 
             static_libs: [
                 "libasync_safe",
+                "libdmabufinfo",
                 "libgif",
                 "libseccomp_policy",
                 "libgrallocusage",
@@ -351,6 +351,7 @@
         "android_graphics_ColorSpace.cpp",
         "android_graphics_drawable_AnimatedVectorDrawable.cpp",
         "android_graphics_drawable_VectorDrawable.cpp",
+        "android_graphics_HardwareRendererObserver.cpp",
         "android_graphics_Picture.cpp",
         "android_nio_utils.cpp",
         "android_view_DisplayListCanvas.cpp",
diff --git a/core/jni/android/graphics/apex/jni_runtime.cpp b/core/jni/android/graphics/apex/jni_runtime.cpp
index 7f9bac0..1f66153 100644
--- a/core/jni/android/graphics/apex/jni_runtime.cpp
+++ b/core/jni/android/graphics/apex/jni_runtime.cpp
@@ -52,6 +52,7 @@
 extern int register_android_graphics_ColorSpace(JNIEnv* env);
 extern int register_android_graphics_DrawFilter(JNIEnv* env);
 extern int register_android_graphics_FontFamily(JNIEnv* env);
+extern int register_android_graphics_HardwareRendererObserver(JNIEnv* env);
 extern int register_android_graphics_Matrix(JNIEnv* env);
 extern int register_android_graphics_Paint(JNIEnv* env);
 extern int register_android_graphics_Path(JNIEnv* env);
@@ -71,7 +72,6 @@
 
 extern int register_android_util_PathParser(JNIEnv* env);
 extern int register_android_view_DisplayListCanvas(JNIEnv* env);
-extern int register_android_view_FrameMetricsObserver(JNIEnv* env);
 extern int register_android_view_RenderNode(JNIEnv* env);
 extern int register_android_view_TextureLayer(JNIEnv* env);
 extern int register_android_view_ThreadedRenderer(JNIEnv* env);
@@ -105,6 +105,7 @@
     REG_JNI(register_android_graphics_ColorFilter),
     REG_JNI(register_android_graphics_DrawFilter),
     REG_JNI(register_android_graphics_FontFamily),
+    REG_JNI(register_android_graphics_HardwareRendererObserver),
     REG_JNI(register_android_graphics_ImageDecoder),
     REG_JNI(register_android_graphics_drawable_AnimatedImageDrawable),
     REG_JNI(register_android_graphics_Interpolator),
@@ -135,7 +136,6 @@
     REG_JNI(register_android_util_PathParser),
     REG_JNI(register_android_view_RenderNode),
     REG_JNI(register_android_view_DisplayListCanvas),
-    REG_JNI(register_android_view_FrameMetricsObserver),
     REG_JNI(register_android_view_TextureLayer),
     REG_JNI(register_android_view_ThreadedRenderer),
 };
diff --git a/core/jni/android_graphics_HardwareRendererObserver.cpp b/core/jni/android_graphics_HardwareRendererObserver.cpp
new file mode 100644
index 0000000..89b77b0
--- /dev/null
+++ b/core/jni/android_graphics_HardwareRendererObserver.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 "android_graphics_HardwareRendererObserver.h"
+
+#include "core_jni_helpers.h"
+#include "nativehelper/jni_macros.h"
+
+#include <array>
+
+namespace android {
+
+struct {
+    jmethodID callback;
+} gHardwareRendererObserverClassInfo;
+
+static JNIEnv* getenv(JavaVM* vm) {
+    JNIEnv* env;
+    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
+    }
+    return env;
+}
+
+HardwareRendererObserver::HardwareRendererObserver(JavaVM *vm, jobject observer) : mVm(vm) {
+    mObserverWeak = getenv(mVm)->NewWeakGlobalRef(observer);
+    LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr,
+            "unable to create frame stats observer reference");
+}
+
+HardwareRendererObserver::~HardwareRendererObserver() {
+    JNIEnv* env = getenv(mVm);
+    env->DeleteWeakGlobalRef(mObserverWeak);
+}
+
+bool HardwareRendererObserver::getNextBuffer(JNIEnv* env, jlongArray metrics, int* dropCount) {
+    jsize bufferSize = env->GetArrayLength(reinterpret_cast<jarray>(metrics));
+    LOG_ALWAYS_FATAL_IF(bufferSize != HardwareRendererObserver::kBufferSize,
+                        "Mismatched Java/Native FrameMetrics data format.");
+
+    FrameMetricsNotification& elem = mRingBuffer[mNextInQueue];
+    if (elem.hasData.load()) {
+        env->SetLongArrayRegion(metrics, 0, kBufferSize, elem.buffer);
+        *dropCount = elem.dropCount;
+        mNextInQueue = (mNextInQueue + 1) % kRingSize;
+        elem.hasData = false;
+        return true;
+    }
+
+    return false;
+}
+
+void HardwareRendererObserver::notify(const int64_t* stats) {
+    FrameMetricsNotification& elem = mRingBuffer[mNextFree];
+
+    if (!elem.hasData.load()) {
+        memcpy(elem.buffer, stats, kBufferSize * sizeof(stats[0]));
+
+        elem.dropCount = mDroppedReports;
+        mDroppedReports = 0;
+        mNextFree = (mNextFree + 1) % kRingSize;
+        elem.hasData = true;
+
+        JNIEnv* env = getenv(mVm);
+        jobject target = env->NewLocalRef(mObserverWeak);
+        if (target != nullptr) {
+            env->CallVoidMethod(target, gHardwareRendererObserverClassInfo.callback);
+            env->DeleteLocalRef(target);
+        }
+    } else {
+        mDroppedReports++;
+    }
+}
+
+static jlong android_graphics_HardwareRendererObserver_createObserver(JNIEnv* env,
+                                                                      jobject observerObj) {
+    JavaVM* vm = nullptr;
+    if (env->GetJavaVM(&vm) != JNI_OK) {
+        LOG_ALWAYS_FATAL("Unable to get Java VM");
+        return 0;
+    }
+
+    HardwareRendererObserver* observer = new HardwareRendererObserver(vm, observerObj);
+    return reinterpret_cast<jlong>(observer);
+}
+
+static jint android_graphics_HardwareRendererObserver_getNextBuffer(JNIEnv* env, jobject,
+                                                                    jlong observerPtr,
+                                                                    jlongArray metrics) {
+    HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr);
+    int dropCount = 0;
+    if (observer->getNextBuffer(env, metrics, &dropCount)) {
+        return dropCount;
+    } else {
+        return -1;
+    }
+}
+
+static const std::array gMethods = {
+    MAKE_JNI_NATIVE_METHOD("nCreateObserver", "()J",
+                           android_graphics_HardwareRendererObserver_createObserver),
+    MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I",
+                           android_graphics_HardwareRendererObserver_getNextBuffer),
+};
+
+int register_android_graphics_HardwareRendererObserver(JNIEnv* env) {
+
+    jclass observerClass = FindClassOrDie(env, "android/graphics/HardwareRendererObserver");
+    gHardwareRendererObserverClassInfo.callback = GetMethodIDOrDie(env, observerClass,
+                                                                   "notifyDataAvailable", "()V");
+
+    return RegisterMethodsOrDie(env, "android/graphics/HardwareRendererObserver",
+                                gMethods.data(), gMethods.size());
+
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/core/jni/android_graphics_HardwareRendererObserver.h b/core/jni/android_graphics_HardwareRendererObserver.h
new file mode 100644
index 0000000..62111fd
--- /dev/null
+++ b/core/jni/android_graphics_HardwareRendererObserver.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+
+#include <FrameInfo.h>
+#include <FrameMetricsObserver.h>
+
+namespace android {
+
+/*
+ * Implements JNI layer for hwui frame metrics reporting.
+ */
+class HardwareRendererObserver : public uirenderer::FrameMetricsObserver {
+public:
+    HardwareRendererObserver(JavaVM *vm, jobject observer);
+    ~HardwareRendererObserver();
+
+    /**
+     * Retrieves frame metrics for the oldest frame that the renderer has retained. The renderer
+     * will retain a buffer until it has been retrieved, via this method, or its internal storage
+     * is exhausted at which point it informs the caller of how many frames it has failed to store
+     * since the last time this method was invoked.
+     * @param env java env required to populate the provided buffer array
+     * @param metrics output parameter that represents the buffer of metrics that is to be filled
+     * @param dropCount output parameter that is updated to reflect the number of buffers that were
+                        discarded since the last successful invocation of this method.
+     * @return true if there was data to populate the array and false otherwise. If false then
+     *         neither the metrics buffer or dropCount will be modified.
+     */
+    bool getNextBuffer(JNIEnv* env, jlongArray metrics, int* dropCount);
+
+    void notify(const int64_t* stats) override;
+
+private:
+    static constexpr int kBufferSize = static_cast<int>(uirenderer::FrameInfoIndex::NumIndexes);
+    static constexpr int kRingSize = 3;
+
+    class FrameMetricsNotification {
+    public:
+        FrameMetricsNotification() {}
+
+        std::atomic_bool hasData = false;
+        int64_t buffer[kBufferSize];
+        int dropCount = 0;
+    private:
+        // non-copyable
+        FrameMetricsNotification(const FrameMetricsNotification&) = delete;
+        FrameMetricsNotification& operator=(const FrameMetricsNotification& ) = delete;
+    };
+
+    JavaVM* const mVm;
+    jweak mObserverWeak;
+
+    int mNextFree = 0;
+    int mNextInQueue = 0;
+    FrameMetricsNotification mRingBuffer[kRingSize];
+
+    int mDroppedReports = 0;
+};
+
+} // namespace android
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index d62d2d9..e21eefb 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -43,6 +43,7 @@
 #include <nativehelper/JNIHelp.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include "jni.h"
+#include <dmabufinfo/dmabufinfo.h>
 #include <meminfo/procmeminfo.h>
 #include <meminfo/sysmeminfo.h>
 #include <memtrack/memtrack.h>
@@ -560,6 +561,7 @@
     MEMINFO_VMALLOC_USED,
     MEMINFO_PAGE_TABLES,
     MEMINFO_KERNEL_STACK,
+    MEMINFO_KERNEL_RECLAIMABLE,
     MEMINFO_COUNT
 };
 
@@ -780,6 +782,59 @@
     return zramFreeKb;
 }
 
+static jlong android_os_Debug_getIonHeapsSizeKb(JNIEnv* env, jobject clazz) {
+    jlong heapsSizeKb = 0;
+    uint64_t size;
+
+    if (meminfo::ReadIonHeapsSizeKb(&size)) {
+        heapsSizeKb = size;
+    }
+
+    return heapsSizeKb;
+}
+
+static jlong android_os_Debug_getIonPoolsSizeKb(JNIEnv* env, jobject clazz) {
+    jlong poolsSizeKb = 0;
+    uint64_t size;
+
+    if (meminfo::ReadIonPoolsSizeKb(&size)) {
+        poolsSizeKb = size;
+    }
+
+    return poolsSizeKb;
+}
+
+static jlong android_os_Debug_getIonMappedSizeKb(JNIEnv* env, jobject clazz) {
+    jlong ionPss = 0;
+    std::vector<dmabufinfo::DmaBuffer> dmabufs;
+
+    std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir("/proc"), closedir);
+    if (!dir) {
+        LOG(ERROR) << "Failed to open /proc directory";
+        return false;
+    }
+
+    struct dirent* dent;
+    while ((dent = readdir(dir.get()))) {
+        if (dent->d_type != DT_DIR) continue;
+
+        int pid = atoi(dent->d_name);
+        if (pid == 0) {
+            continue;
+        }
+
+        if (!AppendDmaBufInfo(pid, &dmabufs, false)) {
+            LOG(ERROR) << "Failed to read maps for pid " << pid;
+        }
+    }
+
+    for (dmabufinfo::DmaBuffer buf : dmabufs) {
+        ionPss += buf.size() / 1024;
+    }
+
+    return ionPss;
+}
+
 /*
  * JNI registration.
  */
@@ -823,6 +878,12 @@
             (void*)android_os_Debug_getUnreachableMemory },
     { "getZramFreeKb", "()J",
             (void*)android_os_Debug_getFreeZramKb },
+    { "getIonHeapsSizeKb", "()J",
+            (void*)android_os_Debug_getIonHeapsSizeKb },
+    { "getIonPoolsSizeKb", "()J",
+            (void*)android_os_Debug_getIonPoolsSizeKb },
+    { "getIonMappedSizeKb", "()J",
+            (void*)android_os_Debug_getIonMappedSizeKb },
 };
 
 int register_android_os_Debug(JNIEnv *env)
diff --git a/core/jni/android_service_DataLoaderService.cpp b/core/jni/android_service_DataLoaderService.cpp
index 4c0f55f..381b386 100644
--- a/core/jni/android_service_DataLoaderService.cpp
+++ b/core/jni/android_service_DataLoaderService.cpp
@@ -16,83 +16,18 @@
 
 #define LOG_TAG "dataloader-jni"
 
-#include <vector>
-
 #include "core_jni_helpers.h"
 #include "dataloader_ndk.h"
-#include "jni.h"
 
 namespace android {
 namespace {
 
-struct JniIds {
-    jfieldID dataBlockFileIno;
-    jfieldID dataBlockBlockIndex;
-    jfieldID dataBlockDataBytes;
-    jfieldID dataBlockCompressionType;
-
-    JniIds(JNIEnv* env) {
-        const auto dataBlock =
-                FindClassOrDie(env,
-                               "android/service/incremental/"
-                               "IncrementalDataLoaderService$FileSystemConnector$DataBlock");
-        dataBlockFileIno = GetFieldIDOrDie(env, dataBlock, "mFileIno", "J");
-        dataBlockBlockIndex =
-                GetFieldIDOrDie(env, dataBlock, "mBlockIndex", "I");
-        dataBlockDataBytes = GetFieldIDOrDie(env, dataBlock, "mDataBytes", "[B");
-        dataBlockCompressionType =
-                GetFieldIDOrDie(env, dataBlock, "mCompressionType", "I");
-    }
-};
-
-const JniIds& jniIds(JNIEnv* env) {
-    static const JniIds ids(env);
-    return ids;
-}
-
-class ScopedJniArrayCritical {
-public:
-    ScopedJniArrayCritical(JNIEnv* env, jarray array) : mEnv(env), mArr(array) {
-        mPtr = array ? env->GetPrimitiveArrayCritical(array, nullptr) : nullptr;
-    }
-    ~ScopedJniArrayCritical() {
-        if (mPtr) {
-            mEnv->ReleasePrimitiveArrayCritical(mArr, mPtr, 0);
-            mPtr = nullptr;
-        }
-    }
-
-    ScopedJniArrayCritical(const ScopedJniArrayCritical&) = delete;
-    void operator=(const ScopedJniArrayCritical&) = delete;
-
-    ScopedJniArrayCritical(ScopedJniArrayCritical&& other)
-        : mEnv(other.mEnv),
-          mArr(std::exchange(mArr, nullptr)),
-          mPtr(std::exchange(mPtr, nullptr)) {}
-    ScopedJniArrayCritical& operator=(ScopedJniArrayCritical&& other) {
-        mEnv = other.mEnv;
-        mArr = std::exchange(other.mArr, nullptr);
-        mPtr = std::exchange(other.mPtr, nullptr);
-        return *this;
-    }
-
-    void* ptr() const { return mPtr; }
-    jsize size() const { return mArr ? mEnv->GetArrayLength(mArr) : 0; }
-
-private:
-    JNIEnv* mEnv;
-    jarray mArr;
-    void* mPtr;
-};
-
 static jboolean nativeCreateDataLoader(JNIEnv* env,
                                        jobject thiz,
                                        jint storageId,
                                        jobject control,
                                        jobject params,
                                        jobject callback) {
-    ALOGE("nativeCreateDataLoader: %p/%d, %d, %p, %p, %p", thiz,
-          env->GetObjectRefType(thiz), storageId, params, control, callback);
     return DataLoaderService_OnCreate(env, thiz,
                      storageId, control, params, callback);
 }
@@ -100,130 +35,22 @@
 static jboolean nativeStartDataLoader(JNIEnv* env,
                                       jobject thiz,
                                       jint storageId) {
-    ALOGE("nativeStartDataLoader: %p/%d, %d", thiz, env->GetObjectRefType(thiz),
-          storageId);
     return DataLoaderService_OnStart(storageId);
 }
 
 static jboolean nativeStopDataLoader(JNIEnv* env,
                                      jobject thiz,
                                      jint storageId) {
-    ALOGE("nativeStopDataLoader: %p/%d, %d", thiz, env->GetObjectRefType(thiz),
-          storageId);
     return DataLoaderService_OnStop(storageId);
 }
 
 static jboolean nativeDestroyDataLoader(JNIEnv* env,
                                         jobject thiz,
                                         jint storageId) {
-    ALOGE("nativeDestroyDataLoader: %p/%d, %d", thiz,
-          env->GetObjectRefType(thiz), storageId);
     return DataLoaderService_OnDestroy(storageId);
 }
 
 
-static jboolean nativeOnFileCreated(JNIEnv* env,
-                                   jobject thiz,
-                                   jint storageId,
-                                   jlong inode,
-                                   jbyteArray metadata) {
-    ALOGE("nativeOnFileCreated: %p/%d, %d", thiz,
-          env->GetObjectRefType(thiz), storageId);
-    return DataLoaderService_OnFileCreated(storageId, inode, metadata);
-}
-
-static jboolean nativeIsFileRangeLoadedNode(JNIEnv* env,
-                                            jobject clazz,
-                                            jlong self,
-                                            jlong node,
-                                            jlong start,
-                                            jlong end) {
-    // TODO(b/136132412): implement this
-    return JNI_FALSE;
-}
-
-static jboolean nativeWriteMissingData(JNIEnv* env,
-                                       jobject clazz,
-                                       jlong self,
-                                       jobjectArray data_block,
-                                       jobjectArray hash_blocks) {
-    const auto& jni = jniIds(env);
-    auto length = env->GetArrayLength(data_block);
-    std::vector<incfs_new_data_block> instructions(length);
-
-    // May not call back into Java after even a single jniArrayCritical, so
-    // let's collect the Java pointers to byte buffers first and lock them in
-    // memory later.
-
-    std::vector<jbyteArray> blockBuffers(length);
-    for (int i = 0; i != length; ++i) {
-        auto& inst = instructions[i];
-        auto jniBlock = env->GetObjectArrayElement(data_block, i);
-        inst.file_ino = env->GetLongField(jniBlock, jni.dataBlockFileIno);
-        inst.block_index = env->GetIntField(jniBlock, jni.dataBlockBlockIndex);
-        blockBuffers[i] = (jbyteArray)env->GetObjectField(
-                jniBlock, jni.dataBlockDataBytes);
-        inst.compression = (incfs_compression_alg)env->GetIntField(
-                jniBlock, jni.dataBlockCompressionType);
-    }
-
-    std::vector<ScopedJniArrayCritical> jniScopedArrays;
-    jniScopedArrays.reserve(length);
-    for (int i = 0; i != length; ++i) {
-        auto buffer = blockBuffers[i];
-        jniScopedArrays.emplace_back(env, buffer);
-        auto& inst = instructions[i];
-        inst.data = (uint64_t)jniScopedArrays.back().ptr();
-        inst.data_len = jniScopedArrays.back().size();
-    }
-
-    auto connector = (DataLoaderFilesystemConnectorPtr)self;
-    if (auto err = DataLoader_FilesystemConnector_writeBlocks(
-                             connector, instructions.data(), length);
-        err < 0) {
-        jniScopedArrays.clear();
-        return JNI_FALSE;
-    }
-
-    return JNI_TRUE;
-}
-
-static jboolean nativeWriteSignerDataNode(JNIEnv* env,
-                                          jobject clazz,
-                                          jlong self,
-                                          jstring relative_path,
-                                          jbyteArray signer_data) {
-    // TODO(b/136132412): implement this
-    return JNI_TRUE;
-}
-
-static jbyteArray nativeGetFileMetadataNode(JNIEnv* env,
-                                            jobject clazz,
-                                            jlong self,
-                                            jlong inode) {
-    auto connector = (DataLoaderFilesystemConnectorPtr)self;
-    std::vector<char> metadata(INCFS_MAX_FILE_ATTR_SIZE);
-    size_t size = metadata.size();
-    if (DataLoader_FilesystemConnector_getRawMetadata(connector, inode,
-                  metadata.data(), &size) < 0) {
-        size = 0;
-    }
-    metadata.resize(size);
-
-    auto buffer = env->NewByteArray(metadata.size());
-    env->SetByteArrayRegion(buffer, 0, metadata.size(),
-                            (jbyte*)metadata.data());
-    return buffer;
-}
-
-static jbyteArray nativeGetFileInfoNode(JNIEnv* env,
-                                        jobject clazz,
-                                        jlong self,
-                                        jlong inode) {
-    // TODO(b/136132412): implement this
-    return nullptr;
-}
-
 static jboolean nativeReportStatus(JNIEnv* env,
                                    jobject clazz,
                                    jlong self,
@@ -235,34 +62,21 @@
 
 static const JNINativeMethod dlc_method_table[] = {
         {"nativeCreateDataLoader",
-         "(ILandroid/os/incremental/IncrementalFileSystemControlParcel;"
-         "Landroid/os/incremental/IncrementalDataLoaderParamsParcel;"
+         "(ILandroid/content/pm/FileSystemControlParcel;"
+         "Landroid/content/pm/DataLoaderParamsParcel;"
          "Landroid/content/pm/IDataLoaderStatusListener;)Z",
          (void*)nativeCreateDataLoader},
         {"nativeStartDataLoader", "(I)Z", (void*)nativeStartDataLoader},
         {"nativeStopDataLoader", "(I)Z", (void*)nativeStopDataLoader},
         {"nativeDestroyDataLoader", "(I)Z", (void*)nativeDestroyDataLoader},
-        {"nativeIsFileRangeLoadedNode", "(JJJJ)Z",
-         (void*)nativeIsFileRangeLoadedNode},
-        {"nativeWriteMissingData",
-         "(J[Landroid/service/incremental/"
-         "IncrementalDataLoaderService$FileSystemConnector$DataBlock;[Landroid/service/incremental/"
-         "IncrementalDataLoaderService$FileSystemConnector$HashBlock;)Z",
-         (void*)nativeWriteMissingData},
-        {"nativeWriteSignerDataNode", "(JJ[B)Z",
-         (void*)nativeWriteSignerDataNode},
-        {"nativeGetFileMetadataNode", "(JJ)[B",
-         (void*)nativeGetFileMetadataNode},
-        {"nativeGetFileInfoNode", "(JJ)[B", (void*)nativeGetFileInfoNode},
         {"nativeReportStatus", "(JI)Z", (void*)nativeReportStatus},
-        {"nativeOnFileCreated", "(IJ[B)Z", (void*)nativeOnFileCreated},
 };
 
 }  // namespace
 
 int register_android_service_DataLoaderService(JNIEnv* env) {
     return jniRegisterNativeMethods(env,
-                                    "android/service/incremental/IncrementalDataLoaderService",
+                                    "android/service/dataloader/DataLoaderService",
                                     dlc_method_table, NELEM(dlc_method_table));
 }
 
diff --git a/core/jni/android_view_FrameMetricsObserver.cpp b/core/jni/android_view_FrameMetricsObserver.cpp
deleted file mode 100644
index febcb55..0000000
--- a/core/jni/android_view_FrameMetricsObserver.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "android_view_FrameMetricsObserver.h"
-
-namespace android {
-
-struct {
-    jfieldID frameMetrics;
-    jfieldID timingDataBuffer;
-    jfieldID messageQueue;
-    jmethodID callback;
-} gFrameMetricsObserverClassInfo;
-
-static JNIEnv* getenv(JavaVM* vm) {
-    JNIEnv* env;
-    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
-        LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
-    }
-    return env;
-}
-
-static jlongArray get_metrics_buffer(JNIEnv* env, jobject observer) {
-    jobject frameMetrics = env->GetObjectField(
-            observer, gFrameMetricsObserverClassInfo.frameMetrics);
-    LOG_ALWAYS_FATAL_IF(frameMetrics == nullptr, "unable to retrieve data sink object");
-    jobject buffer = env->GetObjectField(
-            frameMetrics, gFrameMetricsObserverClassInfo.timingDataBuffer);
-    LOG_ALWAYS_FATAL_IF(buffer == nullptr, "unable to retrieve data sink buffer");
-    return reinterpret_cast<jlongArray>(buffer);
-}
-
-class NotifyHandler : public MessageHandler {
-public:
-    NotifyHandler(JavaVM* vm, FrameMetricsObserverProxy* observer) : mVm(vm), mObserver(observer) {}
-
-    virtual void handleMessage(const Message& message);
-
-private:
-    JavaVM* const mVm;
-    FrameMetricsObserverProxy* const mObserver;
-};
-
-void NotifyHandler::handleMessage(const Message& message) {
-    JNIEnv* env = getenv(mVm);
-
-    jobject target = env->NewLocalRef(mObserver->getObserverReference());
-
-    if (target != nullptr) {
-        jlongArray javaBuffer = get_metrics_buffer(env, target);
-        int dropCount = 0;
-        while (mObserver->getNextBuffer(env, javaBuffer, &dropCount)) {
-            env->CallVoidMethod(target, gFrameMetricsObserverClassInfo.callback, dropCount);
-        }
-        env->DeleteLocalRef(target);
-    }
-
-    mObserver->decStrong(nullptr);
-}
-
-FrameMetricsObserverProxy::FrameMetricsObserverProxy(JavaVM *vm, jobject observer) : mVm(vm) {
-    JNIEnv* env = getenv(mVm);
-
-    mObserverWeak = env->NewWeakGlobalRef(observer);
-    LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr,
-            "unable to create frame stats observer reference");
-
-    jlongArray buffer = get_metrics_buffer(env, observer);
-    jsize bufferSize = env->GetArrayLength(reinterpret_cast<jarray>(buffer));
-    LOG_ALWAYS_FATAL_IF(bufferSize != kBufferSize,
-            "Mismatched Java/Native FrameMetrics data format.");
-
-    jobject messageQueueLocal = env->GetObjectField(
-            observer, gFrameMetricsObserverClassInfo.messageQueue);
-    mMessageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueLocal);
-    LOG_ALWAYS_FATAL_IF(mMessageQueue == nullptr, "message queue not available");
-
-    mMessageHandler = new NotifyHandler(mVm, this);
-    LOG_ALWAYS_FATAL_IF(mMessageHandler == nullptr,
-            "OOM: unable to allocate NotifyHandler");
-}
-
-FrameMetricsObserverProxy::~FrameMetricsObserverProxy() {
-    JNIEnv* env = getenv(mVm);
-    env->DeleteWeakGlobalRef(mObserverWeak);
-}
-
-bool FrameMetricsObserverProxy::getNextBuffer(JNIEnv* env, jlongArray sink, int* dropCount) {
-    FrameMetricsNotification& elem = mRingBuffer[mNextInQueue];
-
-    if (elem.hasData.load()) {
-        env->SetLongArrayRegion(sink, 0, kBufferSize, elem.buffer);
-        *dropCount = elem.dropCount;
-        mNextInQueue = (mNextInQueue + 1) % kRingSize;
-        elem.hasData = false;
-        return true;
-    }
-
-    return false;
-}
-
-void FrameMetricsObserverProxy::notify(const int64_t* stats) {
-    FrameMetricsNotification& elem = mRingBuffer[mNextFree];
-
-    if (!elem.hasData.load()) {
-        memcpy(elem.buffer, stats, kBufferSize * sizeof(stats[0]));
-
-        elem.dropCount = mDroppedReports;
-        mDroppedReports = 0;
-
-        incStrong(nullptr);
-        mNextFree = (mNextFree + 1) % kRingSize;
-        elem.hasData = true;
-
-        mMessageQueue->getLooper()->sendMessage(mMessageHandler, mMessage);
-    } else {
-        mDroppedReports++;
-    }
-}
-
-int register_android_view_FrameMetricsObserver(JNIEnv* env) {
-    jclass observerClass = FindClassOrDie(env, "android/view/FrameMetricsObserver");
-    gFrameMetricsObserverClassInfo.frameMetrics = GetFieldIDOrDie(
-            env, observerClass, "mFrameMetrics", "Landroid/view/FrameMetrics;");
-    gFrameMetricsObserverClassInfo.messageQueue = GetFieldIDOrDie(
-            env, observerClass, "mMessageQueue", "Landroid/os/MessageQueue;");
-    gFrameMetricsObserverClassInfo.callback = GetMethodIDOrDie(
-            env, observerClass, "notifyDataAvailable", "(I)V");
-
-    jclass metricsClass = FindClassOrDie(env, "android/view/FrameMetrics");
-    gFrameMetricsObserverClassInfo.timingDataBuffer = GetFieldIDOrDie(
-            env, metricsClass, "mTimingData", "[J");
-    return JNI_OK;
-}
-
-} // namespace android
\ No newline at end of file
diff --git a/core/jni/android_view_FrameMetricsObserver.h b/core/jni/android_view_FrameMetricsObserver.h
deleted file mode 100644
index 647f51c..0000000
--- a/core/jni/android_view_FrameMetricsObserver.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "jni.h"
-#include "core_jni_helpers.h"
-
-#include "android_os_MessageQueue.h"
-
-#include <FrameInfo.h>
-#include <FrameMetricsObserver.h>
-
-namespace android {
-
-/*
- * Implements JNI layer for hwui frame metrics reporting.
- */
-class FrameMetricsObserverProxy : public uirenderer::FrameMetricsObserver {
-public:
-    FrameMetricsObserverProxy(JavaVM *vm, jobject observer);
-
-    ~FrameMetricsObserverProxy();
-
-    jweak getObserverReference() {
-        return mObserverWeak;
-    }
-
-    bool getNextBuffer(JNIEnv* env, jlongArray sink, int* dropCount);
-
-    virtual void notify(const int64_t* stats);
-
-private:
-    static const int kBufferSize = static_cast<int>(uirenderer::FrameInfoIndex::NumIndexes);
-    static constexpr int kRingSize = 3;
-
-    class FrameMetricsNotification {
-    public:
-        FrameMetricsNotification() : hasData(false) {}
-
-        std::atomic_bool hasData;
-        int64_t buffer[kBufferSize];
-        int dropCount = 0;
-    };
-
-    JavaVM* const mVm;
-    jweak mObserverWeak;
-
-    sp<MessageQueue> mMessageQueue;
-    sp<MessageHandler> mMessageHandler;
-    Message mMessage;
-
-    int mNextFree = 0;
-    int mNextInQueue = 0;
-    FrameMetricsNotification mRingBuffer[kRingSize];
-
-    int mDroppedReports = 0;
-};
-
-} // namespace android
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 170e467..69ca17c 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -30,7 +30,7 @@
 #include <gui/BufferQueue.h>
 #include <gui/Surface.h>
 
-#include "android_view_FrameMetricsObserver.h"
+#include "android_graphics_HardwareRendererObserver.h"
 
 #include <private/EGL/cache.h>
 
@@ -580,28 +580,21 @@
 }
 
 // ----------------------------------------------------------------------------
-// FrameMetricsObserver
+// HardwareRendererObserver
 // ----------------------------------------------------------------------------
 
-static jlong android_view_ThreadedRenderer_addFrameMetricsObserver(JNIEnv* env,
-        jclass clazz, jlong proxyPtr, jobject fso) {
-    JavaVM* vm = nullptr;
-    if (env->GetJavaVM(&vm) != JNI_OK) {
-        LOG_ALWAYS_FATAL("Unable to get Java VM");
-        return 0;
-    }
-
+static void android_view_ThreadedRenderer_addObserver(JNIEnv* env, jclass clazz,
+        jlong proxyPtr, jlong observerPtr) {
+    HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr);
     renderthread::RenderProxy* renderProxy =
             reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
 
-    FrameMetricsObserver* observer = new FrameMetricsObserverProxy(vm, fso);
     renderProxy->addFrameMetricsObserver(observer);
-    return reinterpret_cast<jlong>(observer);
 }
 
-static void android_view_ThreadedRenderer_removeFrameMetricsObserver(JNIEnv* env, jclass clazz,
+static void android_view_ThreadedRenderer_removeObserver(JNIEnv* env, jclass clazz,
         jlong proxyPtr, jlong observerPtr) {
-    FrameMetricsObserver* observer = reinterpret_cast<FrameMetricsObserver*>(observerPtr);
+    HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr);
     renderthread::RenderProxy* renderProxy =
             reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
 
@@ -675,12 +668,8 @@
             (void*)android_view_ThreadedRenderer_setFrameCallback},
     { "nSetFrameCompleteCallback", "(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V",
             (void*)android_view_ThreadedRenderer_setFrameCompleteCallback },
-    { "nAddFrameMetricsObserver",
-            "(JLandroid/view/FrameMetricsObserver;)J",
-            (void*)android_view_ThreadedRenderer_addFrameMetricsObserver },
-    { "nRemoveFrameMetricsObserver",
-            "(JJ)V",
-            (void*)android_view_ThreadedRenderer_removeFrameMetricsObserver },
+    { "nAddObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_addObserver },
+    { "nRemoveObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_removeObserver },
     { "nCopySurfaceInto", "(Landroid/view/Surface;IIIIJ)I",
                 (void*)android_view_ThreadedRenderer_copySurfaceInto },
     { "nCreateHardwareBitmap", "(JII)Landroid/graphics/Bitmap;",
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 0ca0dc8..df5b02c 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -31,6 +31,8 @@
 // sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
 #include <sys/mount.h>
 #include <linux/fs.h>
+#include <sys/types.h>
+#include <dirent.h>
 
 #include <array>
 #include <atomic>
@@ -40,6 +42,7 @@
 #include <sstream>
 #include <string>
 #include <string_view>
+#include <unordered_set>
 
 #include <android/fdsan.h>
 #include <arpa/inet.h>
@@ -51,6 +54,7 @@
 #include <mntent.h>
 #include <paths.h>
 #include <signal.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <sys/capability.h>
 #include <sys/cdefs.h>
@@ -159,6 +163,17 @@
  */
 static int gUsapPoolEventFD = -1;
 
+static constexpr int DEFAULT_DATA_DIR_PERMISSION = 0751;
+
+/**
+ * Property to control if app data isolation is enabled.
+ */
+static const std::string ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY =
+    "persist.zygote.app_data_isolation";
+
+static constexpr const uint64_t UPPER_HALF_WORD_MASK = 0xFFFF'FFFF'0000'0000;
+static constexpr const uint64_t LOWER_HALF_WORD_MASK = 0x0000'0000'FFFF'FFFF;
+
 /**
  * The maximum value that the gUSAPPoolSizeMax variable may take.  This value
  * is a mirror of ZygoteServer.USAP_POOL_SIZE_MAX_LIMIT
@@ -663,7 +678,7 @@
   return 0;
 }
 
-static void CreateDir(const std::string& dir, mode_t mode, uid_t uid, gid_t gid,
+static void PrepareDir(const std::string& dir, mode_t mode, uid_t uid, gid_t gid,
                       fail_fn_t fail_fn) {
   if (fs_prepare_dir(dir.c_str(), mode, uid, gid) != 0) {
     fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s: %s",
@@ -671,6 +686,16 @@
   }
 }
 
+static void PrepareDirIfNotPresent(const std::string& dir, mode_t mode, uid_t uid, gid_t gid,
+                      fail_fn_t fail_fn) {
+  struct stat sb;
+  if (TEMP_FAILURE_RETRY(stat(dir.c_str(), &sb)) != -1) {
+    // Directory exists already
+    return;
+  }
+  PrepareDir(dir, mode, uid, gid, fail_fn);
+}
+
 static void BindMount(const std::string& source_dir, const std::string& target_dir,
                       fail_fn_t fail_fn) {
   if (TEMP_FAILURE_RETRY(mount(source_dir.c_str(), target_dir.c_str(), nullptr,
@@ -680,6 +705,15 @@
   }
 }
 
+static void MountAppDataTmpFs(const std::string& target_dir,
+                      fail_fn_t fail_fn) {
+  if (TEMP_FAILURE_RETRY(mount("tmpfs", target_dir.c_str(), "tmpfs",
+                               MS_NOSUID | MS_NODEV | MS_NOEXEC, "uid=0,gid=0,mode=0751")) == -1) {
+    fail_fn(CREATE_ERROR("Failed to mount tmpfs to %s: %s",
+                         target_dir.c_str(), strerror(errno)));
+  }
+}
+
 // Create a private mount namespace and bind mount appropriate emulated
 // storage for the given user.
 static void MountEmulatedStorage(uid_t uid, jint mount_mode,
@@ -712,7 +746,7 @@
   const std::string pass_through_source = StringPrintf("/mnt/pass_through/%d", user_id);
   bool isFuse = GetBoolProperty(kPropFuse, false);
 
-  CreateDir(user_source, 0751, AID_ROOT, AID_ROOT, fail_fn);
+  PrepareDir(user_source, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
 
   if (isFuse) {
     if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH || mount_mode ==
@@ -1016,6 +1050,231 @@
   return pid;
 }
 
+// Create an app data directory over tmpfs overlayed CE / DE storage, and bind mount it
+// from the actual app data directory in data mirror.
+static void createAndMountAppData(std::string_view package_name,
+    std::string_view mirror_pkg_dir_name, std::string_view mirror_data_path,
+    std::string_view actual_data_path, fail_fn_t fail_fn) {
+
+  char mirrorAppDataPath[PATH_MAX];
+  char actualAppDataPath[PATH_MAX];
+  snprintf(mirrorAppDataPath, PATH_MAX, "%s/%s", mirror_data_path.data(),
+      mirror_pkg_dir_name.data());
+  snprintf(actualAppDataPath, PATH_MAX, "%s/%s", actual_data_path.data(), package_name.data());
+
+  PrepareDir(actualAppDataPath, 0700, AID_ROOT, AID_ROOT, fail_fn);
+
+  // Bind mount from original app data directory in mirror.
+  BindMount(mirrorAppDataPath, actualAppDataPath, fail_fn);
+}
+
+// Get the directory name stored in /data/data. If device is unlocked it should be the same as
+// package name, otherwise it will be an encrypted name but with same inode number.
+static std::string getAppDataDirName(std::string_view parent_path, std::string_view package_name,
+      long long ce_data_inode, fail_fn_t fail_fn) {
+  // Check if directory exists
+  char tmpPath[PATH_MAX];
+  snprintf(tmpPath, PATH_MAX, "%s/%s", parent_path.data(), package_name.data());
+  struct stat s;
+  int err = stat(tmpPath, &s);
+  if (err == 0) {
+    // Directory exists, so return the directory name
+    return package_name.data();
+  } else {
+    if (errno != ENOENT) {
+      fail_fn(CREATE_ERROR("Unexpected error in getAppDataDirName: %s", strerror(errno)));
+      return nullptr;
+    }
+    // Directory doesn't exist, try to search the name from inode
+    DIR* dir = opendir(parent_path.data());
+    if (dir == nullptr) {
+      fail_fn(CREATE_ERROR("Failed to opendir %s", parent_path.data()));
+    }
+    struct dirent* ent;
+    while ((ent = readdir(dir))) {
+      if (ent->d_ino == ce_data_inode) {
+        closedir(dir);
+        return ent->d_name;
+      }
+    }
+    closedir(dir);
+
+    // Fallback due to b/145989852, ce_data_inode stored in package manager may be corrupted
+    // if ino_t is 32 bits.
+    ino_t fixed_ce_data_inode = 0;
+    if ((ce_data_inode & UPPER_HALF_WORD_MASK) == UPPER_HALF_WORD_MASK) {
+      fixed_ce_data_inode = ce_data_inode & LOWER_HALF_WORD_MASK;
+    } else if ((ce_data_inode & LOWER_HALF_WORD_MASK) == LOWER_HALF_WORD_MASK) {
+      fixed_ce_data_inode = ((ce_data_inode >> 32) & LOWER_HALF_WORD_MASK);
+    }
+    if (fixed_ce_data_inode != 0) {
+      dir = opendir(parent_path.data());
+      if (dir == nullptr) {
+        fail_fn(CREATE_ERROR("Failed to opendir %s", parent_path.data()));
+      }
+      while ((ent = readdir(dir))) {
+        if (ent->d_ino == fixed_ce_data_inode) {
+          long long d_ino = ent->d_ino;
+          ALOGW("Fallback success inode %lld -> %lld", ce_data_inode, d_ino);
+          closedir(dir);
+          return ent->d_name;
+        }
+      }
+      closedir(dir);
+    }
+    // Fallback done
+
+    fail_fn(CREATE_ERROR("Unable to find %s:%lld in %s", package_name.data(),
+        ce_data_inode, parent_path.data()));
+    return nullptr;
+  }
+}
+
+// Isolate app's data directory, by mounting a tmpfs on CE DE storage,
+// and create and bind mount app data in related_packages.
+static void isolateAppDataPerPackage(int userId, std::string_view package_name,
+    std::string_view volume_uuid, long long ce_data_inode, std::string_view actualCePath,
+    std::string_view actualDePath, fail_fn_t fail_fn) {
+
+  char mirrorCePath[PATH_MAX];
+  char mirrorDePath[PATH_MAX];
+  char mirrorCeParent[PATH_MAX];
+  snprintf(mirrorCeParent, PATH_MAX, "/data_mirror/data_ce/%s", volume_uuid.data());
+  snprintf(mirrorCePath, PATH_MAX, "%s/%d", mirrorCeParent, userId);
+  snprintf(mirrorDePath, PATH_MAX, "/data_mirror/data_de/%s/%d", volume_uuid.data(), userId);
+
+  createAndMountAppData(package_name, package_name, mirrorDePath, actualDePath, fail_fn);
+
+  std::string ce_data_path = getAppDataDirName(mirrorCePath, package_name, ce_data_inode, fail_fn);
+  createAndMountAppData(package_name, ce_data_path, mirrorCePath, actualCePath, fail_fn);
+}
+
+/**
+ * Make other apps data directory not visible in CE, DE storage.
+ *
+ * Apps without app data isolation can detect if another app is installed on system,
+ * by "touching" other apps data directory like /data/data/com.whatsapp, if it returns
+ * "Permission denied" it means apps installed, otherwise it returns "File not found".
+ * Traditional file permissions or SELinux can only block accessing those directories but
+ * can't fix fingerprinting like this.
+ * We fix it by "overlaying" data directory, and only relevant app data packages exists
+ * in data directories.
+ *
+ * Steps:
+ * 1). Collect a list of all related apps (apps with same uid and whitelisted apps) data info
+ * (package name, data stored volume uuid, and inode number of its CE data directory)
+ * 2). Mount tmpfs on /data/data, /data/user(_de) and /mnt/expand, so apps no longer
+ * able to access apps data directly.
+ * 3). For each related app, create its app data directory and bind mount the actual content
+ * from apps data mirror directory. This works on both CE and DE storage, as DE storage
+ * is always available even storage is FBE locked, while we use inode number to find
+ * the encrypted DE directory in mirror so we can still bind mount it successfully.
+ *
+ * Example:
+ * 0). Assuming com.android.foo CE data is stored in /data/data and no shared uid
+ * 1). Mount a tmpfs on /data/data, /data/user, /data/user_de, /mnt/expand
+ * List = ["com.android.foo", "null" (volume uuid "null"=default),
+ * 123456 (inode number)]
+ * 2). On DE storage, we create a directory /data/user_de/0/com.com.android.foo, and bind
+ * mount (in the app's mount namespace) it from /data_mirror/data_de/0/com.android.foo.
+ * 3). We do similar for CE storage. But in direct boot mode, as /data_mirror/data_ce/0/ is
+ * encrypted, we can't find a directory with name com.android.foo on it, so we will
+ * use the inode number to find the right directory instead, which that directory content will
+ * be decrypted after storage is decrypted.
+ *
+ */
+static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
+    uid_t uid, const char* process_name, jstring managed_nice_name,
+    fail_fn_t fail_fn) {
+
+  const userid_t userId = multiuser_get_user_id(uid);
+
+  auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
+
+  int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0;
+  // Size should be a multiple of 3, as it contains list of <package_name, volume_uuid, inode>
+  if ((size % 3) != 0) {
+    fail_fn(CREATE_ERROR("Wrong pkg_inode_list size %d", size));
+  }
+
+  // Mount tmpfs on all possible data directories, so app no longer see the original apps data.
+  char internalCePath[PATH_MAX];
+  char internalLegacyCePath[PATH_MAX];
+  char internalDePath[PATH_MAX];
+  char externalPrivateMountPath[PATH_MAX];
+
+  snprintf(internalCePath, PATH_MAX, "/data/user");
+  snprintf(internalLegacyCePath, PATH_MAX, "/data/data");
+  snprintf(internalDePath, PATH_MAX, "/data/user_de");
+  snprintf(externalPrivateMountPath, PATH_MAX, "/mnt/expand");
+
+  MountAppDataTmpFs(internalLegacyCePath, fail_fn);
+  MountAppDataTmpFs(internalCePath, fail_fn);
+  MountAppDataTmpFs(internalDePath, fail_fn);
+  MountAppDataTmpFs(externalPrivateMountPath, fail_fn);
+
+  for (int i = 0; i < size; i += 3) {
+    jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i));
+    std::string packageName = extract_fn(package_str).value();
+
+    jstring vol_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i + 1));
+    std::string volUuid = extract_fn(vol_str).value();
+
+    jstring inode_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i + 2));
+    std::string inode = extract_fn(inode_str).value();
+    std::string::size_type sz;
+    long long ceDataInode = std::stoll(inode, &sz);
+
+    std::string actualCePath, actualDePath;
+    if (volUuid.compare("null") != 0) {
+      // Volume that is stored in /mnt/expand
+      char volPath[PATH_MAX];
+      char volCePath[PATH_MAX];
+      char volDePath[PATH_MAX];
+      char volCeUserPath[PATH_MAX];
+      char volDeUserPath[PATH_MAX];
+
+      snprintf(volPath, PATH_MAX, "/mnt/expand/%s", volUuid.c_str());
+      snprintf(volCePath, PATH_MAX, "%s/user", volPath);
+      snprintf(volDePath, PATH_MAX, "%s/user_de", volPath);
+      snprintf(volCeUserPath, PATH_MAX, "%s/%d", volCePath, userId);
+      snprintf(volDeUserPath, PATH_MAX, "%s/%d", volDePath, userId);
+
+      PrepareDirIfNotPresent(volPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+      PrepareDirIfNotPresent(volCePath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+      PrepareDirIfNotPresent(volDePath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+      PrepareDirIfNotPresent(volCeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+          fail_fn);
+      PrepareDirIfNotPresent(volDeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+          fail_fn);
+
+      actualCePath = volCeUserPath;
+      actualDePath = volDeUserPath;
+    } else {
+      // Internal volume that stored in /data
+      char internalCeUserPath[PATH_MAX];
+      char internalDeUserPath[PATH_MAX];
+      snprintf(internalCeUserPath, PATH_MAX, "/data/user/%d", userId);
+      snprintf(internalDeUserPath, PATH_MAX, "/data/user_de/%d", userId);
+      // If it's user 0, create a symlink /data/user/0 -> /data/data,
+      // otherwise create /data/user/$USER
+      if (userId == 0) {
+        symlink(internalLegacyCePath, internalCeUserPath);
+        actualCePath = internalLegacyCePath;
+      } else {
+        PrepareDirIfNotPresent(internalCeUserPath, DEFAULT_DATA_DIR_PERMISSION,
+            AID_ROOT, AID_ROOT, fail_fn);
+        actualCePath = internalCeUserPath;
+      }
+      PrepareDirIfNotPresent(internalDeUserPath, DEFAULT_DATA_DIR_PERMISSION,
+          AID_ROOT, AID_ROOT, fail_fn);
+      actualDePath = internalDeUserPath;
+    }
+    isolateAppDataPerPackage(userId, packageName, volUuid, ceDataInode,
+        actualCePath, actualDePath, fail_fn);
+  }
+}
+
 // Utility routine to specialize a zygote child process.
 static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
                              jint runtime_flags, jobjectArray rlimits,
@@ -1023,7 +1282,8 @@
                              jint mount_external, jstring managed_se_info,
                              jstring managed_nice_name, bool is_system_server,
                              bool is_child_zygote, jstring managed_instruction_set,
-                             jstring managed_app_data_dir, bool is_top_app) {
+                             jstring managed_app_data_dir, bool is_top_app,
+                             jobjectArray pkg_data_info_list) {
   const char* process_name = is_system_server ? "system_server" : "zygote";
   auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1);
   auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
@@ -1059,6 +1319,16 @@
 
   MountEmulatedStorage(uid, mount_external, use_native_bridge, fail_fn);
 
+  // System services, isolated process, webview/app zygote, old target sdk app, should
+  // give a null in same_uid_pkgs and private_volumes so they don't need app data isolation.
+  // Isolated process / webview / app zygote should be gated by SELinux and file permission
+  // so they can't even traverse CE / DE directories.
+  if (pkg_data_info_list != nullptr
+      && GetBoolProperty(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) {
+    isolateAppData(env, pkg_data_info_list, uid, process_name, managed_nice_name,
+        fail_fn);
+  }
+
   // If this zygote isn't root, it won't be able to create a process group,
   // since the directory is owned by root.
   if (!is_system_server && getuid() == 0) {
@@ -1425,7 +1695,8 @@
         jint runtime_flags, jobjectArray rlimits,
         jint mount_external, jstring se_info, jstring nice_name,
         jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
-        jstring instruction_set, jstring app_data_dir, jboolean is_top_app) {
+        jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
+        jobjectArray pkg_data_info_list) {
     jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
 
     if (UNLIKELY(managed_fds_to_close == nullptr)) {
@@ -1457,7 +1728,7 @@
                        capabilities, capabilities,
                        mount_external, se_info, nice_name, false,
                        is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
-                       is_top_app == JNI_TRUE);
+                       is_top_app == JNI_TRUE, pkg_data_info_list);
     }
     return pid;
 }
@@ -1481,10 +1752,13 @@
                          fds_to_ignore,
                          true);
   if (pid == 0) {
+      // System server prcoess does not need data isolation so no need to
+      // know pkg_data_info_list.
       SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
                        permitted_capabilities, effective_capabilities,
                        MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
-                       false, nullptr, nullptr, /* is_top_app= */ false);
+                       false, nullptr, nullptr, /* is_top_app= */ false,
+                       /* pkg_data_info_list */ nullptr);
   } else if (pid > 0) {
       // The zygote process checks whether the child process has died or not.
       ALOGI("System server process %d has been created", pid);
@@ -1607,14 +1881,15 @@
     JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
     jint runtime_flags, jobjectArray rlimits,
     jint mount_external, jstring se_info, jstring nice_name,
-    jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app) {
+    jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
+    jobjectArray pkg_data_info_list) {
   jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
 
   SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
                    capabilities, capabilities,
                    mount_external, se_info, nice_name, false,
                    is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
-                   is_top_app == JNI_TRUE);
+                   is_top_app == JNI_TRUE, pkg_data_info_list);
 }
 
 /**
@@ -1775,7 +2050,7 @@
 
 static const JNINativeMethod gMethods[] = {
     { "nativeForkAndSpecialize",
-      "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z)I",
+      "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;)I",
       (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
     { "nativeForkSystemServer", "(II[II[[IJJ)I",
       (void *) com_android_internal_os_Zygote_nativeForkSystemServer },
@@ -1788,7 +2063,7 @@
     { "nativeForkUsap", "(II[IZ)I",
       (void *) com_android_internal_os_Zygote_nativeForkUsap },
     { "nativeSpecializeAppProcess",
-      "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z)V",
+      "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;)V",
       (void *) com_android_internal_os_Zygote_nativeSpecializeAppProcess },
     { "nativeInitNativeState", "(Z)V",
       (void *) com_android_internal_os_Zygote_nativeInitNativeState },
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 8c1ecae..a46ad6d 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -42,6 +42,7 @@
   "/apex/com.android.telephony/javalib/telephony-common.jar",
   "/apex/com.android.telephony/javalib/ims-common.jar",
   "/apex/com.android.wifi/javalib/framework-wifi.jar",
+  "/apex/com.android.tethering/javalib/framework-tethering.jar",
   "/dev/null",
   "/dev/socket/zygote",
   "/dev/socket/zygote_secondary",
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 44581af..039e458 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2504,4 +2504,14 @@
     // OS: R
     DIALOG_DALTONIZER_EDIT_SHORTCUT = 1814;
 
+    // OPEN: Settings > Accessibility > Magnification > Settings
+    // CATEGORY: SETTINGS
+    // OS: R
+    ACCESSIBILITY_MAGNIFICATION_SETTINGS = 1815;
+
+    // OPEN: Settings > Accessibility > Magnification > Settings > Magnification area dialog
+    // CATEGORY: SETTINGS
+    // OS: R
+    DIALOG_MAGNIFICATION_CAPABILITY = 1816;
+
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ba2f64d..ee86c16 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -637,7 +637,7 @@
 
     <!-- NETWORK_SET_TIME moved from com.android.phone to system server. It should ultimately be
          removed. -->
-    <protected-broadcast android:name="android.intent.action.NETWORK_SET_TIME" />
+    <protected-broadcast android:name="android.telephony.action.NETWORK_SET_TIME" />
 
     <!-- For tether entitlement recheck-->
     <protected-broadcast
@@ -2208,6 +2208,17 @@
     <permission android:name="android.permission.MANAGE_DOCUMENTS"
         android:protectionLevel="signature|documenter" />
 
+    <!-- Allows an application to manage access to crates, usually as part
+         of a crates picker.
+         <p>This permission should <em>only</em> be requested by the platform
+         management app.  This permission cannot be granted to
+         third-party apps.
+         @hide
+         @TestApi
+    -->
+    <permission android:name="android.permission.MANAGE_CRATES"
+                android:protectionLevel="signature" />
+
     <!-- @hide Allows an application to cache content.
          <p>Not for use by third-party applications.
     -->
@@ -2933,6 +2944,14 @@
     <permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE"
         android:protectionLevel="signature" />
 
+    <!-- Allows SystemUI to request third party controls.
+         <p>Should only be requested by the System and required by
+         ControlsService declarations.
+         @hide
+    -->
+    <permission android:name="android.permission.BIND_CONTROLS"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Allows an application to force a BACK operation on whatever is the
          top activity.
          <p>Not for use by third-party applications.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 03f8ebd..85406c7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2357,15 +2357,22 @@
 
     <!-- Whether to only install system packages on a user if they're whitelisted for that user
          type. These are flags and can be freely combined.
-         0 (0b000) - disable whitelist (install all system packages; no logging)
-         1 (0b001) - enforce (only install system packages if they are whitelisted)
-         2 (0b010) - log (log when a non-whitelisted package is run)
-         4 (0b100) - treat any package not mentioned in the whitelist file as implicitly whitelisted
-         8 (0b1000) - ignore OTAs (don't install system packages during OTAs)
+         0  - disable whitelist (install all system packages; no logging)
+         1  - enforce (only install system packages if they are whitelisted)
+         2  - log (log when a non-whitelisted package is run)
+         4  - any package not mentioned in the whitelist file is implicitly whitelisted on all users
+         8  - same as 4, but just for the SYSTEM user
+         16 - ignore OTAs (don't install system packages during OTAs)
+         Common scenarios:
+          - to enable feature (fully enforced) for a complete whitelist: 1
+          - to enable feature for an incomplete whitelist (so use implicit whitelist mode): 5
+          - to enable feature but implicitly whitelist for SYSTEM user to ease local development: 9
+          - to disable feature completely if it had never been enabled: 16
+          - to henceforth disable feature and try to undo its previous effects: 0
         Note: This list must be kept current with PACKAGE_WHITELIST_MODE_PROP in
         frameworks/base/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java -->
-    <integer name="config_userTypePackageWhitelistMode">13</integer> <!-- 0b1101 -->
-    <!-- TODO(b/143200798): Change to value 5, i.e. 0b0101, when b/143200798 is resolved. -->
+    <integer name="config_userTypePackageWhitelistMode">29</integer> <!-- 1+4+8+16 -->
+    <!-- TODO(b/143200798): Change to value 13, i.e. 1+4+8, when b/143200798 is resolved. -->
 
     <!-- Whether UI for multi user should be shown -->
     <bool name="config_enableMultiUserUI">false</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 9791241..2543967 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -772,4 +772,8 @@
     <dimen name="resolver_small_margin">18dp</dimen>
     <dimen name="resolver_edge_margin">24dp</dimen>
     <dimen name="resolver_elevation">1dp</dimen>
+
+    <!-- Assistant handles -->
+    <dimen name="assist_handle_shadow_radius">2dp</dimen>
+
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a8d30c1..1e59c37 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3790,4 +3790,9 @@
   <!-- For contacts provider. -->
   <java-symbol type="string" name="config_rawContactsLocalAccountName" />
   <java-symbol type="string" name="config_rawContactsLocalAccountType" />
+
+  <!-- Assistant handles -->
+  <java-symbol type="dimen" name="assist_handle_shadow_radius" />
+
+
 </resources>
diff --git a/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java b/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
index bbd442d..6c5d548 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
@@ -16,7 +16,11 @@
 
 package android.app.activity;
 
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+
 import android.app.ActivityManager;
+import android.app.ActivityManager.TaskDescription;
 import android.content.Context;
 import android.content.pm.ConfigurationInfo;
 import android.content.res.Configuration;
@@ -110,7 +114,123 @@
             assertNotNull(config.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD);
         }    
     }
-    
+
+    @SmallTest
+    public void testTaskDescriptionCopyFrom() {
+        TaskDescription td1 = new TaskDescription(
+                "test label",            // label
+                null,                    // bitmap
+                21,                      // iconRes
+                "dummy file",            // iconFilename
+                0x111111,                // colorPrimary
+                0x222222,                // colorBackground
+                0x333333,                // statusBarColor
+                0x444444,                // navigationBarColor
+                true,                    // ensureStatusBarContrastWhenTransparent
+                true,                    // ensureNavigationBarContrastWhenTransparent
+                RESIZE_MODE_RESIZEABLE,  // resizeMode
+                10,                      // minWidth
+                20                       // minHeight
+        );
+
+        TaskDescription td2 = new TaskDescription();
+        // Must overwrite all the fields
+        td2.copyFrom(td1);
+
+        assertEquals(td1.getLabel(), td2.getLabel());
+        assertEquals(td1.getInMemoryIcon(), td2.getInMemoryIcon());
+        assertEquals(td1.getIconFilename(), td2.getIconFilename());
+        assertEquals(td1.getIconResource(), td2.getIconResource());
+        assertEquals(td1.getPrimaryColor(), td2.getPrimaryColor());
+        assertEquals(td1.getBackgroundColor(), td2.getBackgroundColor());
+        assertEquals(td1.getStatusBarColor(), td2.getStatusBarColor());
+        assertEquals(td1.getNavigationBarColor(), td2.getNavigationBarColor());
+        assertEquals(td1.getEnsureStatusBarContrastWhenTransparent(),
+                td2.getEnsureStatusBarContrastWhenTransparent());
+        assertEquals(td1.getEnsureNavigationBarContrastWhenTransparent(),
+                td2.getEnsureNavigationBarContrastWhenTransparent());
+        assertEquals(td1.getResizeMode(), td2.getResizeMode());
+        assertEquals(td1.getMinWidth(), td2.getMinWidth());
+        assertEquals(td1.getMinHeight(), td2.getMinHeight());
+    }
+
+    @SmallTest
+    public void testTaskDescriptionCopyFromPreserveHiddenFields() {
+        TaskDescription td1 = new TaskDescription(
+                "test label",              // label
+                null,                      // bitmap
+                21,                        // iconRes
+                "dummy file",              // iconFilename
+                0x111111,                  // colorPrimary
+                0x222222,                  // colorBackground
+                0x333333,                  // statusBarColor
+                0x444444,                  // navigationBarColor
+                false,                     // ensureStatusBarContrastWhenTransparent
+                false,                     // ensureNavigationBarContrastWhenTransparent
+                RESIZE_MODE_UNRESIZEABLE,  // resizeMode
+                10,                        // minWidth
+                20                         // minHeight
+        );
+
+        TaskDescription td2 = new TaskDescription(
+                "test label2",           // label
+                null,                    // bitmap
+                212,                     // iconRes
+                "dummy file2",           // iconFilename
+                0x1111112,               // colorPrimary
+                0x2222222,               // colorBackground
+                0x3333332,               // statusBarColor
+                0x4444442,               // navigationBarColor
+                true,                    // ensureStatusBarContrastWhenTransparent
+                true,                    // ensureNavigationBarContrastWhenTransparent
+                RESIZE_MODE_RESIZEABLE,  // resizeMode
+                102,                     // minWidth
+                202                      // minHeight
+        );
+
+        // Must overwrite all public and hidden fields, since other has all fields set.
+        td2.copyFromPreserveHiddenFields(td1);
+
+        assertEquals(td1.getLabel(), td2.getLabel());
+        assertEquals(td1.getInMemoryIcon(), td2.getInMemoryIcon());
+        assertEquals(td1.getIconFilename(), td2.getIconFilename());
+        assertEquals(td1.getIconResource(), td2.getIconResource());
+        assertEquals(td1.getPrimaryColor(), td2.getPrimaryColor());
+        assertEquals(td1.getBackgroundColor(), td2.getBackgroundColor());
+        assertEquals(td1.getStatusBarColor(), td2.getStatusBarColor());
+        assertEquals(td1.getNavigationBarColor(), td2.getNavigationBarColor());
+        assertEquals(td1.getEnsureStatusBarContrastWhenTransparent(),
+                td2.getEnsureStatusBarContrastWhenTransparent());
+        assertEquals(td1.getEnsureNavigationBarContrastWhenTransparent(),
+                td2.getEnsureNavigationBarContrastWhenTransparent());
+        assertEquals(td1.getResizeMode(), td2.getResizeMode());
+        assertEquals(td1.getMinWidth(), td2.getMinWidth());
+        assertEquals(td1.getMinHeight(), td2.getMinHeight());
+
+        TaskDescription td3 = new TaskDescription();
+        // Must overwrite only public fields, and preserve hidden fields.
+        td2.copyFromPreserveHiddenFields(td3);
+
+        // Overwritten fields
+        assertEquals(td3.getLabel(), td2.getLabel());
+        assertEquals(td3.getInMemoryIcon(), td2.getInMemoryIcon());
+        assertEquals(td3.getIconFilename(), td2.getIconFilename());
+        assertEquals(td3.getIconResource(), td2.getIconResource());
+        assertEquals(td3.getPrimaryColor(), td2.getPrimaryColor());
+        assertEquals(td3.getEnsureStatusBarContrastWhenTransparent(),
+                td2.getEnsureStatusBarContrastWhenTransparent());
+        assertEquals(td3.getEnsureNavigationBarContrastWhenTransparent(),
+                td2.getEnsureNavigationBarContrastWhenTransparent());
+
+        // Preserved fields
+        assertEquals(td1.getBackgroundColor(), td2.getBackgroundColor());
+        assertEquals(td1.getStatusBarColor(), td2.getStatusBarColor());
+        assertEquals(td1.getNavigationBarColor(), td2.getNavigationBarColor());
+        assertEquals(td1.getResizeMode(), td2.getResizeMode());
+        assertEquals(td1.getMinWidth(), td2.getMinWidth());
+        assertEquals(td1.getMinHeight(), td2.getMinHeight());
+    }
+
     // If any entries in appear in the list, sanity check them against all running applications
     private void checkErrorListSanity(List<ActivityManager.ProcessErrorStateInfo> errList) {
         if (errList == null) return;
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 183c04e..20395fb 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -128,7 +128,7 @@
 
 prebuilt_etc {
     name: "privapp_whitelist_com.android.systemui",
-    product_specific: true,
+    system_ext_specific: true,
     sub_dir: "permissions",
     src: "com.android.systemui.xml",
     filename_from_src: true,
diff --git a/data/etc/CleanSpec.mk b/data/etc/CleanSpec.mk
index b76eb15..783a7ed 100644
--- a/data/etc/CleanSpec.mk
+++ b/data/etc/CleanSpec.mk
@@ -53,6 +53,8 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.settings.xml)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.launcher3.xml)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.launcher3.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.systemui.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.systemui.xml)
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
 # ******************************************************************
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 624fc50..238afd4 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -240,7 +240,7 @@
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.tethering">
+    <privapp-permissions package="com.android.networkstack.tethering">
         <permission name="android.permission.MANAGE_USB"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
         <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 3060476..9917cee 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -385,6 +385,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1263316010": {
+      "message": "Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and oldRotation=%s (%d)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
     "-1259022216": {
       "message": "SURFACE HIDE ( %s ): %s",
       "level": "INFO",
@@ -463,6 +469,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1108775960": {
+      "message": "%s is requesting orientation %d (%s)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
     "-1103716954": {
       "message": "Not removing %s due to exit animation",
       "level": "VERBOSE",
@@ -631,6 +643,12 @@
       "group": "WM_DEBUG_FOCUS_LIGHT",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-766059044": {
+      "message": "Display id=%d selected orientation %s (%d), got rotation %s (%d)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
     "-760801764": {
       "message": "onAnimationCancelled",
       "level": "DEBUG",
@@ -1267,12 +1285,6 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimation.java"
     },
-    "481370485": {
-      "message": "Computed rotation=%d for display id=%d based on lastOrientation=%d and oldRotation=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
     "490877640": {
       "message": "onStackOrderChanged(): stack=%s",
       "level": "DEBUG",
@@ -1795,12 +1807,6 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "1573332272": {
-      "message": "Display id=%d selected orientation %d, got rotation %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
     "1577579529": {
       "message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b",
       "level": "ERROR",
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 3f3ad57..3b86413 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -28,7 +28,6 @@
 import android.os.ServiceManager;
 import android.util.Log;
 import android.util.TimeUtils;
-import android.view.FrameMetricsObserver;
 import android.view.IGraphicsStats;
 import android.view.IGraphicsStatsCallback;
 import android.view.NativeVectorDrawableAnimator;
@@ -38,8 +37,6 @@
 import android.view.TextureLayer;
 import android.view.animation.AnimationUtils;
 
-import com.android.internal.util.VirtualRefBasePtr;
-
 import java.io.File;
 import java.io.FileDescriptor;
 import java.lang.annotation.Retention;
@@ -598,9 +595,8 @@
      *
      * @hide
      */
-    public void addFrameMetricsObserver(FrameMetricsObserver observer) {
-        long nativeObserver = nAddFrameMetricsObserver(mNativeProxy, observer);
-        observer.mNative = new VirtualRefBasePtr(nativeObserver);
+    public void addObserver(HardwareRendererObserver observer) {
+        nAddObserver(mNativeProxy, observer.getNativeInstance());
     }
 
     /**
@@ -608,9 +604,8 @@
      *
      * @hide
      */
-    public void removeFrameMetricsObserver(FrameMetricsObserver observer) {
-        nRemoveFrameMetricsObserver(mNativeProxy, observer.mNative.get());
-        observer.mNative = null;
+    public void removeObserver(HardwareRendererObserver observer) {
+        nRemoveObserver(mNativeProxy, observer.getNativeInstance());
     }
 
     /**
@@ -1170,10 +1165,9 @@
     private static native void nSetFrameCompleteCallback(long nativeProxy,
             FrameCompleteCallback callback);
 
-    private static native long nAddFrameMetricsObserver(long nativeProxy,
-            FrameMetricsObserver observer);
+    private static native void nAddObserver(long nativeProxy, long nativeObserver);
 
-    private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
+    private static native void nRemoveObserver(long nativeProxy, long nativeObserver);
 
     private static native int nCopySurfaceInto(Surface surface,
             int srcLeft, int srcTop, int srcRight, int srcBottom, long bitmapHandle);
diff --git a/graphics/java/android/graphics/HardwareRendererObserver.java b/graphics/java/android/graphics/HardwareRendererObserver.java
new file mode 100644
index 0000000..da9d03c
--- /dev/null
+++ b/graphics/java/android/graphics/HardwareRendererObserver.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+
+import com.android.internal.util.VirtualRefBasePtr;
+
+/**
+ * Provides streaming access to frame stats information from HardwareRenderer to apps.
+ *
+ * @hide
+ */
+public class HardwareRendererObserver {
+    private final long[] mFrameMetrics;
+    private final Handler mHandler;
+    private final OnFrameMetricsAvailableListener mListener;
+    private VirtualRefBasePtr mNativePtr;
+
+    /**
+     * Interface for clients that want frame timing information for each frame rendered.
+     * @hide
+     */
+    public interface OnFrameMetricsAvailableListener {
+        /**
+         * Called when information is available for the previously rendered frame.
+         *
+         * Reports can be dropped if this callback takes too long to execute, as the report producer
+         * cannot wait for the consumer to complete.
+         *
+         * It is highly recommended that clients copy the metrics array within this method
+         * and defer additional computation or storage to another thread to avoid unnecessarily
+         * dropping reports.
+         *
+         * @param dropCountSinceLastInvocation the number of reports dropped since the last time
+         * this callback was invoked.
+         */
+        void onFrameMetricsAvailable(int dropCountSinceLastInvocation);
+    }
+
+    /**
+     * Creates a FrameMetricsObserver
+     *
+     * @param frameMetrics the available metrics. This array is reused on every call to the listener
+     * and thus <strong>this reference should only be used within the scope of the listener callback
+     * as data is not guaranteed to be valid outside the scope of that method</strong>.
+     * @param handler the Handler to use when invoking callbacks
+     */
+    public HardwareRendererObserver(@NonNull OnFrameMetricsAvailableListener listener,
+            @NonNull long[] frameMetrics, @NonNull Handler handler) {
+        if (handler == null || handler.getLooper() == null) {
+            throw new NullPointerException("handler and its looper cannot be null");
+        }
+
+        if (handler.getLooper().getQueue() == null) {
+            throw new IllegalStateException("invalid looper, null message queue\n");
+        }
+
+        mFrameMetrics = frameMetrics;
+        mHandler = handler;
+        mListener = listener;
+        mNativePtr = new VirtualRefBasePtr(nCreateObserver());
+    }
+
+    /*package*/ long getNativeInstance() {
+        return mNativePtr.get();
+    }
+
+    // Called by native on the provided Handler
+    @SuppressWarnings("unused")
+    private void notifyDataAvailable() {
+        mHandler.post(() -> {
+            boolean hasMoreData = true;
+            while (hasMoreData) {
+                // a drop count of -1 is a sentinel that no more buffers are available
+                int dropCount = nGetNextBuffer(mNativePtr.get(), mFrameMetrics);
+                if (dropCount >= 0) {
+                    mListener.onFrameMetricsAvailable(dropCount);
+                } else {
+                    hasMoreData = false;
+                }
+            }
+        });
+    }
+
+    private native long nCreateObserver();
+    private static native int nGetNextBuffer(long nativePtr, long[] data);
+}
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index f5fa8c5..e93e7df 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -20,7 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 0840986..e70529b 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -22,7 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 090d915..51b299c 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -17,7 +17,7 @@
 package android.graphics.drawable;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
diff --git a/graphics/java/android/graphics/drawable/DrawableInflater.java b/graphics/java/android/graphics/drawable/DrawableInflater.java
index bad3791..3408b64 100644
--- a/graphics/java/android/graphics/drawable/DrawableInflater.java
+++ b/graphics/java/android/graphics/drawable/DrawableInflater.java
@@ -16,19 +16,19 @@
 
 package android.graphics.drawable;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.util.AttributeSet;
 import android.view.InflateException;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.util.HashMap;
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index 6c90c4c..e197e71 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index c6586ec..3881955 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -22,7 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Px;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index c2e3c64..cc7182c 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -21,7 +21,7 @@
 import android.annotation.IdRes;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index bc8a4cb..005a4d1 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 760d554..fb4146f 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 8561d95..99d27ba 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 1540cc2..e5e4d45 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index db5f082..43766b6 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -16,23 +16,23 @@
 
 package android.graphics.drawable;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.MathUtils;
+import android.util.TypedValue;
+
 import com.android.internal.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.Resources.Theme;
-import android.util.MathUtils;
-import android.util.TypedValue;
-import android.util.AttributeSet;
-
 import java.io.IOException;
 
 /**
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index 91ed061..af7eed4 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -16,14 +16,9 @@
 
 package android.graphics.drawable;
 
-import com.android.internal.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
@@ -34,6 +29,11 @@
 import android.util.TypedValue;
 import android.view.Gravity;
 
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 
 /**
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index f67188c..2920acb 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index 276f366..401e05f 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -16,7 +16,7 @@
 
 package android.graphics.drawable;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.Resources;
 import android.graphics.Canvas;
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index aa19b2a..e6fa866 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -16,7 +16,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.ComplexColor;
diff --git a/graphics/java/android/graphics/fonts/FontVariationAxis.java b/graphics/java/android/graphics/fonts/FontVariationAxis.java
index bcee559..4e6580e 100644
--- a/graphics/java/android/graphics/fonts/FontVariationAxis.java
+++ b/graphics/java/android/graphics/fonts/FontVariationAxis.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.text.TextUtils;
 
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index bd1a492..54710e5 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -19,7 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Matrix;
@@ -29,7 +29,9 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
+
 import com.android.internal.util.Preconditions;
+
 import dalvik.system.CloseGuard;
 
 import libcore.io.IoUtils;
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 048dee6..f53a7dc 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -16,7 +16,7 @@
 
 package android.security;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import com.android.org.bouncycastle.util.io.pem.PemObject;
 import com.android.org.bouncycastle.util.io.pem.PemReader;
diff --git a/keystore/java/android/security/GateKeeper.java b/keystore/java/android/security/GateKeeper.java
index a50ff79..af188a9 100644
--- a/keystore/java/android/security/GateKeeper.java
+++ b/keystore/java/android/security/GateKeeper.java
@@ -16,7 +16,7 @@
 
 package android.security;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.RemoteException;
 import android.os.ServiceManager;
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index d9ed5f3..dc57f55 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -16,10 +16,10 @@
 
 package android.security;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
 import android.app.Application;
 import android.app.KeyguardManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.hardware.face.FaceManager;
@@ -31,7 +31,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.security.KeyStoreException;
 import android.security.keymaster.ExportResult;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index d033294..71e6559 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.security.KeyStore;
 import android.security.keymaster.ExportResult;
 import android.security.keymaster.KeyCharacteristics;
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 6df3b8c..52ff9e0 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -21,8 +21,8 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.KeyguardManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricPrompt;
 import android.security.GateKeeper;
diff --git a/location/java/android/location/Country.java b/location/java/android/location/Country.java
index f3c2a16..8c40338 100644
--- a/location/java/android/location/Country.java
+++ b/location/java/android/location/Country.java
@@ -16,7 +16,7 @@
 
 package android.location;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
diff --git a/location/java/android/location/CountryDetector.java b/location/java/android/location/CountryDetector.java
index ae13949..e344b82 100644
--- a/location/java/android/location/CountryDetector.java
+++ b/location/java/android/location/CountryDetector.java
@@ -16,10 +16,8 @@
 
 package android.location;
 
-import java.util.HashMap;
-
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Build;
 import android.os.Handler;
@@ -27,6 +25,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.util.HashMap;
+
 /**
  * This class provides access to the system country detector service. This
  * service allows applications to obtain the country that the user is in.
diff --git a/location/java/android/location/CountryListener.java b/location/java/android/location/CountryListener.java
index 70a83c5..eb67205 100644
--- a/location/java/android/location/CountryListener.java
+++ b/location/java/android/location/CountryListener.java
@@ -16,7 +16,7 @@
 
 package android.location;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * The listener for receiving the notification when the country is detected or
diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java
index 45d92ee..1c6e9b6 100644
--- a/location/java/android/location/GeocoderParams.java
+++ b/location/java/android/location/GeocoderParams.java
@@ -16,7 +16,7 @@
 
 package android.location;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/location/java/android/location/Geofence.java b/location/java/android/location/Geofence.java
index 9570b26..af57bfd 100644
--- a/location/java/android/location/Geofence.java
+++ b/location/java/android/location/Geofence.java
@@ -16,7 +16,7 @@
 
 package android.location;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index db48ee7..7a12cee 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -19,7 +19,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index aa1484f..687535c3 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -31,9 +31,9 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index ca8f2ac..f3e4d81 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -22,7 +22,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index f9b2fe0..9846436 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -19,6 +19,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -37,8 +38,6 @@
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.telephony.GsmAlphabet;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
 import java.io.UnsupportedEncodingException;
 import java.util.concurrent.TimeUnit;
 
@@ -126,7 +125,7 @@
 
     public static class GpsNiNotification
     {
-        @android.annotation.UnsupportedAppUsage
+        @android.compat.annotation.UnsupportedAppUsage
         public GpsNiNotification() {
         }
         public int notificationId;
diff --git a/location/java/com/android/internal/location/ProviderRequest.java b/location/java/com/android/internal/location/ProviderRequest.java
index 155f788..c23f499 100644
--- a/location/java/com/android/internal/location/ProviderRequest.java
+++ b/location/java/com/android/internal/location/ProviderRequest.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.location;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.location.LocationRequest;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/media/java/android/media/AmrInputStream.java b/media/java/android/media/AmrInputStream.java
index 5088798..3cb224d 100644
--- a/media/java/android/media/AmrInputStream.java
+++ b/media/java/android/media/AmrInputStream.java
@@ -16,14 +16,14 @@
 
 package android.media;
 
-import java.io.InputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.media.MediaCodec.BufferInfo;
 import android.util.Log;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
 
 /**
  * DO NOT USE
diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java
index 8ac2655..c3dc118 100644
--- a/media/java/android/media/AsyncPlayer.java
+++ b/media/java/android/media/AsyncPlayer.java
@@ -17,9 +17,8 @@
 package android.media;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.media.PlayerBase;
 import android.net.Uri;
 import android.os.PowerManager;
 import android.os.SystemClock;
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 8de3e0a..ece5335 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -20,7 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.media.audiopolicy.AudioProductStrategy;
 import android.os.Build;
 import android.os.Bundle;
diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java
index 62b18cb..51909db 100644
--- a/media/java/android/media/AudioDevicePort.java
+++ b/media/java/android/media/AudioDevicePort.java
@@ -16,8 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
-import android.media.AudioSystem;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * The AudioDevicePort is a specialized type of AudioPort
diff --git a/media/java/android/media/AudioDevicePortConfig.java b/media/java/android/media/AudioDevicePortConfig.java
index 0c647ea..51b8037 100644
--- a/media/java/android/media/AudioDevicePortConfig.java
+++ b/media/java/android/media/AudioDevicePortConfig.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * An AudioDevicePortConfig describes a possible configuration of an output or input device
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index f0787e9..489d050 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -20,7 +20,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/media/java/android/media/AudioGain.java b/media/java/android/media/AudioGain.java
index dd129a2..cae1b59 100644
--- a/media/java/android/media/AudioGain.java
+++ b/media/java/android/media/AudioGain.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * The AudioGain describes a gain controller. Gain controllers are exposed by
diff --git a/media/java/android/media/AudioGainConfig.java b/media/java/android/media/AudioGainConfig.java
index f5ebef8..dfefa86 100644
--- a/media/java/android/media/AudioGainConfig.java
+++ b/media/java/android/media/AudioGainConfig.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * The AudioGainConfig is used by APIs setting or getting values on a given gain
diff --git a/media/java/android/media/AudioHandle.java b/media/java/android/media/AudioHandle.java
index 24f81f9..8fc834f 100644
--- a/media/java/android/media/AudioHandle.java
+++ b/media/java/android/media/AudioHandle.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * The AudioHandle is used by the audio framework implementation to
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index fac276c..c8a7ef5 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -28,12 +28,12 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.bluetooth.BluetoothCodecConfig;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/media/java/android/media/AudioMixPort.java b/media/java/android/media/AudioMixPort.java
index c4a5c4d..33d603f 100644
--- a/media/java/android/media/AudioMixPort.java
+++ b/media/java/android/media/AudioMixPort.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * The AudioMixPort is a specialized type of AudioPort
diff --git a/media/java/android/media/AudioMixPortConfig.java b/media/java/android/media/AudioMixPortConfig.java
index 315e46b..9d81206 100644
--- a/media/java/android/media/AudioMixPortConfig.java
+++ b/media/java/android/media/AudioMixPortConfig.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * An AudioMixPortConfig describes a possible configuration of an output or input mixer.
diff --git a/media/java/android/media/AudioPatch.java b/media/java/android/media/AudioPatch.java
index d1f8006..e5107d4 100644
--- a/media/java/android/media/AudioPatch.java
+++ b/media/java/android/media/AudioPatch.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 
 /**
diff --git a/media/java/android/media/AudioPort.java b/media/java/android/media/AudioPort.java
index 83eb240..7c3ca24 100644
--- a/media/java/android/media/AudioPort.java
+++ b/media/java/android/media/AudioPort.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * An audio port is a node of the audio framework or hardware that can be connected to or
diff --git a/media/java/android/media/AudioPortConfig.java b/media/java/android/media/AudioPortConfig.java
index ac19bb1..16fb5b8 100644
--- a/media/java/android/media/AudioPortConfig.java
+++ b/media/java/android/media/AudioPortConfig.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * An AudioPortConfig contains a possible configuration of an audio port chosen
diff --git a/media/java/android/media/AudioPortEventHandler.java b/media/java/android/media/AudioPortEventHandler.java
index 6d9d626..14249cb 100644
--- a/media/java/android/media/AudioPortEventHandler.java
+++ b/media/java/android/media/AudioPortEventHandler.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 95afb09..fd3523d 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -23,8 +23,8 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.media.MediaRecorder.Source;
 import android.media.audiopolicy.AudioMix;
 import android.media.audiopolicy.AudioPolicy;
diff --git a/media/java/android/media/AudioRecordingConfiguration.java b/media/java/android/media/AudioRecordingConfiguration.java
index 874a215..5f32c0f 100644
--- a/media/java/android/media/AudioRecordingConfiguration.java
+++ b/media/java/android/media/AudioRecordingConfiguration.java
@@ -19,7 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.media.audiofx.AudioEffect;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 33ec46a..8e76fcf 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -19,8 +19,8 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.bluetooth.BluetoothCodecConfig;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.media.audiofx.AudioEffect;
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 7cd09de..0ced68ef 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -23,7 +23,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index 963b1d1..e4bab74 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.hardware.Camera;
 import android.hardware.Camera.CameraInfo;
 import android.os.Build;
diff --git a/media/java/android/media/DecoderCapabilities.java b/media/java/android/media/DecoderCapabilities.java
index df5e918..ebfc63b 100644
--- a/media/java/android/media/DecoderCapabilities.java
+++ b/media/java/android/media/DecoderCapabilities.java
@@ -16,9 +16,10 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
-import java.util.List;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * {@hide}
diff --git a/media/java/android/media/EncoderCapabilities.java b/media/java/android/media/EncoderCapabilities.java
index c09c5fa..67ce0f7 100644
--- a/media/java/android/media/EncoderCapabilities.java
+++ b/media/java/android/media/EncoderCapabilities.java
@@ -16,9 +16,10 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
-import java.util.List;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * The EncoderCapabilities class is used to retrieve the
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index ce4aac9..767b67b 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -20,7 +20,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.AssetManager;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 7ba122b..79b8611 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -16,14 +16,13 @@
 
 package android.media;
 
-import java.nio.ByteBuffer;
-import java.lang.AutoCloseable;
-
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Rect;
 import android.hardware.HardwareBuffer;
 
+import java.nio.ByteBuffer;
+
 /**
  * <p>A single complete image buffer to use with a media source such as a
  * {@link MediaCodec} or a
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index e85b3ff9..84ee09b 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -17,7 +17,7 @@
 package android.media;
 
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.AssetFileDescriptor;
 import android.os.Handler;
 import android.os.Looper;
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index d16a216..176bb37 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -19,7 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.ImageFormat;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 91d644b..cbc9683 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -23,7 +23,7 @@
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.SystemProperties;
 import android.util.Log;
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 6523e30..13bd856 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -21,17 +21,17 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringDef;
-import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.Looper;
-import android.os.Message;
 import android.os.Parcel;
 import android.os.PersistableBundle;
 import android.util.Log;
+
 import dalvik.system.CloseGuard;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index c4eb031..9908e04 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -20,7 +20,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.mtp.MtpConstants;
 
 import libcore.content.type.MimeMap;
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index dead066..79b3886 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -19,7 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index 8ee929e..a17ff82 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -18,13 +18,14 @@
 
 import static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.net.NetworkUtils;
 import android.os.IBinder;
 import android.os.StrictMode;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
+
 import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/media/java/android/media/MediaHTTPService.java b/media/java/android/media/MediaHTTPService.java
index 97a0df7..3008067 100644
--- a/media/java/android/media/MediaHTTPService.java
+++ b/media/java/android/media/MediaHTTPService.java
@@ -17,7 +17,7 @@
 package android.media;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.IBinder;
 import android.util.Log;
 
diff --git a/media/java/android/media/MediaInserter.java b/media/java/android/media/MediaInserter.java
index 0749f58..ca7a01c 100644
--- a/media/java/android/media/MediaInserter.java
+++ b/media/java/android/media/MediaInserter.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentProviderClient;
 import android.content.ContentValues;
 import android.net.Uri;
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index 8512dbe..a23191f 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -17,7 +17,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.StringDef;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 5d2bdd7..7fca03c 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -19,7 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index 0fb392b..14a48d7 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -18,8 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
-import android.media.MediaCodec;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.media.MediaCodec.BufferInfo;
 
 import dalvik.system.CloseGuard;
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 7d107dd..71c97534 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -19,8 +19,8 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index abb8206..4198d79 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -23,8 +23,8 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.hardware.Camera;
 import android.os.Build;
 import android.os.Handler;
diff --git a/media/java/android/media/MediaRoute2ProviderInfo.java b/media/java/android/media/MediaRoute2ProviderInfo.java
index 4f203de..b5de88a 100644
--- a/media/java/android/media/MediaRoute2ProviderInfo.java
+++ b/media/java/android/media/MediaRoute2ProviderInfo.java
@@ -51,9 +51,8 @@
     private final ArrayMap<String, MediaRoute2Info> mRoutes;
 
     MediaRoute2ProviderInfo(@NonNull Builder builder) {
-        if (builder == null) {
-            throw new NullPointerException("Builder must not be null.");
-        }
+        Objects.requireNonNull(builder, "builder must not be null.");
+
         mUniqueId = builder.mUniqueId;
         mRoutes = builder.mRoutes;
     }
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index d72231f..9837e1c 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -22,8 +22,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 3e6f4c0..bad0ef4 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -23,6 +23,7 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
@@ -51,7 +52,6 @@
  * @hide
  */
 public class MediaRouter2 {
-
     /** @hide */
     @Retention(SOURCE)
     @IntDef(value = {
@@ -102,13 +102,11 @@
             new CopyOnWriteArrayList<>();
 
     private final String mPackageName;
+    @GuardedBy("sLock")
     private final Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
 
-    //TODO: Use a lock for this to cover the below use case
-    // mRouter.setControlCategories(...);
-    // routes = mRouter.getRoutes();
-    // The current implementation returns empty list
-    private volatile List<String> mControlCategories = Collections.emptyList();
+    @GuardedBy("sLock")
+    private List<String> mControlCategories = Collections.emptyList();
 
     private MediaRoute2Info mSelectedRoute;
     @GuardedBy("sLock")
@@ -117,7 +115,9 @@
     private Client2 mClient;
 
     final Handler mHandler;
-    volatile List<MediaRoute2Info> mFilteredRoutes = Collections.emptyList();
+    @GuardedBy("sLock")
+    private boolean mShouldUpdateRoutes;
+    private volatile List<MediaRoute2Info> mFilteredRoutes = Collections.emptyList();
 
     /**
      * Gets an instance of the media router associated with the context.
@@ -171,8 +171,7 @@
     /**
      * Registers a callback to discover routes and to receive events when they change.
      * <p>
-     * If you register the same callback twice or more, the previous arguments will be overwritten
-     * with the new arguments.
+     * If you register the same callback twice or more, it will be ignored.
      * </p>
      */
     public void registerCallback(@NonNull @CallbackExecutor Executor executor,
@@ -180,18 +179,10 @@
         Objects.requireNonNull(executor, "executor must not be null");
         Objects.requireNonNull(callback, "callback must not be null");
 
-        CallbackRecord record;
-        // This is required to prevent adding the same callback twice.
-        synchronized (mCallbackRecords) {
-            final int index = findCallbackRecordIndexLocked(callback);
-            if (index < 0) {
-                record = new CallbackRecord(callback);
-                mCallbackRecords.add(record);
-            } else {
-                record = mCallbackRecords.get(index);
-            }
-            record.mExecutor = executor;
-            record.mFlags = flags;
+        CallbackRecord record = new CallbackRecord(callback, executor, flags);
+        if (!mCallbackRecords.addIfAbsent(record)) {
+            Log.w(TAG, "Ignoring the same callback");
+            return;
         }
 
         synchronized (sLock) {
@@ -206,8 +197,6 @@
                 }
             }
         }
-        //TODO: Is it thread-safe?
-        record.notifyRoutes();
 
         //TODO: Update discovery request here.
     }
@@ -222,23 +211,20 @@
     public void unregisterCallback(@NonNull Callback callback) {
         Objects.requireNonNull(callback, "callback must not be null");
 
-        synchronized (mCallbackRecords) {
-            final int index = findCallbackRecordIndexLocked(callback);
-            if (index < 0) {
-                Log.w(TAG, "Ignoring to remove unknown callback. " + callback);
-                return;
-            }
-            mCallbackRecords.remove(index);
-            synchronized (sLock) {
-                if (mCallbackRecords.size() == 0 && mClient != null) {
-                    try {
-                        mMediaRouterService.unregisterClient2(mClient);
-                    } catch (RemoteException ex) {
-                        Log.e(TAG, "Unable to unregister media router.", ex);
-                    }
-                    //TODO: Clean up mRoutes. (onHandler?)
-                    mClient = null;
+        if (!mCallbackRecords.remove(new CallbackRecord(callback, null, 0))) {
+            Log.w(TAG, "Ignoring unknown callback");
+            return;
+        }
+
+        synchronized (sLock) {
+            if (mCallbackRecords.size() == 0 && mClient != null) {
+                try {
+                    mMediaRouterService.unregisterClient2(mClient);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Unable to unregister media router.", ex);
                 }
+                //TODO: Clean up mRoutes. (onHandler?)
+                mClient = null;
             }
         }
     }
@@ -246,26 +232,52 @@
     //TODO(b/139033746): Rename "Control Category" when it's finalized.
     /**
      * Sets the control categories of the application.
-     * Routes that support at least one of the given control categories only exists and are handled
+     * Routes that support at least one of the given control categories are handled
      * by the media router.
      */
     public void setControlCategories(@NonNull Collection<String> controlCategories) {
         Objects.requireNonNull(controlCategories, "control categories must not be null");
 
-        // To ensure invoking callbacks correctly according to control categories
-        mHandler.sendMessage(obtainMessage(MediaRouter2::setControlCategoriesOnHandler,
-                MediaRouter2.this, new ArrayList<>(controlCategories)));
+        List<String> newControlCategories = new ArrayList<>(controlCategories);
+
+        synchronized (sLock) {
+            mShouldUpdateRoutes = true;
+
+            // invoke callbacks due to control categories change
+            handleControlCategoriesChangedLocked(newControlCategories);
+            if (mClient != null) {
+                try {
+                    mMediaRouterService.setControlCategories(mClient, mControlCategories);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Unable to set control categories.", ex);
+                }
+            }
+        }
     }
 
     /**
      * Gets the unmodifiable list of {@link MediaRoute2Info routes} currently
      * known to the media router.
+     * Please note that the list can be changed before callbacks are invoked.
      *
      * @return the list of routes that support at least one of the control categories set by
      * the application
      */
     @NonNull
     public List<MediaRoute2Info> getRoutes() {
+        synchronized (sLock) {
+            if (mShouldUpdateRoutes) {
+                mShouldUpdateRoutes = false;
+
+                List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
+                for (MediaRoute2Info route : mRoutes.values()) {
+                    if (route.supportsControlCategory(mControlCategories)) {
+                        filteredRoutes.add(route);
+                    }
+                }
+                mFilteredRoutes = Collections.unmodifiableList(filteredRoutes);
+            }
+        }
         return mFilteredRoutes;
     }
 
@@ -379,43 +391,16 @@
         }
     }
 
-    @GuardedBy("mCallbackRecords")
-    private int findCallbackRecordIndexLocked(Callback callback) {
-        final int count = mCallbackRecords.size();
-        for (int i = 0; i < count; i++) {
-            CallbackRecord callbackRecord = mCallbackRecords.get(i);
-            if (callbackRecord.mCallback == callback) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    private void setControlCategoriesOnHandler(List<String> newControlCategories) {
-        List<String> prevControlCategories = mControlCategories;
+    private void handleControlCategoriesChangedLocked(List<String> newControlCategories) {
         List<MediaRoute2Info> addedRoutes = new ArrayList<>();
         List<MediaRoute2Info> removedRoutes = new ArrayList<>();
-        List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
 
+        List<String> prevControlCategories = mControlCategories;
         mControlCategories = newControlCategories;
-        Client2 client;
-        synchronized (sLock) {
-            client = mClient;
-        }
-        if (client != null) {
-            try {
-                mMediaRouterService.setControlCategories(client, mControlCategories);
-            } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to set control categories.", ex);
-            }
-        }
 
         for (MediaRoute2Info route : mRoutes.values()) {
             boolean preSupported = route.supportsControlCategory(prevControlCategories);
             boolean postSupported = route.supportsControlCategory(newControlCategories);
-            if (postSupported) {
-                filteredRoutes.add(route);
-            }
             if (preSupported == postSupported) {
                 continue;
             }
@@ -425,13 +410,14 @@
                 addedRoutes.add(route);
             }
         }
-        mFilteredRoutes = Collections.unmodifiableList(filteredRoutes);
 
         if (removedRoutes.size() > 0) {
-            notifyRoutesRemoved(removedRoutes);
+            mHandler.sendMessage(obtainMessage(MediaRouter2::notifyRoutesRemoved,
+                    MediaRouter2.this, removedRoutes));
         }
         if (addedRoutes.size() > 0) {
-            notifyRoutesAdded(addedRoutes);
+            mHandler.sendMessage(obtainMessage(MediaRouter2::notifyRoutesAdded,
+                    MediaRouter2.this, addedRoutes));
         }
     }
 
@@ -441,42 +427,47 @@
         //  2) Call onRouteSelected(system_route, reason_fallback) if previously selected route
         //     does not exist anymore. => We may need 'boolean MediaRoute2Info#isSystemRoute()'.
         List<MediaRoute2Info> addedRoutes = new ArrayList<>();
-        for (MediaRoute2Info route : routes) {
-            mRoutes.put(route.getUniqueId(), route);
-            if (route.supportsControlCategory(mControlCategories)) {
-                addedRoutes.add(route);
+        synchronized (sLock) {
+            for (MediaRoute2Info route : routes) {
+                mRoutes.put(route.getUniqueId(), route);
+                if (route.supportsControlCategory(mControlCategories)) {
+                    addedRoutes.add(route);
+                }
             }
+            mShouldUpdateRoutes = true;
         }
         if (addedRoutes.size() > 0) {
-            refreshFilteredRoutes();
             notifyRoutesAdded(addedRoutes);
         }
     }
 
     void removeRoutesOnHandler(List<MediaRoute2Info> routes) {
         List<MediaRoute2Info> removedRoutes = new ArrayList<>();
-        for (MediaRoute2Info route : routes) {
-            mRoutes.remove(route.getUniqueId());
-            if (route.supportsControlCategory(mControlCategories)) {
-                removedRoutes.add(route);
+        synchronized (sLock) {
+            for (MediaRoute2Info route : routes) {
+                mRoutes.remove(route.getUniqueId());
+                if (route.supportsControlCategory(mControlCategories)) {
+                    removedRoutes.add(route);
+                }
             }
+            mShouldUpdateRoutes = true;
         }
         if (removedRoutes.size() > 0) {
-            refreshFilteredRoutes();
             notifyRoutesRemoved(removedRoutes);
         }
     }
 
     void changeRoutesOnHandler(List<MediaRoute2Info> routes) {
         List<MediaRoute2Info> changedRoutes = new ArrayList<>();
-        for (MediaRoute2Info route : routes) {
-            mRoutes.put(route.getUniqueId(), route);
-            if (route.supportsControlCategory(mControlCategories)) {
-                changedRoutes.add(route);
+        synchronized (sLock) {
+            for (MediaRoute2Info route : routes) {
+                mRoutes.put(route.getUniqueId(), route);
+                if (route.supportsControlCategory(mControlCategories)) {
+                    changedRoutes.add(route);
+                }
             }
         }
         if (changedRoutes.size() > 0) {
-            refreshFilteredRoutes();
             notifyRoutesChanged(changedRoutes);
         }
     }
@@ -500,17 +491,6 @@
         notifyRouteSelected(route, reason, controlHints);
     }
 
-    private void refreshFilteredRoutes() {
-        List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
-
-        for (MediaRoute2Info route : mRoutes.values()) {
-            if (route.supportsControlCategory(mControlCategories)) {
-                filteredRoutes.add(route);
-            }
-        }
-        mFilteredRoutes = Collections.unmodifiableList(filteredRoutes);
-    }
-
     private void notifyRoutesAdded(List<MediaRoute2Info> routes) {
         for (CallbackRecord record: mCallbackRecords) {
             record.mExecutor.execute(
@@ -544,13 +524,16 @@
      */
     public static class Callback {
         /**
-         * Called when routes are added.
+         * Called when routes are added. Whenever you registers a callback, this will
+         * be invoked with known routes.
+         *
          * @param routes the list of routes that have been added. It's never empty.
          */
         public void onRoutesAdded(@NonNull List<MediaRoute2Info> routes) {}
 
         /**
          * Called when routes are removed.
+         *
          * @param routes the list of routes that have been removed. It's never empty.
          */
         public void onRoutesRemoved(@NonNull List<MediaRoute2Info> routes) {}
@@ -569,6 +552,7 @@
 
         /**
          * Called when a route is selected. Exactly one route can be selected at a time.
+         *
          * @param route the selected route.
          * @param reason the reason why the route is selected.
          * @param controlHints An optional bundle of provider-specific arguments which may be
@@ -587,16 +571,26 @@
         public Executor mExecutor;
         public int mFlags;
 
-        CallbackRecord(@NonNull Callback callback) {
+        CallbackRecord(@NonNull Callback callback, @Nullable Executor executor, int flags) {
             mCallback = callback;
+            mExecutor = executor;
+            mFlags = flags;
         }
 
-        void notifyRoutes() {
-            final List<MediaRoute2Info> routes = mFilteredRoutes;
-            // notify only when bound to media router service.
-            if (routes.size() > 0) {
-                mExecutor.execute(() -> mCallback.onRoutesAdded(routes));
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
             }
+            if (!(obj instanceof CallbackRecord)) {
+                return false;
+            }
+            return mCallback == ((CallbackRecord) obj).mCallback;
+        }
+
+        @Override
+        public int hashCode() {
+            return mCallback.hashCode();
         }
     }
 
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index d56dd11..502538d 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -57,7 +57,7 @@
     private Client mClient;
     private final IMediaRouterService mMediaRouterService;
     final Handler mHandler;
-    final List<CallbackRecord> mCallbackRecords = new CopyOnWriteArrayList<>();
+    final CopyOnWriteArrayList<CallbackRecord> mCallbackRecords = new CopyOnWriteArrayList<>();
 
     private final Object mRoutesLock = new Object();
     @GuardedBy("mRoutesLock")
@@ -99,14 +99,10 @@
         Objects.requireNonNull(executor, "executor must not be null");
         Objects.requireNonNull(callback, "callback must not be null");
 
-        CallbackRecord callbackRecord;
-        synchronized (mCallbackRecords) {
-            if (findCallbackRecordIndexLocked(callback) >= 0) {
-                Log.w(TAG, "Ignoring to add the same callback twice.");
-                return;
-            }
-            callbackRecord = new CallbackRecord(executor, callback);
-            mCallbackRecords.add(callbackRecord);
+        CallbackRecord callbackRecord = new CallbackRecord(executor, callback);
+        if (!mCallbackRecords.addIfAbsent(callbackRecord)) {
+            Log.w(TAG, "Ignoring to add the same callback twice.");
+            return;
         }
 
         synchronized (sLock) {
@@ -118,8 +114,6 @@
                 } catch (RemoteException ex) {
                     Log.e(TAG, "Unable to register media router manager.", ex);
                 }
-            } else {
-                callbackRecord.notifyRoutes();
             }
         }
     }
@@ -132,36 +126,23 @@
     public void unregisterCallback(@NonNull Callback callback) {
         Objects.requireNonNull(callback, "callback must not be null");
 
-        synchronized (mCallbackRecords) {
-            final int index = findCallbackRecordIndexLocked(callback);
-            if (index < 0) {
-                Log.w(TAG, "Ignore removing unknown callback. " + callback);
-                return;
-            }
-            mCallbackRecords.remove(index);
-            synchronized (sLock) {
-                if (mCallbackRecords.size() == 0 && mClient != null) {
-                    try {
-                        mMediaRouterService.unregisterManager(mClient);
-                    } catch (RemoteException ex) {
-                        Log.e(TAG, "Unable to unregister media router manager", ex);
-                    }
-                    //TODO: clear mRoutes?
-                    mClient = null;
-                }
-            }
+        if (!mCallbackRecords.remove(new CallbackRecord(null, callback))) {
+            Log.w(TAG, "Ignore removing unknown callback. " + callback);
+            return;
         }
-    }
 
-    @GuardedBy("mCallbackRecords")
-    private int findCallbackRecordIndexLocked(Callback callback) {
-        final int count = mCallbackRecords.size();
-        for (int i = 0; i < count; i++) {
-            if (mCallbackRecords.get(i).mCallback == callback) {
-                return i;
+        synchronized (sLock) {
+            if (mCallbackRecords.size() == 0 && mClient != null) {
+                try {
+                    mMediaRouterService.unregisterManager(mClient);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Unable to unregister media router manager", ex);
+                }
+                //TODO: clear mRoutes?
+                mClient = null;
+                mControlCategoryMap.clear();
             }
         }
-        return -1;
     }
 
     //TODO: Use cache not to create array. For now, it's unclear when to purge the cache.
@@ -187,7 +168,6 @@
                 }
             }
         }
-        //TODO: Should we cache this?
         return routes;
     }
 
@@ -342,10 +322,14 @@
     }
 
     void updateControlCategories(String packageName, List<String> categories) {
-        mControlCategoryMap.put(packageName, categories);
+        List<String> prevCategories = mControlCategoryMap.put(packageName, categories);
+        if ((prevCategories == null && categories.size() == 0)
+                || Objects.equals(categories, prevCategories)) {
+            return;
+        }
         for (CallbackRecord record : mCallbackRecords) {
             record.mExecutor.execute(
-                    () -> record.mCallback.onControlCategoriesChanged(packageName));
+                    () -> record.mCallback.onControlCategoriesChanged(packageName, categories));
         }
     }
 
@@ -386,8 +370,10 @@
          * Called when the control categories of an app is changed.
          *
          * @param packageName the package name of the application
+         * @param controlCategories the list of control categories set by an application.
          */
-        public void onControlCategoriesChanged(@NonNull String packageName) {}
+        public void onControlCategoriesChanged(@NonNull String packageName,
+                @NonNull List<String> controlCategories) {}
     }
 
     final class CallbackRecord {
@@ -399,14 +385,20 @@
             mCallback = callback;
         }
 
-        void notifyRoutes() {
-            List<MediaRoute2Info> routes;
-            synchronized (mRoutesLock) {
-                routes = new ArrayList<>(mRoutes.values());
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
             }
-            if (routes.size() > 0) {
-                mExecutor.execute(() -> mCallback.onRoutesAdded(routes));
+            if (!(obj instanceof CallbackRecord)) {
+                return false;
             }
+            return mCallback ==  ((CallbackRecord) obj).mCallback;
+        }
+
+        @Override
+        public int hashCode() {
+            return mCallback.hashCode();
         }
     }
 
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index ca96c9a..aae2606 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentValues;
 import android.content.Context;
 import android.net.Uri;
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
index 792a2ba..ef17073 100644
--- a/media/java/android/media/Metadata.java
+++ b/media/java/android/media/Metadata.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.util.Log;
 import android.util.MathUtils;
diff --git a/media/java/android/media/MicrophoneInfo.java b/media/java/android/media/MicrophoneInfo.java
index f805975..876628f 100644
--- a/media/java/android/media/MicrophoneInfo.java
+++ b/media/java/android/media/MicrophoneInfo.java
@@ -18,7 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Pair;
 
 import java.lang.annotation.Retention;
diff --git a/media/java/android/media/PlaybackParams.java b/media/java/android/media/PlaybackParams.java
index b4325b6..f24f831 100644
--- a/media/java/android/media/PlaybackParams.java
+++ b/media/java/android/media/PlaybackParams.java
@@ -18,7 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 325420b..c5fd3c3 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -16,8 +16,8 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.graphics.Bitmap;
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index f70963a..9e48f1e 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -16,8 +16,8 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Bitmap;
diff --git a/media/java/android/media/RemoteDisplay.java b/media/java/android/media/RemoteDisplay.java
index 2be206f..e529af9 100644
--- a/media/java/android/media/RemoteDisplay.java
+++ b/media/java/android/media/RemoteDisplay.java
@@ -16,12 +16,12 @@
 
 package android.media;
 
-import dalvik.system.CloseGuard;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Handler;
 import android.view.Surface;
 
+import dalvik.system.CloseGuard;
+
 /**
  * Listens for Wifi remote display connections managed by the media server.
  *
diff --git a/media/java/android/media/RemoteDisplayState.java b/media/java/android/media/RemoteDisplayState.java
index 2f4ace0..fed361a 100644
--- a/media/java/android/media/RemoteDisplayState.java
+++ b/media/java/android/media/RemoteDisplayState.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index eb680c8..d35bc41 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -17,7 +17,7 @@
 package android.media;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index a1e1591..d058243 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -23,9 +23,9 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.WorkerThread;
 import android.app.Activity;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.ContentUris;
diff --git a/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl b/media/java/android/media/RouteSessionInfo.aidl
similarity index 66%
copy from core/java/android/os/incremental/NamedParcelFileDescriptor.aidl
copy to media/java/android/media/RouteSessionInfo.aidl
index 038ced1..fb5d836 100644
--- a/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl
+++ b/media/java/android/media/RouteSessionInfo.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,15 +14,6 @@
  * limitations under the License.
  */
 
-package android.os.incremental;
+package android.media;
 
-import android.os.ParcelFileDescriptor;
-
-/**
- * A named ParcelFileDescriptor.
- * @hide
- */
-parcelable NamedParcelFileDescriptor {
-    @utf8InCpp String name;
-    ParcelFileDescriptor fd;
-}
+parcelable RouteSessionInfo;
diff --git a/media/java/android/media/RouteSessionInfo.java b/media/java/android/media/RouteSessionInfo.java
new file mode 100644
index 0000000..0878e6b
--- /dev/null
+++ b/media/java/android/media/RouteSessionInfo.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Describes a route session that is made when a media route is selected.
+ * @hide
+ */
+public class RouteSessionInfo implements Parcelable {
+    @NonNull
+    public static final Creator<RouteSessionInfo> CREATOR =
+            new Creator<RouteSessionInfo>() {
+                @Override
+                public RouteSessionInfo createFromParcel(Parcel in) {
+                    return new RouteSessionInfo(in);
+                }
+                @Override
+                public RouteSessionInfo[] newArray(int size) {
+                    return new RouteSessionInfo[size];
+                }
+            };
+
+    final int mSessionId;
+    final String mPackageName;
+    final String mControlCategory;
+    final List<String> mSelectedRoutes;
+    final List<String> mDeselectableRoutes;
+    final List<String> mGroupableRoutes;
+    final List<String> mTransferrableRoutes;
+
+    RouteSessionInfo(@NonNull Builder builder) {
+        Objects.requireNonNull(builder, "builder must not be null.");
+
+        mSessionId = builder.mSessionId;
+        mPackageName = builder.mPackageName;
+        mControlCategory = builder.mControlCategory;
+
+        mSelectedRoutes = Collections.unmodifiableList(builder.mSelectedRoutes);
+        mDeselectableRoutes = Collections.unmodifiableList(builder.mDeselectableRoutes);
+        mGroupableRoutes = Collections.unmodifiableList(builder.mGroupableRoutes);
+        mTransferrableRoutes = Collections.unmodifiableList(builder.mTransferrableRoutes);
+    }
+
+    RouteSessionInfo(@NonNull Parcel src) {
+        Objects.requireNonNull(src, "src must not be null.");
+
+        mSessionId = src.readInt();
+        mPackageName = ensureString(src.readString());
+        mControlCategory = ensureString(src.readString());
+
+        mSelectedRoutes = ensureList(src.createStringArrayList());
+        mDeselectableRoutes = ensureList(src.createStringArrayList());
+        mGroupableRoutes = ensureList(src.createStringArrayList());
+        mTransferrableRoutes = ensureList(src.createStringArrayList());
+    }
+
+    private static String ensureString(String str) {
+        if (str != null) {
+            return str;
+        }
+        return "";
+    }
+
+    private static <T> List<T> ensureList(List<? extends T> list) {
+        if (list != null) {
+            return Collections.unmodifiableList(list);
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Returns whether the session info is valid or not
+     */
+    public boolean isValid() {
+        return !TextUtils.isEmpty(mPackageName)
+                && !TextUtils.isEmpty(mControlCategory)
+                && mSelectedRoutes.size() > 0;
+    }
+
+    /**
+     * Gets the id of the session
+     */
+    @NonNull
+    public int getSessionId() {
+        return mSessionId;
+    }
+
+    /**
+     * Gets the control category of the session.
+     * Routes that don't support the category can't be added to the session.
+     */
+    @NonNull
+    public String getControlCategory() {
+        return mControlCategory;
+    }
+
+    /**
+     * Gets the list of ids of selected routes for the session. It shouldn't be empty.
+     */
+    @NonNull
+    public List<String> getSelectedRoutes() {
+        return mSelectedRoutes;
+    }
+
+    /**
+     * Gets the list of ids of deselectable routes for the session.
+     */
+    @NonNull
+    public List<String> getDeselectableRoutes() {
+        return mDeselectableRoutes;
+    }
+
+    /**
+     * Gets the list of ids of groupable routes for the session.
+     */
+    @NonNull
+    public List<String> getGroupableRoutes() {
+        return mGroupableRoutes;
+    }
+
+    /**
+     * Gets the list of ids of transferrable routes for the session.
+     */
+    @NonNull
+    public List<String> getTransferrableRoutes() {
+        return mTransferrableRoutes;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mSessionId);
+        dest.writeString(mPackageName);
+        dest.writeString(mControlCategory);
+        dest.writeStringList(mSelectedRoutes);
+        dest.writeStringList(mDeselectableRoutes);
+        dest.writeStringList(mGroupableRoutes);
+        dest.writeStringList(mTransferrableRoutes);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder()
+                .append("RouteSessionInfo{ ")
+                .append("sessionId=").append(mSessionId)
+                .append(", selectedRoutes={");
+        for (int i = 0; i < mSelectedRoutes.size(); i++) {
+            if (i > 0) result.append(", ");
+            result.append(mSelectedRoutes.get(i));
+        }
+        result.append("}");
+        result.append(" }");
+        return result.toString();
+    }
+
+    /**
+     * Builder class for {@link RouteSessionInfo}.
+     */
+    public static final class Builder {
+        final String mPackageName;
+        final int mSessionId;
+        final String mControlCategory;
+        final List<String> mSelectedRoutes;
+        final List<String> mDeselectableRoutes;
+        final List<String> mGroupableRoutes;
+        final List<String> mTransferrableRoutes;
+
+        public Builder(int sessionId, @NonNull String packageName,
+                @NonNull String controlCategory) {
+            mSessionId = sessionId;
+            mPackageName = Objects.requireNonNull(packageName, "packageName must not be null");
+            mControlCategory = Objects.requireNonNull(controlCategory,
+                    "controlCategory must not be null");
+
+            mSelectedRoutes = new ArrayList<>();
+            mDeselectableRoutes = new ArrayList<>();
+            mGroupableRoutes = new ArrayList<>();
+            mTransferrableRoutes = new ArrayList<>();
+        }
+
+        public Builder(RouteSessionInfo sessionInfo) {
+            mSessionId = sessionInfo.mSessionId;
+            mPackageName = sessionInfo.mPackageName;
+            mControlCategory = sessionInfo.mControlCategory;
+
+            mSelectedRoutes = new ArrayList<>(sessionInfo.mSelectedRoutes);
+            mDeselectableRoutes = new ArrayList<>(sessionInfo.mDeselectableRoutes);
+            mGroupableRoutes = new ArrayList<>(sessionInfo.mGroupableRoutes);
+            mTransferrableRoutes = new ArrayList<>(sessionInfo.mTransferrableRoutes);
+        }
+
+        /**
+         * Adds a selected route
+         */
+        @NonNull
+        public Builder addSelectedRoute(String routeId) {
+            mSelectedRoutes.add(routeId);
+            return this;
+        }
+
+        /**
+         * Removes a selected route
+         */
+        @NonNull
+        public Builder removeSelectedRoute(String routeId) {
+            mSelectedRoutes.remove(routeId);
+            return this;
+        }
+
+        /**
+         * Adds a deselectable route
+         */
+        @NonNull
+        public Builder addDeselectableRoute(String routeId) {
+            mDeselectableRoutes.add(routeId);
+            return this;
+        }
+
+        /**
+         * Removes a deselecable route
+         */
+        @NonNull
+        public Builder removeDeselectableRoute(String routeId) {
+            mDeselectableRoutes.remove(routeId);
+            return this;
+        }
+
+        /**
+         * Adds a groupable route
+         */
+        @NonNull
+        public Builder addGroupableRoute(String routeId) {
+            mGroupableRoutes.add(routeId);
+            return this;
+        }
+
+        /**
+         * Removes a groupable route
+         */
+        @NonNull
+        public Builder removeGroupableRoute(String routeId) {
+            mGroupableRoutes.remove(routeId);
+            return this;
+        }
+
+        /**
+         * Adds a transferrable route
+         */
+        @NonNull
+        public Builder addTransferrableRoute(String routeId) {
+            mTransferrableRoutes.add(routeId);
+            return this;
+        }
+
+        /**
+         * Removes a transferrable route
+         */
+        @NonNull
+        public Builder removeTransferrableRoute(String routeId) {
+            mTransferrableRoutes.remove(routeId);
+            return this;
+        }
+
+        /**
+         * Builds a route session info
+         */
+        @NonNull
+        public RouteSessionInfo build() {
+            return new RouteSessionInfo(this);
+        }
+    }
+}
diff --git a/media/java/android/media/SubtitleController.java b/media/java/android/media/SubtitleController.java
index 1a241af..48657a6c 100644
--- a/media/java/android/media/SubtitleController.java
+++ b/media/java/android/media/SubtitleController.java
@@ -16,10 +16,7 @@
 
 package android.media;
 
-import java.util.Locale;
-import java.util.Vector;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.media.MediaPlayer.TrackInfo;
 import android.media.SubtitleTrack.RenderingWidget;
@@ -28,6 +25,9 @@
 import android.os.Message;
 import android.view.accessibility.CaptioningManager;
 
+import java.util.Locale;
+import java.util.Vector;
+
 /**
  * The subtitle controller provides the architecture to display subtitles for a
  * media source.  It allows specifying which tracks to display, on which anchor
diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java
index 0705d97..10669f4 100644
--- a/media/java/android/media/SubtitleTrack.java
+++ b/media/java/android/media/SubtitleTrack.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Canvas;
 import android.media.MediaPlayer.TrackInfo;
 import android.os.Handler;
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index 6705b0c..1f7b5ad 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -24,7 +24,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
diff --git a/media/java/android/media/TimedText.java b/media/java/android/media/TimedText.java
index d8cdf9c..120642a 100644
--- a/media/java/android/media/TimedText.java
+++ b/media/java/android/media/TimedText.java
@@ -16,14 +16,15 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.util.Log;
-import java.util.HashMap;
-import java.util.Set;
-import java.util.List;
+
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
 
 /**
  * Class to hold the timed text's metadata, including:
diff --git a/media/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java
index c6d5ba3..cc114a9 100644
--- a/media/java/android/media/ToneGenerator.java
+++ b/media/java/android/media/ToneGenerator.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 
 
diff --git a/media/java/android/media/TtmlRenderer.java b/media/java/android/media/TtmlRenderer.java
index 34154ce..e578264 100644
--- a/media/java/android/media/TtmlRenderer.java
+++ b/media/java/android/media/TtmlRenderer.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -27,6 +27,10 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
 import java.io.IOException;
 import java.io.StringReader;
 import java.util.ArrayList;
@@ -37,10 +41,6 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
 /** @hide */
 public class TtmlRenderer extends SubtitleController.Renderer {
     private final Context mContext;
diff --git a/media/java/android/media/VolumeShaper.java b/media/java/android/media/VolumeShaper.java
index 663d564..99dfe1e 100644
--- a/media/java/android/media/VolumeShaper.java
+++ b/media/java/android/media/VolumeShaper.java
@@ -19,13 +19,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.lang.AutoCloseable;
 import java.lang.ref.WeakReference;
 import java.util.Arrays;
 import java.util.Objects;
diff --git a/media/java/android/media/WebVttRenderer.java b/media/java/android/media/WebVttRenderer.java
index 36458d7..bc14294 100644
--- a/media/java/android/media/WebVttRenderer.java
+++ b/media/java/android/media/WebVttRenderer.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.text.Layout.Alignment;
 import android.text.SpannableStringBuilder;
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 5b4bbce..4a40c62 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -19,8 +19,8 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index 89a509f..392e8fe 100644
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -16,8 +16,8 @@
 
 package android.media.audiofx;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index a82c78f..dd9877a 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -20,7 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.media.AudioDeviceInfo;
 import android.media.AudioFormat;
 import android.media.AudioSystem;
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index c4afd95..8c204d2 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.media.AudioAttributes;
 import android.os.Parcel;
 import android.util.Log;
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 1fc4f7d..646fc06 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -18,8 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
@@ -443,8 +443,8 @@
      * Get the session's tag for debugging purposes.
      *
      * @return The session's tag.
-     * @hide
      */
+    @NonNull
     public String getTag() {
         if (mTag == null) {
             try {
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index e11715f..5db4e8c 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -19,9 +19,9 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 123c4f7..0d506f0 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -16,9 +16,9 @@
 
 package android.media.session;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -26,7 +26,6 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.RectF;
-import android.media.AudioManager;
 import android.media.MediaMetadata;
 import android.media.MediaMetadataEditor;
 import android.media.MediaMetadataRetriever;
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index a89dc5f..aff7257 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -22,7 +22,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/media/jni/android_media_MediaMetricsJNI.cpp
index e17a617..37aca08 100644
--- a/media/jni/android_media_MediaMetricsJNI.cpp
+++ b/media/jni/android_media_MediaMetricsJNI.cpp
@@ -20,6 +20,7 @@
 #include <jni.h>
 #include <media/MediaMetricsItem.h>
 #include <nativehelper/JNIHelp.h>
+#include <variant>
 
 #include "android_media_MediaMetricsJNI.h"
 #include "android_os_Parcel.h"
@@ -74,6 +75,23 @@
     }
 
     template<>
+    void put(jstring keyName, const std::string& value) {
+        env->CallVoidMethod(bundle, putStringID, keyName, env->NewStringUTF(value.c_str()));
+    }
+
+    template<>
+    void put(jstring keyName, const std::pair<int64_t, int64_t>& value) {
+        ; // rate is currently ignored
+    }
+
+    template<>
+    void put(jstring keyName, const std::monostate& value) {
+        ; // none is currently ignored
+    }
+
+    // string char * helpers
+
+    template<>
     void put(jstring keyName, const char * const& value) {
         env->CallVoidMethod(bundle, putStringID, keyName, env->NewStringUTF(value));
     }
@@ -83,11 +101,6 @@
         env->CallVoidMethod(bundle, putStringID, keyName, env->NewStringUTF(value));
     }
 
-    template<>
-    void put(jstring keyName, const std::pair<int64_t, int64_t>& value) {
-        ; // rate is currently ignored
-    }
-
     // We allow both jstring and non-jstring variants.
     template<typename T>
     void put(const char *keyName, const T& value) {
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
index 2c60d6b..3266285 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
@@ -16,7 +16,15 @@
 
 package com.android.mediaroutertest;
 
+import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORIES_ALL;
+import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORIES_SPECIAL;
+import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_SPECIAL_CATEGORY;
+import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_VARIABLE_VOLUME;
+import static com.android.mediaroutertest.MediaRouterManagerTest.SYSTEM_PROVIDER_ID;
+
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
 import android.media.MediaRoute2Info;
@@ -24,20 +32,37 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class MediaRouter2Test {
+    private static final String TAG = "MediaRouter2Test";
     Context mContext;
+    private MediaRouter2 mRouter2;
+    private Executor mExecutor;
+
+    private static final int TIMEOUT_MS = 5000;
 
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
+        mRouter2 = MediaRouter2.getInstance(mContext);
+        mExecutor = Executors.newSingleThreadExecutor();
     }
 
     @After
@@ -50,4 +75,95 @@
         MediaRoute2Info initiallySelectedRoute = router.getSelectedRoute();
         assertNotNull(initiallySelectedRoute);
     }
+
+    /**
+     * Tests if we get proper routes for application that has special control category.
+     */
+    @Test
+    public void testGetRoutes() throws Exception {
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_SPECIAL);
+
+        assertEquals(1, routes.size());
+        assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
+    }
+
+    @Test
+    public void testControlVolumeWithRouter() throws Exception {
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL);
+
+        MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
+        assertNotNull(volRoute);
+
+        int originalVolume = volRoute.getVolume();
+        int deltaVolume = (originalVolume == volRoute.getVolumeMax() ? -1 : 1);
+
+        awaitOnRouteChanged(
+                () -> mRouter2.requestUpdateVolume(volRoute, deltaVolume),
+                ROUTE_ID_VARIABLE_VOLUME,
+                (route -> route.getVolume() == originalVolume + deltaVolume));
+
+        awaitOnRouteChanged(
+                () -> mRouter2.requestSetVolume(volRoute, originalVolume),
+                ROUTE_ID_VARIABLE_VOLUME,
+                (route -> route.getVolume() == originalVolume));
+    }
+
+
+    // Helper for getting routes easily
+    static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
+        Map<String, MediaRoute2Info> routeMap = new HashMap<>();
+        for (MediaRoute2Info route : routes) {
+            // intentionally not using route.getUniqueId() for convenience.
+            routeMap.put(route.getId(), route);
+        }
+        return routeMap;
+    }
+
+    Map<String, MediaRoute2Info> waitAndGetRoutes(List<String> controlCategories)
+            throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+
+        // A dummy callback is required to send control category info.
+        MediaRouter2.Callback routerCallback = new MediaRouter2.Callback() {
+            @Override
+            public void onRoutesAdded(List<MediaRoute2Info> routes) {
+                for (int i = 0; i < routes.size(); i++) {
+                    //TODO: use isSystem() or similar method when it's ready
+                    if (!TextUtils.equals(routes.get(i).getProviderId(), SYSTEM_PROVIDER_ID)) {
+                        latch.countDown();
+                    }
+                }
+            }
+        };
+
+        mRouter2.setControlCategories(controlCategories);
+        mRouter2.registerCallback(mExecutor, routerCallback);
+        try {
+            latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            return createRouteMap(mRouter2.getRoutes());
+        } finally {
+            mRouter2.unregisterCallback(routerCallback);
+        }
+    }
+
+    void awaitOnRouteChanged(Runnable task, String routeId,
+            Predicate<MediaRoute2Info> predicate) throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        MediaRouter2.Callback callback = new MediaRouter2.Callback() {
+            @Override
+            public void onRoutesChanged(List<MediaRoute2Info> changed) {
+                MediaRoute2Info route = createRouteMap(changed).get(routeId);
+                if (route != null && predicate.test(route)) {
+                    latch.countDown();
+                }
+            }
+        };
+        mRouter2.registerCallback(mExecutor, callback);
+        try {
+            task.run();
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } finally {
+            mRouter2.unregisterCallback(callback);
+        }
+    }
 }
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index c70ad8d..b380aff 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -64,6 +64,9 @@
     public static final String ROUTE_ID_SPECIAL_CATEGORY = "route_special_category";
     public static final String ROUTE_NAME_SPECIAL_CATEGORY = "Special Category Route";
 
+    public static final String SYSTEM_PROVIDER_ID =
+            "com.android.server.media/.SystemMediaRoute2Provider";
+
     public static final int VOLUME_MAX = 100;
     public static final String ROUTE_ID_FIXED_VOLUME = "route_fixed_volume";
     public static final String ROUTE_NAME_FIXED_VOLUME = "Fixed Volume Route";
@@ -78,10 +81,7 @@
     public static final String CATEGORY_SPECIAL =
             "com.android.mediarouteprovider.CATEGORY_SPECIAL";
 
-    // system routes
-    private static final String DEFAULT_ROUTE_ID = "DEFAULT_ROUTE";
     private static final String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO";
-    private static final String CATEGORY_LIVE_VIDEO = "android.media.intent.category.LIVE_VIDEO";
 
     private static final int TIMEOUT_MS = 5000;
 
@@ -93,10 +93,9 @@
 
     private final List<MediaRouter2Manager.Callback> mManagerCallbacks = new ArrayList<>();
     private final List<MediaRouter2.Callback> mRouterCallbacks = new ArrayList<>();
-    private Map<String, MediaRoute2Info> mRoutes;
 
-    private static final List<String> CATEGORIES_ALL = new ArrayList();
-    private static final List<String> CATEGORIES_SPECIAL = new ArrayList();
+    public static final List<String> CATEGORIES_ALL = new ArrayList();
+    public static final List<String> CATEGORIES_SPECIAL = new ArrayList();
     private static final List<String> CATEGORIES_LIVE_AUDIO = new ArrayList<>();
 
     static {
@@ -109,7 +108,6 @@
         CATEGORIES_LIVE_AUDIO.add(CATEGORY_LIVE_AUDIO);
     }
 
-
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
@@ -118,10 +116,6 @@
         //TODO: If we need to support thread pool executors, change this to thread pool executor.
         mExecutor = Executors.newSingleThreadExecutor();
         mPackageName = mContext.getPackageName();
-
-        // ensure media router 2 client
-        addRouterCallback(new MediaRouter2.Callback());
-        mRoutes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
     }
 
     @After
@@ -168,6 +162,9 @@
     @Test
     public void testOnRoutesRemoved() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+
+        addRouterCallback(new MediaRouter2.Callback());
         addManagerCallback(new MediaRouter2Manager.Callback() {
             @Override
             public void onRoutesRemoved(List<MediaRoute2Info> routes) {
@@ -182,7 +179,7 @@
 
         //TODO: Figure out a more proper way to test.
         // (Control requests shouldn't be used in this way.)
-        mRouter2.sendControlRequest(mRoutes.get(ROUTE_ID2), new Intent(ACTION_REMOVE_ROUTE));
+        mRouter2.sendControlRequest(routes.get(ROUTE_ID2), new Intent(ACTION_REMOVE_ROUTE));
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
@@ -198,23 +195,15 @@
     }
 
     /**
-     * Tests if we get proper routes for application that has special control category.
-     */
-    @Test
-    public void testGetRoutes() throws Exception {
-        Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_SPECIAL);
-
-        assertEquals(1, routes.size());
-        assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
-    }
-
-    /**
      * Tests if MR2.Callback.onRouteSelected is called when a route is selected from MR2Manager.
      */
     @Test
     public void testRouterOnRouteSelected() throws Exception {
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+
         CountDownLatch latch = new CountDownLatch(1);
 
+        addManagerCallback(new MediaRouter2Manager.Callback());
         addRouterCallback(new MediaRouter2.Callback() {
             @Override
             public void onRouteSelected(MediaRoute2Info route, int reason, Bundle controlHints) {
@@ -224,12 +213,16 @@
             }
         });
 
-        MediaRoute2Info routeToSelect = mRoutes.get(ROUTE_ID1);
+        MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
         assertNotNull(routeToSelect);
 
-        mManager.selectRoute(mPackageName, routeToSelect);
+        try {
+            mManager.selectRoute(mPackageName, routeToSelect);
 
-        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } finally {
+            mManager.unselectRoute(mPackageName);
+        }
     }
 
     /**
@@ -239,7 +232,9 @@
     @Test
     public void testManagerOnRouteSelected() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
 
+        addRouterCallback(new MediaRouter2.Callback());
         addManagerCallback(new MediaRouter2Manager.Callback() {
             @Override
             public void onRouteSelected(String packageName, MediaRoute2Info route) {
@@ -250,12 +245,15 @@
             }
         });
 
-        MediaRoute2Info routeToSelect = mRoutes.get(ROUTE_ID1);
+        MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
         assertNotNull(routeToSelect);
 
-        mManager.selectRoute(mPackageName, routeToSelect);
-
-        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        try {
+            mManager.selectRoute(mPackageName, routeToSelect);
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } finally {
+            mManager.unselectRoute(mPackageName);
+        }
     }
 
     /**
@@ -263,13 +261,16 @@
      */
     @Test
     public void testSingleProviderSelect() throws Exception {
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+        addRouterCallback(new MediaRouter2.Callback());
+
         awaitOnRouteChangedManager(
-                () -> mManager.selectRoute(mPackageName, mRoutes.get(ROUTE_ID1)),
+                () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1)),
                 ROUTE_ID1,
                 route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
 
         awaitOnRouteChangedManager(
-                () -> mManager.selectRoute(mPackageName, mRoutes.get(ROUTE_ID2)),
+                () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID2)),
                 ROUTE_ID2,
                 route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
 
@@ -280,27 +281,10 @@
     }
 
     @Test
-    public void testControlVolumeWithRouter() throws Exception {
-        Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL);
-
-        MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
-        int originalVolume = volRoute.getVolume();
-        int deltaVolume = (originalVolume == volRoute.getVolumeMax() ? -1 : 1);
-
-        awaitOnRouteChanged(
-                () -> mRouter2.requestUpdateVolume(volRoute, deltaVolume),
-                ROUTE_ID_VARIABLE_VOLUME,
-                (route -> route.getVolume() == originalVolume + deltaVolume));
-
-        awaitOnRouteChanged(
-                () -> mRouter2.requestSetVolume(volRoute, originalVolume),
-                ROUTE_ID_VARIABLE_VOLUME,
-                (route -> route.getVolume() == originalVolume));
-    }
-
-    @Test
     public void testControlVolumeWithManager() throws Exception {
-        MediaRoute2Info volRoute = mRoutes.get(ROUTE_ID_VARIABLE_VOLUME);
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+        MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
+
         int originalVolume = volRoute.getVolume();
         int deltaVolume = (originalVolume == volRoute.getVolumeMax() ? -1 : 1);
 
@@ -317,39 +301,16 @@
 
     @Test
     public void testVolumeHandling() throws Exception {
-        MediaRoute2Info fixedVolumeRoute = mRoutes.get(ROUTE_ID_FIXED_VOLUME);
-        MediaRoute2Info variableVolumeRoute = mRoutes.get(ROUTE_ID_VARIABLE_VOLUME);
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+
+        MediaRoute2Info fixedVolumeRoute = routes.get(ROUTE_ID_FIXED_VOLUME);
+        MediaRoute2Info variableVolumeRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
 
         assertEquals(PLAYBACK_VOLUME_FIXED, fixedVolumeRoute.getVolumeHandling());
         assertEquals(PLAYBACK_VOLUME_VARIABLE, variableVolumeRoute.getVolumeHandling());
         assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax());
     }
 
-    @Test
-    public void testDefaultRoute() throws Exception {
-        Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_LIVE_AUDIO);
-
-        assertNotNull(routes.get(DEFAULT_ROUTE_ID));
-    }
-
-    Map<String, MediaRoute2Info> waitAndGetRoutes(List<String> controlCategories) throws Exception {
-        CountDownLatch latch = new CountDownLatch(1);
-        MediaRouter2.Callback callback = new MediaRouter2.Callback() {
-            @Override
-            public void onRoutesAdded(List<MediaRoute2Info> added) {
-                if (added.size() > 0) latch.countDown();
-            }
-        };
-        mRouter2.setControlCategories(controlCategories);
-        mRouter2.registerCallback(mExecutor, callback);
-        try {
-            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-            return createRouteMap(mRouter2.getRoutes());
-        } finally {
-            mRouter2.unregisterCallback(callback);
-        }
-    }
-
     Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> controlCategories)
             throws Exception {
         CountDownLatch latch = new CountDownLatch(2);
@@ -359,13 +320,17 @@
         MediaRouter2Manager.Callback managerCallback = new MediaRouter2Manager.Callback() {
             @Override
             public void onRoutesAdded(List<MediaRoute2Info> routes) {
-                if (routes.size() > 0) {
-                    latch.countDown();
+                for (int i = 0; i < routes.size(); i++) {
+                    //TODO: use isSystem() or similar method when it's ready
+                    if (!TextUtils.equals(routes.get(i).getProviderId(), SYSTEM_PROVIDER_ID)) {
+                        latch.countDown();
+                        break;
+                    }
                 }
             }
 
             @Override
-            public void onControlCategoriesChanged(String packageName) {
+            public void onControlCategoriesChanged(String packageName, List<String> categories) {
                 if (TextUtils.equals(mPackageName, packageName)) {
                     latch.countDown();
                 }
@@ -375,7 +340,7 @@
         mRouter2.setControlCategories(controlCategories);
         mRouter2.registerCallback(mExecutor, routerCallback);
         try {
-            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
             return createRouteMap(mManager.getAvailableRoutes(mPackageName));
         } finally {
             mRouter2.unregisterCallback(routerCallback);
@@ -383,27 +348,6 @@
         }
     }
 
-    void awaitOnRouteChanged(Runnable task, String routeId,
-            Predicate<MediaRoute2Info> predicate) throws Exception {
-        CountDownLatch latch = new CountDownLatch(1);
-        MediaRouter2.Callback callback = new MediaRouter2.Callback() {
-            @Override
-            public void onRoutesChanged(List<MediaRoute2Info> changed) {
-                MediaRoute2Info route = createRouteMap(changed).get(routeId);
-                if (route != null && predicate.test(route)) {
-                    latch.countDown();
-                }
-            }
-        };
-        mRouter2.registerCallback(mExecutor, callback);
-        try {
-            task.run();
-            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        } finally {
-            mRouter2.unregisterCallback(callback);
-        }
-    }
-
     void awaitOnRouteChangedManager(Runnable task, String routeId,
             Predicate<MediaRoute2Info> predicate) throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteSessionTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteSessionTest.java
new file mode 100644
index 0000000..2e81a64
--- /dev/null
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteSessionTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediaroutertest;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.media.RouteSessionInfo;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RouteSessionTest {
+    private static final String TEST_PACKAGE_NAME = "com.android.mediaroutertest";
+    private static final String TEST_CONTROL_CATEGORY = "com.android.mediaroutertest.category";
+
+    private static final String TEST_ROUTE_ID1 = "route_id1";
+
+    @Test
+    public void testValidity() {
+        RouteSessionInfo emptyPackageSession = new RouteSessionInfo.Builder(1,
+                "",
+                TEST_CONTROL_CATEGORY)
+                .addSelectedRoute(TEST_ROUTE_ID1)
+                .build();
+        RouteSessionInfo emptyCategorySession = new RouteSessionInfo.Builder(1,
+                TEST_PACKAGE_NAME, "")
+                .addSelectedRoute(TEST_ROUTE_ID1)
+                .build();
+
+        RouteSessionInfo emptySelectedRouteSession = new RouteSessionInfo.Builder(1,
+                TEST_PACKAGE_NAME, TEST_CONTROL_CATEGORY)
+                .build();
+
+        RouteSessionInfo validSession = new RouteSessionInfo.Builder(emptySelectedRouteSession)
+                .addSelectedRoute(TEST_ROUTE_ID1)
+                .build();
+
+        assertFalse(emptySelectedRouteSession.isValid());
+        assertFalse(emptyPackageSession.isValid());
+        assertFalse(emptyCategorySession.isValid());
+        assertTrue(validSession.isValid());
+    }
+}
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index b2451c9..2a8a39a 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -53,7 +53,6 @@
     ],
 
     libs: [
-        "telephony-common",
         "android.car",
     ],
 
@@ -108,7 +107,6 @@
     ],
     libs: [
         "android.test.runner",
-        "telephony-common",
         "android.test.base",
         "android.car",
     ],
@@ -129,7 +127,6 @@
     ],
 
     libs: [
-        "telephony-common",
         "android.car",
     ],
 
@@ -140,7 +137,7 @@
     ],
 
     platform_apis: true,
-    product_specific: true,
+    system_ext_specific: true,
     certificate: "platform",
     privileged: true,
 
diff --git a/packages/CarSystemUI/CleanSpec.mk b/packages/CarSystemUI/CleanSpec.mk
new file mode 100644
index 0000000..ceac67c
--- /dev/null
+++ b/packages/CarSystemUI/CleanSpec.mk
@@ -0,0 +1,50 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/priv-app/CarSystemUI)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/priv-app/CarSystemUI)
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 03bd61a..b862e95 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -21,6 +21,7 @@
 
 import android.content.Context;
 
+import com.android.systemui.car.CarDeviceProvisionedControllerImpl;
 import com.android.systemui.car.CarNotificationEntryManager;
 import com.android.systemui.car.CarNotificationInterruptionStateProvider;
 import com.android.systemui.dagger.SystemUIRootComponent;
@@ -46,6 +47,7 @@
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.volume.CarVolumeDialogComponent;
 import com.android.systemui.volume.VolumeDialogComponent;
@@ -143,4 +145,8 @@
     @Binds
     abstract StatusBarKeyguardViewManager bindStatusBarKeyguardViewManager(
             CarStatusBarKeyguardViewManager keyguardViewManager);
+
+    @Binds
+    abstract DeviceProvisionedController bindDeviceProvisionedController(
+            CarDeviceProvisionedControllerImpl deviceProvisionedController);
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedController.java b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedController.java
new file mode 100644
index 0000000..c870cec
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedController.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car;
+
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+
+/**
+ * This interface defines controller that monitors the status of SUW progress for each user in
+ * addition to the functionality defined by {@link DeviceProvisionedController}.
+ */
+public interface CarDeviceProvisionedController extends DeviceProvisionedController {
+    /**
+     * Returns {@code true} then SUW is in progress for the given user.
+     */
+    boolean isUserSetupInProgress(int user);
+
+    /**
+     * Returns {@code true} then SUW is in progress for the current user.
+     */
+    default boolean isCurrentUserSetupInProgress() {
+        return isUserSetupInProgress(getCurrentUser());
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java
new file mode 100644
index 0000000..ab1feef
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.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.systemui.car;
+
+import android.app.ActivityManager;
+import android.car.settings.CarSettings;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * A controller that monitors the status of SUW progress for each user in addition to the
+ * functionality provided by {@link DeviceProvisionedControllerImpl}.
+ */
+@Singleton
+public class CarDeviceProvisionedControllerImpl extends DeviceProvisionedControllerImpl implements
+        CarDeviceProvisionedController {
+    private static final Uri USER_SETUP_IN_PROGRESS_URI = Settings.Secure.getUriFor(
+            CarSettings.Secure.KEY_SETUP_WIZARD_IN_PROGRESS);
+    private final ContentObserver mCarSettingsObserver = new ContentObserver(
+            Dependency.get(Dependency.MAIN_HANDLER)) {
+        @Override
+        public void onChange(boolean selfChange, Uri uri, int userId) {
+            if (USER_SETUP_IN_PROGRESS_URI.equals(uri)) {
+                notifyUserSetupInProgressChanged();
+            }
+        }
+    };
+    private final ContentResolver mContentResolver;
+
+    @Inject
+    public CarDeviceProvisionedControllerImpl(Context context, @MainHandler Handler mainHandler,
+            BroadcastDispatcher broadcastDispatcher) {
+        super(context, mainHandler, broadcastDispatcher);
+        mContentResolver = context.getContentResolver();
+    }
+
+    @Override
+    public boolean isUserSetupInProgress(int user) {
+        return Settings.Secure.getIntForUser(mContentResolver,
+                CarSettings.Secure.KEY_SETUP_WIZARD_IN_PROGRESS, /* def= */ 0, user) != 0;
+    }
+
+    @Override
+    public boolean isCurrentUserSetupInProgress() {
+        return isUserSetupInProgress(ActivityManager.getCurrentUser());
+    }
+
+    @Override
+    public void addCallback(DeviceProvisionedListener listener) {
+        super.addCallback(listener);
+        if (listener instanceof CarDeviceProvisionedListener) {
+            ((CarDeviceProvisionedListener) listener).onUserSetupInProgressChanged();
+        }
+    }
+
+    @Override
+    protected void startListening(int user) {
+        mContentResolver.registerContentObserver(
+                USER_SETUP_IN_PROGRESS_URI, /* notifyForDescendants= */ true, mCarSettingsObserver,
+                user);
+        // The SUW Flag observer is registered before super.startListening() so that the observer is
+        // in place before DeviceProvisionedController starts to track user switches which avoids
+        // an edge case where our observer gets registered twice.
+        super.startListening(user);
+    }
+
+    @Override
+    protected void stopListening() {
+        super.stopListening();
+        mContentResolver.unregisterContentObserver(mCarSettingsObserver);
+    }
+
+    @Override
+    public void onUserSwitched(int newUserId) {
+        super.onUserSwitched(newUserId);
+        mContentResolver.unregisterContentObserver(mCarSettingsObserver);
+        mContentResolver.registerContentObserver(
+                USER_SETUP_IN_PROGRESS_URI, /* notifyForDescendants= */ true, mCarSettingsObserver,
+                newUserId);
+    }
+
+    private void notifyUserSetupInProgressChanged() {
+        for (int i = mListeners.size() - 1; i >= 0; --i) {
+            DeviceProvisionedListener listener = mListeners.get(i);
+            if (listener instanceof CarDeviceProvisionedListener) {
+                ((CarDeviceProvisionedListener) listener).onUserSetupInProgressChanged();
+            }
+        }
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedListener.java b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedListener.java
new file mode 100644
index 0000000..0086322
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedListener.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car;
+
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+
+/**
+ * A listener that listens for changes in SUW progress for a user in addition to the
+ * functionality defined by {@link DeviceProvisionedListener}.
+ */
+public interface CarDeviceProvisionedListener extends DeviceProvisionedListener {
+    @Override
+    default void onUserSwitched() {
+        onUserSetupChanged();
+        onUserSetupInProgressChanged();
+    }
+    /**
+     * A callback for when a change occurs in SUW progress for a user.
+     */
+    default void onUserSetupInProgressChanged() {
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
index 998d2b9..e0b0922 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
@@ -33,6 +33,8 @@
 import com.android.internal.statusbar.RegisterStatusBarResult;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
+import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarDeviceProvisionedListener;
 import com.android.systemui.dagger.qualifiers.MainHandler;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.CommandQueue;
@@ -53,7 +55,7 @@
 
     private final CarNavigationBarController mCarNavigationBarController;
     private final WindowManager mWindowManager;
-    private final DeviceProvisionedController mDeviceProvisionedController;
+    private final CarDeviceProvisionedController mCarDeviceProvisionedController;
     private final CommandQueue mCommandQueue;
     private final Lazy<FacetButtonTaskStackListener> mFacetButtonTaskStackListenerLazy;
     private final Handler mMainHandler;
@@ -82,6 +84,7 @@
     // To be attached to the navigation bars such that they can close the notification panel if
     // it's open.
     private boolean mDeviceIsSetUpForUser = true;
+    private boolean mIsUserSetupInProgress = false;
 
     @Inject
     public CarNavigationBar(Context context,
@@ -98,7 +101,8 @@
         super(context);
         mCarNavigationBarController = carNavigationBarController;
         mWindowManager = windowManager;
-        mDeviceProvisionedController = deviceProvisionedController;
+        mCarDeviceProvisionedController = (CarDeviceProvisionedController)
+                deviceProvisionedController;
         mCommandQueue = commandQueue;
         mFacetButtonTaskStackListenerLazy = facetButtonTaskStackListenerLazy;
         mMainHandler = mainHandler;
@@ -129,9 +133,15 @@
             ex.rethrowFromSystemServer();
         }
 
-        mDeviceIsSetUpForUser = mDeviceProvisionedController.isCurrentUserSetup();
-        mDeviceProvisionedController.addCallback(
-                new DeviceProvisionedController.DeviceProvisionedListener() {
+        mDeviceIsSetUpForUser = mCarDeviceProvisionedController.isCurrentUserSetup();
+        mIsUserSetupInProgress = mCarDeviceProvisionedController.isCurrentUserSetupInProgress();
+        mCarDeviceProvisionedController.addCallback(
+                new CarDeviceProvisionedListener() {
+                    @Override
+                    public void onUserSetupInProgressChanged() {
+                        mMainHandler.post(() -> restartNavBarsIfNecessary());
+                    }
+
                     @Override
                     public void onUserSetupChanged() {
                         mMainHandler.post(() -> restartNavBarsIfNecessary());
@@ -152,9 +162,13 @@
     }
 
     private void restartNavBarsIfNecessary() {
-        boolean currentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
-        if (mDeviceIsSetUpForUser != currentUserSetup) {
+        boolean currentUserSetup = mCarDeviceProvisionedController.isCurrentUserSetup();
+        boolean currentUserSetupInProgress = mCarDeviceProvisionedController
+                .isCurrentUserSetupInProgress();
+        if (mIsUserSetupInProgress != currentUserSetupInProgress
+                || mDeviceIsSetUpForUser != currentUserSetup) {
             mDeviceIsSetUpForUser = currentUserSetup;
+            mIsUserSetupInProgress = currentUserSetupInProgress;
             restartNavBars();
         }
     }
@@ -193,10 +207,14 @@
         // If the UI was rebuilt (day/night change) while the keyguard was up we need to
         // correctly respect that state.
         if (mKeyguardStateControllerLazy.get().isShowing()) {
-            mCarNavigationBarController.showAllKeyguardButtons(mDeviceIsSetUpForUser);
+            mCarNavigationBarController.showAllKeyguardButtons(isDeviceSetupForUser());
         }
     }
 
+    private boolean isDeviceSetupForUser() {
+        return mDeviceIsSetUpForUser && !mIsUserSetupInProgress;
+    }
+
     private void createNavigationBar(RegisterStatusBarResult result) {
         buildNavBarWindows();
         buildNavBarContent();
@@ -225,22 +243,22 @@
     }
 
     private void buildNavBarContent() {
-        mTopNavigationBarView = mCarNavigationBarController.getTopBar(mDeviceIsSetUpForUser);
+        mTopNavigationBarView = mCarNavigationBarController.getTopBar(isDeviceSetupForUser());
         if (mTopNavigationBarView != null) {
             mTopNavigationBarWindow.addView(mTopNavigationBarView);
         }
 
-        mBottomNavigationBarView = mCarNavigationBarController.getBottomBar(mDeviceIsSetUpForUser);
+        mBottomNavigationBarView = mCarNavigationBarController.getBottomBar(isDeviceSetupForUser());
         if (mBottomNavigationBarView != null) {
             mBottomNavigationBarWindow.addView(mBottomNavigationBarView);
         }
 
-        mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(mDeviceIsSetUpForUser);
+        mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(isDeviceSetupForUser());
         if (mLeftNavigationBarView != null) {
             mLeftNavigationBarWindow.addView(mLeftNavigationBarView);
         }
 
-        mRightNavigationBarView = mCarNavigationBarController.getRightBar(mDeviceIsSetUpForUser);
+        mRightNavigationBarView = mCarNavigationBarController.getRightBar(isDeviceSetupForUser());
         if (mRightNavigationBarView != null) {
             mRightNavigationBarWindow.addView(mRightNavigationBarView);
         }
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index fbc03c0..1b171e8 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -63,6 +63,8 @@
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarDeviceProvisionedListener;
 import com.android.systemui.car.CarServiceProvider;
 import com.android.systemui.classifier.FalsingLog;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -175,11 +177,14 @@
 
     private final Object mQueueLock = new Object();
     private final CarNavigationBarController mCarNavigationBarController;
+    private final FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
     private final Lazy<PowerManagerHelper> mPowerManagerHelperLazy;
     private final ShadeController mShadeController;
     private final CarServiceProvider mCarServiceProvider;
+    private final CarDeviceProvisionedController mCarDeviceProvisionedController;
 
-    private DeviceProvisionedController mDeviceProvisionedController;
+    private boolean mDeviceIsSetUpForUser = true;
+    private boolean mIsUserSetupInProgress = false;
     private PowerManagerHelper mPowerManagerHelper;
     private FlingAnimationUtils mFlingAnimationUtils;
     private NotificationDataManager mNotificationDataManager;
@@ -318,7 +323,8 @@
             CarServiceProvider carServiceProvider,
             Lazy<PowerManagerHelper> powerManagerHelperLazy,
             Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy,
-            CarNavigationBarController carNavigationBarController) {
+            CarNavigationBarController carNavigationBarController,
+            FlingAnimationUtils.Builder flingAnimationUtilsBuilder) {
         super(
                 context,
                 featureFlags,
@@ -395,16 +401,21 @@
                 dismissCallbackRegistry);
         mScrimController = scrimController;
         mLockscreenLockIconController = lockscreenLockIconController;
-        mDeviceProvisionedController = deviceProvisionedController;
+        mCarDeviceProvisionedController =
+                (CarDeviceProvisionedController) deviceProvisionedController;
         mShadeController = shadeController;
         mCarServiceProvider = carServiceProvider;
         mPowerManagerHelperLazy = powerManagerHelperLazy;
         mFullscreenUserSwitcherLazy = fullscreenUserSwitcherLazy;
         mCarNavigationBarController = carNavigationBarController;
+        mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
     }
 
     @Override
     public void start() {
+        mDeviceIsSetUpForUser = mCarDeviceProvisionedController.isCurrentUserSetup();
+        mIsUserSetupInProgress = mCarDeviceProvisionedController.isCurrentUserSetupInProgress();
+
         // Need to initialize screen lifecycle before calling super.start - before switcher is
         // created.
         mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
@@ -436,8 +447,10 @@
                 R.integer.notification_settle_open_percentage);
         mSettleClosePercentage = mContext.getResources().getInteger(
                 R.integer.notification_settle_close_percentage);
-        mFlingAnimationUtils = new FlingAnimationUtils(mContext,
-                FLING_ANIMATION_MAX_TIME, FLING_SPEED_UP_FACTOR);
+        mFlingAnimationUtils = mFlingAnimationUtilsBuilder
+                .setMaxLengthSeconds(FLING_ANIMATION_MAX_TIME)
+                .setSpeedUpFactor(FLING_SPEED_UP_FACTOR)
+                .build();
 
         createBatteryController();
         mCarBatteryController.startListening();
@@ -445,6 +458,33 @@
         mPowerManagerHelper = mPowerManagerHelperLazy.get();
         mPowerManagerHelper.setCarPowerStateListener(mCarPowerStateListener);
         mPowerManagerHelper.connectToCarService();
+
+        mCarDeviceProvisionedController.addCallback(
+                new CarDeviceProvisionedListener() {
+                    @Override
+                    public void onUserSetupInProgressChanged() {
+                        mDeviceIsSetUpForUser = mCarDeviceProvisionedController
+                                .isCurrentUserSetup();
+                        mIsUserSetupInProgress = mCarDeviceProvisionedController
+                                .isCurrentUserSetupInProgress();
+                    }
+
+                    @Override
+                    public void onUserSetupChanged() {
+                        mDeviceIsSetUpForUser = mCarDeviceProvisionedController
+                                .isCurrentUserSetup();
+                        mIsUserSetupInProgress = mCarDeviceProvisionedController
+                                .isCurrentUserSetupInProgress();
+                    }
+
+                    @Override
+                    public void onUserSwitched() {
+                        mDeviceIsSetUpForUser = mCarDeviceProvisionedController
+                                .isCurrentUserSetup();
+                        mIsUserSetupInProgress = mCarDeviceProvisionedController
+                                .isCurrentUserSetupInProgress();
+                    }
+                });
     }
 
     /**
@@ -460,16 +500,18 @@
     @Override
     public boolean hideKeyguard() {
         boolean result = super.hideKeyguard();
-        mCarNavigationBarController.hideAllKeyguardButtons(
-                mDeviceProvisionedController.isCurrentUserSetup());
+        mCarNavigationBarController.hideAllKeyguardButtons(isDeviceSetupForUser());
         return result;
     }
 
     @Override
     public void showKeyguard() {
         super.showKeyguard();
-        mCarNavigationBarController.showAllKeyguardButtons(
-                mDeviceProvisionedController.isCurrentUserSetup());
+        mCarNavigationBarController.showAllKeyguardButtons(isDeviceSetupForUser());
+    }
+
+    private boolean isDeviceSetupForUser() {
+        return mDeviceIsSetUpForUser && !mIsUserSetupInProgress;
     }
 
     @Override
@@ -531,7 +573,7 @@
                 new HandleBarCloseNotificationGestureListener());
 
         mTopNavBarNotificationTouchListener = (v, event) -> {
-            if (!mDeviceProvisionedController.isCurrentUserSetup()) {
+            if (!isDeviceSetupForUser()) {
                 return true;
             }
             boolean consumed = openGestureDetector.onTouchEvent(event);
@@ -695,8 +737,8 @@
      */
     protected void onUseenCountUpdate(int unseenNotificationCount) {
         boolean hasUnseen = unseenNotificationCount > 0;
-        mCarNavigationBarController.toggleAllNotificationsUnseenIndicator(
-                mDeviceProvisionedController.isCurrentUserSetup(), hasUnseen);
+        mCarNavigationBarController.toggleAllNotificationsUnseenIndicator(isDeviceSetupForUser(),
+                hasUnseen);
     }
 
     /**
@@ -1262,8 +1304,10 @@
 
         @Override
         protected void setHeadsUpVisible() {
-            // if the Notifications panel is showing don't show the Heads up
-            if (!mEnableHeadsUpNotificationWhenNotificationShadeOpen && mPanelExpanded) {
+            // if the Notifications panel is showing or SUW for user is in progress then don't show
+            // heads up notifications
+            if ((!mEnableHeadsUpNotificationWhenNotificationShadeOpen && mPanelExpanded)
+                    || !isDeviceSetupForUser()) {
                 return;
             }
 
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index ff4dc9c..7b21d9d 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -43,6 +43,7 @@
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.NavigationBarController;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -191,7 +192,8 @@
             CarServiceProvider carServiceProvider,
             Lazy<PowerManagerHelper> powerManagerHelperLazy,
             Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy,
-            CarNavigationBarController carNavigationBarController) {
+            CarNavigationBarController carNavigationBarController,
+            FlingAnimationUtils.Builder flingAnimationUtilsBuilder) {
         return new CarStatusBar(
                 context,
                 featureFlags,
@@ -268,6 +270,7 @@
                 carServiceProvider,
                 powerManagerHelperLazy,
                 fullscreenUserSwitcherLazy,
-                carNavigationBarController);
+                carNavigationBarController,
+                flingAnimationUtilsBuilder);
     }
 }
diff --git a/packages/Incremental/NativeAdbDataLoader/src/com/android/incremental/nativeadb/NativeAdbDataLoaderService.java b/packages/Incremental/NativeAdbDataLoader/src/com/android/incremental/nativeadb/NativeAdbDataLoaderService.java
index 1f88114..bd5b795 100644
--- a/packages/Incremental/NativeAdbDataLoader/src/com/android/incremental/nativeadb/NativeAdbDataLoaderService.java
+++ b/packages/Incremental/NativeAdbDataLoader/src/com/android/incremental/nativeadb/NativeAdbDataLoaderService.java
@@ -16,10 +16,10 @@
 
 package com.android.incremental.nativeadb;
 
-import android.service.incremental.IncrementalDataLoaderService;
+import android.service.dataloader.DataLoaderService;
 
 /** This code is used for testing only. */
-public class NativeAdbDataLoaderService extends IncrementalDataLoaderService {
+public class NativeAdbDataLoaderService extends DataLoaderService {
     public static final String TAG = "NativeAdbDataLoaderService";
     static {
         System.loadLibrary("nativeadbdataloaderservice_jni");
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 14f233d..2c001b0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -1,7 +1,5 @@
 package com.android.settingslib;
 
-import static android.telephony.ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
-
 import android.annotation.ColorInt;
 import android.content.Context;
 import android.content.Intent;
@@ -25,6 +23,8 @@
 import android.os.UserManager;
 import android.print.PrintManager;
 import android.provider.Settings;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.NetworkRegistrationInfo;
 import android.telephony.ServiceState;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -412,15 +412,30 @@
         // service" or "emergency calls only" text that indicates that voice
         // is not available. Note that we ignore the IWLAN service state
         // because that state indicates the use of VoWIFI and not cell service
-        int state = serviceState.getState();
-        int dataState = serviceState.getDataRegState();
+        final int state = serviceState.getState();
+        final int dataState = serviceState.getDataRegState();
+
         if (state == ServiceState.STATE_OUT_OF_SERVICE
                 || state == ServiceState.STATE_EMERGENCY_ONLY) {
-            if (dataState == ServiceState.STATE_IN_SERVICE
-                    && serviceState.getDataNetworkType() != RIL_RADIO_TECHNOLOGY_IWLAN) {
+            if (dataState == ServiceState.STATE_IN_SERVICE && isNotInIwlan(serviceState)) {
                 return ServiceState.STATE_IN_SERVICE;
             }
         }
         return state;
     }
+
+    private static boolean isNotInIwlan(ServiceState serviceState) {
+        final NetworkRegistrationInfo networkRegWlan = serviceState.getNetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_PS,
+                AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+        if (networkRegWlan == null) {
+            return true;
+        }
+
+        final boolean isInIwlan = (networkRegWlan.getRegistrationState()
+                == NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
+                || (networkRegWlan.getRegistrationState()
+                == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING);
+        return !isInIwlan;
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index fc69b1a..f18ffe1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -34,6 +34,8 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.NetworkRegistrationInfo;
 import android.telephony.ServiceState;
 import android.text.TextUtils;
 
@@ -69,6 +71,8 @@
     private LocationManager mLocationManager;
     @Mock
     private ServiceState mServiceState;
+    @Mock
+    private NetworkRegistrationInfo mNetworkRegistrationInfo;
 
     @Before
     public void setUp() {
@@ -207,6 +211,7 @@
     @Test
     public void isInService_voiceInService_returnTrue() {
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+
         assertThat(Utils.isInService(mServiceState)).isTrue();
     }
 
@@ -214,15 +219,23 @@
     public void isInService_voiceOutOfServiceDataInService_returnTrue() {
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
         when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+        when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
+                AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).thenReturn(mNetworkRegistrationInfo);
+        when(mNetworkRegistrationInfo.getRegistrationState()).thenReturn(
+                NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN);
+
         assertThat(Utils.isInService(mServiceState)).isTrue();
     }
 
     @Test
     public void isInService_voiceOutOfServiceDataInServiceOnIwLan_returnFalse() {
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
-        when(mServiceState.getDataNetworkType())
-                .thenReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN);
+        when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
+                AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).thenReturn(mNetworkRegistrationInfo);
+        when(mNetworkRegistrationInfo.getRegistrationState()).thenReturn(
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
         when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+
         assertThat(Utils.isInService(mServiceState)).isFalse();
     }
 
@@ -230,12 +243,14 @@
     public void isInService_voiceOutOfServiceDataOutOfService_returnFalse() {
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
         when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
+
         assertThat(Utils.isInService(mServiceState)).isFalse();
     }
 
     @Test
     public void isInService_ServiceStatePowerOff_returnFalse() {
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_POWER_OFF);
+
         assertThat(Utils.isInService(mServiceState)).isFalse();
     }
 
@@ -248,6 +263,7 @@
     @Test
     public void getCombinedServiceState_ServiceStatePowerOff_returnPowerOff() {
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_POWER_OFF);
+
         assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo(
                 ServiceState.STATE_POWER_OFF);
     }
@@ -255,6 +271,7 @@
     @Test
     public void getCombinedServiceState_voiceInService_returnInService() {
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+
         assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo(
                 ServiceState.STATE_IN_SERVICE);
     }
@@ -263,14 +280,33 @@
     public void getCombinedServiceState_voiceOutOfServiceDataInService_returnInService() {
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
         when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+        when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
+                AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).thenReturn(mNetworkRegistrationInfo);
+        when(mNetworkRegistrationInfo.getRegistrationState()).thenReturn(
+                NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN);
+
         assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo(
                 ServiceState.STATE_IN_SERVICE);
     }
 
     @Test
+    public void getCombinedServiceState_voiceOutOfServiceDataInServiceOnIwLan_returnOutOfService() {
+        when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
+        when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+        when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
+                AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).thenReturn(mNetworkRegistrationInfo);
+        when(mNetworkRegistrationInfo.getRegistrationState()).thenReturn(
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+
+        assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo(
+                ServiceState.STATE_OUT_OF_SERVICE);
+    }
+
+    @Test
     public void getCombinedServiceState_voiceOutOfServiceDataOutOfService_returnOutOfService() {
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
         when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
+
         assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo(
                 ServiceState.STATE_OUT_OF_SERVICE);
     }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 51bf441..aefdce4 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -227,6 +227,9 @@
     <!-- Permission required for CTS test - TetheringManagerTest -->
     <uses-permission android:name="android.permission.TETHER_PRIVILEGED"/>
 
+    <!-- Permission required for CTS test - CtsOsTestCases -->
+    <uses-permission android:name="android.permission.MANAGE_CRATES"/>
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 404e791..4fb3be2 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -80,7 +80,7 @@
 filegroup {
     name: "SystemUI-tests-utils",
     srcs: [
-        "tests/src/com/android/systemui/statusbar/NotificationEntryBuilder.java",
+        "tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java",
         "tests/src/com/android/systemui/statusbar/RankingBuilder.java",
         "tests/src/com/android/systemui/statusbar/SbnBuilder.java",
     ],
@@ -154,7 +154,7 @@
     resource_dirs: [],
 
     platform_apis: true,
-    product_specific: true,
+    system_ext_specific: true,
     certificate: "platform",
     privileged: true,
 
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index a8318d6..2a1e74e 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -174,6 +174,9 @@
     <!-- Adding Quick Settings tiles -->
     <uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />
 
+    <!-- Adding Controls to SystemUI -->
+    <uses-permission android:name="android.permission.BIND_CONTROLS" />
+
     <!-- Quick Settings tile: Night Mode / Dark Theme -->
     <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE" />
 
diff --git a/packages/SystemUI/CleanSpec.mk b/packages/SystemUI/CleanSpec.mk
new file mode 100644
index 0000000..2a2e4e4
--- /dev/null
+++ b/packages/SystemUI/CleanSpec.mk
@@ -0,0 +1,50 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/priv-app/SystemUI)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/priv-app/SystemUI)
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 45318fd..380dcfd 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1140,13 +1140,16 @@
     <string name="battery_saver_notification_action_text">Turn off Battery Saver</string>
 
     <!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] -->
-    <string name="media_projection_dialog_text">While recording or casting, <xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> can capture any sensitive information that is displayed on your screen or played from your device, including sensitive information such as audio, passwords, payment info, photos and messages.</string>
+    <string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.</string>
 
     <!-- Media projection permission dialog warning text for system services. [CHAR LIMIT=NONE] -->
-    <string name="media_projection_dialog_service_text">While recording or casting, the service providing this function can capture any sensitive information that is displayed on your screen or played from your device, including sensitive information such as audio, passwords, payment info, photos and messages.</string>
+    <string name="media_projection_dialog_service_text">The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.</string>
+
+    <!-- Media projection permission dialog warning title for system services. [CHAR LIMIT=NONE] -->
+    <string name="media_projection_dialog_service_title">Start recording or casting ?</string>
 
     <!-- Media projection permission dialog warning title. [CHAR LIMIT=NONE] -->
-    <string name="media_projection_dialog_title">Exposing sensitive info during casting/recording </string>
+    <string name="media_projection_dialog_title">Start recording or casting with <xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g>?</string>
 
     <!-- Media projection permission dialog permanent grant check box. [CHAR LIMIT=NONE] -->
     <string name="media_projection_remember_text">Don\'t show again</string>
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
index 41a7bc4..47a10af 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -19,117 +19,99 @@
 import android.view.View;
 
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+import java.util.Optional;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
+import dagger.Lazy;
+
 /**
  * Single common instance of ActivityStarter that can be gotten and referenced from anywhere, but
- * delegates to an actual implementation such as StatusBar, assuming it exists.
+ * delegates to an actual implementation (StatusBar).
  */
+@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
 @Singleton
 public class ActivityStarterDelegate implements ActivityStarter {
 
-    private ActivityStarter mActualStarter;
+    private Optional<Lazy<StatusBar>> mActualStarter;
 
     @Inject
-    public ActivityStarterDelegate() {
+    public ActivityStarterDelegate(Optional<Lazy<StatusBar>> statusBar) {
+        mActualStarter = statusBar;
     }
 
     @Override
     public void startPendingIntentDismissingKeyguard(PendingIntent intent) {
-        if (mActualStarter == null) {
-            return;
-        }
-        mActualStarter.startPendingIntentDismissingKeyguard(intent);
+        mActualStarter.ifPresent(
+                starter -> starter.get().startPendingIntentDismissingKeyguard(intent));
     }
 
     @Override
     public void startPendingIntentDismissingKeyguard(PendingIntent intent,
             Runnable intentSentCallback) {
-        if (mActualStarter == null) {
-            return;
-        }
-        mActualStarter.startPendingIntentDismissingKeyguard(intent, intentSentCallback);
+        mActualStarter.ifPresent(
+                starter -> starter.get().startPendingIntentDismissingKeyguard(intent,
+                        intentSentCallback));
     }
 
     @Override
     public void startPendingIntentDismissingKeyguard(PendingIntent intent,
             Runnable intentSentCallback, View associatedView) {
-        if (mActualStarter == null) {
-            return;
-        }
-        mActualStarter.startPendingIntentDismissingKeyguard(intent, intentSentCallback,
-                associatedView);
+        mActualStarter.ifPresent(
+                starter -> starter.get().startPendingIntentDismissingKeyguard(intent,
+                        intentSentCallback, associatedView));
     }
 
     @Override
     public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade,
             int flags) {
-        if (mActualStarter == null) {
-            return;
-        }
-        mActualStarter.startActivity(intent, onlyProvisioned, dismissShade, flags);
+        mActualStarter.ifPresent(
+                starter -> starter.get().startActivity(intent, onlyProvisioned, dismissShade,
+                        flags));
     }
 
     @Override
     public void startActivity(Intent intent, boolean dismissShade) {
-        if (mActualStarter == null) {
-            return;
-        }
-        mActualStarter.startActivity(intent, dismissShade);
+        mActualStarter.ifPresent(starter -> starter.get().startActivity(intent, dismissShade));
     }
 
     @Override
     public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade) {
-        if (mActualStarter == null) {
-            return;
-        }
-        mActualStarter.startActivity(intent, onlyProvisioned, dismissShade);
+        mActualStarter.ifPresent(
+                starter -> starter.get().startActivity(intent, onlyProvisioned, dismissShade));
     }
 
     @Override
     public void startActivity(Intent intent, boolean dismissShade, Callback callback) {
-        if (mActualStarter == null) {
-            return;
-        }
-        mActualStarter.startActivity(intent, dismissShade, callback);
+        mActualStarter.ifPresent(
+                starter -> starter.get().startActivity(intent, dismissShade, callback));
     }
 
     @Override
     public void postStartActivityDismissingKeyguard(Intent intent, int delay) {
-        if (mActualStarter == null) {
-            return;
-        }
-        mActualStarter.postStartActivityDismissingKeyguard(intent, delay);
+        mActualStarter.ifPresent(
+                starter -> starter.get().postStartActivityDismissingKeyguard(intent, delay));
     }
 
     @Override
     public void postStartActivityDismissingKeyguard(PendingIntent intent) {
-        if (mActualStarter == null) {
-            return;
-        }
-        mActualStarter.postStartActivityDismissingKeyguard(intent);
+        mActualStarter.ifPresent(
+                starter -> starter.get().postStartActivityDismissingKeyguard(intent));
     }
 
     @Override
     public void postQSRunnableDismissingKeyguard(Runnable runnable) {
-        if (mActualStarter == null) {
-            return;
-        }
-        mActualStarter.postQSRunnableDismissingKeyguard(runnable);
+        mActualStarter.ifPresent(
+                starter -> starter.get().postQSRunnableDismissingKeyguard(runnable));
     }
 
     @Override
     public void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancel,
             boolean afterKeyguardGone) {
-        if (mActualStarter == null) {
-            return;
-        }
-        mActualStarter.dismissKeyguardThenExecute(action, cancel, afterKeyguardGone);
-    }
-
-    public void setActivityStarterImpl(ActivityStarter starter) {
-        mActualStarter = starter;
+        mActualStarter.ifPresent(starter -> starter.get().dismissKeyguardThenExecute(action, cancel,
+                afterKeyguardGone));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
index 8e472f9..8503396 100644
--- a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
+++ b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
@@ -57,6 +57,7 @@
         mPaint.setStyle(Paint.Style.STROKE);
         mPaint.setStrokeCap(Paint.Cap.ROUND);
         mPaint.setStrokeWidth(getStrokePx());
+        setLayerType(View.LAYER_TYPE_SOFTWARE, mPaint);
 
         final int dualToneDarkTheme = Utils.getThemeAttr(mContext, R.attr.darkIconTheme);
         final int dualToneLightTheme = Utils.getThemeAttr(mContext, R.attr.lightIconTheme);
@@ -114,10 +115,17 @@
      * appropriately. Intention is to match the home handle color.
      */
     public void updateDarkness(float darkIntensity) {
+        // Handle color is same as home handle color.
         int color = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
                 mLightColor, mDarkColor);
+        // Shadow color is inverse of handle color.
+        int shadowColor = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
+                mDarkColor, mLightColor);
         if (mPaint.getColor() != color) {
             mPaint.setColor(color);
+            mPaint.setShadowLayer(/** radius */ getResources().getDimensionPixelSize(
+                    com.android.internal.R.dimen.assist_handle_shadow_radius), /** shadowDx */ 0,
+                    /** shadowDy */ 0, /** color */ shadowColor);
             if (getVisibility() == VISIBLE && getAlpha() > 0) {
                 invalidate();
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index dd38a33..94e7c68c 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -210,7 +210,6 @@
     private final ArrayMap<Object, LazyDependencyCreator> mProviders = new ArrayMap<>();
 
     @Inject Lazy<ActivityStarter> mActivityStarter;
-    @Inject Lazy<ActivityStarterDelegate> mActivityStarterDelegate;
     @Inject Lazy<BroadcastDispatcher> mBroadcastDispatcher;
     @Inject Lazy<AsyncSensorManager> mAsyncSensorManager;
     @Inject Lazy<BluetoothController> mBluetoothController;
@@ -341,7 +340,6 @@
         mProviders.put(MAIN_LOOPER, mMainLooper::get);
         mProviders.put(MAIN_HANDLER, mMainHandler::get);
         mProviders.put(ActivityStarter.class, mActivityStarter::get);
-        mProviders.put(ActivityStarterDelegate.class, mActivityStarterDelegate::get);
         mProviders.put(BroadcastDispatcher.class, mBroadcastDispatcher::get);
 
         mProviders.put(AsyncSensorManager.class, mAsyncSensorManager::get);
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index ecf4c0a..e2b12da 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -179,7 +179,8 @@
         mTouchSlop = configuration.getScaledTouchSlop();
 
         mSGD = new ScaleGestureDetector(context, mScaleGestureListener);
-        mFlingAnimationUtils = new FlingAnimationUtils(context, EXPAND_DURATION);
+        mFlingAnimationUtils = new FlingAnimationUtils(mContext.getResources().getDisplayMetrics(),
+                EXPAND_DURATION);
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 58c52a1..4728327 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -93,13 +93,11 @@
     private boolean mTouchAboveFalsingThreshold;
     private boolean mDisableHwLayers;
     private final boolean mFadeDependingOnAmountSwiped;
-    private final Context mContext;
 
     private final ArrayMap<View, Animator> mDismissPendingMap = new ArrayMap<>();
 
     public SwipeHelper(
             int swipeDirection, Callback callback, Context context, FalsingManager falsingManager) {
-        mContext = context;
         mCallback = callback;
         mHandler = new Handler();
         mSwipeDirection = swipeDirection;
@@ -114,7 +112,8 @@
         mFalsingThreshold = res.getDimensionPixelSize(R.dimen.swipe_helper_falsing_threshold);
         mFadeDependingOnAmountSwiped = res.getBoolean(R.bool.config_fadeDependingOnAmountSwiped);
         mFalsingManager = falsingManager;
-        mFlingAnimationUtils = new FlingAnimationUtils(context, getMaxEscapeAnimDuration() / 1000f);
+        mFlingAnimationUtils = new FlingAnimationUtils(res.getDisplayMetrics(),
+                getMaxEscapeAnimDuration() / 1000f);
     }
 
     public void setDensityScale(float densityScale) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
index a6a3ce0..dc24996 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
@@ -16,22 +16,15 @@
 package com.android.systemui.bubbles;
 
 import android.annotation.Nullable;
-import android.app.Notification;
 import android.content.Context;
-import android.content.pm.LauncherApps;
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Matrix;
 import android.graphics.Path;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
 import android.util.AttributeSet;
 import android.util.PathParser;
 import android.widget.ImageView;
 
-import com.android.internal.graphics.ColorUtils;
-import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.DotRenderer;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -46,9 +39,9 @@
 public class BadgedImageView extends ImageView {
 
     /** Same value as Launcher3 dot code */
-    private static final float WHITE_SCRIM_ALPHA = 0.54f;
+    public static final float WHITE_SCRIM_ALPHA = 0.54f;
     /** Same as value in Launcher3 IconShape */
-    private static final int DEFAULT_PATH_SIZE = 100;
+    public static final int DEFAULT_PATH_SIZE = 100;
 
     static final int DOT_STATE_DEFAULT = 0;
     static final int DOT_STATE_SUPPRESSED_FOR_FLYOUT = 1;
@@ -58,7 +51,6 @@
     private int mCurrentDotState = DOT_STATE_SUPPRESSED_FOR_FLYOUT;
 
     private Bubble mBubble;
-    private BubbleIconFactory mBubbleIconFactory;
 
     private int mIconBitmapSize;
     private DotRenderer mDotRenderer;
@@ -94,6 +86,18 @@
         mDotRenderer = new DotRenderer(mIconBitmapSize, iconPath, DEFAULT_PATH_SIZE);
     }
 
+    /**
+     * Updates the view with provided info.
+     */
+    public void update(Bubble bubble, Bitmap bubbleImage, int dotColor, Path dotPath) {
+        mBubble = bubble;
+        setImageBitmap(bubbleImage);
+        setDotState(DOT_STATE_SUPPRESSED_FOR_FLYOUT);
+        mDotColor = dotColor;
+        drawDot(dotPath);
+        animateDot();
+    }
+
     @Override
     public void onDraw(Canvas canvas) {
         super.onDraw(canvas);
@@ -140,14 +144,6 @@
     }
 
     /**
-     * The colour to use for the dot.
-     */
-    void setDotColor(int color) {
-        mDotColor = ColorUtils.setAlphaComponent(color, 255 /* alpha */);
-        invalidate();
-    }
-
-    /**
      * @param iconPath The new icon path to use when calculating dot position.
      */
     void drawDot(Path iconPath) {
@@ -187,25 +183,6 @@
     }
 
     /**
-     * Populates this view with a bubble.
-     * <p>
-     * This should only be called when a new bubble is being set on the view, updates to the
-     * current bubble should use {@link #update(Bubble)}.
-     *
-     * @param bubble the bubble to display in this view.
-     */
-    public void setBubble(Bubble bubble) {
-        mBubble = bubble;
-    }
-
-    /**
-     * @param factory Factory for creating normalized bubble icons.
-     */
-    public void setBubbleIconFactory(BubbleIconFactory factory) {
-        mBubbleIconFactory = factory;
-    }
-
-    /**
      * The key for the {@link Bubble} associated with this view, if one exists.
      */
     @Nullable
@@ -213,15 +190,6 @@
         return (mBubble != null) ? mBubble.getKey() : null;
     }
 
-    /**
-     * Updates the UI based on the bubble, updates badge and animates messages as needed.
-     */
-    public void update(Bubble bubble) {
-        mBubble = bubble;
-        setDotState(DOT_STATE_SUPPRESSED_FOR_FLYOUT);
-        updateViews();
-    }
-
     int getDotColor() {
         return mDotColor;
     }
@@ -277,47 +245,4 @@
                     }
                 }).start();
     }
-
-    void updateViews() {
-        if (mBubble == null || mBubbleIconFactory == null) {
-            return;
-        }
-
-        Drawable bubbleDrawable = getBubbleDrawable(mContext);
-        BitmapInfo badgeBitmapInfo = mBubbleIconFactory.getBadgedBitmap(mBubble);
-        BitmapInfo bubbleBitmapInfo = mBubbleIconFactory.getBubbleBitmap(bubbleDrawable,
-                badgeBitmapInfo);
-        setImageBitmap(bubbleBitmapInfo.icon);
-
-        // Update badge.
-        mDotColor = ColorUtils.blendARGB(badgeBitmapInfo.color, Color.WHITE, WHITE_SCRIM_ALPHA);
-        setDotColor(mDotColor);
-
-        // Update dot.
-        Path iconPath = PathParser.createPathFromPathData(
-                getResources().getString(com.android.internal.R.string.config_icon_mask));
-        Matrix matrix = new Matrix();
-        float scale = mBubbleIconFactory.getNormalizer().getScale(bubbleDrawable,
-                null /* outBounds */, null /* path */, null /* outMaskShape */);
-        float radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f;
-        matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
-                radius /* pivot y */);
-        iconPath.transform(matrix);
-        drawDot(iconPath);
-
-        animateDot();
-    }
-
-    Drawable getBubbleDrawable(Context context) {
-        if (mBubble.getShortcutInfo() != null && mBubble.usingShortcutInfo()) {
-            LauncherApps launcherApps =
-                    (LauncherApps) getContext().getSystemService(Context.LAUNCHER_APPS_SERVICE);
-            int density = getContext().getResources().getConfiguration().densityDpi;
-            return launcherApps.getShortcutIconDrawable(mBubble.getShortcutInfo(), density);
-        } else {
-            Notification.BubbleMetadata metadata = mBubble.getEntry().getBubbleMetadata();
-            Icon ic = metadata.getIcon();
-            return ic.loadDrawable(context);
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 7934e10..77c8e0b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -16,6 +16,7 @@
 package com.android.systemui.bubbles;
 
 
+import static android.os.AsyncTask.Status.FINISHED;
 import static android.view.Display.INVALID_DISPLAY;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
@@ -26,20 +27,17 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.content.pm.ShortcutInfo;
 import android.content.res.Resources;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.LayoutInflater;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
@@ -59,19 +57,19 @@
     private NotificationEntry mEntry;
     private final String mKey;
     private final String mGroupId;
-    private String mAppName;
-    private Drawable mUserBadgedAppIcon;
-    private ShortcutInfo mShortcutInfo;
-
-    private boolean mInflated;
-    private BadgedImageView mIconView;
-    private BubbleExpandedView mExpandedView;
-    private BubbleIconFactory mBubbleIconFactory;
 
     private long mLastUpdated;
     private long mLastAccessed;
 
-    private boolean mIsUserCreated;
+    // Items that are typically loaded later
+    private String mAppName;
+    private ShortcutInfo mShortcutInfo;
+    private BadgedImageView mIconView;
+    private BubbleExpandedView mExpandedView;
+
+    private boolean mInflated;
+    private BubbleViewInfoTask mInflationTask;
+    private boolean mInflateSynchronously;
 
     /**
      * Whether this notification should be shown in the shade when it is also displayed as a bubble.
@@ -94,37 +92,11 @@
 
     /** Used in tests when no UI is required. */
     @VisibleForTesting(visibility = PRIVATE)
-    Bubble(Context context, NotificationEntry e) {
+    Bubble(NotificationEntry e) {
         mEntry = e;
         mKey = e.getKey();
         mLastUpdated = e.getSbn().getPostTime();
         mGroupId = groupId(e);
-
-        String shortcutId = e.getSbn().getNotification().getShortcutId();
-        if (BubbleExperimentConfig.useShortcutInfoToBubble(context)
-                && shortcutId != null) {
-            mShortcutInfo = BubbleExperimentConfig.getShortcutInfo(context,
-                    e.getSbn().getPackageName(),
-                    e.getSbn().getUser(), shortcutId);
-        }
-
-        PackageManager pm = context.getPackageManager();
-        ApplicationInfo info;
-        try {
-            info = pm.getApplicationInfo(
-                mEntry.getSbn().getPackageName(),
-                PackageManager.MATCH_UNINSTALLED_PACKAGES
-                    | PackageManager.MATCH_DISABLED_COMPONENTS
-                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                    | PackageManager.MATCH_DIRECT_BOOT_AWARE);
-            if (info != null) {
-                mAppName = String.valueOf(pm.getApplicationLabel(info));
-            }
-            Drawable appIcon = pm.getApplicationIcon(mEntry.getSbn().getPackageName());
-            mUserBadgedAppIcon = pm.getUserBadgedIcon(appIcon, mEntry.getSbn().getUser());
-        } catch (PackageManager.NameNotFoundException unused) {
-            mAppName = mEntry.getSbn().getPackageName();
-        }
     }
 
     public String getKey() {
@@ -143,41 +115,22 @@
         return mEntry.getSbn().getPackageName();
     }
 
+    @Nullable
     public String getAppName() {
         return mAppName;
     }
 
-    Drawable getUserBadgedAppIcon() {
-        return mUserBadgedAppIcon;
-    }
-
     @Nullable
     public ShortcutInfo getShortcutInfo() {
         return mShortcutInfo;
     }
 
-    /**
-     * Whether shortcut information should be used to populate the bubble.
-     * <p>
-     * To populate the activity use {@link LauncherApps#startShortcut(ShortcutInfo, Rect, Bundle)}.
-     * To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
-     */
-    public boolean usingShortcutInfo() {
-        return BubbleExperimentConfig.isShortcutIntent(getBubbleIntent());
-    }
-
-    void setBubbleIconFactory(BubbleIconFactory factory) {
-        mBubbleIconFactory = factory;
-    }
-
-    boolean isInflated() {
-        return mInflated;
-    }
-
+    @Nullable
     BadgedImageView getIconView() {
         return mIconView;
     }
 
+    @Nullable
     BubbleExpandedView getExpandedView() {
         return mExpandedView;
     }
@@ -188,20 +141,62 @@
         }
     }
 
-    void inflate(LayoutInflater inflater, BubbleStackView stackView) {
-        if (mInflated) {
-            return;
+    /**
+     * Sets whether to perform inflation on the same thread as the caller. This method should only
+     * be used in tests, not in production.
+     */
+    @VisibleForTesting
+    void setInflateSynchronously(boolean inflateSynchronously) {
+        mInflateSynchronously = inflateSynchronously;
+    }
+
+    /**
+     * Starts a task to inflate & load any necessary information to display a bubble.
+     *
+     * @param callback the callback to notify one the bubble is ready to be displayed.
+     * @param context the context for the bubble.
+     * @param stackView the stackView the bubble is eventually added to.
+     * @param iconFactory the iconfactory use to create badged images for the bubble.
+     */
+    void inflate(BubbleViewInfoTask.Callback callback,
+            Context context,
+            BubbleStackView stackView,
+            BubbleIconFactory iconFactory) {
+        if (isBubbleLoading()) {
+            mInflationTask.cancel(true /* mayInterruptIfRunning */);
         }
-        mIconView = (BadgedImageView) inflater.inflate(
-                R.layout.bubble_view, stackView, false /* attachToRoot */);
-        mIconView.setBubbleIconFactory(mBubbleIconFactory);
-        mIconView.setBubble(this);
+        mInflationTask = new BubbleViewInfoTask(this,
+                context,
+                stackView,
+                iconFactory,
+                callback);
+        if (mInflateSynchronously) {
+            mInflationTask.onPostExecute(mInflationTask.doInBackground());
+        } else {
+            mInflationTask.execute();
+        }
+    }
 
-        mExpandedView = (BubbleExpandedView) inflater.inflate(
-                R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
-        mExpandedView.setBubble(this, stackView);
+    private boolean isBubbleLoading() {
+        return mInflationTask != null && mInflationTask.getStatus() != FINISHED;
+    }
 
-        mInflated = true;
+    boolean isInflated() {
+        return mInflated;
+    }
+
+    void setViewInfo(BubbleViewInfoTask.BubbleViewInfo info) {
+        if (!isInflated()) {
+            mIconView = info.imageView;
+            mExpandedView = info.expandedView;
+            mInflated = true;
+        }
+
+        mShortcutInfo = info.shortcutInfo;
+        mAppName = info.appName;
+
+        mExpandedView.update(this);
+        mIconView.update(this, info.badgedBubbleImage, info.dotColor, info.dotPath);
     }
 
     /**
@@ -218,13 +213,12 @@
         }
     }
 
-    void updateEntry(NotificationEntry entry) {
+    /**
+     * Sets the entry associated with this bubble.
+     */
+    void setEntry(NotificationEntry entry) {
         mEntry = entry;
         mLastUpdated = entry.getSbn().getPostTime();
-        if (mInflated) {
-            mIconView.update(this);
-            mExpandedView.update(this);
-        }
     }
 
     /**
@@ -242,13 +236,6 @@
     }
 
     /**
-     * @return the timestamp in milliseconds when this bubble was last displayed in expanded state
-     */
-    long getLastAccessTime() {
-        return mLastAccessed;
-    }
-
-    /**
      * @return the display id of the virtual display on which bubble contents is drawn.
      */
     int getDisplayId() {
@@ -352,6 +339,16 @@
         }
     }
 
+    /**
+     * Whether shortcut information should be used to populate the bubble.
+     * <p>
+     * To populate the activity use {@link LauncherApps#startShortcut(ShortcutInfo, Rect, Bundle)}.
+     * To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
+     */
+    boolean usingShortcutInfo() {
+        return BubbleExperimentConfig.isShortcutIntent(getBubbleIntent());
+    }
+
     @Nullable
     PendingIntent getBubbleIntent() {
         Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index c82bc30..7cd29ea 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -150,6 +150,7 @@
 
     private BubbleData mBubbleData;
     @Nullable private BubbleStackView mStackView;
+    private BubbleIconFactory mBubbleIconFactory;
 
     // Tracks the id of the current (foreground) user.
     private int mCurrentUserId;
@@ -183,6 +184,8 @@
     /** Last known orientation, used to detect orientation changes in {@link #onConfigChanged}. */
     private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
 
+    private boolean mInflateSynchronously;
+
     /**
      * Listener to be notified when some states of the bubbles change.
      */
@@ -352,6 +355,16 @@
         mUserBlockedBubbles = new HashSet<>();
 
         mScreenshotHelper = new ScreenshotHelper(context);
+        mBubbleIconFactory = new BubbleIconFactory(context);
+    }
+
+    /**
+     * Sets whether to perform inflation on the same thread as the caller. This method should only
+     * be used in tests, not in production.
+     */
+    @VisibleForTesting
+    void setInflateSynchronously(boolean inflateSynchronously) {
+        mInflateSynchronously = inflateSynchronously;
     }
 
     /**
@@ -415,16 +428,23 @@
 
     @Override
     public void onUiModeChanged() {
-        if (mStackView != null) {
-            mStackView.onThemeChanged();
-        }
+        updateForThemeChanges();
     }
 
     @Override
     public void onOverlayChanged() {
+        updateForThemeChanges();
+    }
+
+    private void updateForThemeChanges() {
         if (mStackView != null) {
             mStackView.onThemeChanged();
         }
+        mBubbleIconFactory = new BubbleIconFactory(mContext);
+        for (Bubble b: mBubbleData.getBubbles()) {
+            // Reload each bubble
+            b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory);
+        }
     }
 
     @Override
@@ -508,14 +528,10 @@
         return (isSummary && isSuppressedSummary) || isBubbleAndSuppressed;
     }
 
-    void selectBubble(Bubble bubble) {
-        mBubbleData.setSelectedBubble(bubble);
-    }
-
     @VisibleForTesting
     void selectBubble(String key) {
         Bubble bubble = mBubbleData.getBubbleWithKey(key);
-        selectBubble(bubble);
+        mBubbleData.setSelectedBubble(bubble);
     }
 
     /**
@@ -562,11 +578,19 @@
     }
 
     void updateBubble(NotificationEntry notif, boolean suppressFlyout, boolean showInShade) {
+        if (mStackView == null) {
+            // Lazy init stack view when a bubble is created
+            ensureStackViewCreated();
+        }
         // If this is an interruptive notif, mark that it's interrupted
         if (notif.getImportance() >= NotificationManager.IMPORTANCE_HIGH) {
             notif.setInterruption();
         }
-        mBubbleData.notificationEntryUpdated(notif, suppressFlyout, showInShade);
+        Bubble bubble = mBubbleData.getOrCreateBubble(notif);
+        bubble.setInflateSynchronously(mInflateSynchronously);
+        bubble.inflate(
+                b -> mBubbleData.notificationEntryUpdated(b, suppressFlyout, showInShade),
+                mContext, mStackView, mBubbleIconFactory);
     }
 
     /**
@@ -783,16 +807,6 @@
 
         @Override
         public void applyUpdate(BubbleData.Update update) {
-            if (mStackView == null && update.addedBubble != null) {
-                // Lazy init stack view when the first bubble is added.
-                ensureStackViewCreated();
-            }
-
-            // If not yet initialized, ignore all other changes.
-            if (mStackView == null) {
-                return;
-            }
-
             if (update.addedBubble != null) {
                 mStackView.addBubble(update.addedBubble);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index b7df5ba..97224f1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -33,6 +33,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
 import com.android.systemui.bubbles.BubbleController.DismissReason;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
@@ -48,7 +49,6 @@
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
-import com.android.systemui.R;
 
 /**
  * Keeps track of active bubbles.
@@ -180,28 +180,44 @@
         dispatchPendingChanges();
     }
 
-    void notificationEntryUpdated(NotificationEntry entry, boolean suppressFlyout,
-            boolean showInShade) {
+    /**
+     * Constructs a new bubble or returns an existing one. Does not add new bubbles to
+     * bubble data, must go through {@link #notificationEntryUpdated(Bubble, boolean, boolean)}
+     * for that.
+     */
+    Bubble getOrCreateBubble(NotificationEntry entry) {
+        Bubble bubble = getBubbleWithKey(entry.getKey());
+        if (bubble == null) {
+            bubble = new Bubble(entry);
+        } else {
+            bubble.setEntry(entry);
+        }
+        return bubble;
+    }
+
+    /**
+     * When this method is called it is expected that all info in the bubble has completed loading.
+     * @see Bubble#inflate(BubbleViewInfoTask.Callback, Context,
+     * BubbleStackView, BubbleIconFactory).
+     */
+    void notificationEntryUpdated(Bubble bubble, boolean suppressFlyout, boolean showInShade) {
         if (DEBUG_BUBBLE_DATA) {
-            Log.d(TAG, "notificationEntryUpdated: " + entry);
+            Log.d(TAG, "notificationEntryUpdated: " + bubble);
         }
 
-        Bubble bubble = getBubbleWithKey(entry.getKey());
-        suppressFlyout |= !shouldShowFlyout(entry);
+        Bubble prevBubble = getBubbleWithKey(bubble.getKey());
+        suppressFlyout |= !shouldShowFlyout(bubble.getEntry());
 
-        if (bubble == null) {
+        if (prevBubble == null) {
             // Create a new bubble
-            bubble = new Bubble(mContext, entry);
             bubble.setSuppressFlyout(suppressFlyout);
             doAdd(bubble);
             trim();
         } else {
             // Updates an existing bubble
-            bubble.updateEntry(entry);
             bubble.setSuppressFlyout(suppressFlyout);
             doUpdate(bubble);
         }
-
         if (bubble.shouldAutoExpand()) {
             setSelectedBubbleInternal(bubble);
             if (!mExpanded) {
@@ -214,6 +230,7 @@
         bubble.setShowInShade(!isBubbleExpandedAndSelected && showInShade);
         bubble.setShowDot(!isBubbleExpandedAndSelected /* show */, true /* animate */);
         dispatchPendingChanges();
+
     }
 
     public void notificationEntryRemoved(NotificationEntry entry, @DismissReason int reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 63d036d..c1705db 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -99,7 +99,6 @@
     private int mExpandedViewTouchSlop;
 
     private Bubble mBubble;
-    private String mAppName;
 
     private BubbleController mBubbleController = Dependency.get(BubbleController.class);
     private WindowManager mWindowManager;
@@ -339,26 +338,41 @@
         }
     }
 
-    /**
-     * Sets the bubble used to populate this view.
-     */
-    public void setBubble(Bubble bubble, BubbleStackView stackView) {
-        if (DEBUG_BUBBLE_EXPANDED_VIEW) {
-            Log.d(TAG, "setBubble: bubble=" + (bubble != null ? bubble.getKey() : "null"));
-        }
+    void setStackView(BubbleStackView stackView) {
         mStackView = stackView;
-        mBubble = bubble;
-        mAppName = bubble.getAppName();
-
-        applyThemeAttrs();
-        showSettingsIcon();
-        updateExpandedView();
     }
 
     /**
-     * Lets activity view know it should be shown / populated.
+     * Sets the bubble used to populate this view.
      */
-    public void populateExpandedView() {
+    void update(Bubble bubble) {
+        if (DEBUG_BUBBLE_EXPANDED_VIEW) {
+            Log.d(TAG, "update: bubble=" + (bubble != null ? bubble.getKey() : "null"));
+        }
+        boolean isNew = mBubble == null;
+        if (isNew || bubble.getKey().equals(mBubble.getKey())) {
+            mBubble = bubble;
+            mSettingsIcon.setContentDescription(getResources().getString(
+                    R.string.bubbles_settings_button_description, bubble.getAppName()));
+
+            if (isNew) {
+                mBubbleIntent = mBubble.getBubbleIntent();
+                if (mBubbleIntent != null) {
+                    setContentVisibility(false);
+                    mActivityView.setVisibility(VISIBLE);
+                }
+            }
+            applyThemeAttrs();
+        } else {
+            Log.w(TAG, "Trying to update entry with different key, new bubble: "
+                    + bubble.getKey() + " old bubble: " + bubble.getKey());
+        }
+    }
+
+    /**
+     * Lets activity view know it should be shown / populated with activity content.
+     */
+    void populateExpandedView() {
         if (DEBUG_BUBBLE_EXPANDED_VIEW) {
             Log.d(TAG, "populateExpandedView: "
                     + "bubble=" + getBubbleKey());
@@ -371,38 +385,6 @@
         }
     }
 
-    /**
-     * Updates the bubble backing this view. This will not re-populate ActivityView, it will
-     * only update the deep-links in the title, and the height of the view.
-     */
-    public void update(Bubble bubble) {
-        if (DEBUG_BUBBLE_EXPANDED_VIEW) {
-            Log.d(TAG, "update: bubble=" + (bubble != null ? bubble.getKey() : "null"));
-        }
-        if (bubble.getKey().equals(mBubble.getKey())) {
-            mBubble = bubble;
-            updateSettingsContentDescription();
-            updateHeight();
-        } else {
-            Log.w(TAG, "Trying to update entry with different key, new bubble: "
-                    + bubble.getKey() + " old bubble: " + bubble.getKey());
-        }
-    }
-
-    private void updateExpandedView() {
-        if (DEBUG_BUBBLE_EXPANDED_VIEW) {
-            Log.d(TAG, "updateExpandedView: bubble="
-                    + getBubbleKey());
-        }
-
-        mBubbleIntent = mBubble.getBubbleIntent();
-        if (mBubbleIntent != null) {
-            setContentVisibility(false);
-            mActivityView.setVisibility(VISIBLE);
-        }
-        updateView();
-    }
-
     boolean performBackPressIfNeeded() {
         if (!usingActivityView()) {
             return false;
@@ -490,16 +472,6 @@
         }
     }
 
-    private void updateSettingsContentDescription() {
-        mSettingsIcon.setContentDescription(getResources().getString(
-                R.string.bubbles_settings_button_description, mAppName));
-    }
-
-    void showSettingsIcon() {
-        updateSettingsContentDescription();
-        mSettingsIcon.setVisibility(VISIBLE);
-    }
-
     /**
      * Update appearance of the expanded view being displayed.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
index 9ff033c..b32dbb7 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
@@ -15,11 +15,14 @@
  */
 package com.android.systemui.bubbles;
 
+import android.app.Notification;
 import android.content.Context;
+import android.content.pm.LauncherApps;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 
 import com.android.launcher3.icons.BaseIconFactory;
 import com.android.launcher3.icons.BitmapInfo;
@@ -42,19 +45,40 @@
         return mContext.getResources().getDimensionPixelSize(
                 com.android.launcher3.icons.R.dimen.profile_badge_size);
     }
+    /**
+     * Returns the drawable that the developer has provided to display in the bubble.
+     */
+    Drawable getBubbleDrawable(Bubble b, Context context) {
+        if (b.getShortcutInfo() != null && b.usingShortcutInfo()) {
+            LauncherApps launcherApps =
+                    (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
+            int density = context.getResources().getConfiguration().densityDpi;
+            return launcherApps.getShortcutIconDrawable(b.getShortcutInfo(), density);
+        } else {
+            Notification.BubbleMetadata metadata = b.getEntry().getBubbleMetadata();
+            Icon ic = metadata.getIcon();
+            return ic.loadDrawable(context);
+        }
+    }
 
-    BitmapInfo getBadgedBitmap(Bubble b) {
+    /**
+     * Returns a {@link BitmapInfo} for the app-badge that is shown on top of each bubble. This
+     * will include the workprofile indicator on the badge if appropriate.
+     */
+    BitmapInfo getBadgeBitmap(Drawable userBadgedAppIcon) {
         Bitmap userBadgedBitmap = createIconBitmap(
-                b.getUserBadgedAppIcon(), 1f, getBadgeSize());
+                userBadgedAppIcon, 1f, getBadgeSize());
 
         Canvas c = new Canvas();
         ShadowGenerator shadowGenerator = new ShadowGenerator(getBadgeSize());
         c.setBitmap(userBadgedBitmap);
         shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c);
-        BitmapInfo bitmapInfo = createIconBitmap(userBadgedBitmap);
-        return bitmapInfo;
+        return createIconBitmap(userBadgedBitmap);
     }
 
+    /**
+     * Returns a {@link BitmapInfo} for the entire bubble icon including the badge.
+     */
     BitmapInfo getBubbleBitmap(Drawable bubble, BitmapInfo badge) {
         BitmapInfo bubbleIconInfo = createBadgedIconBitmap(bubble,
                 null /* user */,
@@ -64,5 +88,4 @@
                 new BitmapDrawable(mContext.getResources(), badge.icon));
         return bubbleIconInfo;
     }
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 245b232..8987683 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -516,14 +516,7 @@
      * Handle theme changes.
      */
     public void onThemeChanged() {
-        // Recreate icon factory to update default adaptive icon scale.
-        mBubbleIconFactory = new BubbleIconFactory(mContext);
         setUpFlyout();
-        for (Bubble b: mBubbleData.getBubbles()) {
-            b.getIconView().setBubbleIconFactory(mBubbleIconFactory);
-            b.getIconView().updateViews();
-            b.getExpandedView().applyThemeAttrs();
-        }
     }
 
     /** Respond to the phone being rotated by repositioning the stack and hiding any flyouts. */
@@ -749,10 +742,6 @@
             mStackOnLeftOrWillBe = mStackAnimationController.isStackOnLeftSide();
         }
 
-        bubble.setBubbleIconFactory(mBubbleIconFactory);
-        bubble.inflate(mInflater, this);
-        bubble.getIconView().updateViews();
-
         // Set the dot position to the opposite of the side the stack is resting on, since the stack
         // resting slightly off-screen would result in the dot also being off-screen.
         bubble.getIconView().setDotPosition(
@@ -1567,9 +1556,6 @@
 
         mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
         if (mIsExpanded) {
-            // First update the view so that it calculates a new height (ensuring the y position
-            // calculation is correct)
-            mExpandedBubble.getExpandedView().updateView();
             final float y = getExpandedViewY();
             if (!mExpandedViewYAnim.isRunning()) {
                 // We're not animating so set the value
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
new file mode 100644
index 0000000..41f5028
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bubbles;
+
+import static com.android.systemui.bubbles.BadgedImageView.DEFAULT_PATH_SIZE;
+import static com.android.systemui.bubbles.BadgedImageView.WHITE_SCRIM_ALPHA;
+import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ShortcutInfo;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Path;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.util.PathParser;
+import android.view.LayoutInflater;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.graphics.ColorUtils;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.systemui.R;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Simple task to inflate views & load necessary info to display a bubble.
+ */
+public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask.BubbleViewInfo> {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleViewInfoTask" : TAG_BUBBLES;
+
+
+    /**
+     * Callback to find out when the bubble has been inflated & necessary data loaded.
+     */
+    public interface Callback {
+        /**
+         * Called when data has been loaded for the bubble.
+         */
+        void onBubbleViewsReady(Bubble bubble);
+    }
+
+    private Bubble mBubble;
+    private WeakReference<Context> mContext;
+    private WeakReference<BubbleStackView> mStackView;
+    private BubbleIconFactory mIconFactory;
+    private Callback mCallback;
+
+    /**
+     * Creates a task to load information for the provided {@link Bubble}. Once all info
+     * is loaded, {@link Callback} is notified.
+     */
+    BubbleViewInfoTask(Bubble b,
+            Context context,
+            BubbleStackView stackView,
+            BubbleIconFactory factory,
+            Callback c) {
+        mBubble = b;
+        mContext = new WeakReference<>(context);
+        mStackView = new WeakReference<>(stackView);
+        mIconFactory = factory;
+        mCallback = c;
+    }
+
+    @Override
+    protected BubbleViewInfo doInBackground(Void... voids) {
+        return BubbleViewInfo.populate(mContext.get(), mStackView.get(), mIconFactory, mBubble);
+    }
+
+    @Override
+    protected void onPostExecute(BubbleViewInfo viewInfo) {
+        if (viewInfo != null) {
+            mBubble.setViewInfo(viewInfo);
+            if (mCallback != null && !isCancelled()) {
+                mCallback.onBubbleViewsReady(mBubble);
+            }
+        }
+    }
+
+    static class BubbleViewInfo {
+        BadgedImageView imageView;
+        BubbleExpandedView expandedView;
+        ShortcutInfo shortcutInfo;
+        String appName;
+        Bitmap badgedBubbleImage;
+        int dotColor;
+        Path dotPath;
+
+        @Nullable
+        static BubbleViewInfo populate(Context c, BubbleStackView stackView,
+                BubbleIconFactory iconFactory, Bubble b) {
+            BubbleViewInfo info = new BubbleViewInfo();
+
+            // View inflation: only should do this once per bubble
+            if (!b.isInflated()) {
+                LayoutInflater inflater = LayoutInflater.from(c);
+                info.imageView = (BadgedImageView) inflater.inflate(
+                        R.layout.bubble_view, stackView, false /* attachToRoot */);
+
+                info.expandedView = (BubbleExpandedView) inflater.inflate(
+                        R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
+                info.expandedView.setStackView(stackView);
+            }
+
+            StatusBarNotification sbn = b.getEntry().getSbn();
+            String packageName = sbn.getPackageName();
+
+            // Shortcut info for this bubble
+            String shortcutId = sbn.getNotification().getShortcutId();
+            if (BubbleExperimentConfig.useShortcutInfoToBubble(c)
+                    && shortcutId != null) {
+                info.shortcutInfo = BubbleExperimentConfig.getShortcutInfo(c,
+                        packageName,
+                        sbn.getUser(), shortcutId);
+            }
+
+            // App name & app icon
+            PackageManager pm = c.getPackageManager();
+            ApplicationInfo appInfo;
+            Drawable badgedIcon;
+            try {
+                appInfo = pm.getApplicationInfo(
+                        packageName,
+                        PackageManager.MATCH_UNINSTALLED_PACKAGES
+                                | PackageManager.MATCH_DISABLED_COMPONENTS
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_AWARE);
+                if (appInfo != null) {
+                    info.appName = String.valueOf(pm.getApplicationLabel(appInfo));
+                }
+                Drawable appIcon = pm.getApplicationIcon(packageName);
+                badgedIcon = pm.getUserBadgedIcon(appIcon, sbn.getUser());
+            } catch (PackageManager.NameNotFoundException exception) {
+                // If we can't find package... don't think we should show the bubble.
+                Log.w(TAG, "Unable to find package: " + packageName);
+                return null;
+            }
+
+            // Badged bubble image
+            Drawable bubbleDrawable = iconFactory.getBubbleDrawable(b, c);
+            BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon);
+            info.badgedBubbleImage = iconFactory.getBubbleBitmap(bubbleDrawable,
+                    badgeBitmapInfo).icon;
+
+            // Dot color & placement
+            Path iconPath = PathParser.createPathFromPathData(
+                    c.getResources().getString(com.android.internal.R.string.config_icon_mask));
+            Matrix matrix = new Matrix();
+            float scale = iconFactory.getNormalizer().getScale(bubbleDrawable,
+                    null /* outBounds */, null /* path */, null /* outMaskShape */);
+            float radius = DEFAULT_PATH_SIZE / 2f;
+            matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
+                    radius /* pivot y */);
+            iconPath.transform(matrix);
+            info.dotPath = iconPath;
+            info.dotColor = ColorUtils.blendARGB(badgeBitmapInfo.color,
+                    Color.WHITE, WHITE_SCRIM_ALPHA);
+            return info;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 6ea3f4e..0d161ce 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -35,7 +35,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.BgHandler;
 import com.android.systemui.dagger.qualifiers.BgLooper;
 import com.android.systemui.dagger.qualifiers.MainHandler;
@@ -54,8 +53,6 @@
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DataSaverController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.util.leak.LeakDetector;
 
@@ -223,13 +220,6 @@
         return DevicePolicyManagerWrapper.getInstance();
     }
 
-    @Singleton
-    @Provides
-    public DeviceProvisionedController provideDeviceProvisionedController(Context context,
-            @MainHandler Handler mainHandler, BroadcastDispatcher broadcastDispatcher) {
-        return new DeviceProvisionedControllerImpl(context, mainHandler, broadcastDispatcher);
-    }
-
     /** */
     @Provides
     public LockPatternUtils provideLockPatternUtils(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index ccb6c2f..5fc789c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -40,6 +40,8 @@
 import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.ShadeControllerImpl;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import java.util.Optional;
@@ -114,4 +116,8 @@
             CommandQueue commandQueue) {
         return new Recents(context, recentsImplementation, commandQueue);
     }
+
+    @Binds
+    abstract DeviceProvisionedController bindDeviceProvisionedController(
+            DeviceProvisionedControllerImpl deviceProvisionedController);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index ef853e6..3ccad64 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -81,7 +81,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.util.EmergencyAffordanceManager;
 import com.android.internal.util.ScreenRecordHelper;
 import com.android.internal.util.ScreenshotHelper;
@@ -190,7 +189,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
+        filter.addAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
         mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter);
 
         ConnectivityManager cm = (ConnectivityManager)
@@ -314,7 +313,7 @@
                     mIsWaitingForEcmExit = true;
                     // Launch ECM exit dialog
                     Intent ecmDialogIntent =
-                            new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
+                            new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
                     ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                     mContext.startActivity(ecmDialogIntent);
                 } else {
@@ -1420,7 +1419,7 @@
                 if (!SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
                     mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISMISS, reason));
                 }
-            } else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
+            } else if (TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
                 // Airplane mode can be changed after ECM exits if airplane toggle button
                 // is pressed during ECM mode
                 if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) &&
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
index ca04633..24ad75d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -52,12 +52,6 @@
     private static final String TAG = "WorkLockActivity";
 
     /**
-     * Add additional extra {@link com.android.settings.password.ConfirmDeviceCredentialActivity} to
-     * enable device policy management enforcement from systemui.
-     */
-    public static final String EXTRA_FROM_WORK_LOCK_ACTIVITY = "from_work_lock_activity";
-
-    /**
      * Contains a {@link TaskDescription} for the activity being covered.
      */
     static final String EXTRA_TASK_DESCRIPTION =
@@ -156,7 +150,8 @@
         }
 
         final Intent credential = getKeyguardManager()
-                .createConfirmDeviceCredentialIntent(null, null, getTargetUserId());
+                .createConfirmDeviceCredentialIntent(null, null, getTargetUserId(),
+                true /* disallowBiometricsIfPolicyExists */);
         if (credential == null) {
             return;
         }
@@ -172,7 +167,6 @@
 
         if (target != null) {
             credential.putExtra(Intent.EXTRA_INTENT, target.getIntentSender());
-            credential.putExtra(EXTRA_FROM_WORK_LOCK_ACTIVITY, true);
         }
 
         final ActivityOptions launchOptions = ActivityOptions.makeBasic();
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index f784293..66c51d2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -98,8 +98,10 @@
         paint.setTextSize(42);
 
         CharSequence dialogText = null;
+        CharSequence dialogTitle = null;
         if (Utils.isHeadlessRemoteDisplayProvider(packageManager, mPackageName)) {
             dialogText = getString(R.string.media_projection_dialog_service_text);
+            dialogTitle = getString(R.string.media_projection_dialog_service_title);
         } else {
             String label = aInfo.loadLabel(packageManager).toString();
 
@@ -138,10 +140,9 @@
                         appNameIndex, appNameIndex + appName.length(), 0);
             }
             dialogText = message;
+            dialogTitle = getString(R.string.media_projection_dialog_title, appName);
         }
 
-        String dialogTitle = getString(R.string.media_projection_dialog_title);
-
         View dialogTitleView = View.inflate(this, R.layout.media_projection_dialog_title, null);
         TextView titleText = (TextView) dialogTitleView.findViewById(R.id.dialog_title);
         titleText.setText(dialogTitle);
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 2e90a3e..2347a47 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -194,7 +194,8 @@
         mMenuController.addListener(mMenuListener);
         mDismissViewController = new PipDismissViewController(context);
         mSnapAlgorithm = new PipSnapAlgorithm(mContext);
-        mFlingAnimationUtils = new FlingAnimationUtils(context, 2.5f);
+        mFlingAnimationUtils = new FlingAnimationUtils(context.getResources().getDisplayMetrics(),
+                2.5f);
         mGestures = new PipTouchGesture[] {
                 mDefaultMovementGesture
         };
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 4afcf01..5e297e2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -26,11 +26,11 @@
 import android.provider.Settings.Global;
 import android.service.quicksettings.Tile;
 import android.sysprop.TelephonyProperties;
+import android.telephony.TelephonyManager;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.telephony.TelephonyIntents;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.ActivityStarter;
@@ -76,7 +76,7 @@
         MetricsLogger.action(mContext, getMetricsCategory(), !airplaneModeEnabled);
         if (!airplaneModeEnabled && TelephonyProperties.in_ecm_mode().orElse(false)) {
             mActivityStarter.postStartActivityDismissingKeyguard(
-                    new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS), 0);
+                    new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS), 0);
             return;
         }
         setEnabled(!airplaneModeEnabled);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index f2b4ad8..325af24 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -295,7 +295,7 @@
                 R.integer.long_press_dock_anim_duration);
         mGrowRecents = getResources().getBoolean(R.bool.recents_grow_in_multiwindow);
         mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
-        mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.3f);
+        mFlingAnimationUtils = new FlingAnimationUtils(getResources().getDisplayMetrics(), 0.3f);
         updateDisplayInfo();
         boolean landscape = getResources().getConfiguration().orientation
                 == Configuration.ORIENTATION_LANDSCAPE;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
index d427260..525b5b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
@@ -17,7 +17,7 @@
 package com.android.systemui.statusbar;
 
 import android.animation.Animator;
-import android.content.Context;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.ViewPropertyAnimator;
 import android.view.animation.Interpolator;
@@ -25,7 +25,8 @@
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.statusbar.notification.NotificationUtils;
-import com.android.systemui.statusbar.phone.StatusBar;
+
+import javax.inject.Inject;
 
 /**
  * Utility class to calculate general fling animation when the finger is released.
@@ -56,8 +57,8 @@
     private float mCachedStartGradient = -1;
     private float mCachedVelocityFactor = -1;
 
-    public FlingAnimationUtils(Context ctx, float maxLengthSeconds) {
-        this(ctx, maxLengthSeconds, 0.0f);
+    public FlingAnimationUtils(DisplayMetrics displayMetrics, float maxLengthSeconds) {
+        this(displayMetrics, maxLengthSeconds, 0.0f);
     }
 
     /**
@@ -66,8 +67,9 @@
      *                      the end of the animation. 0 means it's at the beginning and no
      *                      acceleration will take place.
      */
-    public FlingAnimationUtils(Context ctx, float maxLengthSeconds, float speedUpFactor) {
-        this(ctx, maxLengthSeconds, speedUpFactor, -1.0f, 1.0f);
+    public FlingAnimationUtils(DisplayMetrics displayMetrics, float maxLengthSeconds,
+            float speedUpFactor) {
+        this(displayMetrics, maxLengthSeconds, speedUpFactor, -1.0f, 1.0f);
     }
 
     /**
@@ -79,8 +81,8 @@
      *           is provided, the value is automatically calculated.
      * @param y2 the y value to take for the second point of the bezier spline
      */
-    public FlingAnimationUtils(Context ctx, float maxLengthSeconds, float speedUpFactor, float x2,
-            float y2) {
+    public FlingAnimationUtils(DisplayMetrics displayMetrics, float maxLengthSeconds,
+            float speedUpFactor, float x2, float y2) {
         mMaxLengthSeconds = maxLengthSeconds;
         mSpeedUpFactor = speedUpFactor;
         if (x2 < 0) {
@@ -92,10 +94,8 @@
         }
         mY2 = y2;
 
-        mMinVelocityPxPerSecond
-                = MIN_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
-        mHighVelocityPxPerSecond
-                = HIGH_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
+        mMinVelocityPxPerSecond = MIN_VELOCITY_DP_PER_SECOND * displayMetrics.density;
+        mHighVelocityPxPerSecond = HIGH_VELOCITY_DP_PER_SECOND * displayMetrics.density;
     }
 
     /**
@@ -365,4 +365,41 @@
         long duration;
     }
 
+    public static class Builder {
+        private final DisplayMetrics mDisplayMetrics;
+        float mMaxLengthSeconds;
+        float mSpeedUpFactor = 0.0f;
+        float mX2 = -1.0f;
+        float mY2 = 1.0f;
+
+        @Inject
+        public Builder(DisplayMetrics displayMetrics) {
+            mDisplayMetrics = displayMetrics;
+        }
+
+        public Builder setMaxLengthSeconds(float maxLengthSeconds) {
+            mMaxLengthSeconds = maxLengthSeconds;
+            return this;
+        }
+
+        public Builder setSpeedUpFactor(float speedUpFactor) {
+            mSpeedUpFactor = speedUpFactor;
+            return this;
+        }
+
+        public Builder setX2(float x2) {
+            mX2 = x2;
+            return this;
+        }
+
+        public Builder setY2(float y2) {
+            mY2 = y2;
+            return this;
+        }
+
+        public FlingAnimationUtils build() {
+            return new FlingAnimationUtils(mDisplayMetrics, mMaxLengthSeconds, mSpeedUpFactor,
+                    mX2, mY2);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 6adaa0d..2c29635 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -138,7 +138,8 @@
         mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize(
                 R.dimen.keyguard_affordance_min_background_radius);
         mColorInterpolator = new ArgbEvaluator();
-        mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.3f);
+        mFlingAnimationUtils = new FlingAnimationUtils(mContext.getResources().getDisplayMetrics(),
+                0.3f);
 
         a.recycle();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
index 052473a..601b3e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
@@ -18,7 +18,6 @@
 
 import android.annotation.Nullable;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.notification.collection.provider.DerivedMember;
 import com.android.systemui.statusbar.notification.collection.provider.IsHighPriorityProvider;
@@ -68,8 +67,7 @@
         return mParent;
     }
 
-    @VisibleForTesting
-    public void setParent(@Nullable GroupEntry parent) {
+    void setParent(@Nullable GroupEntry parent) {
         if (!Objects.equals(mParent, parent)) {
             invalidateParent();
             mParent = parent;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
index a1cfb54..f0a003f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
@@ -20,9 +20,12 @@
 import static com.android.systemui.statusbar.notification.collection.ListDumper.dumpList;
 import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_BUILD_PENDING;
 import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_BUILD_STARTED;
-import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_FILTERING;
 import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_FINALIZING;
+import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_GROUPING;
 import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_IDLE;
+import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_PRE_GROUP_FILTERING;
+import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_PRE_RENDER_FILTERING;
+import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_RESETTING;
 import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_SORTING;
 import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_TRANSFORMING;
 
@@ -63,16 +66,17 @@
     private final SystemClock mSystemClock;
     private final NotifLog mNotifLog;
 
-    private final List<ListEntry> mNotifList = new ArrayList<>();
+    private List<ListEntry> mNotifList = new ArrayList<>();
+    private List<ListEntry> mNewNotifList = new ArrayList<>();
 
     private final PipelineState mPipelineState = new PipelineState();
     private final Map<String, GroupEntry> mGroups = new ArrayMap<>();
     private Collection<NotificationEntry> mAllEntries = Collections.emptyList();
-    private final List<ListEntry> mNewEntries = new ArrayList<>();
     private int mIterationCount = 0;
 
-    private final List<NotifFilter> mNotifFilters = new ArrayList<>();
+    private final List<NotifFilter> mNotifPreGroupFilters = new ArrayList<>();
     private final List<NotifPromoter> mNotifPromoters = new ArrayList<>();
+    private final List<NotifFilter> mNotifPreRenderFilters = new ArrayList<>();
     private final List<NotifComparator> mNotifComparators = new ArrayList<>();
     private SectionsProvider mSectionsProvider = new DefaultSectionsProvider();
 
@@ -138,12 +142,21 @@
     }
 
     @Override
-    public void addFilter(NotifFilter filter) {
+    public void addPreGroupFilter(NotifFilter filter) {
         Assert.isMainThread();
         mPipelineState.requireState(STATE_IDLE);
 
-        mNotifFilters.add(filter);
-        filter.setInvalidationListener(this::onFilterInvalidated);
+        mNotifPreGroupFilters.add(filter);
+        filter.setInvalidationListener(this::onPreGroupFilterInvalidated);
+    }
+
+    @Override
+    public void addPreRenderFilter(NotifFilter filter) {
+        Assert.isMainThread();
+        mPipelineState.requireState(STATE_IDLE);
+
+        mNotifPreRenderFilters.add(filter);
+        filter.setInvalidationListener(this::onPreRenderFilterInvalidated);
     }
 
     @Override
@@ -202,15 +215,15 @@
                 }
             };
 
-    private void onFilterInvalidated(NotifFilter filter) {
+    private void onPreGroupFilterInvalidated(NotifFilter filter) {
         Assert.isMainThread();
 
-        mNotifLog.log(NotifEvent.FILTER_INVALIDATED, String.format(
+        mNotifLog.log(NotifEvent.PRE_GROUP_FILTER_INVALIDATED, String.format(
                 "Filter \"%s\" invalidated; pipeline state is %d",
                 filter.getName(),
                 mPipelineState.getState()));
 
-        rebuildListIfBefore(STATE_FILTERING);
+        rebuildListIfBefore(STATE_PRE_GROUP_FILTERING);
     }
 
     private void onPromoterInvalidated(NotifPromoter filter) {
@@ -235,6 +248,17 @@
         rebuildListIfBefore(STATE_SORTING);
     }
 
+    private void onPreRenderFilterInvalidated(NotifFilter filter) {
+        Assert.isMainThread();
+
+        mNotifLog.log(NotifEvent.PRE_RENDER_FILTER_INVALIDATED, String.format(
+                "Filter \"%s\" invalidated; pipeline state is %d",
+                filter.getName(),
+                mPipelineState.getState()));
+
+        rebuildListIfBefore(STATE_PRE_RENDER_FILTERING);
+    }
+
     private void onNotifComparatorInvalidated(NotifComparator comparator) {
         Assert.isMainThread();
 
@@ -247,6 +271,17 @@
     }
 
     /**
+     * Points mNotifList to the list stored in mNewNotifList.
+     * Reuses the (emptied) mNotifList as mNewNotifList.
+     */
+    private void applyNewNotifList() {
+        mNotifList.clear();
+        List<ListEntry> emptyList = mNotifList;
+        mNotifList = mNewNotifList;
+        mNewNotifList = emptyList;
+    }
+
+    /**
      * The core algorithm of the pipeline. See the top comment in {@link NotifListBuilder} for
      * details on our contracts with other code.
      *
@@ -261,35 +296,47 @@
         mPipelineState.requireIsBefore(STATE_BUILD_STARTED);
         mPipelineState.setState(STATE_BUILD_STARTED);
 
-        // Step 1: Filtering and initial grouping
-        // Filter out any notifs that shouldn't be shown right now and cluster any that are part of
-        // a group
-        mPipelineState.incrementTo(STATE_FILTERING);
-        mNotifList.clear();
-        mNewEntries.clear();
-        filterAndGroup(mAllEntries, mNotifList, mNewEntries);
-        pruneIncompleteGroups(mNotifList, mNewEntries);
+        // Step 1: Reset notification states
+        mPipelineState.incrementTo(STATE_RESETTING);
+        resetNotifs();
 
-        // Step 2: Group transforming
+        // Step 2: Filter out any notifications that shouldn't be shown right now
+        mPipelineState.incrementTo(STATE_PRE_GROUP_FILTERING);
+        filterNotifs(mAllEntries, mNotifList, mNotifPreGroupFilters);
+
+        // Step 3: Group notifications with the same group key and set summaries
+        mPipelineState.incrementTo(STATE_GROUPING);
+        groupNotifs(mNotifList, mNewNotifList);
+        applyNewNotifList();
+        pruneIncompleteGroups(mNotifList);
+
+        // Step 4: Group transforming
         // Move some notifs out of their groups and up to top-level (mostly used for heads-upping)
-        dispatchOnBeforeTransformGroups(mReadOnlyNotifList, mNewEntries);
+        dispatchOnBeforeTransformGroups(mReadOnlyNotifList);
         mPipelineState.incrementTo(STATE_TRANSFORMING);
         promoteNotifs(mNotifList);
-        pruneIncompleteGroups(mNotifList, mNewEntries);
+        pruneIncompleteGroups(mNotifList);
 
-        // Step 3: Sort
+        // Step 5: Sort
         // Assign each top-level entry a section, then sort the list by section and then within
         // section by our list of custom comparators
         dispatchOnBeforeSort(mReadOnlyNotifList);
         mPipelineState.incrementTo(STATE_SORTING);
         sortList();
 
-        // Step 4: Lock in our group structure and log anything that's changed since the last run
+        // Step 6: Filter out entries after pre-group filtering, grouping, promoting and sorting
+        // Now filters can see grouping information to determine whether to filter or not
+        mPipelineState.incrementTo(STATE_PRE_RENDER_FILTERING);
+        filterNotifs(mNotifList, mNewNotifList, mNotifPreRenderFilters);
+        applyNewNotifList();
+        pruneIncompleteGroups(mNotifList);
+
+        // Step 7: Lock in our group structure and log anything that's changed since the last run
         mPipelineState.incrementTo(STATE_FINALIZING);
         logParentingChanges();
         freeEmptyGroups();
 
-        // Step 5: Dispatch the new list, first to any listeners and then to the view layer
+        // Step 6: Dispatch the new list, first to any listeners and then to the view layer
         mNotifLog.log(NotifEvent.DISPATCH_FINAL_LIST, "List finalized, is:\n"
                 + dumpList(mNotifList));
         dispatchOnBeforeRenderList(mReadOnlyNotifList);
@@ -297,20 +344,14 @@
             mOnRenderListListener.onRenderList(mReadOnlyNotifList);
         }
 
-        // Step 6: We're done!
+        // Step 7: We're done!
         mNotifLog.log(NotifEvent.LIST_BUILD_COMPLETE,
                 "Notif list build #" + mIterationCount + " completed");
         mPipelineState.setState(STATE_IDLE);
         mIterationCount++;
     }
 
-    private void filterAndGroup(
-            Collection<NotificationEntry> entries,
-            List<ListEntry> out,
-            List<ListEntry> newlyVisibleEntries) {
-
-        long now = mSystemClock.uptimeMillis();
-
+    private void resetNotifs() {
         for (GroupEntry group : mGroups.values()) {
             group.setPreviousParent(group.getParent());
             group.setParent(null);
@@ -318,22 +359,57 @@
             group.setSummary(null);
         }
 
-        for (NotificationEntry entry : entries) {
+        for (NotificationEntry entry : mAllEntries) {
             entry.setPreviousParent(entry.getParent());
             entry.setParent(null);
 
-            // See if we should filter out this notification
-            boolean shouldFilterOut = applyFilters(entry, now);
-            if (shouldFilterOut) {
-                continue;
-            }
-
             if (entry.mFirstAddedIteration == -1) {
                 entry.mFirstAddedIteration = mIterationCount;
-                newlyVisibleEntries.add(entry);
             }
+        }
 
-            // Otherwise, group it
+        mNotifList.clear();
+    }
+
+    private void filterNotifs(Collection<? extends ListEntry> entries,
+            List<ListEntry> out, List<NotifFilter> filters) {
+        final long now = mSystemClock.uptimeMillis();
+        for (ListEntry entry : entries)  {
+            if (entry instanceof GroupEntry) {
+                final GroupEntry groupEntry = (GroupEntry) entry;
+
+                // apply filter on its summary
+                final NotificationEntry summary = groupEntry.getRepresentativeEntry();
+                if (applyFilters(summary, now, filters)) {
+                    groupEntry.setSummary(null);
+                    annulAddition(summary);
+                }
+
+                // apply filter on its children
+                final List<NotificationEntry> children = groupEntry.getRawChildren();
+                for (int j = children.size() - 1; j >= 0; j--) {
+                    final NotificationEntry child = children.get(j);
+                    if (applyFilters(child, now, filters)) {
+                        children.remove(child);
+                        annulAddition(child);
+                    }
+                }
+
+                out.add(groupEntry);
+            } else {
+                if (applyFilters((NotificationEntry) entry, now, filters)) {
+                    annulAddition(entry);
+                } else {
+                    out.add(entry);
+                }
+            }
+        }
+    }
+
+    private void groupNotifs(List<ListEntry> entries, List<ListEntry> out) {
+        for (ListEntry listEntry : entries) {
+            // since grouping hasn't happened yet, all notifs are NotificationEntries
+            NotificationEntry entry = (NotificationEntry) listEntry;
             if (entry.getSbn().isGroup()) {
                 final String topLevelKey = entry.getSbn().getGroupKey();
 
@@ -341,7 +417,6 @@
                 if (group == null) {
                     group = new GroupEntry(topLevelKey);
                     group.mFirstAddedIteration = mIterationCount;
-                    newlyVisibleEntries.add(group);
                     mGroups.put(topLevelKey, group);
                 }
                 if (group.getParent() == null) {
@@ -367,9 +442,9 @@
                         if (entry.getSbn().getPostTime()
                                 > existingSummary.getSbn().getPostTime()) {
                             group.setSummary(entry);
-                            annulAddition(existingSummary, out, newlyVisibleEntries);
+                            annulAddition(existingSummary, out);
                         } else {
-                            annulAddition(entry, out, newlyVisibleEntries);
+                            annulAddition(entry, out);
                         }
                     }
                 } else {
@@ -411,10 +486,7 @@
         }
     }
 
-    private void pruneIncompleteGroups(
-            List<ListEntry> shadeList,
-            List<ListEntry> newlyVisibleEntries) {
-
+    private void pruneIncompleteGroups(List<ListEntry> shadeList) {
         for (int i = 0; i < shadeList.size(); i++) {
             final ListEntry tle = shadeList.get(i);
 
@@ -431,7 +503,7 @@
                     shadeList.add(summary);
 
                     group.setSummary(null);
-                    annulAddition(group, shadeList, newlyVisibleEntries);
+                    annulAddition(group, shadeList);
 
                 } else if (group.getSummary() == null
                         || children.size() < MIN_CHILDREN_FOR_GROUP) {
@@ -444,7 +516,7 @@
                     if (group.getSummary() != null) {
                         final NotificationEntry summary = group.getSummary();
                         group.setSummary(null);
-                        annulAddition(summary, shadeList, newlyVisibleEntries);
+                        annulAddition(summary, shadeList);
                     }
 
                     for (int j = 0; j < children.size(); j++) {
@@ -454,7 +526,7 @@
                     }
                     children.clear();
 
-                    annulAddition(group, shadeList, newlyVisibleEntries);
+                    annulAddition(group, shadeList);
                 }
             }
         }
@@ -468,10 +540,7 @@
      * Before calling this method, the entry must already have been removed from its parent. If
      * it's a group, its summary must be null and its children must be empty.
      */
-    private void annulAddition(
-            ListEntry entry,
-            List<ListEntry> shadeList,
-            List<ListEntry> newlyVisibleEntries) {
+    private void annulAddition(ListEntry entry, List<ListEntry> shadeList) {
 
         // This function does very little, but if any of its assumptions are violated (and it has a
         // lot of them), it will put the system into an inconsistent state. So we check all of them
@@ -508,13 +577,18 @@
             }
         }
 
+        annulAddition(entry);
+
+    }
+
+    /**
+     * Erases bookkeeping traces stored on an entry when it is removed from the notif list.
+     * This can happen if the entry is removed from a group that was broken up or if the entry was
+     * filtered out during any of the filtering steps.
+     */
+    private void annulAddition(ListEntry entry) {
         entry.setParent(null);
         if (entry.mFirstAddedIteration == mIterationCount) {
-            if (!newlyVisibleEntries.remove(entry)) {
-                throw new IllegalStateException("Cannot late-filter entry " + entry.getKey() + " "
-                        + entry + " from " + newlyVisibleEntries + " "
-                        + entry.mFirstAddedIteration);
-            }
             entry.mFirstAddedIteration = -1;
         }
     }
@@ -606,8 +680,8 @@
         return cmp;
     };
 
-    private boolean applyFilters(NotificationEntry entry, long now) {
-        NotifFilter filter = findRejectingFilter(entry, now);
+    private boolean applyFilters(NotificationEntry entry, long now, List<NotifFilter> filters) {
+        NotifFilter filter = findRejectingFilter(entry, now, filters);
 
         if (filter != entry.mExcludingFilter) {
             if (entry.mExcludingFilter == null) {
@@ -637,9 +711,12 @@
         return filter != null;
     }
 
-    @Nullable private NotifFilter findRejectingFilter(NotificationEntry entry, long now) {
-        for (int i = 0; i < mNotifFilters.size(); i++) {
-            NotifFilter filter = mNotifFilters.get(i);
+    @Nullable private static NotifFilter findRejectingFilter(NotificationEntry entry, long now,
+            List<NotifFilter> filters) {
+        final int size = filters.size();
+
+        for (int i = 0; i < size; i++) {
+            NotifFilter filter = filters.get(i);
             if (filter.shouldFilterOut(entry, now)) {
                 return filter;
             }
@@ -691,12 +768,9 @@
         }
     }
 
-    private void dispatchOnBeforeTransformGroups(
-            List<ListEntry> entries,
-            List<ListEntry> newlyVisibleEntries) {
+    private void dispatchOnBeforeTransformGroups(List<ListEntry> entries) {
         for (int i = 0; i < mOnBeforeTransformGroupsListeners.size(); i++) {
-            mOnBeforeTransformGroupsListeners.get(i)
-                    .onBeforeTransformGroups(entries, newlyVisibleEntries);
+            mOnBeforeTransformGroupsListeners.get(i).onBeforeTransformGroups(entries);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
index b68cb0d..5e7dd98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
@@ -55,7 +55,7 @@
     public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
         mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
 
-        notifListBuilder.addFilter(mNotifFilter);
+        notifListBuilder.addPreGroupFilter(mNotifFilter);
     }
 
     private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
index 378599b..ee841c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
@@ -83,7 +83,7 @@
         mAppOpsController.addCallback(ForegroundServiceController.APP_OPS, this::onAppOpsChanged);
 
         // filter out foreground service notifications that aren't necessary anymore
-        notifListBuilder.addFilter(mNotifFilter);
+        notifListBuilder.addPreGroupFilter(mNotifFilter);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index 232246e..9312c22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -85,7 +85,7 @@
     @Override
     public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
         setupInvalidateNotifListCallbacks();
-        notifListBuilder.addFilter(mNotifFilter);
+        notifListBuilder.addPreRenderFilter(mNotifFilter);
     }
 
     private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
@@ -131,9 +131,8 @@
                     }
                 }
 
-                // ... neither this notification nor its summary have high enough priority
+                // ... neither this notification nor its group have high enough priority
                 // to be shown on the lockscreen
-                // TODO: grouping hasn't happened yet (b/145134683)
                 if (entry.getParent() != null) {
                     final GroupEntry parent = entry.getParent();
                     if (priorityExceedsLockscreenShowingThreshold(parent)) {
@@ -152,11 +151,10 @@
         }
         if (NotificationUtils.useNewInterruptionModel(mContext)
                 && hideSilentNotificationsOnLockscreen()) {
-            // TODO: make sure in the NewNotifPipeline that entry.isHighPriority() has been
-            //  correctly updated before reaching this point (b/145134683)
             return entry.isHighPriority();
         } else {
-            return !entry.getRepresentativeEntry().getRanking().isAmbient();
+            return entry.getRepresentativeEntry() != null
+                    && !entry.getRepresentativeEntry().getRanking().isAmbient();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
index 24e7a79..0751aa8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
@@ -46,7 +46,7 @@
     public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
         mStatusBarStateController.addCallback(mStatusBarStateCallback);
 
-        notifListBuilder.addFilter(mNotifFilter);
+        notifListBuilder.addPreGroupFilter(mNotifFilter);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifListBuilder.java
index 15d3b92..7580924 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifListBuilder.java
@@ -59,11 +59,12 @@
 public interface NotifListBuilder {
 
     /**
-     * Registers a filter with the pipeline. Filters are called on each notification in the order
-     * that they were registered. If any filter returns true, the notification is removed from the
-     * pipeline (and no other filters are called on that notif).
+     * Registers a filter with the pipeline before grouping, promoting and sorting occurs. Filters
+     * are called on each notification in the order that they were registered. If any filter
+     * returns true, the notification is removed from the pipeline (and no other filters are
+     * called on that notif).
      */
-    void addFilter(NotifFilter filter);
+    void addPreGroupFilter(NotifFilter filter);
 
     /**
      * Registers a promoter with the pipeline. Promoters are able to promote child notifications to
@@ -91,6 +92,15 @@
     void setComparators(List<NotifComparator> comparators);
 
     /**
+     * Registers a filter with the pipeline to filter right before rendering the list (after
+     * pre-group filtering, grouping, promoting and sorting occurs). Filters are
+     * called on each notification in the order that they were registered. If any filter returns
+     * true, the notification is removed from the pipeline (and no other filters are called on that
+     * notif).
+     */
+    void addPreRenderFilter(NotifFilter filter);
+
+    /**
      * Called after notifications have been filtered and after the initial grouping has been
      * performed but before NotifPromoters have had a chance to promote children out of groups.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java
index 170ff48..d7a0815 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java
@@ -33,8 +33,6 @@
      * @param list The current filtered and grouped list of (top-level) entries. Note that this is
      *             a live view into the current notif list and will change as the list moves through
      *             the pipeline.
-     * @param newlyVisibleEntries The list of all entries (both top-level and children) who have
-     *                            been added to the list for the first time.
      */
-    void onBeforeTransformGroups(List<ListEntry> list, List<ListEntry> newlyVisibleEntries);
+    void onBeforeTransformGroups(List<ListEntry> list);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
index ad4bbd9..85f828d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
@@ -78,18 +78,24 @@
     public static final int STATE_IDLE = 0;
     public static final int STATE_BUILD_PENDING = 1;
     public static final int STATE_BUILD_STARTED = 2;
-    public static final int STATE_FILTERING = 3;
-    public static final int STATE_TRANSFORMING = 4;
-    public static final int STATE_SORTING = 5;
-    public static final int STATE_FINALIZING = 6;
+    public static final int STATE_RESETTING = 3;
+    public static final int STATE_PRE_GROUP_FILTERING = 4;
+    public static final int STATE_GROUPING = 5;
+    public static final int STATE_TRANSFORMING = 6;
+    public static final int STATE_SORTING = 7;
+    public static final int STATE_PRE_RENDER_FILTERING = 8;
+    public static final int STATE_FINALIZING = 9;
 
     @IntDef(prefix = { "STATE_" }, value = {
             STATE_IDLE,
             STATE_BUILD_PENDING,
             STATE_BUILD_STARTED,
-            STATE_FILTERING,
+            STATE_RESETTING,
+            STATE_PRE_GROUP_FILTERING,
+            STATE_GROUPING,
             STATE_TRANSFORMING,
             STATE_SORTING,
+            STATE_PRE_RENDER_FILTERING,
             STATE_FINALIZING,
     })
     @Retention(RetentionPolicy.SOURCE)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java
index 685eac8..e6189ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java
@@ -20,8 +20,8 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
 
 /**
- * Pluggable for participating in notif filtering. See
- * {@link NotifListBuilder#addFilter(NotifFilter)}.
+ * Pluggable for participating in notif filtering.
+ * See {@link NotifListBuilder#addPreGroupFilter} and {@link NotifListBuilder#addPreRenderFilter}.
  */
 public abstract class NotifFilter extends Pluggable<NotifFilter> {
     protected NotifFilter(String name) {
@@ -34,7 +34,11 @@
      * This doesn't necessarily mean that your filter will get called on every notification,
      * however. If another filter returns true before yours, we'll skip straight to the next notif.
      *
-     * @param entry The entry in question
+     * @param entry The entry in question.
+     *              If this filter is registered via {@link NotifListBuilder#addPreGroupFilter},
+     *              this entry will not have any grouping nor sorting information.
+     *              If this filter is registered via {@link NotifListBuilder#addPreRenderFilter},
+     *              this entry will have grouping and sorting information.
      * @param now A timestamp in SystemClock.uptimeMillis that represents "now" for the purposes of
      *            pipeline execution. This value will be the same for all pluggable calls made
      *            during this pipeline run, giving pluggables a stable concept of "now" to compare
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
index 3b06220..c18af80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
@@ -88,13 +88,14 @@
             START_BUILD_LIST,
             DISPATCH_FINAL_LIST,
             LIST_BUILD_COMPLETE,
-            FILTER_INVALIDATED,
+            PRE_GROUP_FILTER_INVALIDATED,
             PROMOTER_INVALIDATED,
             SECTIONS_PROVIDER_INVALIDATED,
             COMPARATOR_INVALIDATED,
             PARENT_CHANGED,
             FILTER_CHANGED,
             PROMOTER_CHANGED,
+            PRE_RENDER_FILTER_INVALIDATED,
 
             // NotificationEntryManager events:
             NOTIF_ADDED,
@@ -127,6 +128,7 @@
                     "ParentChanged",
                     "FilterChanged",
                     "PromoterChanged",
+                    "FinalFilterInvalidated",
 
                     // NEM event labels:
                     "NotifAdded",
@@ -152,14 +154,15 @@
     public static final int START_BUILD_LIST = 2;
     public static final int DISPATCH_FINAL_LIST = 3;
     public static final int LIST_BUILD_COMPLETE = 4;
-    public static final int FILTER_INVALIDATED = 5;
+    public static final int PRE_GROUP_FILTER_INVALIDATED = 5;
     public static final int PROMOTER_INVALIDATED = 6;
     public static final int SECTIONS_PROVIDER_INVALIDATED = 7;
     public static final int COMPARATOR_INVALIDATED = 8;
     public static final int PARENT_CHANGED = 9;
     public static final int FILTER_CHANGED = 10;
     public static final int PROMOTER_CHANGED = 11;
-    private static final int TOTAL_LIST_BUILDER_EVENT_TYPES = 12;
+    public static final int PRE_RENDER_FILTER_INVALIDATED = 12;
+    private static final int TOTAL_LIST_BUILDER_EVENT_TYPES = 13;
 
     /**
      * Events related to {@link NotificationEntryManager}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 66b1dd8..858023d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -101,7 +101,8 @@
                 R.dimen.keyguard_affordance_touch_target_size);
         mHintGrowAmount =
                 mContext.getResources().getDimensionPixelSize(R.dimen.hint_grow_amount_sideways);
-        mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.4f);
+        mFlingAnimationUtils = new FlingAnimationUtils(mContext.getResources().getDisplayMetrics(),
+                0.4f);
     }
 
     private void initIcons() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
index 1281953..8c3420a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
@@ -35,8 +35,6 @@
 @Singleton
 public class LockscreenGestureLogger {
     private ArrayMap<Integer, Integer> mLegacyMap;
-    private LogMaker mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN)
-            .setType(MetricsEvent.TYPE_ACTION);
     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
     @Inject
@@ -48,7 +46,7 @@
     }
 
     public void write(int gesture, int length, int velocity) {
-        mMetricsLogger.write(mLogMaker.setCategory(gesture)
+        mMetricsLogger.write(new LogMaker(gesture)
                 .setType(MetricsEvent.TYPE_ACTION)
                 .addTaggedData(MetricsEvent.FIELD_GESTURE_LENGTH, length)
                 .addTaggedData(MetricsEvent.FIELD_GESTURE_VELOCITY, velocity));
@@ -64,7 +62,7 @@
      */
     public void writeAtFractionalPosition(
             int category, int xPercent, int yPercent, int rotation) {
-        mMetricsLogger.write(mLogMaker.setCategory(category)
+        mMetricsLogger.write(new LogMaker(category)
                 .setType(MetricsEvent.TYPE_ACTION)
                 .addTaggedData(MetricsEvent.FIELD_GESTURE_X_PERCENT, xPercent)
                 .addTaggedData(MetricsEvent.FIELD_GESTURE_Y_PERCENT, yPercent)
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 ed2fb0f..199d52f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -609,7 +609,7 @@
     @Override
     protected void loadDimens() {
         super.loadDimens();
-        mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.4f);
+        mFlingAnimationUtils = new FlingAnimationUtils(getResources().getDisplayMetrics(), 0.4f);
         mStatusBarMinHeight = getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.status_bar_height);
         mQsPeekHeight = getResources().getDimensionPixelSize(R.dimen.qs_peek_height);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index e8e5e1f..78a5eb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -26,6 +26,7 @@
 import android.os.SystemClock;
 import android.os.VibrationEffect;
 import android.util.AttributeSet;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.InputDevice;
 import android.view.MotionEvent;
@@ -208,11 +209,12 @@
         super(context, attrs);
         mKeyguardStateController = keyguardStateController;
         mStatusBarStateController = statusBarStateController;
-        mFlingAnimationUtils = new FlingAnimationUtils(context, 0.6f /* maxLengthSeconds */,
-                0.6f /* speedUpFactor */);
-        mFlingAnimationUtilsClosing = new FlingAnimationUtils(context, 0.5f /* maxLengthSeconds */,
-                0.6f /* speedUpFactor */);
-        mFlingAnimationUtilsDismissing = new FlingAnimationUtils(context,
+        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
+        mFlingAnimationUtils = new FlingAnimationUtils(displayMetrics,
+                0.6f /* maxLengthSeconds */, 0.6f /* speedUpFactor */);
+        mFlingAnimationUtilsClosing = new FlingAnimationUtils(displayMetrics,
+                0.5f /* maxLengthSeconds */, 0.6f /* speedUpFactor */);
+        mFlingAnimationUtilsDismissing = new FlingAnimationUtils(displayMetrics,
                 0.5f /* maxLengthSeconds */, 0.2f /* speedUpFactor */, 0.6f /* x2 */,
                 0.84f /* y2 */);
         mBounceInterpolator = new BounceInterpolator();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 8d43c66..3ee5d31 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -385,8 +385,11 @@
                 mContext.getString(R.string.accessibility_quick_settings_bluetooth_on);
         boolean bluetoothVisible = false;
         if (mBluetooth != null) {
-            if (mBluetooth.isBluetoothConnected()) {
-                contentDescription = mContext.getString(R.string.accessibility_bluetooth_connected);
+            if (mBluetooth.isBluetoothConnected()
+                    && (mBluetooth.isBluetoothAudioActive()
+                    || !mBluetooth.isBluetoothAudioProfileOnly())) {
+                contentDescription = mContext.getString(
+                        R.string.accessibility_bluetooth_connected);
                 bluetoothVisible = mBluetooth.isBluetoothEnabled();
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index f4c7e23..312f9c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -124,7 +124,6 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.ActivityIntentHelper;
-import com.android.systemui.ActivityStarterDelegate;
 import com.android.systemui.AutoReinflateContainer;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.DemoMode;
@@ -898,8 +897,6 @@
                 mStatusBarWindowViewController,
                 mNotificationPanel, mAmbientIndicationContainer);
 
-        Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
-
         mConfigurationController.addCallback(this);
 
         // set the initial view visibility
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 42e02d5..0c5b851 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -31,6 +31,8 @@
 
     boolean isBluetoothConnected();
     boolean isBluetoothConnecting();
+    boolean isBluetoothAudioProfileOnly();
+    boolean isBluetoothAudioActive();
     String getConnectedDeviceName();
     void setBluetoothEnabled(boolean enabled);
     Collection<CachedBluetoothDevice> getDevices();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 76683b6..6ededd2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -32,6 +32,7 @@
 import com.android.settingslib.bluetooth.BluetoothCallback;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
 import com.android.systemui.dagger.qualifiers.BgLooper;
 import com.android.systemui.dagger.qualifiers.MainLooper;
@@ -65,6 +66,8 @@
 
     private boolean mEnabled;
     private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
+    private boolean mAudioProfileOnly;
+    private boolean mIsActive;
 
     private final H mHandler;
     private int mState;
@@ -103,6 +106,8 @@
         }
         pw.print("  mEnabled="); pw.println(mEnabled);
         pw.print("  mConnectionState="); pw.println(stateToString(mConnectionState));
+        pw.print("  mAudioProfileOnly="); pw.println(mAudioProfileOnly);
+        pw.print("  mIsActive="); pw.println(mIsActive);
         pw.print("  mConnectedDevices="); pw.println(mConnectedDevices);
         pw.print("  mCallbacks.size="); pw.println(mHandler.mCallbacks.size());
         pw.println("  Bluetooth Devices:");
@@ -176,6 +181,16 @@
     }
 
     @Override
+    public boolean isBluetoothAudioProfileOnly() {
+        return mAudioProfileOnly;
+    }
+
+    @Override
+    public boolean isBluetoothAudioActive() {
+        return mIsActive;
+    }
+
+    @Override
     public void setBluetoothEnabled(boolean enabled) {
         if (mLocalBluetoothManager != null) {
             mLocalBluetoothManager.getBluetoothAdapter().setBluetoothEnabled(enabled);
@@ -239,6 +254,48 @@
             mConnectionState = state;
             mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
         }
+        updateAudioProfile();
+    }
+
+    private void updateActive() {
+        boolean isActive = false;
+
+        for (CachedBluetoothDevice device : getDevices()) {
+            isActive |= device.isActiveDevice(BluetoothProfile.HEADSET)
+                    || device.isActiveDevice(BluetoothProfile.A2DP)
+                    || device.isActiveDevice(BluetoothProfile.HEARING_AID);
+        }
+
+        if (mIsActive != isActive) {
+            mIsActive = isActive;
+            mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
+        }
+    }
+
+    private void updateAudioProfile() {
+        boolean audioProfileConnected = false;
+        boolean otherProfileConnected = false;
+
+        for (CachedBluetoothDevice device : getDevices()) {
+            for (LocalBluetoothProfile profile : device.getProfiles()) {
+                int profileId = profile.getProfileId();
+                boolean isConnected = device.isConnectedProfile(profile);
+                if (profileId == BluetoothProfile.HEADSET
+                        || profileId == BluetoothProfile.A2DP
+                        || profileId == BluetoothProfile.HEARING_AID) {
+                    audioProfileConnected |= isConnected;
+                } else {
+                    otherProfileConnected |= isConnected;
+                }
+            }
+        }
+
+        boolean audioProfileOnly = (audioProfileConnected && !otherProfileConnected);
+        if (audioProfileOnly != mAudioProfileOnly) {
+            mAudioProfileOnly = audioProfileOnly;
+            mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
+        }
+
     }
 
     @Override
@@ -306,6 +363,16 @@
     }
 
     @Override
+    public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
+        if (DEBUG) {
+            Log.d(TAG, "ActiveDeviceChanged=" + activeDevice.getAddress()
+                    + " profileId=" + bluetoothProfile);
+        }
+        updateActive();
+        mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
+    }
+
+    @Override
     public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
         if (DEBUG) {
             Log.d(TAG, "ACLConnectionStateChanged=" + cachedDevice.getAddress() + " "
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
index b6ffd58..f6b770c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
@@ -40,7 +40,7 @@
         DeviceProvisionedController {
 
     protected static final String TAG = DeviceProvisionedControllerImpl.class.getSimpleName();
-    private final ArrayList<DeviceProvisionedListener> mListeners = new ArrayList<>();
+    protected final ArrayList<DeviceProvisionedListener> mListeners = new ArrayList<>();
     private final ContentResolver mContentResolver;
     private final Context mContext;
     private final Uri mDeviceProvisionedUri;
@@ -104,7 +104,7 @@
         }
     }
 
-    private void startListening(int user) {
+    protected void startListening(int user) {
         mContentResolver.registerContentObserver(mDeviceProvisionedUri, true,
                 mSettingsObserver, 0);
         mContentResolver.registerContentObserver(mUserSetupUri, true,
@@ -112,7 +112,7 @@
         startTracking();
     }
 
-    private void stopListening() {
+    protected void stopListening() {
         stopTracking();
         mContentResolver.unregisterContentObserver(mSettingsObserver);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index 4cb5472..9c9a627 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -46,11 +46,11 @@
 
 import com.android.internal.messages.nano.SystemMessageProto;
 import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 
 import junit.framework.Assert;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java
index 212c93d..46a473b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java
@@ -27,8 +27,8 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 2bf855a..e0b4b81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -45,9 +45,7 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
-import android.content.Intent;
 import android.content.res.Resources;
-import android.graphics.drawable.Icon;
 import android.hardware.face.FaceManager;
 import android.service.notification.ZenModeConfig;
 import android.testing.AndroidTestingRunner;
@@ -57,7 +55,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.colorextraction.ColorExtractor;
-import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -731,6 +728,7 @@
                     data, Runnable::run, configurationController, interruptionStateProvider,
                     zenModeController, lockscreenUserManager, groupManager, entryManager,
                     remoteInputUriController);
+            setInflateSynchronously(true);
         }
     }
 
@@ -746,17 +744,6 @@
     }
 
     /**
-     * @return basic {@link android.app.Notification.BubbleMetadata.Builder}
-     */
-    private Notification.BubbleMetadata.Builder getBuilder() {
-        Intent target = new Intent(mContext, BubblesTestActivity.class);
-        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target, 0);
-        return new Notification.BubbleMetadata.Builder()
-                .setIntent(bubbleIntent)
-                .setIcon(Icon.createWithResource(mContext, R.drawable.android));
-    }
-
-    /**
      * Sets the bubble metadata flags for this entry. These flags are normally set by
      * NotificationManagerService when the notification is sent, however, these tests do not
      * go through that path so we set them explicitly when testing.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
index 1554abc..c4ae409 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -39,9 +39,9 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.bubbles.BubbleData.TimeSource;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
 import com.google.common.collect.ImmutableList;
@@ -85,6 +85,8 @@
     private Bubble mBubbleB2;
     private Bubble mBubbleB3;
     private Bubble mBubbleC1;
+    private Bubble mBubbleInterruptive;
+    private Bubble mBubbleDismissed;
 
     private BubbleData mBubbleData;
 
@@ -119,18 +121,20 @@
         modifyRanking(mEntryInterruptive)
                 .setVisuallyInterruptive(true)
                 .build();
+        mBubbleInterruptive = new Bubble(mEntryInterruptive);
 
         ExpandableNotificationRow row = mNotificationTestHelper.createBubble();
         mEntryDismissed = createBubbleEntry(1, "dismissed", "package.d");
         mEntryDismissed.setRow(row);
+        mBubbleDismissed = new Bubble(mEntryDismissed);
 
-        mBubbleA1 = new Bubble(mContext, mEntryA1);
-        mBubbleA2 = new Bubble(mContext, mEntryA2);
-        mBubbleA3 = new Bubble(mContext, mEntryA3);
-        mBubbleB1 = new Bubble(mContext, mEntryB1);
-        mBubbleB2 = new Bubble(mContext, mEntryB2);
-        mBubbleB3 = new Bubble(mContext, mEntryB3);
-        mBubbleC1 = new Bubble(mContext, mEntryC1);
+        mBubbleA1 = new Bubble(mEntryA1);
+        mBubbleA2 = new Bubble(mEntryA2);
+        mBubbleA3 = new Bubble(mEntryA3);
+        mBubbleB1 = new Bubble(mEntryB1);
+        mBubbleB2 = new Bubble(mEntryB2);
+        mBubbleB3 = new Bubble(mEntryB3);
+        mBubbleC1 = new Bubble(mEntryC1);
 
         mBubbleData = new BubbleData(getContext());
 
@@ -180,7 +184,7 @@
         mBubbleData.setListener(mListener);
 
         // Test
-        mBubbleData.notificationEntryUpdated(mEntryC1, /* suppressFlyout */ true, /* showInShade */
+        mBubbleData.notificationEntryUpdated(mBubbleC1, /* suppressFlyout */ true, /* showInShade */
                 true);
 
         // Verify
@@ -195,7 +199,7 @@
         mBubbleData.setListener(mListener);
 
         // Test
-        mBubbleData.notificationEntryUpdated(mEntryInterruptive,
+        mBubbleData.notificationEntryUpdated(mBubbleInterruptive,
                 false /* suppressFlyout */, true  /* showInShade */);
 
         // Verify
@@ -210,11 +214,11 @@
         mBubbleData.setListener(mListener);
 
         // Test
-        mBubbleData.notificationEntryUpdated(mEntryC1, false /* suppressFlyout */,
+        mBubbleData.notificationEntryUpdated(mBubbleC1, false /* suppressFlyout */,
                 true /* showInShade */);
         verifyUpdateReceived();
 
-        mBubbleData.notificationEntryUpdated(mEntryC1, false /* suppressFlyout */,
+        mBubbleData.notificationEntryUpdated(mBubbleC1, false /* suppressFlyout */,
                 true /* showInShade */);
         verifyUpdateReceived();
 
@@ -229,16 +233,16 @@
         mBubbleData.setListener(mListener);
 
         // Test
-        mBubbleData.notificationEntryUpdated(mEntryDismissed, false /* suppressFlyout */,
-                false /* showInShade */);
+        mBubbleData.notificationEntryUpdated(mBubbleDismissed, false /* suppressFlyout */,
+                true /* showInShade */);
         verifyUpdateReceived();
 
         // Make it look like user swiped away row
         mEntryDismissed.getRow().dismiss(false /* refocusOnDismiss */);
-        assertThat(mBubbleData.getBubbleWithKey(mEntryDismissed.getKey()).showInShade()).isFalse();
+        assertThat(mBubbleData.getBubbleWithKey(mBubbleDismissed.getKey()).showInShade()).isFalse();
 
-        mBubbleData.notificationEntryUpdated(mEntryDismissed, false /* suppressFlyout */,
-                false /* showInShade */);
+        mBubbleData.notificationEntryUpdated(mBubbleDismissed, false /* suppressFlyout */,
+                true /* showInShade */);
         verifyUpdateReceived();
 
         // Verify
@@ -974,7 +978,10 @@
 
     private void sendUpdatedEntryAtTime(NotificationEntry entry, long postTime) {
         setPostTime(entry, postTime);
-        mBubbleData.notificationEntryUpdated(entry, false /* suppressFlyout*/,
+        // BubbleController calls this:
+        Bubble b = mBubbleData.getOrCreateBubble(entry);
+        // And then this
+        mBubbleData.notificationEntryUpdated(b, false /* suppressFlyout*/,
                 true /* showInShade */);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
index 5757861..3c42fd1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
@@ -28,8 +28,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -58,7 +58,7 @@
         mEntry = new NotificationEntryBuilder()
                 .setNotification(mNotif)
                 .build();
-        mBubble = new Bubble(mContext, mEntry);
+        mBubble = new Bubble(mEntry);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 8004562..b7e9f07 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -31,6 +31,7 @@
 import android.widget.FrameLayout;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.keyguard.CarrierText;
@@ -64,7 +65,7 @@
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
-@Ignore
+@Suppress
 public class QSFragmentTest extends SysuiBaseFragmentTest {
 
     private MetricsLogger mMockMetricsLogger;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 49b47c5..6bd24b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -47,6 +47,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -83,6 +84,7 @@
         String spec = "spec";
         mTestableLooper = TestableLooper.get(this);
         mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+        mDependency.injectMockDependency(ActivityStarter.class);
         mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
         mStatusBarStateController =
             mDependency.injectMockDependency(StatusBarStateController.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index c6dd232..a5395e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -40,6 +40,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
 import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
index 9b860c9..677a6fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
@@ -52,6 +52,7 @@
 import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
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 cef210c..3a6acce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -56,6 +56,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 8aac189..64b10c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -29,6 +29,7 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager.SmartReplyHistoryExtender;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 88546b9..c7810be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -44,6 +44,7 @@
 import com.android.systemui.bubbles.BubblesTestActivity;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
 import com.android.systemui.statusbar.notification.row.NotificationContentInflaterTest;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 07d2e31..1b05216 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -47,6 +47,7 @@
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 3f62412..22dc080 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -41,6 +41,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index e0dfe7e..7f5105e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -66,7 +66,6 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -80,6 +79,7 @@
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index 7fabb0f..5aed61b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -41,11 +41,11 @@
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ShadeController;
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 133d52b..7343e5e 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
@@ -30,9 +30,9 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
index 6a4ddc7..9079223 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
@@ -31,9 +31,9 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
 import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryTest.java
index 721bbdc..a06d6c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryTest.java
@@ -27,7 +27,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.RankingBuilder;
 
 import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 8d9537d..0dcd253 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -48,7 +48,6 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationListener.NotifServiceListener;
 import com.android.systemui.statusbar.RankingBuilder;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
index bbabb11..9f90396 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
@@ -28,6 +28,7 @@
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
@@ -38,7 +39,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl.OnRenderListListener;
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
@@ -336,7 +336,7 @@
         // GIVEN a notification that is initially added to the list
         PackageFilter filter = new PackageFilter(PACKAGE_2);
         filter.setEnabled(false);
-        mListBuilder.addFilter(filter);
+        mListBuilder.addPreGroupFilter(filter);
 
         addNotif(0, PACKAGE_1);
         addNotif(1, PACKAGE_2);
@@ -373,24 +373,54 @@
                 notif(2)
         );
 
-        // THEN the list of newly visible entries doesn't contain the summary or the group
-        assertEquals(
-                Arrays.asList(
-                        mEntrySet.get(0),
-                        mEntrySet.get(2)),
-                listener.newlyVisibleEntries
-        );
-
         // THEN the summary has a null parent and an unset firstAddedIteration
         assertNull(mEntrySet.get(1).getParent());
         assertEquals(-1, mEntrySet.get(1).mFirstAddedIteration);
     }
 
     @Test
-    public void testNotifsAreFiltered() {
+    public void testPreGroupNotifsAreFiltered() {
+        // GIVEN a PreGroupNotifFilter and PreRenderFilter that filters out the same package
+        NotifFilter preGroupFilter = spy(new PackageFilter(PACKAGE_2));
+        NotifFilter preRenderFilter = spy(new PackageFilter(PACKAGE_2));
+        mListBuilder.addPreGroupFilter(preGroupFilter);
+        mListBuilder.addPreRenderFilter(preRenderFilter);
+
+        // WHEN the pipeline is kicked off on a list of notifs
+        addNotif(0, PACKAGE_1);
+        addNotif(1, PACKAGE_2);
+        addNotif(2, PACKAGE_3);
+        addNotif(3, PACKAGE_2);
+        dispatchBuild();
+
+        // THEN the preGroupFilter is called on each notif in the original set
+        verify(preGroupFilter).shouldFilterOut(eq(mEntrySet.get(0)), anyLong());
+        verify(preGroupFilter).shouldFilterOut(eq(mEntrySet.get(1)), anyLong());
+        verify(preGroupFilter).shouldFilterOut(eq(mEntrySet.get(2)), anyLong());
+        verify(preGroupFilter).shouldFilterOut(eq(mEntrySet.get(3)), anyLong());
+
+        // THEN the preRenderFilter is only called on the notifications not already filtered out
+        verify(preRenderFilter).shouldFilterOut(eq(mEntrySet.get(0)), anyLong());
+        verify(preRenderFilter, never()).shouldFilterOut(eq(mEntrySet.get(1)), anyLong());
+        verify(preRenderFilter).shouldFilterOut(eq(mEntrySet.get(2)), anyLong());
+        verify(preRenderFilter, never()).shouldFilterOut(eq(mEntrySet.get(3)), anyLong());
+
+        // THEN the final list doesn't contain any filtered-out notifs
+        verifyBuiltList(
+                notif(0),
+                notif(2)
+        );
+
+        // THEN each filtered notif records the NotifFilter that did it
+        assertEquals(preGroupFilter, mEntrySet.get(1).mExcludingFilter);
+        assertEquals(preGroupFilter, mEntrySet.get(3).mExcludingFilter);
+    }
+
+    @Test
+    public void testPreRenderNotifsAreFiltered() {
         // GIVEN a NotifFilter that filters out a specific package
         NotifFilter filter1 = spy(new PackageFilter(PACKAGE_2));
-        mListBuilder.addFilter(filter1);
+        mListBuilder.addPreRenderFilter(filter1);
 
         // WHEN the pipeline is kicked off on a list of notifs
         addNotif(0, PACKAGE_1);
@@ -421,8 +451,8 @@
         // GIVEN two notif filters
         NotifFilter filter1 = spy(new PackageFilter(PACKAGE_2));
         NotifFilter filter2 = spy(new PackageFilter(PACKAGE_5));
-        mListBuilder.addFilter(filter1);
-        mListBuilder.addFilter(filter2);
+        mListBuilder.addPreGroupFilter(filter1);
+        mListBuilder.addPreGroupFilter(filter2);
 
         // WHEN the pipeline is kicked off on a list of notifs
         addNotif(0, PACKAGE_1);
@@ -522,7 +552,7 @@
     public void testNotifsAreSectioned() {
         // GIVEN a filter that removes all PACKAGE_4 notifs and a SectionsProvider that divides
         // notifs based on package name
-        mListBuilder.addFilter(new PackageFilter(PACKAGE_4));
+        mListBuilder.addPreGroupFilter(new PackageFilter(PACKAGE_4));
         final SectionsProvider sectionsProvider = spy(new PackageSectioner());
         mListBuilder.setSectionsProvider(sectionsProvider);
 
@@ -596,17 +626,19 @@
     @Test
     public void testListenersAndPluggablesAreFiredInOrder() {
         // GIVEN a bunch of registered listeners and pluggables
-        NotifFilter filter = spy(new PackageFilter(PACKAGE_1));
+        NotifFilter preGroupFilter = spy(new PackageFilter(PACKAGE_1));
         NotifPromoter promoter = spy(new IdPromoter(3));
         PackageSectioner sectioner = spy(new PackageSectioner());
         NotifComparator comparator = spy(new HypeComparator(PACKAGE_4));
-        mListBuilder.addFilter(filter);
+        NotifFilter preRenderFilter = spy(new PackageFilter(PACKAGE_5));
+        mListBuilder.addPreGroupFilter(preGroupFilter);
         mListBuilder.addOnBeforeTransformGroupsListener(mOnBeforeTransformGroupsListener);
         mListBuilder.addPromoter(promoter);
         mListBuilder.addOnBeforeSortListener(mOnBeforeSortListener);
         mListBuilder.setComparators(Collections.singletonList(comparator));
         mListBuilder.setSectionsProvider(sectioner);
         mListBuilder.addOnBeforeRenderListListener(mOnBeforeRenderListListener);
+        mListBuilder.addPreRenderFilter(preRenderFilter);
 
         // WHEN a few new notifs are added
         addNotif(0, PACKAGE_1);
@@ -620,25 +652,28 @@
 
         // THEN the pluggables and listeners are called in order
         InOrder inOrder = inOrder(
-                filter,
+                preGroupFilter,
                 mOnBeforeTransformGroupsListener,
                 promoter,
                 mOnBeforeSortListener,
                 sectioner,
                 comparator,
+                preRenderFilter,
                 mOnBeforeRenderListListener,
                 mOnRenderListListener);
 
-        inOrder.verify(filter, atLeastOnce())
+        inOrder.verify(preGroupFilter, atLeastOnce())
                 .shouldFilterOut(any(NotificationEntry.class), anyLong());
         inOrder.verify(mOnBeforeTransformGroupsListener)
-                .onBeforeTransformGroups(anyList(), anyList());
+                .onBeforeTransformGroups(anyList());
         inOrder.verify(promoter, atLeastOnce())
                 .shouldPromoteToTopLevel(any(NotificationEntry.class));
         inOrder.verify(mOnBeforeSortListener).onBeforeSort(anyList());
         inOrder.verify(sectioner, atLeastOnce()).getSection(any(ListEntry.class));
         inOrder.verify(comparator, atLeastOnce())
                 .compare(any(ListEntry.class), any(ListEntry.class));
+        inOrder.verify(preRenderFilter, atLeastOnce())
+                .shouldFilterOut(any(NotificationEntry.class), anyLong());
         inOrder.verify(mOnBeforeRenderListListener).onBeforeRenderList(anyList());
         inOrder.verify(mOnRenderListListener).onRenderList(anyList());
     }
@@ -651,7 +686,7 @@
         SectionsProvider sectionsProvider = new PackageSectioner();
         NotifComparator hypeComparator = new HypeComparator(PACKAGE_2);
 
-        mListBuilder.addFilter(packageFilter);
+        mListBuilder.addPreGroupFilter(packageFilter);
         mListBuilder.addPromoter(idPromoter);
         mListBuilder.setSectionsProvider(sectionsProvider);
         mListBuilder.setComparators(Collections.singletonList(hypeComparator));
@@ -687,9 +722,9 @@
         NotifFilter filter1 = spy(new PackageFilter(PACKAGE_5));
         NotifFilter filter2 = spy(new PackageFilter(PACKAGE_5));
         NotifFilter filter3 = spy(new PackageFilter(PACKAGE_5));
-        mListBuilder.addFilter(filter1);
-        mListBuilder.addFilter(filter2);
-        mListBuilder.addFilter(filter3);
+        mListBuilder.addPreGroupFilter(filter1);
+        mListBuilder.addPreGroupFilter(filter2);
+        mListBuilder.addPreGroupFilter(filter3);
 
         // GIVEN the SystemClock is set to a particular time:
         mSystemClock.setUptimeMillis(47);
@@ -709,13 +744,13 @@
     }
 
     @Test
-    public void testNewlyAddedEntries() {
+    public void testGroupTransformEntries() {
         // GIVEN a registered OnBeforeTransformGroupsListener
         RecordingOnBeforeTransformGroupsListener listener =
                 spy(new RecordingOnBeforeTransformGroupsListener());
         mListBuilder.addOnBeforeTransformGroupsListener(listener);
 
-        // Given some new notifs
+        // GIVEN some new notifs
         addNotif(0, PACKAGE_1);
         addGroupChild(1, PACKAGE_2, GROUP_1);
         addGroupSummary(2, PACKAGE_2, GROUP_1);
@@ -743,27 +778,18 @@
                         mEntrySet.get(0),
                         mBuiltList.get(1),
                         mEntrySet.get(4)
-                ),
-                Arrays.asList(
-                        mEntrySet.get(0),
-                        mEntrySet.get(1),
-                        mBuiltList.get(1),
-                        mEntrySet.get(2),
-                        mEntrySet.get(3),
-                        mEntrySet.get(4),
-                        mEntrySet.get(5)
                 )
         );
     }
 
     @Test
-    public void testNewlyAddedEntriesOnSecondRun() {
+    public void testGroupTransformEntriesOnSecondRun() {
         // GIVEN a registered OnBeforeTransformGroupsListener
         RecordingOnBeforeTransformGroupsListener listener =
                 spy(new RecordingOnBeforeTransformGroupsListener());
         mListBuilder.addOnBeforeTransformGroupsListener(listener);
 
-        // Given some notifs that have already been added (two of which are in malformed groups)
+        // GIVEN some notifs that have already been added (two of which are in malformed groups)
         addNotif(0, PACKAGE_1);
         addGroupChild(1, PACKAGE_2, GROUP_1);
         addGroupChild(2, PACKAGE_3, GROUP_2);
@@ -799,13 +825,6 @@
                         mEntrySet.get(1),
                         mBuiltList.get(2),
                         mEntrySet.get(7)
-                ),
-                Arrays.asList(
-                        mBuiltList.get(2),
-                        mEntrySet.get(4),
-                        mEntrySet.get(5),
-                        mEntrySet.get(6),
-                        mEntrySet.get(7)
                 )
         );
     }
@@ -842,19 +861,18 @@
     }
 
     @Test(expected = IllegalStateException.class)
-    public void testOutOfOrderFilterInvalidationThrows() {
-        // GIVEN a NotifFilter that gets invalidated during the grouping stage
+    public void testOutOfOrderPreGroupFilterInvalidationThrows() {
+        // GIVEN a PreGroupNotifFilter that gets invalidated during the grouping stage
         NotifFilter filter = new PackageFilter(PACKAGE_5);
-        OnBeforeTransformGroupsListener listener =
-                (list, newlyVisibleEntries) -> filter.invalidateList();
-        mListBuilder.addFilter(filter);
+        OnBeforeTransformGroupsListener listener = (list) -> filter.invalidateList();
+        mListBuilder.addPreGroupFilter(filter);
         mListBuilder.addOnBeforeTransformGroupsListener(listener);
 
         // WHEN we try to run the pipeline and the filter is invalidated
         addNotif(0, PACKAGE_1);
         dispatchBuild();
 
-        // Then an exception is thrown
+        // THEN an exception is thrown
     }
 
     @Test(expected = IllegalStateException.class)
@@ -870,7 +888,7 @@
         addNotif(0, PACKAGE_1);
         dispatchBuild();
 
-        // Then an exception is thrown
+        // THEN an exception is thrown
     }
 
     @Test(expected = IllegalStateException.class)
@@ -886,7 +904,37 @@
         addNotif(0, PACKAGE_1);
         dispatchBuild();
 
-        // Then an exception is thrown
+        // THEN an exception is thrown
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testOutOfOrderPreRenderFilterInvalidationThrows() {
+        // GIVEN a PreRenderNotifFilter that gets invalidated during the finalizing stage
+        NotifFilter filter = new PackageFilter(PACKAGE_5);
+        OnBeforeRenderListListener listener = (list) -> filter.invalidateList();
+        mListBuilder.addPreRenderFilter(filter);
+        mListBuilder.addOnBeforeRenderListListener(listener);
+
+        // WHEN we try to run the pipeline and the PreRenderFilter is invalidated
+        addNotif(0, PACKAGE_1);
+        dispatchBuild();
+
+        // THEN an exception is thrown
+    }
+
+    @Test
+    public void testInOrderPreRenderFilter() {
+        // GIVEN a PreRenderFilter that gets invalidated during the grouping stage
+        NotifFilter filter = new PackageFilter(PACKAGE_5);
+        OnBeforeTransformGroupsListener listener = (list) -> filter.invalidateList();
+        mListBuilder.addPreRenderFilter(filter);
+        mListBuilder.addOnBeforeTransformGroupsListener(listener);
+
+        // WHEN we try to run the pipeline and the filter is invalidated
+        addNotif(0, PACKAGE_1);
+        dispatchBuild();
+
+        // THEN no exception thrown
     }
 
     /**
@@ -1178,13 +1226,9 @@
 
     private static class RecordingOnBeforeTransformGroupsListener
             implements OnBeforeTransformGroupsListener {
-        public List<ListEntry> newlyVisibleEntries;
 
         @Override
-        public void onBeforeTransformGroups(List<ListEntry> list,
-                List<ListEntry> newlyVisibleEntries) {
-            this.newlyVisibleEntries = newlyVisibleEntries;
-        }
+        public void onBeforeTransformGroups(List<ListEntry> list) { }
     }
 
     private static final String PACKAGE_1 = "com.test1";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
similarity index 86%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryBuilder.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index d18b16b..e6a61d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -14,18 +14,19 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.notification.collection;
 
 import android.annotation.Nullable;
 import android.app.Notification;
 import android.app.NotificationChannel;
-import android.app.NotificationManager.Importance;
+import android.app.NotificationManager;
 import android.content.Context;
 import android.os.UserHandle;
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
 
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.SbnBuilder;
 
 import java.util.ArrayList;
 
@@ -34,6 +35,8 @@
  * and Ranking. Is largely a proxy for the SBN and Ranking builders, but does a little extra magic
  * to make sure the keys match between the two, etc.
  *
+ * Has the ability to set ListEntry properties as well.
+ *
  * Only for use in tests.
  */
 public class NotificationEntryBuilder {
@@ -41,10 +44,35 @@
     private final RankingBuilder mRankingBuilder = new RankingBuilder();
     private StatusBarNotification mSbn = null;
 
+    /* ListEntry properties */
+    private GroupEntry mParent;
+    private int mSection;
+
     public NotificationEntry build() {
         StatusBarNotification sbn = mSbn != null ? mSbn : mSbnBuilder.build();
         mRankingBuilder.setKey(sbn.getKey());
-        return new NotificationEntry(sbn, mRankingBuilder.build());
+        final NotificationEntry entry = new NotificationEntry(sbn, mRankingBuilder.build());
+
+        /* ListEntry properties */
+        entry.setParent(mParent);
+        entry.setSection(mSection);
+        return entry;
+    }
+
+    /**
+     * Sets the parent.
+     */
+    public NotificationEntryBuilder setParent(@Nullable GroupEntry parent) {
+        mParent = parent;
+        return this;
+    }
+
+    /**
+     * Sets the section.
+     */
+    public NotificationEntryBuilder setSection(int section) {
+        mSection = section;
+        return this;
     }
 
     /**
@@ -176,7 +204,7 @@
         return this;
     }
 
-    public NotificationEntryBuilder setImportance(@Importance int importance) {
+    public NotificationEntryBuilder setImportance(@NotificationManager.Importance int importance) {
         mRankingBuilder.setImportance(importance);
         return this;
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index 17d556d..39ae68a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -52,7 +52,6 @@
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.SbnBuilder;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index 1764bef..10450fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -24,7 +24,6 @@
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.NotificationEntryBuilder
 import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking
 import com.android.systemui.statusbar.NotificationMediaManager
 import com.android.systemui.statusbar.notification.NotificationFilter
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
index a9413c7..ea6c70a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
@@ -35,10 +35,10 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
@@ -85,7 +85,7 @@
 
         ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
         mDeviceProvisionedCoordinator.attach(null, mNotifListBuilder);
-        verify(mNotifListBuilder, times(1)).addFilter(filterCaptor.capture());
+        verify(mNotifListBuilder, times(1)).addPreGroupFilter(filterCaptor.capture());
         mDeviceProvisionedFilter = filterCaptor.getValue();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java
index ffaa335..01bca0d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java
@@ -36,11 +36,11 @@
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
 import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 
 import org.junit.Before;
@@ -85,7 +85,7 @@
                 ArgumentCaptor.forClass(NotifLifetimeExtender.class);
 
         mForegroundCoordinator.attach(mNotifCollection, mNotifListBuilder);
-        verify(mNotifListBuilder, times(1)).addFilter(filterCaptor.capture());
+        verify(mNotifListBuilder, times(1)).addPreGroupFilter(filterCaptor.capture());
         verify(mNotifCollection, times(1)).addNotificationLifetimeExtender(
                 lifetimeExtenderCaptor.capture());
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
index 527370e..979b8a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -38,12 +38,12 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.notification.collection.GroupEntry;
 import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
@@ -86,14 +86,14 @@
 
         ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
         mKeyguardCoordinator.attach(null, mNotifListBuilder);
-        verify(mNotifListBuilder, times(1)).addFilter(filterCaptor.capture());
+        verify(mNotifListBuilder, times(1)).addPreRenderFilter(filterCaptor.capture());
         mKeyguardFilter = filterCaptor.getValue();
     }
 
     @Test
     public void unfilteredState() {
         // GIVEN an 'unfiltered-keyguard-showing' state
-        setupUnfilteredState();
+        setupUnfilteredState(mEntry);
 
         // THEN don't filter out the entry
         assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
@@ -102,7 +102,7 @@
     @Test
     public void notificationNotForCurrentProfile() {
         // GIVEN the notification isn't for the given user
-        setupUnfilteredState();
+        setupUnfilteredState(mEntry);
         when(mLockscreenUserManager.isCurrentProfile(NOTIF_USER_ID)).thenReturn(false);
 
         // THEN filter out the entry
@@ -112,7 +112,7 @@
     @Test
     public void keyguardNotShowing() {
         // GIVEN the lockscreen isn't showing
-        setupUnfilteredState();
+        setupUnfilteredState(mEntry);
         when(mKeyguardStateController.isShowing()).thenReturn(false);
 
         // THEN don't filter out the entry
@@ -122,7 +122,7 @@
     @Test
     public void doNotShowLockscreenNotifications() {
         // GIVEN an 'unfiltered-keyguard-showing' state
-        setupUnfilteredState();
+        setupUnfilteredState(mEntry);
 
         // WHEN we shouldn't show any lockscreen notifications
         when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
@@ -134,7 +134,7 @@
     @Test
     public void lockdown() {
         // GIVEN an 'unfiltered-keyguard-showing' state
-        setupUnfilteredState();
+        setupUnfilteredState(mEntry);
 
         // WHEN the notification's user is in lockdown:
         when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
@@ -146,7 +146,7 @@
     @Test
     public void publicMode_settingsDisallow() {
         // GIVEN an 'unfiltered-keyguard-showing' state
-        setupUnfilteredState();
+        setupUnfilteredState(mEntry);
 
         // WHEN the notification's user is in public mode and settings are configured to disallow
         // notifications in public mode
@@ -161,7 +161,7 @@
     @Test
     public void publicMode_notifDisallowed() {
         // GIVEN an 'unfiltered-keyguard-showing' state
-        setupUnfilteredState();
+        setupUnfilteredState(mEntry);
 
         // WHEN the notification's user is in public mode and settings are configured to disallow
         // notifications in public mode
@@ -177,7 +177,7 @@
     @Test
     public void doesNotExceedThresholdToShow() {
         // GIVEN an 'unfiltered-keyguard-showing' state
-        setupUnfilteredState();
+        setupUnfilteredState(mEntry);
 
         // WHEN the notification doesn't exceed the threshold to show on the lockscreen
         mEntry.setRanking(new RankingBuilder()
@@ -191,34 +191,42 @@
 
     @Test
     public void summaryExceedsThresholdToShow() {
-        // GIVEN an 'unfiltered-keyguard-showing' state
-        setupUnfilteredState();
+        // GIVEN the notification doesn't exceed the threshold to show on the lockscreen
+        // but it's part of a group (has a parent)
+        final GroupEntry parent = new GroupEntry("test_group_key");
+        final NotificationEntry entryWithParent = new NotificationEntryBuilder()
+                .setParent(parent)
+                .setUser(new UserHandle(NOTIF_USER_ID))
+                .build();
 
-        // WHEN the notification doesn't exceed the threshold to show on the lockscreen
-        // but its summary does
-        mEntry.setRanking(new RankingBuilder()
-                .setKey(mEntry.getKey())
+        setupUnfilteredState(entryWithParent);
+        entryWithParent.setRanking(new RankingBuilder()
+                .setKey(entryWithParent.getKey())
                 .setImportance(IMPORTANCE_MIN)
                 .build());
 
-        final NotificationEntry summary = new NotificationEntryBuilder().build();
-        summary.setRanking(new RankingBuilder()
-                .setKey(summary.getKey())
+        // WHEN its parent has a summary that exceeds threshold to show on lockscreen
+        parent.setSummary(new NotificationEntryBuilder()
                 .setImportance(IMPORTANCE_HIGH)
                 .build());
-        final GroupEntry group = new GroupEntry(mEntry.getSbn().getGroupKey());
-        group.setSummary(summary);
-        mEntry.setParent(group);
 
         // THEN don't filter out the entry
-        assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
+        assertFalse(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
+
+        // WHEN its parent has a summary that doesn't exceed threshold to show on lockscreen
+        parent.setSummary(new NotificationEntryBuilder()
+                .setImportance(IMPORTANCE_MIN)
+                .build());
+
+        // THEN filter out the entry
+        assertTrue(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
     }
 
     /**
      * setup a state where the notification will not be filtered by the
      * KeyguardNotificationCoordinator when the keyguard is showing.
      */
-    private void setupUnfilteredState() {
+    private void setupUnfilteredState(NotificationEntry entry) {
         // notification is for current profile
         when(mLockscreenUserManager.isCurrentProfile(NOTIF_USER_ID)).thenReturn(true);
 
@@ -239,7 +247,7 @@
 
         // entry's ranking - should show on all lockscreens
         // + priority of the notification exceeds the threshold to be shown on the lockscreen
-        mEntry.setRanking(new RankingBuilder()
+        entry.setRanking(new RankingBuilder()
                 .setKey(mEntry.getKey())
                 .setVisibilityOverride(VISIBILITY_PUBLIC)
                 .setImportance(IMPORTANCE_HIGH)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
index 182e866..d3b16c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
@@ -32,10 +32,10 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 
 import org.junit.Before;
@@ -63,7 +63,7 @@
 
         ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
         mRankingCoordinator.attach(null, mNotifListBuilder);
-        verify(mNotifListBuilder, times(1)).addFilter(filterCaptor.capture());
+        verify(mNotifListBuilder, times(1)).addPreGroupFilter(filterCaptor.capture());
         mRankingFilter = filterCaptor.getValue();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProviderTest.java
index 11488a0..6fa1a89 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/IsHighPriorityProviderTest.java
@@ -33,8 +33,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index d139866..e23d0ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -39,12 +39,12 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.UiOffloadThread;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index 27e3a66..c7e59ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -42,6 +42,7 @@
 import android.widget.RemoteViews;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.InflationTask;
@@ -64,7 +65,7 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper(setAsMainLooper = true)
-@Ignore
+@Suppress
 public class NotificationContentInflaterTest extends SysuiTestCase {
 
     private NotificationContentInflater mNotificationInflater;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index bdca7ef..f513c2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -78,10 +78,10 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.bubbles.BubblesTestActivity;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.SbnBuilder;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
index 9eba4eb..f48c40c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
@@ -38,8 +38,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 
 import org.junit.After;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index d2b4a20..deca51f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -55,7 +55,6 @@
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.EmptyShadeView;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
@@ -71,6 +70,7 @@
 import com.android.systemui.statusbar.notification.TestableNotificationEntryManager;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
 import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index dfd9941..7fa6901 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -33,9 +33,9 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.AlertingNotificationManagerTest;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
index 3ad1e39..54dc728 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
@@ -26,8 +26,8 @@
 import android.os.UserHandle;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
 /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 575f145..f6ed4e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -40,7 +40,6 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardIndicationController;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -54,6 +53,7 @@
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index d3fce56..d3ae7a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -98,7 +98,6 @@
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.NavigationBarController;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
@@ -120,6 +119,7 @@
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index e629a4f..fbbfa96 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -38,6 +38,7 @@
 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
 import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
 import com.android.systemui.SysuiTestCase;
 
@@ -204,4 +205,28 @@
         assertTrue(mBluetoothControllerImpl.isBluetoothConnected());
         verify(callback, atLeastOnce()).onBluetoothStateChange(anyBoolean());
     }
+
+    @Test
+    public void testOnActiveDeviceChanged_updatesAudioActive() {
+        assertFalse(mBluetoothControllerImpl.isBluetoothAudioActive());
+        assertFalse(mBluetoothControllerImpl.isBluetoothAudioProfileOnly());
+
+        CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+        mDevices.add(device);
+        when(device.isActiveDevice(BluetoothProfile.HEADSET)).thenReturn(true);
+
+        List<LocalBluetoothProfile> profiles = new ArrayList<>();
+        LocalBluetoothProfile profile = mock(LocalBluetoothProfile.class);
+        profiles.add(profile);
+        when(profile.getProfileId()).thenReturn(BluetoothProfile.HEADSET);
+        when(device.getProfiles()).thenReturn(profiles);
+        when(device.isConnectedProfile(profile)).thenReturn(true);
+
+        mBluetoothControllerImpl.onAclConnectionStateChanged(device,
+                BluetoothProfile.STATE_CONNECTED);
+        mBluetoothControllerImpl.onActiveDeviceChanged(device, BluetoothProfile.HEADSET);
+
+        assertTrue(mBluetoothControllerImpl.isBluetoothAudioActive());
+        assertTrue(mBluetoothControllerImpl.isBluetoothAudioProfileOnly());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
index c1f376b..53d8e58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
@@ -42,9 +42,9 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
 import com.android.systemui.shared.system.PackageManagerWrapper;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationEntryHelper;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAndActions;
 import com.android.systemui.statusbar.policy.SmartReplyView.SmartActions;
 import com.android.systemui.statusbar.policy.SmartReplyView.SmartReplies;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index b5e4cb9..f1a6e67 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -51,10 +51,10 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 import com.android.systemui.statusbar.phone.ShadeController;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt
index a39fbc4..709a1a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt
@@ -280,7 +280,12 @@
 
         // Spring TRANSLATION_X to 100f, with an update and end listener provided.
         animator
-                .spring(DynamicAnimation.TRANSLATION_X, 100f, springConfig)
+                .spring(
+                        DynamicAnimation.TRANSLATION_X,
+                        100f,
+                        // Use very low stiffness to ensure that all of the keyframes we're testing
+                        // for are reported to the update listener.
+                        springConfig.apply { stiffness = SpringForce.STIFFNESS_VERY_LOW })
                 .addUpdateListener(mockUpdateListener)
                 .addEndListener(mockEndListener)
                 .start()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
index cac6bf7..6cbd175 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
@@ -57,6 +57,16 @@
     }
 
     @Override
+    public boolean isBluetoothAudioProfileOnly() {
+        return false;
+    }
+
+    @Override
+    public boolean isBluetoothAudioActive() {
+        return false;
+    }
+
+    @Override
     public String getConnectedDeviceName() {
         return null;
     }
diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml
index 1430ed0..8ba05df 100644
--- a/packages/Tethering/AndroidManifest.xml
+++ b/packages/Tethering/AndroidManifest.xml
@@ -17,7 +17,7 @@
  */
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.tethering"
+          package="com.android.networkstack.tethering"
           android:sharedUserId="android.uid.networkstack">
     <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
 
diff --git a/packages/Tethering/AndroidManifestBase.xml b/packages/Tethering/AndroidManifestBase.xml
index dc013da..fa85f66 100644
--- a/packages/Tethering/AndroidManifestBase.xml
+++ b/packages/Tethering/AndroidManifestBase.xml
@@ -17,7 +17,7 @@
  */
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.tethering"
+          package="com.android.networkstack.tethering"
           android:versionCode="1"
           android:versionName="R-initial">
     <application
diff --git a/packages/Tethering/AndroidManifest_InProcess.xml b/packages/Tethering/AndroidManifest_InProcess.xml
index 28d405c..029b6c3 100644
--- a/packages/Tethering/AndroidManifest_InProcess.xml
+++ b/packages/Tethering/AndroidManifest_InProcess.xml
@@ -17,7 +17,7 @@
  */
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.tethering.inprocess"
+          package="com.android.networkstack.tethering.inprocess"
           android:sharedUserId="android.uid.system"
           android:process="system">
     <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
diff --git a/packages/Tethering/apex/Android.bp b/packages/Tethering/apex/Android.bp
index bca01ebd..af6af93 100644
--- a/packages/Tethering/apex/Android.bp
+++ b/packages/Tethering/apex/Android.bp
@@ -15,21 +15,21 @@
 //
 
 apex {
-    name: "com.android.tethering.apex",
+    name: "com.android.tethering",
     apps: ["Tethering"],
     manifest: "manifest.json",
-    key: "com.android.tethering.apex.key",
+    key: "com.android.tethering.key",
 
     androidManifest: "AndroidManifest.xml",
 }
 
 apex_key {
-    name: "com.android.tethering.apex.key",
-    public_key: "com.android.tethering.apex.avbpubkey",
-    private_key: "com.android.tethering.apex.pem",
+    name: "com.android.tethering.key",
+    public_key: "com.android.tethering.avbpubkey",
+    private_key: "com.android.tethering.pem",
 }
 
 android_app_certificate {
-    name: "com.android.tethering.apex.certificate",
-    certificate: "com.android.tethering.apex",
+    name: "com.android.tethering.certificate",
+    certificate: "com.android.tethering",
 }
diff --git a/packages/Tethering/apex/AndroidManifest.xml b/packages/Tethering/apex/AndroidManifest.xml
index 7769b79..5c35c51 100644
--- a/packages/Tethering/apex/AndroidManifest.xml
+++ b/packages/Tethering/apex/AndroidManifest.xml
@@ -15,7 +15,7 @@
  * limitations under the License.
  -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-  package="com.android.tethering.apex">
+  package="com.android.tethering">
   <!-- APEX does not have classes.dex -->
   <application android:hasCode="false" />
   <!-- b/145383354: Current minSdk is locked to Q for development cycle, lock it to next version
diff --git a/packages/Tethering/apex/com.android.tethering.apex.avbpubkey b/packages/Tethering/apex/com.android.tethering.apex.avbpubkey
deleted file mode 100644
index 9c87111..0000000
--- a/packages/Tethering/apex/com.android.tethering.apex.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/packages/Tethering/apex/com.android.tethering.apex.pem b/packages/Tethering/apex/com.android.tethering.apex.pem
deleted file mode 100644
index a8cd12e..0000000
--- a/packages/Tethering/apex/com.android.tethering.apex.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKQIBAAKCAgEAwloHpMmwszNBEgUVion141BTvF/oJ5g5DlQIYBtmht4tSpc3
-6elWXd+dhMzFxf/RkxSNRsU+dhD11cPKGp9nUYQQGrHEf3xEKwAHJKRMq26TkJ3o
-1TwOO70TaRKKA4ThNiM3VFDX2vy1ijArhZDIBTGVJCUl9HOHiO+ZJG5DKCx3KXbO
-QWz3c+Lbprr1L76dwIsl5kuoAFwgG0J+9BZhHEzIG1lVpGG7RRLxc8eDIxNN/oKT
-gPYBcOxFYqOECKGBBvElf6MxdRv6xG7gooALY2/HDMYUjAJSOosfwzeymugCzMhK
-e+6CSTAaEfUzuVZvMc2qnd1ly7zpLo9x+TOdH5LEVZpSwqmu2n5bqrUnSEAJUvMz
-SSw0YbsLWJZuTiTV7lecSITgqsmwuZyDexDmUkDQChzrTixsQV6S8vsh/FanjWoi
-zBlPneX8Q7/LME3hxHyLbrabxX0zWiyj8iM9h/8Y4mpO/MjEmmavglTAP4J8zrKD
-FBsntCoch9I49IpYBuO6NfKw1h7AUpLf8gARAjFjRxiJVcSgGY/Wt4/pBzJ57T5g
-xPvqxfpPQP0OA2CT8LqqzZIR8jXs8/TquvwLkkY2kRRPXx+azd5oU2A0uonrUY31
-Bc1obfmWPuEMz9bO/i06ETHuWPd4RiUNaB8qEmjYuKJfhv72YNcRwhrAYJECAwEA
-AQKCAgAaQn3b5yCH5fn5zFQPxvpBP35A6ph8mRXEeNg03B7rRCPMe0gjw9JWlrs6
-0Uw7p4gSnmlEUaxR2ZLN0kmBdV5JZlWitbg+HXU8diGA8u4lD6jCloN6JEYsDi0M
-OmQJe6/OV83HB7FStmh1BnMq9dgA06U6IAbT07RRbUY85OUQDYoAQTw3HNkGgHV7
-PrGYROIdvO9fAYPuoIP6Cu8KXee7Iii7gUOQFWBvQdL7+M4gNCCKrevuNc8WCeaK
-IFvbqq67WGPfrhYlo6UrW2vgqPpg8h5r/GuUS0/+9wNQpjrssUKHltxxiFV0PBqZ
-qI7XkPUvPoG6GMsDT0AWeW1F5ZJqEGPN67Xek0BCD0cpUli+nHD0yWGVHtkpHU2D
-qUOZdB2COfBuXRdW1LsYNPg8YjTCPsmGhISLTwiTNcZJeTxoK1y0CcVW9d7Af2aD
-lYzCegscQlXkSZiFj9s90Vd3KdD2XKrH/ADxzsOxQJ89ka004efdQa5/MKs9aChG
-/5XrwBEfN4O92OjY7KqXUAwB7CcVzNymOjD6r07LM24zbkRpwwXlkP0wmjsHBXkh
-8p0ISmY9QRdvhBgYmFmoPWZncM0zym9LI8atBs4CijQ7JjuOQ8HgHg+Se2eppWfe
-t8r6TVkDB8JeNAMxjX9q0G7icf3JjlIrgERZfyXLmpduR9NdkQKCAQEA5rp2fSKh
-RwihHNtJhNktFJuLR9OA++vyfjqhWnB8CrLPo3//LGWW/+WBr8EwXi/76hQpeKlf
-u8SmkTtxIHlTP2Brh2koh1Qf8HKzPHGjZeDFOoVPKHPqe3nV+cv3srd1mS0Eq3BA
-ZFQq+l61f2iiTZKxDroCahNEa8VMzirW6nKb5xhyMPHXgncCUdphHbwAGatas6be
-RUFg4ChH8BwX6jYw7leRUy2K6OqEl0fckT4Laitlb/ezKtwmD4PPE95q5hH0v3SO
-wetHWafiNrOXPn2wQqBrI2y+AfbTjNmQiaIPgcFKAQ7V3n+c3XfGZ9Xfv4L8m/wo
-RZ4ika1zur021QKCAQEA16OUBPA7BnWd+RJFri2kJBG5JZElaV9chO2ZHcXUbFR9
-HIPkWN19bJbki8Ca0w8FUQuS/M7JeeFjoZ194NlczbR899GVmb0X2AUKXilMacs3
-IONxIDczx3KFtsge8ewXRAjQvgE7M3NpmmJfPLPog7spMCbUIxbc3jzjiZgB/J1s
-WytlUTUY/Zy4V1wujkoydgK2KcHcEWG2oIy7EP0RwnL1NhTksXOtBH6+MoRMAT+H
-fcBK6yfJBNBRQzJ0PdkCCLdQPN1VtwRlWjPXZ3ey4fWvZ399wSLUkM2V1jB4GcOZ
-+DAgtwFKs9+HfOdV42GgFWFcjP+bkM3bcdrQFnmYzQKCAQAQnf1KpePXqddwrJpu
-5vVINquhUKpJeoTMcoyMZu2IF7i8nctS9z4Yz/63GcLSBcKu6STTe99ZNqCIdS+A
-lzxXpCoaZoh0tqpWNuyRvd12yOlrfY5l63NH0U6H3xjH1k6x6XwcnMkGcMlnnsqT
-koWd8KKv3NWvrhOPb3ZIou03lWmFC02uGLzcuJWCL6gu7AtVzfGKXspDUqIXgs8r
-i9ptE9oSUFw3EWCfxcQm4RYRn9ZSny1/EufkflZ/Z47Sb4Jjb4ehAlQFw1wwKNcx
-+V07MvIu2j7dHkfQ/GXgDwtJ3lIfljwuN1NP4wD5Mlcnw0+KC3UGBvMfkHQM6eEb
-4eTBAoIBAQDWfZsqHlpX3n431XkB+9wdFJP5ThrMaVJ51mxLNRBKgO/BgV+NFSNA
-9AZ5DCf0cCh1qPGYDYhSd2LGywT+trac1j7Hse0AcxpYgQsDBkk/oic/y3wm80HJ
-zZw7Z2uAb7nkrnATzt24G8CbE+ZvVvScs3oQr06raH5hgGdD4bN4No4lUVECKbKl
-8VFbdBHK7vqqb6AKgQ4JLAygPduE1nTn2bkXBklESS98HSXK0dVYGH0JFFBw/63v
-39Y05ObC7iwbx1tEb1RnKzQ1OQO1o1aHc/35ENNhXOfa8ONtneCYn/ty50xjPCG2
-MU1vbBv+hIjbO3D3vvhaXKk+4svAz0qxAoIBAQC84FJEjKHJHx17jLeoTuDfuxwX
-6bOQrI3nHbtnFRvPrMryWRDtHLv89Zma3o68/n4vTn5+AnvgYMZifOYlTlIPxinH
-tlE+qCD8KBXUlZdrc+5GGM18lp5tF3Ro4LireH+OhiOAWawaSzDIDYdiR6Kz9NU+
-SjcHKjDObeM6iMEukoaRsufMedpUSrnbzMraAJgBZGay1NZs/o8Icl3OySYPZWEK
-MJxVBMXU9QcUp2GEioYd/eNuP9rwyjq/EIUDJbP2vESAe6+FdGbIgvyYTV/gnKaH
-GcvyMNVZbCMp/wCYNonjlu+18m2w+pVs2uuZLqORkrKYhisK83TKxh4YOWJh
------END RSA PRIVATE KEY-----
diff --git a/packages/Tethering/apex/com.android.tethering.apex.pk8 b/packages/Tethering/apex/com.android.tethering.apex.pk8
deleted file mode 100644
index 5663246..0000000
--- a/packages/Tethering/apex/com.android.tethering.apex.pk8
+++ /dev/null
Binary files differ
diff --git a/packages/Tethering/apex/com.android.tethering.apex.x509.pem b/packages/Tethering/apex/com.android.tethering.apex.x509.pem
deleted file mode 100644
index a5e9401..0000000
--- a/packages/Tethering/apex/com.android.tethering.apex.x509.pem
+++ /dev/null
@@ -1,36 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIGMzCCBBugAwIBAgIUXVtoDaXanhs7ma8VIICambMkj5UwDQYJKoZIhvcNAQEL
-BQAwgacxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
-DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
-b2lkMSMwIQYDVQQDDBpjb20uYW5kcm9pZC50ZXRoZXJpbmcuYXBleDEiMCAGCSqG
-SIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAgFw0xOTExMjgwNjU4MTRaGA80
-NzU3MTAyNDA2NTgxNFowgacxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9y
-bmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAw
-DgYDVQQLDAdBbmRyb2lkMSMwIQYDVQQDDBpjb20uYW5kcm9pZC50ZXRoZXJpbmcu
-YXBleDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCAiIwDQYJ
-KoZIhvcNAQEBBQADggIPADCCAgoCggIBANwzufMBdOj9XlNwiX+bXl/94G0DklWW
-nzob0jPlubCFfRqYkjCf2eOd28Mu/O1pOBcvobnrs9OTpGzcHkz2h58L5/0UMVTS
-tBugwCE49XF5FHawqVHNZE+s5tDmnp2cufhNc5HXHY4oZKh80/WVdbcKxiLjSY2T
-PgRAfB6E6XByKD3t1cSsc3liRVKADoJOVDvmF+xnyvSV/SN38bvTQk9aVs95mj0W
-yov6gzXBnqN7iQlvkhcijZBnFWxvoNbJ5KFy1abYOrm+ueXje4BcNhVOeRMb4E9N
-eo7+9k1GEI7TYG7laNNcp7UJ1IXCJzv/wBFKRg3f1HB3unKfx2rtKerDnVsr3o7V
-KProkgRNKNhhQ6opNguiH1YMzKpWMaC988n4AQPryPdIOmVIxIC5jJrixdxgzDXT
-qeiwFiXis291uyls08B03PQFlY9oWaY9P8s+4hIUjB6rLl+XZXsLDtDFxXeJ97NB
-8XZN1gBJoBoLknFs0C4LKpmJZB/EBao9tXV9dL/5lydRo6HzQDpjW8QX06CTUM6z
-Lr3LVelhqbsuZsV42yBKl+/LfrvNjBLEPdSevt2oMrlJW7m4iSNaMtDtJ2Oy8fA5
-WSIgLWuMbkaFDza3JzwiMzxbtbJHYiy6rY7aVywo3Vqwr1+KO3cq4eLQq62zUjRY
-e6KJwvgE2YmpAgMBAAGjUzBRMB0GA1UdDgQWBBQ8h1oF5JfKFmJCN8nfimbUK+IR
-wjAfBgNVHSMEGDAWgBQ8h1oF5JfKFmJCN8nfimbUK+IRwjAPBgNVHRMBAf8EBTAD
-AQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAP5hIkAxSyt9hRafMKiFlmXcL277bgoxNd
-qGZYbdcCFjfvM2r0QQcM/K7x2ZslFe7mJSzcyMifpm4YQTEo2yYbzKItXQV+eV1K
-9RNksRGFG9umsdWaSHhfQmcmxtr2nu9rGAgxy5OQFtyXmJPUPEM2cb/YeILwYhuQ
-Ux3kaj/fxGltX1JBag7HnMzCTZK++fRo5nqFVOJQgJH8ZpuzGeM9kZvP1+b55046
-PhSnlqmZoKhG4i5POPvvZvaakh/lM3x/N7lIlSaQpCGf7jmldni4L0/GenULVKzH
-iN73aBfh4GEvE0HRcOoH3L7V6kc3WMMLve0chZBHpoVYbzUJEJOUL4yrmwEehqtf
-xm4vlYg3vqtcE3UnU/UGdMb16t77Nz88LlpBY5ierIt0jZMU0M81ppRhr1uiD2Lj
-091sEA0Bxcw/6Q8QNF2eR7SG7Qwipnms+lw6Vcxve+7DdTrdEA0k3XgpdXp8Ya+2
-PAp9SLVp1UHiGq3qD9Jvm34QmlUWAIUTHZs3DSgs1y3K5eyw/cnzTvUUOljc/n2y
-VF0FFZtJ1dVLrzQ80Ik7apEXpBqkgBGV04/L3QYk4C0/sP+1yk6zjeeeAvDtUcHS
-gLtjAfacQl/kwfVQWfrF7VByLcivApC6EUdvT3cURM5DfZRQ4RcKr1D61VYPnNRH
-+/NVbMObwQ==
------END CERTIFICATE-----
diff --git a/packages/Tethering/apex/com.android.tethering.avbpubkey b/packages/Tethering/apex/com.android.tethering.avbpubkey
new file mode 100644
index 0000000..9a2c017
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.avbpubkey
Binary files differ
diff --git a/packages/Tethering/apex/com.android.tethering.pem b/packages/Tethering/apex/com.android.tethering.pem
new file mode 100644
index 0000000..d4f39ab
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKgIBAAKCAgEA+AWTp03PBRMGt4mVNLt5PDoFFSfmFOVTM7jt5AJXnQMIDsAM
+1cyWGWRridGIpoHAaCALVgW5aRySgi8yV5xP4w0YHcKbfh9M6I9oz4RUo4GQBZfX
++lFIGaLjb6I3tEJxPuxps4sW26Io63ihwTnKeGyADHdHGWDUs9WU0Ml+QTvKrdjy
+qC03M0dehYXILGiA9m+UXwKoKxhWgfDUhWLhDBUtLJLPL4WeqKc9sG9h+zzVqE+8
+LzJsfrodKhTTrLpWOXi6YLRTk8dzsuPz/Nu98sJd1w3fHd20DrmkqsxVhgN1h+nk
+zcPpxyGYIP6qYVZCmIXCwZZNtPeb7y/tOs967VHoZ4Qj7p2tE0CAWFMZFGjA/pcZ
+7fi6CsIuMOYBbj4+wRlJwpG1g5zSJBCjzhv7dZp8S5oXmLShNYOMYEdsPfaZbm08
+3pVY+k8DVf7idcANXNw1lM+sPbE2hp5VuEuVpK+ca5x8hIMpTqJ84wDAjnC1kCwm
+X2xfNvYPKNF58SvqlNCPN8X7hQjoeaEb7w24vCdZMRqeGBmu1GNQvCyzbBO0huQm
+f5CQPrZjPcnoImlP879VPxY4YB6tAjsA/ZLiub9VdT108lCjb5r8criMzpMAA/AQ
+NqQLWFI3M43xPemGBTiIguTYgpRgGcdRZf7XuTgTY5qzQZZuZMVuwaqSD2cCAwEA
+AQKCAgEA0jMvw3BPTrakT7Lb8JgelKt7mUV6WyVMUZ6eh0pw5JIoJxAfEKfWYmjY
+NzKNRMjcv6LA2MP7MplTld/YI6ZHkl+Lm9VOISL39HVuV8mIThbFb+gT1INEvu1t
+IjRyT2SsQ67rmo377mLNmVtgg7mt3kfecjI44MpPGqad/CF4zmKVUKd4aI4BpYUM
+F8+dKf3bpoBEWA2RZwy2bGQmSXHW132vDoLR8y2knL04rCqJ+PrC/WWuULXEe9bS
+VtLV3yMBZq3qD4Fk/+7fILLPGvNFVdPi4htQiChYrM4rP9HzfaO63VieYMF0hR70
+pqoOznXj9Q4QVC9FZmUgFCQjQ1+KhqJw3OldIo0SnvpsLdTO/inKkhQWKC5HlPyh
+/rqvro2j3pTHWPAziuBr+oQPcdVCOlCBZ+B99L1tO7aGktVPEIVQG7G7jlFMBiJ1
+j/kRGk2RTX8RaPQJTnwUqp8mWUV2fwxHiXNadjejA5ZU3eQT2eAOhXl1w6Lv2jEl
+0wMOwPMJGcF77CcqnnWHON8fkxCbAfyy5Uo6Pm9g/Zzecn+ji2sabG7Ge5t0gzdL
+LKRcGoyakN2CrbQ8pxlCTgE4HX5oPY+VuqOf8L3AIWIJBsyLbXHVkL1mqQ/Ed2uz
+zaaSFYUZw81+m/5bl8JLPaIFNPyikZrXTD0YRer3V06XiyP/kYECggEBAP033xeF
+OhgRwkRTjd68hwRJpyHsZDWxHiUqQf6l6yFv5mEE355G2IGI7cZmR2+tUDjQdxLv
+tAZIszTK4PFCdVTeWfGVFbVF84eNWLB124pHDMM79GN/AMcuHnQPR756a8IO1hIy
+4KxIUE1a1PKN5b9IgE5Lu4TZM96HDpFcUAmCT5urdYDmg3++IWT9PYQlGS7Hhiar
+r+Hh646waM8Qx619CwXBqy+Y37+WHVbYqJClr6AcpVMrGA+6cgpskFpZAPLsoy7G
+RSsVfyV8pH2JKm/hzk7XCwIpczxeWQSfpJWZ+oOPFHu+zM60Cdj2UrQyKrNHwew8
++WYe9eCA+MiNBcECggEBAPq/F1vdqROiLv9uzhKb8ybgdL7CmREELiqwK+MvNE9t
+W7lQz7lcWzav+b2n0M+VJBxUWB3XClgoIvA/AllgTgsYXfKAxNakhKLSBoMmvKCW
+HtWcGr/D3RcmacK+DTMWlVS/LuueAFLuH6UmBIUFKc+qA5x7oQecAFALBFupE3G4
+LtAspLBI6P8gRtRav5p2whs9H8qjYcyf2f6liWpkmFITcXvPvAxFHicR6ZJdwZ/S
+PiX2LJQnOpT7L3+2PWnYwzFStb4MkMGlFKcscU9CvS53JcP/J4Asjk0I4zDB2gri
+xzFHPlVzCr2IVVGptKCQ3sdYiMIzQKzEXQHCU8h37ycCggEBAJu8aC48Fz3Edlm1
+ldS+2L9vWSaJEBzhoSu0cMBgZVu8SdGzwKDE69XHVI4oS5lI28UFmaaA3JTc07MN
+cAmSGT2oP2NQkPhbXGsrKLfm1K6YAiZ1Ulp7OwxFth8lYreo7Wt92nV46yuqkhDx
+Y3UGhp39xkPhWiRbvgYHxJLsVqFyjumsK2mq3IeNdVZ6VgJXGsTlnAFeqJ7hZxHs
+N5natSRjeosA0PtGJ57agZLvT8Ue0gREef3LzFGoFwmIOcQHZ4kAt2BGOzZDU17H
+6Rb4bKxBEbT1l2St/5zKXi90zDHicOvG7Q8qiyY6HrBc1wLSs+ZtpLxZx/3h3tFE
+IT6fVUECggEBAMSAQm8Ey76OJ+SXUjk1K50442SnHcs/Cmr7urkEQitImUwl71Pk
+87pst/uP6szypOTqmE9yOTIS6iZ6Sn3+QcriIqWrkhZfwW3Tx7S6A7KZUrq15iSH
++thsiw9JXxC9TvOmC8AsBzb2U6hZncsc28JZCxFztSNAduJDb/vhCVLiMxWDFuDr
+kmR1R+yc3XDQRpeQFDz6QudYEj9EPOc6xD/16sZLaqP2+oVFvVSt0tJLsdaQECle
+gMNGAdhE2eX8MCOUHMc+E6cdlozYAEhMFfO2/cqWR79jq3TlVR3dnOFRDScqHMhc
+KnuTvsELjHkUbvGsCSiff7yk+fop7vy4OJsCggEAPemJdItO2rhib8EofrZdY72I
+oifX1jhPZ1BWD2GKgcx+eVyJGbONBbJVexvvskTfZBvCcAegmgp+sngP6MO6yZkr
+cHMfAJeApYZnshsgXksHGMDtSB50/w1JLrc/nqpxdpy/aTazt0Eu1pLWpze1HFZ/
+Xyu4PcmrU+4P1vN7c396slHMktEvly6QqOn4nfBbGDJ17Ow6X1XFvGjAxQPIDTB+
+6loV14AHymwmqwMrGn84O72rzqyw+41GxW5+oXhOZ4MeXF3u89TBLWvXDpPy/YQU
+EiKpodN0YeEn6Ghzplan8rUha+7TP7AYnS5pCszsCHKd03Py0lMLkF+uAfVsDA==
+-----END RSA PRIVATE KEY-----
diff --git a/packages/Tethering/apex/com.android.tethering.pk8 b/packages/Tethering/apex/com.android.tethering.pk8
new file mode 100644
index 0000000..3b94405
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.pk8
Binary files differ
diff --git a/packages/Tethering/apex/com.android.tethering.x509.pem b/packages/Tethering/apex/com.android.tethering.x509.pem
new file mode 100644
index 0000000..a1786e3
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.x509.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGKTCCBBGgAwIBAgIUNiSs5EMqxCZ31gWWCcRJVp9HffAwDQYJKoZIhvcNAQEL
+BQAwgaIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMR4wHAYDVQQDDBVjb20uYW5kcm9pZC50ZXRoZXJpbmcxIjAgBgkqhkiG9w0B
+CQEWE2FuZHJvaWRAYW5kcm9pZC5jb20wIBcNMTkxMjE4MDcwMDQ4WhgPNDc1NzEx
+MTMwNzAwNDhaMIGiMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEW
+MBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UE
+CwwHQW5kcm9pZDEeMBwGA1UEAwwVY29tLmFuZHJvaWQudGV0aGVyaW5nMSIwIAYJ
+KoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxvTUA4seblYjZLfTVNwZuJH914QVNFTj+vD94pWmt5Aq
+sH1DVTpBvpXXegc/P5HI2XF/71poSBib1WaQSuXG0fU5K75T18bOGL0qF+fhMtBO
+wUyvulcjO0h4XE/xf0txY54exUjAA4JS9ERGJOgb4GOwSbPyzekfmzIyCZ2Yawwu
++oGwD2ZNzZRaPOoWxjwohBWQ6mySuvF9RRRb300qmxxUGFM9Ki3aqrWlYlHEOwOC
+M+gIXxYFO7S+yUzf6/gMZLOz2YqfcTOup4hAxtExR7niutxJSsRLPBL237exAJoz
+OupoXjtWAlPK4ZwZ/Nl1jdTWauJ+Kv3WqzhHGEb2gn3ZpeO3IdOjJhDgFJ6m1OT/
+kjRbW1LCuKGrKaoqsEDT2X3a7Izfripn65hSNTfR5gNLtgELaI3/vXi8Fmzw1AfH
++qi6ulElZvSwx0qm+S0QiPyGFlxrsdnHoGJl1tzjJW8KdNZRvzRLUQtbphPp+VkL
+5i0bNKum+AwbfdUkLkNLfw9XdbujgBkZTZDQbZGsNjgrvyXcPO2KiJee0hVCZRs0
+rhDi5Pfm7BnN/I2vaTRz/W4mdct9H2RWMuqlSH90JvmKtWcND8ahmOJ3sggrvzfO
+QNs3k4JTRecamMzqIkylhlnEC4FjWc6Bx4wsEpwBMZOkF/tGGMZYf2C09a8tpP0C
+AwEAAaNTMFEwHQYDVR0OBBYEFNP5gIpNWmq0xa411M1GaRPbEijvMB8GA1UdIwQY
+MBaAFNP5gIpNWmq0xa411M1GaRPbEijvMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggIBADJGmU3QP4EGbt6eBhVPeo/efsqrHsuB2fvFzvIobJbfkSob
+cmvjbzIikOlPAgFWj8lT5SDcIWRorFf1u2JylClJ0nSDcqJMHVKmT7wseV/KtX//
+1yUyJFRQVzmjC89dp8OIc00GmItivKLer3NbJdkR3rTUjg7+bNUO27Qp3AFREmiJ
+P+M7ouvcQRvByUWbp/LOrJpMdJLysRBO562RwrtwTjltdvufyYswbBZOKEiUh1Jc
+Ged+3+SJdhwq3Wy+R3Uj7YE7mUMu1QNbANIMrwF8W93EA53eoL2+cKmuaVU6ZURL
+xgSJaY6TrunnSI9XTROLtjsFlJorYWy2tvG7Q5Hw3OkO2Xdz/mm85VTkiusg9DMB
+WWTv607YtsIO0FhKmcV4bp3q/EkRj3t/zLvL9uFJrWDGkuShZq6fQvqbCvaokOPY
++M0ZRIwgwa9UpEE0BMklVWqR6BGyap614gOgcOjYM70WRNl59Qne+g128ZN7g9nz
+61F70i7kUngV0ZUz1/Fu/NCG+6wGF85ZbFmQl60YHPDw1FtjVUuKyBblaDzdJunx
+yQr2t9RUokzFBFK0lGW3+yf0WDQ5fqTMs5h8bz1FCq8/HzWmpdOfqePLe4zsld3b
+1nFuSohaIfbn/HDdTNtTBGQPgz8ZswQ6ejJJqTLz9D/odbqn9LeIhDZXcQTf
+-----END CERTIFICATE-----
diff --git a/packages/Tethering/apex/manifest.json b/packages/Tethering/apex/manifest.json
index 078302a..538ffb3 100644
--- a/packages/Tethering/apex/manifest.json
+++ b/packages/Tethering/apex/manifest.json
@@ -1,4 +1,4 @@
 {
-  "name": "com.android.tethering.apex",
+  "name": "com.android.tethering",
   "version": 300000000
 }
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 743fd6a..c4b360d 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -109,7 +109,7 @@
 import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
-import com.android.tethering.R;
+import com.android.networkstack.tethering.R;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/packages/Tethering/tests/unit/AndroidManifest.xml b/packages/Tethering/tests/unit/AndroidManifest.xml
index 049ff6d..0a1cdd3 100644
--- a/packages/Tethering/tests/unit/AndroidManifest.xml
+++ b/packages/Tethering/tests/unit/AndroidManifest.xml
@@ -14,13 +14,13 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.tethering.tests.unit">
+          package="com.android.networkstack.tethering.tests.unit">
 
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
     </application>
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.tethering.tests.unit"
+        android:targetPackage="com.android.networkstack.tethering.tests.unit"
         android:label="Tethering service tests">
     </instrumentation>
 </manifest>
diff --git a/services/Android.bp b/services/Android.bp
index 8be6e16..cf0c15c 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -111,7 +111,7 @@
     srcs: [":services-sources"],
     installable: false,
     // TODO: remove the --hide options below
-    args: " --show-single-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.INTERNAL,process=android.annotation.SystemApi.Process.SYSTEM_SERVER\\)" +
+    args: " --show-single-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES,process=android.annotation.SystemApi.Process.SYSTEM_SERVER\\)" +
         " --hide-annotation android.annotation.Hide" +
         " --hide-package com.google.android.startop.iorap" +
         " --hide ReferencesHidden" +
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 49046b2..d2f1113 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -133,6 +133,12 @@
             @PackageInfoFlags int flags, int filterCallingUid, int userId);
 
     /**
+     * Retrieve CE data directory inode number of an application.
+     * Return 0 if there's error.
+     */
+    public abstract long getCeDataInode(String packageName, int userId);
+
+    /**
      * Return a List of all application packages that are installed on the
      * device, for a specific user. If flag GET_UNINSTALLED_PACKAGES has been
      * set, a list of all applications including those deleted with
diff --git a/services/core/java/com/android/server/CountryDetectorService.java b/services/core/java/com/android/server/CountryDetectorService.java
index d8a2fe3..861c731 100644
--- a/services/core/java/com/android/server/CountryDetectorService.java
+++ b/services/core/java/com/android/server/CountryDetectorService.java
@@ -16,14 +16,6 @@
 
 package com.android.server;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.HashMap;
-
-import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.DumpUtils;
-import com.android.server.location.ComprehensiveCountryDetector;
-
 import android.content.Context;
 import android.location.Country;
 import android.location.CountryListener;
@@ -36,17 +28,25 @@
 import android.util.Printer;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.DumpUtils;
+import com.android.server.location.ComprehensiveCountryDetector;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.HashMap;
+
 /**
- * This class detects the country that the user is in through
- * {@link ComprehensiveCountryDetector}.
+ * This class detects the country that the user is in through {@link ComprehensiveCountryDetector}.
  *
  * @hide
  */
-public class CountryDetectorService extends ICountryDetector.Stub implements Runnable {
+public class CountryDetectorService extends ICountryDetector.Stub {
 
     /**
-     * The class represents the remote listener, it will also removes itself
-     * from listener list when the remote process was died.
+     * The class represents the remote listener, it will also removes itself from listener list when
+     * the remote process was died.
      */
     private final class Receiver implements IBinder.DeathRecipient {
         private final ICountryListener mListener;
@@ -79,9 +79,11 @@
         }
     }
 
-    private final static String TAG = "CountryDetector";
+    private static final String TAG = "CountryDetector";
 
-    /** Whether to dump the state of the country detector service to bugreports */
+    /**
+     * Whether to dump the state of the country detector service to bugreports
+     */
     private static final boolean DEBUG = false;
 
     private final HashMap<IBinder, Receiver> mReceivers;
@@ -92,15 +94,21 @@
     private CountryListener mLocationBasedDetectorListener;
 
     public CountryDetectorService(Context context) {
+        this(context, BackgroundThread.getHandler());
+    }
+
+    @VisibleForTesting
+    CountryDetectorService(Context context, Handler handler) {
         super();
-        mReceivers = new HashMap<IBinder, Receiver>();
+        mReceivers = new HashMap<>();
         mContext = context;
+        mHandler = handler;
     }
 
     @Override
     public Country detectCountry() {
         if (!mSystemReady) {
-            return null;   // server not yet active
+            return null; // server not yet active
         } else {
             return mCountryDetector.detectCountry();
         }
@@ -154,9 +162,8 @@
         }
     }
 
-
     protected void notifyReceivers(Country country) {
-        synchronized(mReceivers) {
+        synchronized (mReceivers) {
             for (Receiver receiver : mReceivers.values()) {
                 try {
                     receiver.getListener().onCountryDetected(country);
@@ -170,38 +177,23 @@
 
     void systemRunning() {
         // Shall we wait for the initialization finish.
-        BackgroundThread.getHandler().post(this);
+        mHandler.post(
+                () -> {
+                    initialize();
+                    mSystemReady = true;
+                });
     }
 
     private void initialize() {
         mCountryDetector = new ComprehensiveCountryDetector(mContext);
-        mLocationBasedDetectorListener = new CountryListener() {
-            public void onCountryDetected(final Country country) {
-                mHandler.post(new Runnable() {
-                    public void run() {
-                        notifyReceivers(country);
-                    }
-                });
-            }
-        };
-    }
-
-    public void run() {
-        mHandler = new Handler();
-        initialize();
-        mSystemReady = true;
+        mLocationBasedDetectorListener = country -> mHandler.post(() -> notifyReceivers(country));
     }
 
     protected void setCountryListener(final CountryListener listener) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mCountryDetector.setCountryListener(listener);
-            }
-        });
+        mHandler.post(() -> mCountryDetector.setCountryListener(listener));
     }
 
-    // For testing
+    @VisibleForTesting
     boolean isSystemReady() {
         return mSystemReady;
     }
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index c0f10a3..92d1da5 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -16,6 +16,8 @@
 
 package com.android.server;
 
+import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+
 import android.Manifest;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -37,6 +39,7 @@
 import android.os.UserHandle;
 import android.service.carrier.CarrierMessagingService;
 import android.telephony.SmsManager;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.Slog;
@@ -523,11 +526,11 @@
 
                 // Grant permission for the carrier app.
                 Intent intent = new Intent(action);
-                TelephonyManager telephonyManager =
-                        (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
-                List<String> carrierPackages =
-                        telephonyManager.getCarrierPackageNamesForIntentAndPhone(
-                                intent, SubscriptionManager.getPhoneId(subId));
+                TelephonyManager telephonyManager = (TelephonyManager)
+                        mContext.getSystemService(Context.TELEPHONY_SERVICE);
+                List<String> carrierPackages = telephonyManager
+                        .getCarrierPackageNamesForIntentAndPhone(
+                                intent, getPhoneIdFromSubId(subId));
                 if (carrierPackages != null && carrierPackages.size() == 1) {
                     LocalServices.getService(UriGrantsManagerInternal.class)
                             .grantUriPermissionFromIntent(callingUid, carrierPackages.get(0),
@@ -539,4 +542,13 @@
             return contentUri;
         }
     }
+
+    private int getPhoneIdFromSubId(int subId) {
+        SubscriptionManager subManager = (SubscriptionManager)
+                mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+        if (subManager == null) return INVALID_SIM_SLOT_INDEX;
+        SubscriptionInfo info = subManager.getActiveSubscriptionInfo(subId);
+        if (info == null) return INVALID_SIM_SLOT_INDEX;
+        return info.getSimSlotIndex();
+    }
 }
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
index b0b45f4..39be311 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
@@ -35,11 +35,11 @@
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.provider.Settings;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.util.NtpTrustedTime;
 import android.util.TimeUtils;
 
-import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.util.DumpUtils;
 
 import java.io.FileDescriptor;
@@ -137,7 +137,7 @@
 
     private void registerForTelephonyIntents() {
         IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
+        intentFilter.addAction(TelephonyManager.ACTION_NETWORK_SET_TIME);
         mContext.registerReceiver(mNitzReceiver, intentFilter);
     }
 
@@ -247,7 +247,7 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             if (DBG) Log.d(TAG, "Received " + action);
-            if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
+            if (TelephonyManager.ACTION_NETWORK_SET_TIME.equals(action)) {
                 mNitzTimeSetTime = SystemClock.elapsedRealtime();
             }
         }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 5a78036..22fa8ff4 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -144,6 +144,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.server.pm.Installer;
 import com.android.server.storage.AppFuseBridge;
 import com.android.server.storage.StorageSessionController;
 import com.android.server.storage.StorageSessionController.ExternalStorageServiceException;
@@ -367,6 +368,8 @@
 
     private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
 
+    private final Installer mInstaller;
+
     /** Holding lock for AppFuse business */
     private final Object mAppFuseLock = new Object();
 
@@ -1245,6 +1248,13 @@
                     vol.state = newState;
                     onVolumeStateChangedLocked(vol, oldState, newState);
                 }
+                try {
+                    if (vol.type == VolumeInfo.TYPE_PRIVATE && state == VolumeInfo.STATE_MOUNTED) {
+                        mInstaller.onPrivateVolumeMounted(vol.getFsUuid());
+                    }
+                } catch (Installer.InstallerException e) {
+                    Slog.i(TAG, "Failed when private volume mounted " + vol, e);
+                }
             }
         }
 
@@ -1290,6 +1300,13 @@
 
             if (vol != null) {
                 mStorageSessionController.onVolumeRemove(vol);
+                try {
+                    if (vol.type == VolumeInfo.TYPE_PRIVATE) {
+                        mInstaller.onPrivateVolumeRemoved(vol.getFsUuid());
+                    }
+                } catch (Installer.InstallerException e) {
+                    Slog.i(TAG, "Failed when private volume unmounted " + vol, e);
+                }
             }
         }
     };
@@ -1601,6 +1618,9 @@
 
         mStorageSessionController = new StorageSessionController(mContext, mIsFuseEnabled);
 
+        mInstaller = new Installer(mContext);
+        mInstaller.onStart();
+
         // Initialize the last-fstrim tracking if necessary
         File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
@@ -1974,6 +1994,13 @@
         try {
             mVold.unmount(vol.id);
             mStorageSessionController.onVolumeUnmount(vol);
+            try {
+                if (vol.type == VolumeInfo.TYPE_PRIVATE) {
+                    mInstaller.onPrivateVolumeRemoved(vol.getFsUuid());
+                }
+            } catch (Installer.InstallerException e) {
+                Slog.e(TAG, "Failed unmount mirror data", e);
+            }
         } catch (Exception e) {
             Slog.wtf(TAG, e);
         }
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index 5e659b6..c5409f8 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -29,6 +29,10 @@
 
 import com.android.server.pm.UserManagerService;
 
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * The base class for services running in the system process. Override and implement
  * the lifecycle event callback methods as needed.
@@ -164,6 +168,25 @@
     }
 
     /**
+     * Helper method used to dump which users are {@link #onStartUser(UserInfo) supported}.
+     */
+    protected void dumpSupportedUsers(@NonNull PrintWriter pw, @NonNull String prefix) {
+        final List<UserInfo> allUsers = UserManager.get(mContext).getUsers();
+        final List<Integer> supportedUsers = new ArrayList<>(allUsers.size());
+        for (UserInfo user : allUsers) {
+            supportedUsers.add(user.id);
+        }
+        if (allUsers.isEmpty()) {
+            pw.print(prefix); pw.println("No supported users");
+        } else {
+            final int size = supportedUsers.size();
+            pw.print(prefix); pw.print(size); pw.print(" supported user");
+            if (size > 1) pw.print("s");
+            pw.print(": "); pw.println(supportedUsers);
+        }
+    }
+
+    /**
      * @deprecated subclasses should extend {@link #onStartUser(UserInfo)} instead (which by default
      * calls this method).
      */
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 0e144ed..13eb556 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
 import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
 import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_DATA;
 import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_VOICE;
@@ -58,6 +59,7 @@
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
@@ -96,7 +98,7 @@
  * and 15973975 by saving the phoneId of the registrant and then using the
  * phoneId when deciding to to make a callback. This is necessary because
  * a subId changes from to a dummy value when a SIM is removed and thus won't
- * compare properly. Because SubscriptionManager.getPhoneId(int subId) handles
+ * compare properly. Because getPhoneIdFromSubId(int subId) handles
  * the dummy value conversion we properly do the callbacks.
  *
  * Eventually we may want to remove the notion of dummy value but for now this
@@ -130,7 +132,7 @@
 
         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
-        int phoneId = SubscriptionManager.INVALID_PHONE_INDEX;
+        int phoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
 
         boolean matchPhoneStateListenerEvent(int events) {
             return (callback != null) && ((events & this.events) != 0);
@@ -228,7 +230,7 @@
 
     private int mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
-    private int mDefaultPhoneId = SubscriptionManager.INVALID_PHONE_INDEX;
+    private int mDefaultPhoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
 
     private int[] mRingingCallState;
 
@@ -357,7 +359,7 @@
                         SubscriptionManager.getDefaultSubscriptionId());
                 int newDefaultPhoneId = intent.getIntExtra(
                         SubscriptionManager.EXTRA_SLOT_INDEX,
-                        SubscriptionManager.getPhoneId(newDefaultSubId));
+                        getPhoneIdFromSubId(newDefaultSubId));
                 if (DBG) {
                     log("onReceive:current mDefaultSubId=" + mDefaultSubId
                             + " current mDefaultPhoneId=" + mDefaultPhoneId
@@ -763,7 +765,7 @@
                 return;
             }
 
-            int phoneId = SubscriptionManager.getPhoneId(subId);
+            int phoneId = getPhoneIdFromSubId(subId);
             synchronized (mRecords) {
                 // register
                 IBinder b = callback.asBinder();
@@ -1090,7 +1092,7 @@
         // Called only by Telecomm to communicate call state across different phone accounts. So
         // there is no need to add a valid subId or slotId.
         broadcastCallStateChanged(state, phoneNumber,
-                SubscriptionManager.INVALID_PHONE_INDEX,
+                SubscriptionManager.INVALID_SIM_SLOT_INDEX,
                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
     }
 
@@ -1315,7 +1317,7 @@
         synchronized (mRecords) {
             mCarrierNetworkChangeState = active;
             for (int subId : subIds) {
-                int phoneId = SubscriptionManager.getPhoneId(subId);
+                int phoneId = getPhoneIdFromSubId(subId);
 
                 if (VDBG) {
                     log("notifyCarrierNetworkChange: active=" + active + "subId: " + subId);
@@ -1348,7 +1350,7 @@
             log("notifyCellInfoForSubscriber: subId=" + subId
                 + " cellInfo=" + cellInfo);
         }
-        int phoneId = SubscriptionManager.getPhoneId(subId);
+        int phoneId = getPhoneIdFromSubId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mCellInfo.set(phoneId, cellInfo);
@@ -1439,7 +1441,7 @@
             log("notifyCallForwardingChangedForSubscriber: subId=" + subId
                 + " cfi=" + cfi);
         }
-        int phoneId = SubscriptionManager.getPhoneId(subId);
+        int phoneId = getPhoneIdFromSubId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mCallForwarding[phoneId] = cfi;
@@ -1467,7 +1469,7 @@
         if (!checkNotifyPermission("notifyDataActivity()" )) {
             return;
         }
-        int phoneId = SubscriptionManager.getPhoneId(subId);
+        int phoneId = getPhoneIdFromSubId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mDataActivity[phoneId] = state;
@@ -1641,7 +1643,7 @@
             log("notifyCellLocationForSubscriber: subId=" + subId
                 + " cellLocation=" + cellLocation);
         }
-        int phoneId = SubscriptionManager.getPhoneId(subId);
+        int phoneId = getPhoneIdFromSubId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mCellLocation[phoneId] = cellLocation;
@@ -1750,7 +1752,7 @@
         if (!checkNotifyPermission("notifyImsCallDisconnectCause()")) {
             return;
         }
-        int phoneId = SubscriptionManager.getPhoneId(subId);
+        int phoneId = getPhoneIdFromSubId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mImsReasonInfo.set(phoneId, imsReasonInfo);
@@ -1817,7 +1819,7 @@
         if (VDBG) {
             log("notifySrvccStateChanged: subId=" + subId + " srvccState=" + state);
         }
-        int phoneId = SubscriptionManager.getPhoneId(subId);
+        int phoneId = getPhoneIdFromSubId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mSrvccState[phoneId] = state;
@@ -2223,7 +2225,7 @@
             intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
         }
         // If the phoneId is invalid, the broadcast is for overall call state.
-        if (phoneId != SubscriptionManager.INVALID_PHONE_INDEX) {
+        if (phoneId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
             intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
             intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
         }
@@ -2680,4 +2682,18 @@
     private static CallQuality createCallQuality() {
         return new CallQuality(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
     }
+
+    private int getPhoneIdFromSubId(int subId) {
+        SubscriptionManager subManager = (SubscriptionManager)
+                mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+        if (subManager == null) return INVALID_SIM_SLOT_INDEX;
+
+        if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
+            subId = SubscriptionManager.getDefaultSubscriptionId();
+        }
+
+        SubscriptionInfo info = subManager.getActiveSubscriptionInfo(subId);
+        if (info == null) return INVALID_SIM_SLOT_INDEX;
+        return info.getSimSlotIndex();
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f1cee034..1852e01 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -158,7 +158,6 @@
 import android.app.ApplicationThreadConstants;
 import android.app.BroadcastOptions;
 import android.app.ContentProviderHolder;
-import android.app.Dialog;
 import android.app.IActivityController;
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
@@ -957,10 +956,12 @@
             new DeviceConfig.OnPropertiesChangedListener() {
                 @Override
                 public void onPropertiesChanged(Properties properties) {
-                    mPssDeferralTime = properties.getLong(ACTIVITY_START_PSS_DEFER_CONFIG, 0);
-                    if (DEBUG_PSS) {
-                        Slog.d(TAG_PSS, "Activity-start PSS delay now "
-                                + mPssDeferralTime + " ms");
+                    if (properties.getKeyset().contains(ACTIVITY_START_PSS_DEFER_CONFIG)) {
+                        mPssDeferralTime = properties.getLong(ACTIVITY_START_PSS_DEFER_CONFIG, 0);
+                        if (DEBUG_PSS) {
+                            Slog.d(TAG_PSS, "Activity-start PSS delay now "
+                                    + mPssDeferralTime + " ms");
+                        }
                     }
                 }
             };
@@ -1619,82 +1620,72 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-            case SHOW_ERROR_UI_MSG: {
-                mAppErrors.handleShowAppErrorUi(msg);
-                ensureBootCompleted();
-            } break;
-            case SHOW_NOT_RESPONDING_UI_MSG: {
-                mAppErrors.handleShowAnrUi(msg);
-                ensureBootCompleted();
-            } break;
-            case SHOW_STRICT_MODE_VIOLATION_UI_MSG: {
-                HashMap<String, Object> data = (HashMap<String, Object>) msg.obj;
-                synchronized (ActivityManagerService.this) {
-                    ProcessRecord proc = (ProcessRecord) data.get("app");
-                    if (proc == null) {
-                        Slog.e(TAG, "App not found when showing strict mode dialog.");
-                        break;
-                    }
-                    if (proc.crashDialog != null) {
-                        Slog.e(TAG, "App already has strict mode dialog: " + proc);
-                        return;
-                    }
-                    AppErrorResult res = (AppErrorResult) data.get("result");
-                    if (mAtmInternal.showStrictModeViolationDialog()) {
-                        Dialog d = new StrictModeViolationDialog(mUiContext,
-                                ActivityManagerService.this, res, proc);
-                        d.show();
-                        proc.crashDialog = d;
-                    } else {
-                        // The device is asleep, so just pretend that the user
-                        // saw a crash dialog and hit "force quit".
-                        res.set(0);
-                    }
-                }
-                ensureBootCompleted();
-            } break;
-            case WAIT_FOR_DEBUGGER_UI_MSG: {
-                synchronized (ActivityManagerService.this) {
-                    ProcessRecord app = (ProcessRecord)msg.obj;
-                    if (msg.arg1 != 0) {
-                        if (!app.waitedForDebugger) {
-                            Dialog d = new AppWaitingForDebuggerDialog(
-                                    ActivityManagerService.this,
-                                    mUiContext, app);
-                            app.waitDialog = d;
-                            app.waitedForDebugger = true;
-                            d.show();
+                case SHOW_ERROR_UI_MSG: {
+                    mAppErrors.handleShowAppErrorUi(msg);
+                    ensureBootCompleted();
+                } break;
+                case SHOW_NOT_RESPONDING_UI_MSG: {
+                    mAppErrors.handleShowAnrUi(msg);
+                    ensureBootCompleted();
+                } break;
+                case SHOW_STRICT_MODE_VIOLATION_UI_MSG: {
+                    HashMap<String, Object> data = (HashMap<String, Object>) msg.obj;
+                    synchronized (ActivityManagerService.this) {
+                        ProcessRecord proc = (ProcessRecord) data.get("app");
+                        if (proc == null) {
+                            Slog.e(TAG, "App not found when showing strict mode dialog.");
+                            break;
                         }
-                    } else {
-                        if (app.waitDialog != null) {
-                            app.waitDialog.dismiss();
-                            app.waitDialog = null;
+                        if (proc.getDialogController().hasViolationDialogs()) {
+                            Slog.e(TAG, "App already has strict mode dialog: " + proc);
+                            return;
+                        }
+                        AppErrorResult res = (AppErrorResult) data.get("result");
+                        if (mAtmInternal.showStrictModeViolationDialog()) {
+                            proc.getDialogController().showViolationDialogs(res);
+                        } else {
+                            // The device is asleep, so just pretend that the user
+                            // saw a crash dialog and hit "force quit".
+                            res.set(0);
                         }
                     }
+                    ensureBootCompleted();
+                } break;
+                case WAIT_FOR_DEBUGGER_UI_MSG: {
+                    synchronized (ActivityManagerService.this) {
+                        ProcessRecord app = (ProcessRecord) msg.obj;
+                        if (msg.arg1 != 0) {
+                            if (!app.waitedForDebugger) {
+                                app.getDialogController().showDebugWaitingDialogs();
+                                app.waitedForDebugger = true;
+                            }
+                        } else {
+                            app.getDialogController().clearWaitingDialog();
+                        }
+                    }
+                } break;
+                case DISPATCH_PROCESSES_CHANGED_UI_MSG: {
+                    dispatchProcessesChanged();
+                    break;
                 }
-            } break;
-            case DISPATCH_PROCESSES_CHANGED_UI_MSG: {
-                dispatchProcessesChanged();
-                break;
-            }
-            case DISPATCH_PROCESS_DIED_UI_MSG: {
-                final int pid = msg.arg1;
-                final int uid = msg.arg2;
-                dispatchProcessDied(pid, uid);
-                break;
-            }
-            case DISPATCH_UIDS_CHANGED_UI_MSG: {
-                if (false) { // DO NOT SUBMIT WITH TRUE
-                    maybeTriggerWatchdog();
+                case DISPATCH_PROCESS_DIED_UI_MSG: {
+                    final int pid = msg.arg1;
+                    final int uid = msg.arg2;
+                    dispatchProcessDied(pid, uid);
+                    break;
                 }
-                dispatchUidsChanged();
-            } break;
-            case DISPATCH_OOM_ADJ_OBSERVER_MSG: {
-                dispatchOomAdjObserver((String)msg.obj);
-            } break;
-            case PUSH_TEMP_WHITELIST_UI_MSG: {
-                pushTempWhitelist();
-            } break;
+                case DISPATCH_UIDS_CHANGED_UI_MSG: {
+                    if (false) { // DO NOT SUBMIT WITH TRUE
+                        maybeTriggerWatchdog();
+                    }
+                    dispatchUidsChanged();
+                } break;
+                case DISPATCH_OOM_ADJ_OBSERVER_MSG: {
+                    dispatchOomAdjObserver((String) msg.obj);
+                } break;
+                case PUSH_TEMP_WHITELIST_UI_MSG: {
+                    pushTempWhitelist();
+                } break;
             }
         }
     }
@@ -9379,9 +9370,9 @@
         }
     }
 
-    void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) {
+    void killAppAtUsersRequest(ProcessRecord app) {
         synchronized (this) {
-            mAppErrors.killAppAtUserRequestLocked(app, fromDialog);
+            mAppErrors.killAppAtUserRequestLocked(app);
         }
     }
 
@@ -14006,18 +13997,7 @@
         ProcessList.abortNextPssTime(app.procStateMemTracker);
 
         // Dismiss any open dialogs.
-        if (app.crashDialog != null && !app.forceCrashReport) {
-            app.crashDialog.dismiss();
-            app.crashDialog = null;
-        }
-        if (app.anrDialog != null) {
-            app.anrDialog.dismiss();
-            app.anrDialog = null;
-        }
-        if (app.waitDialog != null) {
-            app.waitDialog.dismiss();
-            app.waitDialog = null;
-        }
+        app.getDialogController().clearAllErrorDialogs();
 
         app.setCrashing(false);
         app.setNotResponding(false);
diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index 852c9b65..d76e2d7 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -167,8 +167,10 @@
 
     private void setResult(int result) {
         synchronized (mService) {
-            if (mProc != null && mProc.crashDialog == AppErrorDialog.this) {
-                mProc.crashDialog = null;
+            if (mProc != null) {
+                // Don't dismiss again since it leads to recursive call between dismiss and this
+                // method.
+                mProc.getDialogController().clearCrashDialogs(false /* needDismiss */);
             }
         }
         mResult.set(result);
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 83a7341..c380726 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -29,7 +29,6 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ApplicationErrorReport;
-import android.app.Dialog;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
@@ -313,13 +312,8 @@
         }
     }
 
-    void killAppAtUserRequestLocked(ProcessRecord app, Dialog fromDialog) {
-        if (app.anrDialog == fromDialog) {
-            app.anrDialog = null;
-        }
-        if (app.waitDialog == fromDialog) {
-            app.waitDialog = null;
-        }
+    void killAppAtUserRequestLocked(ProcessRecord app) {
+        app.getDialogController().clearAllErrorDialogs();
         killAppImmediateLocked(app, "user-terminated", "user request after error");
     }
 
@@ -795,7 +789,6 @@
         boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
 
-        AppErrorDialog dialogToShow = null;
         final String packageName;
         final int userId;
         synchronized (mService) {
@@ -807,7 +800,7 @@
             }
             packageName = proc.info.packageName;
             userId = proc.userId;
-            if (proc.crashDialog != null) {
+            if (proc.getDialogController().hasCrashDialogs()) {
                 Slog.e(TAG, "App already has crash dialog: " + proc);
                 if (res != null) {
                     res.set(AppErrorDialog.ALREADY_SHOWING);
@@ -840,7 +833,7 @@
             if ((mService.mAtmInternal.canShowErrorDialogs() || showBackground)
                     && !crashSilenced
                     && (showFirstCrash || showFirstCrashDevOption || data.repeating)) {
-                proc.crashDialog = dialogToShow = new AppErrorDialog(mContext, mService, data);
+                proc.getDialogController().showCrashDialogs(data);
             } else {
                 // The device is asleep, so just pretend that the user
                 // saw a crash dialog and hit "force quit".
@@ -849,11 +842,6 @@
                 }
             }
         }
-        // If we've created a crash dialog, show it without the lock held
-        if (dialogToShow != null) {
-            Slog.i(TAG, "Showing crash dialog for package " + packageName + " u" + userId);
-            dialogToShow.show();
-        }
     }
 
     private void stopReportingCrashesLocked(ProcessRecord proc) {
@@ -864,7 +852,6 @@
     }
 
     void handleShowAnrUi(Message msg) {
-        Dialog dialogToShow = null;
         List<VersionedPackage> packageList = null;
         synchronized (mService) {
             AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj;
@@ -876,7 +863,7 @@
             if (!proc.isPersistent()) {
                 packageList = proc.getPackageListWithVersionCode();
             }
-            if (proc.anrDialog != null) {
+            if (proc.getDialogController().hasAnrDialogs()) {
                 Slog.e(TAG, "App already has anr dialog: " + proc);
                 MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
                         AppNotRespondingDialog.ALREADY_SHOWING);
@@ -886,19 +873,14 @@
             boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
                     Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
             if (mService.mAtmInternal.canShowErrorDialogs() || showBackground) {
-                dialogToShow = new AppNotRespondingDialog(mService, mContext, data);
-                proc.anrDialog = dialogToShow;
+                proc.getDialogController().showAnrDialogs(data);
             } else {
                 MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
                         AppNotRespondingDialog.CANT_SHOW);
                 // Just kill the app if there is no dialog to be shown.
-                mService.killAppAtUsersRequest(proc, null);
+                mService.killAppAtUsersRequest(proc);
             }
         }
-        // If we've created a crash dialog, show it without the lock held
-        if (dialogToShow != null) {
-            dialogToShow.show();
-        }
         // Notify PackageWatchdog without the lock held
         if (packageList != null) {
             mPackageWatchdog.onPackageFailure(packageList,
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index 65d7e01..dac5325 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -16,13 +16,10 @@
 
 package com.android.server.am;
 
-import android.content.pm.ApplicationInfo;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
-
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.Handler;
@@ -35,6 +32,9 @@
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+
 final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnClickListener {
     private static final String TAG = "AppNotRespondingDialog";
 
@@ -145,7 +145,7 @@
             switch (msg.what) {
                 case FORCE_CLOSE:
                     // Kill the application.
-                    mService.killAppAtUsersRequest(mProc, AppNotRespondingDialog.this);
+                    mService.killAppAtUsersRequest(mProc);
                     break;
                 case WAIT_AND_REPORT:
                 case WAIT:
@@ -160,9 +160,7 @@
 
                         app.setNotResponding(false);
                         app.notRespondingReport = null;
-                        if (app.anrDialog == AppNotRespondingDialog.this) {
-                            app.anrDialog = null;
-                        }
+                        app.getDialogController().clearAnrDialogs();
                         mService.mServices.scheduleServiceTimeoutLocked(app);
                     }
                     break;
diff --git a/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
index 27865a8..3ce2471 100644
--- a/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
+++ b/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
@@ -66,7 +66,7 @@
             switch (msg.what) {
                 case 1:
                     // Kill the application.
-                    mService.killAppAtUsersRequest(mProc, AppWaitingForDebuggerDialog.this);
+                    mService.killAppAtUsersRequest(mProc);
                     break;
             }
         }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index ee06419..557def4 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -59,6 +59,7 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.os.AppZygote;
@@ -78,6 +79,7 @@
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageManagerInternal;
+import android.provider.DeviceConfig;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
@@ -85,6 +87,7 @@
 import android.util.ArrayMap;
 import android.util.EventLog;
 import android.util.LongSparseArray;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -117,6 +120,7 @@
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Activity manager code dealing with processes.
@@ -124,6 +128,13 @@
 public final class ProcessList {
     static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM;
 
+    // A device config to control the minimum target SDK to enable app data isolation
+    static final String ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY =
+            "persist.zygote.app_data_isolation";
+
+    // A device config to control the minimum target SDK to enable app data isolation
+    static final String ANDROID_APP_DATA_ISOLATION_MIN_SDK = "android_app_data_isolation_min_sdk";
+
     // The minimum time we allow between crashes, for us to consider this
     // application to be bad and stop and its services and reject broadcasts.
     static final int MIN_CRASH_INTERVAL = 60 * 1000;
@@ -337,6 +348,8 @@
 
     private boolean mOomLevelsSet = false;
 
+    private boolean mAppDataIsolationEnabled = false;
+
     /**
      * Temporary to avoid allocations.  Protected by main lock.
      */
@@ -621,6 +634,10 @@
         mService = service;
         mActiveUids = activeUids;
         mPlatformCompat = platformCompat;
+        // Get this after boot, and won't be changed until it's rebooted, as we don't
+        // want some apps enabled while some apps disabled
+        mAppDataIsolationEnabled =
+                SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
 
         if (sKillHandler == null) {
             sKillThread = new ServiceThread(TAG + ":kill",
@@ -1853,6 +1870,32 @@
         }
     }
 
+    private boolean shouldIsolateAppData(ProcessRecord app) {
+        if (!mAppDataIsolationEnabled) {
+            return false;
+        }
+        if (!UserHandle.isApp(app.uid)) {
+            return false;
+        }
+        final int minTargetSdk = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                ANDROID_APP_DATA_ISOLATION_MIN_SDK, Build.VERSION_CODES.R);
+        return app.info.targetSdkVersion >= minTargetSdk;
+    }
+
+    private Map<String, Pair<String, Long>> getPackageAppDataInfoMap(PackageManagerInternal pmInt,
+            String[] packages, int uid) {
+        Map<String, Pair<String, Long>> result = new ArrayMap<>(packages.length);
+        int userId = UserHandle.getUserId(uid);
+        for (String packageName : packages) {
+            String volumeUuid = pmInt.getPackage(packageName).getVolumeUuid();
+            long inode = pmInt.getCeDataInode(packageName, userId);
+            if (inode != 0) {
+                result.put(packageName, Pair.create(volumeUuid, inode));
+            }
+        }
+        return result;
+    }
+
     private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
             ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
             String seInfo, String requiredAbi, String instructionSet, String invokeWith,
@@ -1869,6 +1912,21 @@
                 app.setHasForegroundActivities(true);
             }
 
+            final Map<String, Pair<String, Long>> pkgDataInfoMap;
+
+            if (shouldIsolateAppData(app)) {
+                // Get all packages belongs to the same shared uid. sharedPackages is empty array
+                // if it doesn't have shared uid.
+                final PackageManagerInternal pmInt = mService.getPackageManagerInternalLocked();
+                final String sharedUserId = pmInt.getSharedUserIdForPackage(app.info.packageName);
+                final String[] sharedPackages = pmInt.getPackagesForSharedUserId(sharedUserId,
+                        app.userId);
+                pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, sharedPackages.length == 0
+                        ? new String[]{app.info.packageName} : sharedPackages, uid);
+            } else {
+                pkgDataInfoMap = null;
+            }
+
             final Process.ProcessStartResult startResult;
             if (hostingRecord.usesWebviewZygote()) {
                 startResult = startWebView(entryPoint,
@@ -1884,13 +1942,13 @@
                         app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                         app.info.dataDir, null, app.info.packageName,
                         /*useUsapPool=*/ false, isTopApp, app.mDisabledCompatChanges,
-                        new String[]{PROC_START_SEQ_IDENT + app.startSeq});
+                        pkgDataInfoMap, new String[]{PROC_START_SEQ_IDENT + app.startSeq});
             } else {
                 startResult = Process.start(entryPoint,
                         app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                         app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                         app.info.dataDir, invokeWith, app.info.packageName, isTopApp,
-                        app.mDisabledCompatChanges,
+                        app.mDisabledCompatChanges, pkgDataInfoMap,
                         new String[]{PROC_START_SEQ_IDENT + app.startSeq});
             }
             checkSlow(startTime, "startProcess: returned from zygote!");
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 24fc743..1fef353 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -62,6 +62,8 @@
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.ProcessCpuTracker;
 import com.android.internal.os.Zygote;
+import com.android.server.LocalServices;
+import com.android.server.wm.WindowManagerInternal;
 import com.android.server.wm.WindowProcessController;
 import com.android.server.wm.WindowProcessListener;
 
@@ -70,6 +72,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * Full information about a particular process that
@@ -246,6 +249,8 @@
     Debug.MemoryInfo lastMemInfo;
     long lastMemInfoTime;
 
+    // Controller for error dialogs
+    private final ErrorDialogController mDialogController = new ErrorDialogController();
     // Controller for driving the process state on the window manager side.
     final private WindowProcessController mWindowProcessController;
     // all ServiceRecord running in this process
@@ -272,16 +277,13 @@
     boolean execServicesFg;     // do we need to be executing services in the foreground?
     private boolean mPersistent;// always keep this application running?
     private boolean mCrashing;  // are we in the process of crashing?
-    Dialog crashDialog;         // dialog being displayed due to crash.
     boolean forceCrashReport;   // suppress normal auto-dismiss of crash dialog & report UI?
     private boolean mNotResponding; // does the app have a not responding dialog?
-    Dialog anrDialog;           // dialog being displayed due to app not resp.
     volatile boolean removed;   // Whether this process should be killed and removed from process
                                 // list. It is set when the package is force-stopped or the process
                                 // has crashed too many times.
     private boolean mDebugging; // was app launched for debugging?
     boolean waitedForDebugger;  // has process show wait for debugger dialog?
-    Dialog waitDialog;          // current wait for debugger dialog
 
     String shortStringName;     // caching of toShortString() result.
     String stringName;          // caching of toString() result.
@@ -518,21 +520,21 @@
                     pw.print(" killedByAm="); pw.print(killedByAm);
                     pw.print(" waitingToKill="); pw.println(waitingToKill);
         }
-        if (mDebugging || mCrashing || crashDialog != null || mNotResponding
-                || anrDialog != null || bad) {
+        if (mDebugging || mCrashing || mDialogController.hasCrashDialogs() || mNotResponding
+                || mDialogController.hasAnrDialogs() || bad) {
             pw.print(prefix); pw.print("mDebugging="); pw.print(mDebugging);
-                    pw.print(" mCrashing="); pw.print(mCrashing);
-                    pw.print(" "); pw.print(crashDialog);
-                    pw.print(" mNotResponding="); pw.print(mNotResponding);
-                    pw.print(" " ); pw.print(anrDialog);
-                    pw.print(" bad="); pw.print(bad);
+            pw.print(" mCrashing=" + mCrashing);
+            pw.print(" " + mDialogController.mCrashDialogs);
+            pw.print(" mNotResponding=" + mNotResponding);
+            pw.print(" " + mDialogController.mAnrDialogs);
+            pw.print(" bad=" + bad);
 
-                    // mCrashing or mNotResponding is always set before errorReportReceiver
-                    if (errorReportReceiver != null) {
-                        pw.print(" errorReportReceiver=");
-                        pw.print(errorReportReceiver.flattenToShortString());
-                    }
-                    pw.println();
+            // mCrashing or mNotResponding is always set before errorReportReceiver
+            if (errorReportReceiver != null) {
+                pw.print(" errorReportReceiver=");
+                pw.print(errorReportReceiver.flattenToShortString());
+            }
+            pw.println();
         }
         if (whitelistManager) {
             pw.print(prefix); pw.print("whitelistManager="); pw.println(whitelistManager);
@@ -1775,4 +1777,153 @@
             mCachedAdj += minLayer;
         }
     }
+
+    ErrorDialogController getDialogController() {
+        return mDialogController;
+    }
+
+    /** A controller to generate error dialogs in {@link ProcessRecord} */
+    class ErrorDialogController {
+        /** dialogs being displayed due to crash */
+        private List<AppErrorDialog> mCrashDialogs;
+        /** dialogs being displayed due to app not responding */
+        private List<AppNotRespondingDialog> mAnrDialogs;
+        /** dialogs displayed due to strict mode violation */
+        private List<StrictModeViolationDialog> mViolationDialogs;
+        /** current wait for debugger dialog */
+        private AppWaitingForDebuggerDialog mWaitDialog;
+
+        private final WindowManagerInternal mWmInternal =
+                LocalServices.getService(WindowManagerInternal.class);
+
+        boolean hasCrashDialogs() {
+            return mCrashDialogs != null;
+        }
+
+        boolean hasAnrDialogs() {
+            return mAnrDialogs != null;
+        }
+
+        boolean hasViolationDialogs() {
+            return mViolationDialogs != null;
+        }
+
+        boolean hasDebugWaitingDialog() {
+            return mWaitDialog != null;
+        }
+
+        void clearAllErrorDialogs() {
+            clearCrashDialogs();
+            clearAnrDialogs();
+            clearViolationDialogs();
+            clearWaitingDialog();
+        }
+
+        void clearCrashDialogs() {
+            clearCrashDialogs(true /* needDismiss */);
+        }
+
+        void clearCrashDialogs(boolean needDismiss) {
+            if (mCrashDialogs == null) {
+                return;
+            }
+            if (needDismiss) {
+                forAllDialogs(mCrashDialogs, Dialog::dismiss);
+            }
+            mCrashDialogs = null;
+        }
+
+        void clearAnrDialogs() {
+            if (mAnrDialogs == null) {
+                return;
+            }
+            forAllDialogs(mAnrDialogs, Dialog::dismiss);
+            mAnrDialogs = null;
+        }
+
+        void clearViolationDialogs() {
+            if (mViolationDialogs == null) {
+                return;
+            }
+            forAllDialogs(mViolationDialogs, Dialog::dismiss);
+            mViolationDialogs = null;
+        }
+
+        void clearWaitingDialog() {
+            if (mWaitDialog == null) {
+                return;
+            }
+            mWaitDialog.dismiss();
+            mWaitDialog = null;
+        }
+
+        void forAllDialogs(List<? extends BaseErrorDialog> dialogs,
+                Consumer<BaseErrorDialog> c) {
+            for (int i = dialogs.size() - 1; i >= 0; i--) {
+                c.accept(dialogs.get(i));
+            }
+        }
+
+        void showCrashDialogs(AppErrorDialog.Data data) {
+            List<Context> contexts = getDisplayContexts(false /* lastUsedOnly */);
+            mCrashDialogs = new ArrayList<>();
+
+            for (int i = contexts.size() - 1; i >= 0; i--) {
+                final Context c = contexts.get(i);
+                mCrashDialogs.add(new AppErrorDialog(c, mService, data));
+            }
+            mService.mUiHandler.post(() -> mCrashDialogs.forEach(Dialog::show));
+        }
+
+        void showAnrDialogs(AppNotRespondingDialog.Data data) {
+            List<Context> contexts = getDisplayContexts(isSilentAnr() /* lastUsedOnly */);
+            mAnrDialogs = new ArrayList<>();
+
+            for (int i = contexts.size() - 1; i >= 0; i--) {
+                final Context c = contexts.get(i);
+                mAnrDialogs.add(new AppNotRespondingDialog(mService, c, data));
+            }
+            mService.mUiHandler.post(() -> mAnrDialogs.forEach(Dialog::show));
+        }
+
+        void showViolationDialogs(AppErrorResult res) {
+            List<Context> contexts = getDisplayContexts(false /* lastUsedOnly */);
+            mViolationDialogs = new ArrayList<>();
+
+            for (int i = contexts.size() - 1; i >= 0; i--) {
+                final Context c = contexts.get(i);
+                mViolationDialogs.add(
+                        new StrictModeViolationDialog(c, mService, res, ProcessRecord.this));
+            }
+            mService.mUiHandler.post(() -> mViolationDialogs.forEach(Dialog::show));
+        }
+
+        void showDebugWaitingDialogs() {
+            List<Context> contexts = getDisplayContexts(true /* lastUsedOnly */);
+            final Context c = contexts.get(0);
+            mWaitDialog = new AppWaitingForDebuggerDialog(mService, c, ProcessRecord.this);
+            mService.mUiHandler.post(() -> mWaitDialog.show());
+        }
+
+        /**
+         * Helper function to collect contexts from crashed app located displays
+         *
+         * @param lastUsedOnly Sets to {@code true} to indicate to only get last used context.
+         *                     Sets to {@code false} to collect contexts from crashed app located
+         *                     displays.
+         *
+         * @return display context list
+         */
+        private List<Context> getDisplayContexts(boolean lastUsedOnly) {
+            List<Context> displayContexts = new ArrayList<>();
+            if (!lastUsedOnly) {
+                mWindowProcessController.getDisplayContextsWithErrorDialogs(displayContexts);
+            }
+            // If there is no foreground window display, fallback to last used display.
+            if (displayContexts.isEmpty() || lastUsedOnly) {
+                displayContexts.add(mWmInternal.getTopFocusedDisplayUiContext());
+            }
+            return displayContexts;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/StrictModeViolationDialog.java b/services/core/java/com/android/server/am/StrictModeViolationDialog.java
index 6da84bd..783f150 100644
--- a/services/core/java/com/android/server/am/StrictModeViolationDialog.java
+++ b/services/core/java/com/android/server/am/StrictModeViolationDialog.java
@@ -85,8 +85,8 @@
     private final Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
             synchronized (mService) {
-                if (mProc != null && mProc.crashDialog == StrictModeViolationDialog.this) {
-                    mProc.crashDialog = null;
+                if (mProc != null) {
+                    mProc.getDialogController().clearViolationDialogs();
                 }
             }
             mResult.set(msg.what);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index df56004..352d0d5 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -125,7 +125,7 @@
                     + " codec: " + Integer.toHexString(mDeviceCodecFormat) + "]";
         }
 
-        String getKey() {
+        @NonNull String getKey() {
             return makeDeviceListKey(mDeviceType, mDeviceAddress);
         }
 
@@ -133,7 +133,7 @@
          * Generate a unique key for the mConnectedDevices List by composing the device "type"
          * and the "address" associated with a specific instance of that device type
          */
-        private static String makeDeviceListKey(int device, String deviceAddress) {
+        @NonNull private static String makeDeviceListKey(int device, String deviceAddress) {
             return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
         }
     }
@@ -726,8 +726,8 @@
                 DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
 
         mConnectedDevices.remove(deviceToRemoveKey);
-        if (!mApmConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)
-                .equals(deviceToRemoveKey)) {
+        if (!deviceToRemoveKey
+                .equals(mApmConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP))) {
             // removing A2DP device not currently used by AudioPolicy, log but don't act on it
             AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
                     "A2DP device " + address + " made unavailable, was not used")).printLog(TAG));
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 0f51e39..e1a9f3b 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -28,6 +28,7 @@
 import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.app.UserSwitchObserver;
+import android.app.admin.DevicePolicyManager;
 import android.app.trust.ITrustManager;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -210,6 +211,7 @@
     }
 
     private final Injector mInjector;
+    private final DevicePolicyManager mDevicePolicyManager;
     @VisibleForTesting
     final IBiometricService.Stub mImpl;
     @VisibleForTesting
@@ -648,6 +650,10 @@
                 throw new SecurityException("Invalid authenticator configuration");
             }
 
+            if (bundle.getBoolean(BiometricPrompt.EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS)) {
+                checkInternalPermission();
+            }
+
             Utils.combineAuthenticatorBundles(bundle);
 
             // Check the usage of this in system server. Need to remove this check if it becomes a
@@ -712,8 +718,8 @@
             int biometricConstantsResult = BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE;
             final long ident = Binder.clearCallingIdentity();
             try {
-                biometricConstantsResult =
-                        checkAndGetAuthenticators(userId, bundle, opPackageName).second;
+                biometricConstantsResult = checkAndGetAuthenticators(userId, bundle, opPackageName,
+                        false /* checkDevicePolicyManager */).second;
                 if (biometricConstantsResult != BiometricConstants.BIOMETRIC_SUCCESS
                         && Utils.isDeviceCredentialAllowed(bundle)) {
                     // If there's an issue with biometrics, but device credential is allowed and
@@ -947,6 +953,8 @@
         super(context);
 
         mInjector = injector;
+        mDevicePolicyManager = (DevicePolicyManager) context
+                .getSystemService(context.DEVICE_POLICY_SERVICE);
         mImpl = new BiometricServiceWrapper();
         mEnabledOnKeyguardCallbacks = new ArrayList<>();
         mSettingObserver = mInjector.getSettingObserver(context, mHandler,
@@ -978,6 +986,42 @@
     }
 
     /**
+     * @param modality one of {@link BiometricAuthenticator#TYPE_FINGERPRINT},
+     * {@link BiometricAuthenticator#TYPE_IRIS} or {@link BiometricAuthenticator#TYPE_FACE}
+     * @return
+     */
+    private int mapModalityToDevicePolicyType(int modality) {
+        switch (modality) {
+            case TYPE_FINGERPRINT:
+                return DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
+            case TYPE_IRIS:
+                return DevicePolicyManager.KEYGUARD_DISABLE_IRIS;
+            case TYPE_FACE:
+                return DevicePolicyManager.KEYGUARD_DISABLE_FACE;
+            default:
+                Slog.e(TAG, "Error modality=" + modality);
+                return DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+        }
+    }
+
+    // TODO(joshmccloskey): Update this to throw an error if a new modality is added and this
+    // logic is not updated.
+    private boolean isBiometricDisabledByDevicePolicy(int modality, int effectiveUserId) {
+        final int biometricToCheck = mapModalityToDevicePolicyType(modality);
+        if (biometricToCheck == DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE) {
+            Slog.e(TAG, "Allowing unknown modality " + modality + " to pass Device Policy check");
+            return false;
+        }
+        final int devicePolicyDisabledFeatures =
+                mDevicePolicyManager.getKeyguardDisabledFeatures(null, effectiveUserId);
+        final boolean isBiometricDisabled =
+                (biometricToCheck & devicePolicyDisabledFeatures) != 0;
+        Slog.w(TAG, "isBiometricDisabledByDevicePolicy(" + modality + "," + effectiveUserId
+                + ")=" + isBiometricDisabled);
+        return isBiometricDisabled;
+    }
+
+    /**
      * Checks if there are any available biometrics, and returns the modality. This method also
      * returns errors through the callback (no biometric feature, hardware not detected, no
      * templates enrolled, etc). This service must not start authentication if errors are sent.
@@ -996,7 +1040,7 @@
      * TODO(kchyn): Update this to handle DEVICE_CREDENTIAL better, reduce duplicate code in callers
      */
     private Pair<Integer, Integer> checkAndGetAuthenticators(int userId, Bundle bundle,
-            String opPackageName) throws RemoteException {
+            String opPackageName, boolean checkDevicePolicyManager) throws RemoteException {
         if (!Utils.isBiometricAllowed(bundle)
                 && Utils.isDeviceCredentialAllowed(bundle)
                 && !mTrustManager.isDeviceSecure(userId)) {
@@ -1033,6 +1077,11 @@
                     }
                     if (authenticator.impl.hasEnrolledTemplates(userId, opPackageName)) {
                         hasTemplatesEnrolled = true;
+                        // If the device policy manager disables a specific biometric, skip it.
+                        if (checkDevicePolicyManager &&
+                                isBiometricDisabledByDevicePolicy(modality, userId)) {
+                            continue;
+                        }
                         if (isEnabledForApp(modality, userId)) {
                             enabledForApps = true;
                             break;
@@ -1043,6 +1092,7 @@
         }
 
         Slog.d(TAG, "checkAndGetAuthenticators: user=" + userId
+                + " checkDevicePolicyManager=" + checkDevicePolicyManager
                 + " isHardwareDetected=" + isHardwareDetected
                 + " hasTemplatesEnrolled=" + hasTemplatesEnrolled
                 + " enabledForApps=" + enabledForApps);
@@ -1502,8 +1552,10 @@
             int result;
 
             try {
+                final boolean checkDevicePolicyManager = bundle.getBoolean(
+                        BiometricPrompt.EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS, false);
                 final Pair<Integer, Integer> pair = checkAndGetAuthenticators(userId, bundle,
-                        opPackageName);
+                        opPackageName, checkDevicePolicyManager);
                 modality = pair.first;
                 result = pair.second;
             } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerService.java b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
index 1b1a292..789551b 100644
--- a/services/core/java/com/android/server/incremental/IncrementalManagerService.java
+++ b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.content.pm.DataLoaderManager;
+import android.content.pm.DataLoaderParamsParcel;
+import android.content.pm.FileSystemControlParcel;
 import android.content.pm.IDataLoader;
 import android.content.pm.IDataLoaderStatusListener;
 import android.os.Bundle;
@@ -27,8 +29,6 @@
 import android.os.ServiceManager;
 import android.os.ShellCallback;
 import android.os.incremental.IIncrementalManager;
-import android.os.incremental.IncrementalDataLoaderParamsParcel;
-import android.os.incremental.IncrementalFileSystemControlParcel;
 import android.util.Slog;
 
 import java.io.FileDescriptor;
@@ -80,8 +80,8 @@
      * Finds data loader service provider and binds to it. This requires PackageManager.
      */
     @Override
-    public boolean prepareDataLoader(int mountId, IncrementalFileSystemControlParcel control,
-            IncrementalDataLoaderParamsParcel params,
+    public boolean prepareDataLoader(int mountId, FileSystemControlParcel control,
+            DataLoaderParamsParcel params,
             IDataLoaderStatusListener listener) {
         Bundle dataLoaderParams = new Bundle();
         dataLoaderParams.putCharSequence("packageName", params.packageName);
@@ -138,10 +138,6 @@
             Slog.e(TAG, "Failed to retrieve data loader for ID=" + mountId);
             return;
         }
-        try {
-            dataLoader.onFileCreated(inode, metadata);
-        } catch (RemoteException ex) {
-        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java b/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java
index d35e806..6a8434a 100644
--- a/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java
+++ b/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java
@@ -24,6 +24,7 @@
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentSender;
+import android.content.pm.DataLoaderParams;
 import android.content.pm.InstallationFile;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
@@ -31,7 +32,6 @@
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.ShellCommand;
-import android.os.incremental.IncrementalDataLoaderParams;
 import android.util.Slog;
 
 import java.io.FileDescriptor;
@@ -111,7 +111,7 @@
             pw.println("File names and sizes don't match.");
             return ERROR_DATA_LOADER_INIT;
         }
-        final IncrementalDataLoaderParams params = new IncrementalDataLoaderParams(
+        final DataLoaderParams params = new DataLoaderParams(
                 "", LOADER_PACKAGE_NAME, dataLoaderDynamicArgs);
         PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
                 PackageInstaller.SessionParams.MODE_FULL_INSTALL);
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index d71ffb7..58f6ba2 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -762,6 +762,7 @@
             if (mUpdatingPackageNames != null) {
                 pw.print("Packages being updated: "); pw.println(mUpdatingPackageNames);
             }
+            dumpSupportedUsers(pw, prefix);
             if (mServiceNameResolver != null) {
                 pw.print(prefix); pw.print("Name resolver: ");
                 mServiceNameResolver.dumpShort(pw); pw.println();
diff --git a/services/core/java/com/android/server/input/ConfigurationProcessor.java b/services/core/java/com/android/server/input/ConfigurationProcessor.java
index 970e86a..3888b1b 100644
--- a/services/core/java/com/android/server/input/ConfigurationProcessor.java
+++ b/services/core/java/com/android/server/input/ConfigurationProcessor.java
@@ -17,7 +17,6 @@
 package com.android.server.input;
 
 import android.text.TextUtils;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.Xml;
 
@@ -29,7 +28,9 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 
 class ConfigurationProcessor {
@@ -86,9 +87,9 @@
      * the second item in the pair is the display port.
      */
     @VisibleForTesting
-    static List<Pair<String, String>> processInputPortAssociations(InputStream xml)
+    static Map<String, Integer> processInputPortAssociations(InputStream xml)
             throws Exception {
-        List<Pair<String, String>> associations = new ArrayList<>();
+        Map<String, Integer> associations = new HashMap<String, Integer>();
         try (InputStreamReader confReader = new InputStreamReader(xml)) {
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(confReader);
@@ -101,19 +102,18 @@
                     break;
                 }
                 String inputPort = parser.getAttributeValue(null, "input");
-                String displayPort = parser.getAttributeValue(null, "display");
-                if (TextUtils.isEmpty(inputPort) || TextUtils.isEmpty(displayPort)) {
+                String displayPortStr = parser.getAttributeValue(null, "display");
+                if (TextUtils.isEmpty(inputPort) || TextUtils.isEmpty(displayPortStr)) {
                     // This is likely an error by an OEM during device configuration
                     Slog.wtf(TAG, "Ignoring incomplete entry");
                     continue;
                 }
                 try {
-                    Integer.parseUnsignedInt(displayPort);
+                    int displayPort = Integer.parseUnsignedInt(displayPortStr);
+                    associations.put(inputPort, displayPort);
                 } catch (NumberFormatException e) {
                     Slog.wtf(TAG, "Display port should be an integer");
-                    continue;
                 }
-                associations.add(new Pair<>(inputPort, displayPort));
             }
         }
         return associations;
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 16b7d99..b77c859 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -64,7 +64,6 @@
 import android.provider.Settings.SettingNotFoundException;
 import android.text.TextUtils;
 import android.util.Log;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
@@ -113,8 +112,8 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Objects;
-
 /*
  * Wraps the C++ InputManager and provides its callbacks.
  */
@@ -184,6 +183,10 @@
     IInputFilter mInputFilter; // guarded by mInputFilterLock
     InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
 
+    // The associations of input devices to displays by port. Maps from input device port (String)
+    // to display id (int). Currently only accessed by InputReader.
+    private final Map<String, Integer> mStaticAssociations;
+
     private static native long nativeInit(InputManagerService service,
             Context context, MessageQueue messageQueue);
     private static native void nativeStart(long ptr);
@@ -325,6 +328,7 @@
         mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
             new File(doubleTouchGestureEnablePath);
 
+        mStaticAssociations = loadStaticInputPortAssociations();
         LocalServices.addService(InputManagerInternal.class, new LocalService());
     }
 
@@ -1727,6 +1731,17 @@
         String dumpStr = nativeDump(mPtr);
         if (dumpStr != null) {
             pw.println(dumpStr);
+            dumpAssociations(pw);
+        }
+    }
+
+    private void dumpAssociations(PrintWriter pw) {
+        if (!mStaticAssociations.isEmpty()) {
+            pw.println("Static Associations:");
+            mStaticAssociations.forEach((k, v) -> {
+                pw.print("  port: " + k);
+                pw.println("  display: " + v);
+            });
         }
     }
 
@@ -1910,15 +1925,16 @@
     }
 
     /**
-     * Flatten a list of pairs into a list, with value positioned directly next to the key
+     * Flatten a map into a string list, with value positioned directly next to the
+     * key.
      * @return Flattened list
      */
-    private static <T> List<T> flatten(@NonNull List<Pair<T, T>> pairs) {
-        List<T> list = new ArrayList<>(pairs.size() * 2);
-        for (Pair<T, T> pair : pairs) {
-            list.add(pair.first);
-            list.add(pair.second);
-        }
+    private static List<String> flatten(@NonNull Map<String, Integer> map) {
+        List<String> list = new ArrayList<>(map.size() * 2);
+        map.forEach((k, v)-> {
+            list.add(k);
+            list.add(v.toString());
+        });
         return list;
     }
 
@@ -1926,23 +1942,26 @@
      * Ports are highly platform-specific, so only allow these to be specified in the vendor
      * directory.
      */
-    // Native callback
-    private static String[] getInputPortAssociations() {
+    private static Map<String, Integer> loadStaticInputPortAssociations() {
         File baseDir = Environment.getVendorDirectory();
         File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH);
 
         try {
             InputStream stream = new FileInputStream(confFile);
-            List<Pair<String, String>> associations =
-                    ConfigurationProcessor.processInputPortAssociations(stream);
-            List<String> associationList = flatten(associations);
-            return associationList.toArray(new String[0]);
+            return ConfigurationProcessor.processInputPortAssociations(stream);
         } catch (FileNotFoundException e) {
             // Most of the time, file will not exist, which is expected.
         } catch (Exception e) {
             Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e);
         }
-        return new String[0];
+
+        return new HashMap<>();
+    }
+
+    // Native callback
+    private String[] getInputPortAssociations() {
+        List<String> associationList = flatten(mStaticAssociations);
+        return associationList.toArray(new String[0]);
     }
 
     /**
diff --git a/services/core/java/com/android/server/integrity/OWNERS b/services/core/java/com/android/server/integrity/OWNERS
index 019aa4f..55a4e40 100644
--- a/services/core/java/com/android/server/integrity/OWNERS
+++ b/services/core/java/com/android/server/integrity/OWNERS
@@ -3,4 +3,3 @@
 mdchurchill@google.com
 sturla@google.com
 songpan@google.com
-bjy@google.com
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexTypeIdentifier.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexTypeIdentifier.java
deleted file mode 100644
index 4d3961d..0000000
--- a/services/core/java/com/android/server/integrity/serializer/RuleIndexTypeIdentifier.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.integrity.serializer;
-
-import android.annotation.IntDef;
-import android.content.integrity.AtomicFormula;
-import android.content.integrity.CompoundFormula;
-import android.content.integrity.Formula;
-import android.content.integrity.Rule;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/** A helper class for identifying the indexing type of a given rule. */
-public class RuleIndexTypeIdentifier {
-
-    static final int NOT_INDEXED = 0;
-    static final int PACKAGE_NAME_INDEXED = 1;
-    static final int APP_CERTIFICATE_INDEXED = 2;
-
-    /** Represents which indexed file the rule should be located. */
-    @IntDef(
-            value = {
-                    NOT_INDEXED,
-                    PACKAGE_NAME_INDEXED,
-                    APP_CERTIFICATE_INDEXED
-            })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface IndexType {
-    }
-
-    /** Determines the indexing file type that a given rule should be located at. */
-    public static int getIndexType(Rule rule) {
-        if (rule == null) {
-            throw new IllegalArgumentException("Indexing type cannot be determined for null rule.");
-        }
-        return getIndexType(rule.getFormula());
-    }
-
-    private static int getIndexType(Formula formula) {
-        if (formula == null) {
-            throw new IllegalArgumentException(
-                    "Indexing type cannot be determined for null formula.");
-        }
-
-        switch (formula.getTag()) {
-            case Formula.COMPOUND_FORMULA_TAG:
-                return getIndexTypeForCompoundFormula((CompoundFormula) formula);
-            case Formula.STRING_ATOMIC_FORMULA_TAG:
-                return getIndexTypeForAtomicStringFormula((AtomicFormula) formula);
-            case Formula.INT_ATOMIC_FORMULA_TAG:
-            case Formula.BOOLEAN_ATOMIC_FORMULA_TAG:
-                // Package name and app certificate related formulas are string atomic formulas.
-                return NOT_INDEXED;
-            default:
-                throw new IllegalArgumentException(
-                        String.format("Invalid formula tag type: %s", formula.getTag()));
-        }
-    }
-
-    private static int getIndexTypeForCompoundFormula(CompoundFormula compoundFormula) {
-        int connector = compoundFormula.getConnector();
-        List<Formula> formulas = compoundFormula.getFormulas();
-
-        switch (connector) {
-            case CompoundFormula.NOT:
-                // Having a NOT operator in the indexing messes up the indexing; e.g., deny
-                // installation if app certificate is NOT X (should not be indexed with app cert
-                // X). We will not keep these rules indexed.
-                return NOT_INDEXED;
-            case CompoundFormula.AND:
-            case CompoundFormula.OR:
-                Set<Integer> indexingTypesForAllFormulas =
-                        formulas.stream()
-                                .map(formula -> getIndexType(formula))
-                                .collect(Collectors.toSet());
-                if (indexingTypesForAllFormulas.contains(PACKAGE_NAME_INDEXED)) {
-                    return PACKAGE_NAME_INDEXED;
-                } else if (indexingTypesForAllFormulas.contains(APP_CERTIFICATE_INDEXED)) {
-                    return APP_CERTIFICATE_INDEXED;
-                } else {
-                    return NOT_INDEXED;
-                }
-            default:
-                return NOT_INDEXED;
-        }
-    }
-
-    private static int getIndexTypeForAtomicStringFormula(AtomicFormula atomicFormula) {
-        switch (atomicFormula.getKey()) {
-            case AtomicFormula.PACKAGE_NAME:
-                return PACKAGE_NAME_INDEXED;
-            case AtomicFormula.APP_CERTIFICATE:
-                return APP_CERTIFICATE_INDEXED;
-            default:
-                return NOT_INDEXED;
-        }
-    }
-}
-
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetails.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetails.java
new file mode 100644
index 0000000..dd871e2
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetails.java
@@ -0,0 +1,67 @@
+/*
+ * 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.integrity.serializer;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** Holds the indexing type and indexing key of a given formula. */
+class RuleIndexingDetails {
+
+    static final int NOT_INDEXED = 0;
+    static final int PACKAGE_NAME_INDEXED = 1;
+    static final int APP_CERTIFICATE_INDEXED = 2;
+
+    /** Represents which indexed file the rule should be located. */
+    @IntDef(
+            value = {
+                    NOT_INDEXED,
+                    PACKAGE_NAME_INDEXED,
+                    APP_CERTIFICATE_INDEXED
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface IndexType {
+    }
+
+    private @IndexType int mIndexType;
+    private String mRuleKey;
+
+    /** Constructor without a ruleKey for {@code NOT_INDEXED}. */
+    RuleIndexingDetails(@IndexType int indexType) {
+        this.mIndexType = indexType;
+        this.mRuleKey = null;
+    }
+
+    /** Constructor with a ruleKey for indexed rules. */
+    RuleIndexingDetails(@IndexType int indexType, String ruleKey) {
+        this.mIndexType = indexType;
+        this.mRuleKey = ruleKey;
+    }
+
+    /** Returns the indexing type for the rule. */
+    @IndexType
+    public int getIndexType() {
+        return mIndexType;
+    }
+
+    /** Returns the identified rule key. */
+    public String getRuleKey() {
+        return mRuleKey;
+    }
+}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java
new file mode 100644
index 0000000..7d5e836
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java
@@ -0,0 +1,169 @@
+/*
+ * 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.integrity.serializer;
+
+import static com.android.server.integrity.serializer.RuleIndexingDetails.APP_CERTIFICATE_INDEXED;
+import static com.android.server.integrity.serializer.RuleIndexingDetails.NOT_INDEXED;
+import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAGE_NAME_INDEXED;
+
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Formula;
+import android.content.integrity.Rule;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.TreeMap;
+
+/** A helper class for identifying the indexing type and key of a given rule. */
+class RuleIndexingDetailsIdentifier {
+
+    private static final String DEFAULT_RULE_KEY = "N/A";
+
+    /**
+     * Splits a given rule list into three indexing categories and returns a sorted list of rules
+     * per each index.
+     *
+     * The sorting guarantees an order based on the key but the rules that have the same key
+     * can be in arbitrary order. For example, given the rules of [package_name_a_rule_1,
+     * package_name_a_rule_2, package_name_b_rule_3, package_name_b_rule_4], the  method will
+     * guarantee that package_name_b rules (i.e., 3 and 4) will never come before package_name_a
+     * rules (i.e., 1 and 2). However, we do not care about the ordering between rule 1 and 2.
+     * We also do not care about the ordering between rule 3 and 4.
+     */
+    public static Map<Integer, List<Rule>> splitRulesIntoIndexBuckets(List<Rule> rules) {
+        if (rules == null) {
+            throw new IllegalArgumentException(
+                    "Index buckets cannot be created for null rule list.");
+        }
+
+        Map<Integer, Map<String, List<Rule>>> typeOrganizedRuleMap = new HashMap();
+        typeOrganizedRuleMap.put(NOT_INDEXED, new TreeMap());
+        typeOrganizedRuleMap.put(PACKAGE_NAME_INDEXED, new TreeMap());
+        typeOrganizedRuleMap.put(APP_CERTIFICATE_INDEXED, new TreeMap());
+
+        // Split the rules into the appropriate indexed pattern. The Tree Maps help us to keep the
+        // entries sorted by their index key.
+        for (Rule rule : rules) {
+            RuleIndexingDetails indexingDetails = getIndexingDetails(rule.getFormula());
+            String ruleKey =
+                    indexingDetails.getIndexType() != NOT_INDEXED
+                            ? indexingDetails.getRuleKey()
+                            : DEFAULT_RULE_KEY;
+
+            if (!typeOrganizedRuleMap.get(indexingDetails.getIndexType()).containsKey(ruleKey)) {
+                typeOrganizedRuleMap
+                        .get(indexingDetails.getIndexType())
+                        .put(ruleKey, new ArrayList());
+            }
+
+            typeOrganizedRuleMap
+                    .get(indexingDetails.getIndexType())
+                    .get(ruleKey)
+                    .add(rule);
+        }
+
+        // Per indexing type, create the sorted rule set based on their key.
+        Map<Integer, List<Rule>> orderedListPerIndexingType = new HashMap<>();
+
+        for (Integer indexingKey : typeOrganizedRuleMap.keySet()) {
+            List<Rule> sortedRules = new ArrayList();
+            for (Map.Entry<String, List<Rule>> entry :
+                    typeOrganizedRuleMap.get(indexingKey).entrySet()) {
+                sortedRules.addAll(entry.getValue());
+            }
+            orderedListPerIndexingType.put(indexingKey, sortedRules);
+        }
+
+        return orderedListPerIndexingType;
+    }
+
+    private static RuleIndexingDetails getIndexingDetails(Formula formula) {
+        switch (formula.getTag()) {
+            case Formula.COMPOUND_FORMULA_TAG:
+                return getIndexingDetailsForCompoundFormula((CompoundFormula) formula);
+            case Formula.STRING_ATOMIC_FORMULA_TAG:
+                return getIndexingDetailsForStringAtomicFormula(
+                        (AtomicFormula.StringAtomicFormula) formula);
+            case Formula.INT_ATOMIC_FORMULA_TAG:
+            case Formula.BOOLEAN_ATOMIC_FORMULA_TAG:
+                // Package name and app certificate related formulas are string atomic formulas.
+                return new RuleIndexingDetails(NOT_INDEXED);
+            default:
+                throw new IllegalArgumentException(
+                        String.format("Invalid formula tag type: %s", formula.getTag()));
+        }
+    }
+
+    private static RuleIndexingDetails getIndexingDetailsForCompoundFormula(
+            CompoundFormula compoundFormula) {
+        int connector = compoundFormula.getConnector();
+        List<Formula> formulas = compoundFormula.getFormulas();
+
+        switch (connector) {
+            case CompoundFormula.AND:
+            case CompoundFormula.OR:
+                // If there is a package name related atomic rule, return package name indexed.
+                Optional<RuleIndexingDetails> packageNameRule =
+                        formulas.stream()
+                                .map(formula -> getIndexingDetails(formula))
+                                .filter(ruleIndexingDetails -> ruleIndexingDetails.getIndexType()
+                                        == PACKAGE_NAME_INDEXED)
+                                .findAny();
+                if (packageNameRule.isPresent()) {
+                    return packageNameRule.get();
+                }
+
+                // If there is an app certificate related atomic rule but no package name related
+                // atomic rule, return app certificate indexed.
+                Optional<RuleIndexingDetails> appCertificateRule =
+                        formulas.stream()
+                                .map(formula -> getIndexingDetails(formula))
+                                .filter(ruleIndexingDetails -> ruleIndexingDetails.getIndexType()
+                                        == APP_CERTIFICATE_INDEXED)
+                                .findAny();
+                if (appCertificateRule.isPresent()) {
+                    return appCertificateRule.get();
+                }
+
+                // Do not index when there is not package name or app certificate indexing.
+                return new RuleIndexingDetails(NOT_INDEXED);
+            default:
+                // Having a NOT operator in the indexing messes up the indexing; e.g., deny
+                // installation if app certificate is NOT X (should not be indexed with app cert
+                // X). We will not keep these rules indexed.
+                // Also any other type of unknown operators will not be indexed.
+                return new RuleIndexingDetails(NOT_INDEXED);
+        }
+    }
+
+    private static RuleIndexingDetails getIndexingDetailsForStringAtomicFormula(
+            AtomicFormula.StringAtomicFormula atomicFormula) {
+        switch (atomicFormula.getKey()) {
+            case AtomicFormula.PACKAGE_NAME:
+                return new RuleIndexingDetails(PACKAGE_NAME_INDEXED, atomicFormula.getValue());
+            case AtomicFormula.APP_CERTIFICATE:
+                return new RuleIndexingDetails(APP_CERTIFICATE_INDEXED, atomicFormula.getValue());
+            default:
+                return new RuleIndexingDetails(NOT_INDEXED);
+        }
+    }
+}
+
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index ec4aedd..51fcbb0 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1325,6 +1325,8 @@
     private void unlockUser(int userId, byte[] token, byte[] secret,
             @ChallengeType int challengeType, long challenge,
             @Nullable ArrayList<PendingResetLockout> resetLockouts) {
+        Slog.i(TAG, "Unlocking user " + userId + " with secret only, length "
+                + (secret != null ? secret.length : 0));
         // TODO: make this method fully async so we can update UI with progress strings
         final boolean alreadyUnlocked = mUserManager.isUserUnlockingOrUnlocked(userId);
         final CountDownLatch latch = new CountDownLatch(1);
@@ -2651,11 +2653,7 @@
                 }
             }
         }
-
         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
-            setUserPasswordMetrics(userCredential, userId);
-            unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
-
             // Do resetLockout / revokeChallenge when all profiles are unlocked
             if (hasEnrolledBiometrics) {
                 if (resetLockouts == null) {
@@ -2664,18 +2662,13 @@
                 resetLockouts.add(new PendingResetLockout(userId, response.getPayload()));
             }
 
-            final byte[] secret = authResult.authToken.deriveDiskEncryptionKey();
-            Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length);
-            unlockUser(userId, null, secret, challengeType, challenge, resetLockouts);
-
-            activateEscrowTokens(authResult.authToken, userId);
-
-            if (isManagedProfileWithSeparatedLock(userId)) {
-                setDeviceUnlockedForUser(userId);
-            }
-            mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
-
-            onAuthTokenKnownForUser(userId, authResult.authToken);
+            // TODO: Move setUserPasswordMetrics() inside onCredentialVerified(): this will require
+            // LSS to store an encrypted version of the latest password metric for every user,
+            // because user credential is not known when onCredentialVerified() is called during
+            // a token-based unlock.
+            setUserPasswordMetrics(userCredential, userId);
+            onCredentialVerified(authResult.authToken, challengeType, challenge, resetLockouts,
+                    userId);
         } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
             if (response.getTimeout() > 0) {
                 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
@@ -2685,6 +2678,27 @@
         return response;
     }
 
+    private void onCredentialVerified(AuthenticationToken authToken,
+            @ChallengeType int challengeType, long challenge,
+            @Nullable ArrayList<PendingResetLockout> resetLockouts, int userId) {
+
+        unlockKeystore(authToken.deriveKeyStorePassword(), userId);
+
+        {
+            final byte[] secret = authToken.deriveDiskEncryptionKey();
+            unlockUser(userId, null, secret, challengeType, challenge, resetLockouts);
+            Arrays.fill(secret, (byte) 0);
+        }
+        activateEscrowTokens(authToken, userId);
+
+        if (isManagedProfileWithSeparatedLock(userId)) {
+            setDeviceUnlockedForUser(userId);
+        }
+        mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
+
+        onAuthTokenKnownForUser(userId, authToken);
+    }
+
     private void setDeviceUnlockedForUser(int userId) {
         final TrustManager trustManager = mContext.getSystemService(TrustManager.class);
         trustManager.setDeviceLockedForUser(userId, false);
@@ -3057,8 +3071,10 @@
                 return false;
             }
         }
-        unlockUser(userId, null, authResult.authToken.deriveDiskEncryptionKey());
-        onAuthTokenKnownForUser(userId, authResult.authToken);
+        // TODO: Reset biometrics lockout here. Ideally that should be self-contained inside
+        // onCredentialVerified(), which will require some refactoring on the current lockout
+        // reset logic.
+        onCredentialVerified(authResult.authToken, CHALLENGE_NONE, 0, null, userId);
         return true;
     }
 
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 9fcee50..e7b8860 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -183,8 +183,9 @@
     }
 
     public void setControlCategories(@NonNull IMediaRouter2Client client,
-            @Nullable List<String> categories) {
+            @NonNull List<String> categories) {
         Objects.requireNonNull(client, "client must not be null");
+        Objects.requireNonNull(categories, "categories must not be null");
 
         final long token = Binder.clearCallingIdentity();
         try {
@@ -390,8 +391,11 @@
 
     private void setControlCategoriesLocked(Client2Record clientRecord, List<String> categories) {
         if (clientRecord != null) {
-            clientRecord.mControlCategories = categories;
+            if (clientRecord.mControlCategories.equals(categories)) {
+                return;
+            }
 
+            clientRecord.mControlCategories = categories;
             clientRecord.mUserRecord.mHandler.sendMessage(
                     obtainMessage(UserHandler::updateClientUsage,
                             clientRecord.mUserRecord.mHandler, clientRecord));
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 82d74bc..83d0ecd 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1032,6 +1032,7 @@
             // READ_NETWORK_USAGE_HISTORY permission above.
 
             synchronized (mNetworkPoliciesSecondLock) {
+                updateNetworkRulesNL();
                 updateNetworkEnabledNL();
                 updateNotificationsNL();
             }
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 673e830..0288f0c 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -873,6 +873,8 @@
                     + mPersistThreshold);
         }
 
+        final long oldGlobalAlertBytes = mGlobalAlertBytes;
+
         // update and persist if beyond new thresholds
         final long currentTime = mClock.millis();
         synchronized (mStatsLock) {
@@ -886,8 +888,9 @@
             mUidTagRecorder.maybePersistLocked(currentTime);
         }
 
-        // re-arm global alert
-        registerGlobalAlert();
+        if (oldGlobalAlertBytes != mGlobalAlertBytes) {
+            registerGlobalAlert();
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/package-info.java b/services/core/java/com/android/server/package-info.java
index a783e8d..dd94edd 100644
--- a/services/core/java/com/android/server/package-info.java
+++ b/services/core/java/com/android/server/package-info.java
@@ -13,5 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+/**
+ * @hide
+ * TODO(b/146466118) remove this javadoc tag
+ */
 @android.annotation.Hide
 package com.android.server;
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 26cd42d..f962eed 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -28,6 +28,7 @@
 import android.os.IInstalld;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.storage.CrateMetadata;
 import android.text.format.DateUtils;
 import android.util.Slog;
 
@@ -293,6 +294,43 @@
         }
     }
 
+    /**
+     * To get all of the CrateMetadata of the crates for the specified user app by the installd.
+     *
+     * @param uuid the UUID
+     * @param packageNames the application package names
+     * @param userId the user id
+     * @return the array of CrateMetadata
+     */
+    @Nullable
+    public CrateMetadata[] getAppCrates(@NonNull String uuid, @NonNull String[] packageNames,
+            @UserIdInt int userId) throws InstallerException {
+        if (!checkBeforeRemote()) return null;
+        try {
+            return mInstalld.getAppCrates(uuid, packageNames, userId);
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
+    /**
+     * To retrieve all of the CrateMetadata of the crate for the specified user app by the installd.
+     *
+     * @param uuid the UUID
+     * @param userId the user id
+     * @return the array of CrateMetadata
+     */
+    @Nullable
+    public CrateMetadata[] getUserCrates(String uuid, @UserIdInt int userId)
+            throws InstallerException {
+        if (!checkBeforeRemote()) return null;
+        try {
+            return mInstalld.getUserCrates(uuid, userId);
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
     public void setAppQuota(String uuid, int userId, int appId, long cacheQuota)
             throws InstallerException {
         if (!checkBeforeRemote()) return;
@@ -580,6 +618,30 @@
         }
     }
 
+    /**
+     * Bind mount private volume CE and DE mirror storage.
+     */
+    public void onPrivateVolumeMounted(String volumeUuid) throws InstallerException {
+        if (!checkBeforeRemote()) return;
+        try {
+            mInstalld.onPrivateVolumeMounted(volumeUuid);
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
+    /**
+     * Unmount private volume CE and DE mirror storage.
+     */
+    public void onPrivateVolumeRemoved(String volumeUuid) throws InstallerException {
+        if (!checkBeforeRemote()) return;
+        try {
+            mInstalld.onPrivateVolumeRemoved(volumeUuid);
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
     public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId,
             String profileName, String codePath, String dexMetadataPath) throws InstallerException {
         if (!checkBeforeRemote()) return false;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 286d291..0acf7c8 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -57,6 +57,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageInstallObserver2;
 import android.content.pm.IPackageInstallerSession;
+import android.content.pm.IPackageInstallerSessionFileSystemConnector;
 import android.content.pm.InstallationFile;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
@@ -1003,6 +1004,21 @@
         mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
     }
 
+    private class FileSystemConnector extends IPackageInstallerSessionFileSystemConnector.Stub {
+        @Override
+        public void writeData(String name, long offsetBytes, long lengthBytes,
+                ParcelFileDescriptor incomingFd) {
+            if (incomingFd == null) {
+                throw new IllegalArgumentException("incomingFd can't be null");
+            }
+            try {
+                doWriteInternal(name, offsetBytes, lengthBytes, incomingFd);
+            } catch (IOException e) {
+                throw ExceptionUtils.wrap(e);
+            }
+        }
+    }
+
     private class ChildStatusIntentReceiver {
         private final SparseIntArray mChildSessionsRemaining;
         private final IntentSender mStatusReceiver;
@@ -2356,6 +2372,8 @@
         if (mIncrementalFileStorages != null) {
             try {
                 mIncrementalFileStorages.addFile(new InstallationFile(name, lengthBytes, metadata));
+                //TODO(b/136132412): merge incremental and callback installation schemes
+                return;
             } catch (IOException ex) {
                 throw new IllegalStateException(
                         "Failed to add and configure Incremental File: " + name, ex);
@@ -2405,7 +2423,7 @@
             return;
         }
 
-        FilesystemConnector connector = new FilesystemConnector();
+        FileSystemConnector connector = new FileSystemConnector();
 
         FileInfo[] addedFiles = mFiles.stream().filter(
                 file -> sAddedFilter.accept(new File(file.name))).toArray(FileInfo[]::new);
@@ -2430,19 +2448,11 @@
         }
     }
 
-    // TODO(b/146080380): implement DataLoader using Incremental infrastructure.
-    class FilesystemConnector {
-        void writeData(FileInfo fileInfo, long offset, long lengthBytes,
-                ParcelFileDescriptor incomingFd) throws IOException {
-            doWriteInternal(fileInfo.name, offset, lengthBytes, incomingFd);
-        }
-    }
-
     static class DataLoader {
         private ParcelFileDescriptor mInFd = null;
-        private FilesystemConnector mConnector = null;
+        private FileSystemConnector mConnector = null;
 
-        void onCreate(FilesystemConnector connector) throws IOException {
+        void onCreate(FileSystemConnector connector) throws IOException {
             mConnector = connector;
         }
 
@@ -2460,14 +2470,14 @@
                         return false;
                     }
                     ParcelFileDescriptor inFd = ParcelFileDescriptor.dup(mInFd.getFileDescriptor());
-                    mConnector.writeData(fileInfo, 0, fileInfo.lengthBytes, inFd);
+                    mConnector.writeData(fileInfo.name, 0, fileInfo.lengthBytes, inFd);
                 } else {
                     File localFile = new File(filePath);
                     ParcelFileDescriptor incomingFd = null;
                     try {
                         incomingFd = ParcelFileDescriptor.open(localFile,
                                 ParcelFileDescriptor.MODE_READ_ONLY);
-                        mConnector.writeData(fileInfo, 0, localFile.length(), incomingFd);
+                        mConnector.writeData(fileInfo.name, 0, localFile.length(), incomingFd);
                     } finally {
                         IoUtils.closeQuietly(incomingFd);
                     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 99d5e4a..cb362b0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -22626,6 +22626,18 @@
         }
 
         @Override
+        public long getCeDataInode(String packageName, int userId) {
+            synchronized (mLock) {
+                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                if (ps != null) {
+                    return ps.getCeDataInode(userId);
+                }
+                Slog.e(TAG, "failed to find package " + packageName);
+                return 0;
+            }
+        }
+
+        @Override
         public Bundle getSuspendedPackageLauncherExtras(String packageName, int userId) {
             synchronized (mLock) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 5fabdb6..3515cb7 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -84,7 +84,6 @@
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.IntArray;
-import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -1510,7 +1509,7 @@
     public void setUserIcon(@UserIdInt int userId, Bitmap bitmap) {
         checkManageUsersPermission("update users");
         if (hasUserRestriction(UserManager.DISALLOW_SET_USER_ICON, userId)) {
-            Log.w(LOG_TAG, "Cannot set user icon. DISALLOW_SET_USER_ICON is enabled.");
+            Slog.w(LOG_TAG, "Cannot set user icon. DISALLOW_SET_USER_ICON is enabled.");
             return;
         }
         mLocalService.setUserIcon(userId, bitmap);
@@ -1558,7 +1557,7 @@
             return ParcelFileDescriptor.open(
                     new File(iconPath), ParcelFileDescriptor.MODE_READ_ONLY);
         } catch (FileNotFoundException e) {
-            Log.e(LOG_TAG, "Couldn't find icon file", e);
+            Slog.e(LOG_TAG, "Couldn't find icon file", e);
         }
         return null;
     }
@@ -1656,7 +1655,7 @@
             }
         }
         if (DBG) {
-            Log.d(LOG_TAG, "setDevicePolicyUserRestrictions: "
+            Slog.d(LOG_TAG, "setDevicePolicyUserRestrictions: "
                     + " originatingUserId=" + originatingUserId
                     + " global=" + global + (globalChanged ? " (changed)" : "")
                     + " local=" + local + (localChanged ? " (changed)" : "")
@@ -1718,7 +1717,7 @@
     @GuardedBy("mRestrictionsLock")
     private void invalidateEffectiveUserRestrictionsLR(@UserIdInt int userId) {
         if (DBG) {
-            Log.d(LOG_TAG, "invalidateEffectiveUserRestrictions userId=" + userId);
+            Slog.d(LOG_TAG, "invalidateEffectiveUserRestrictions userId=" + userId);
         }
         mCachedEffectiveUserRestrictions.remove(userId);
     }
@@ -1940,7 +1939,7 @@
                     try {
                         mAppOpsService.setUserRestrictions(effective, mUserRestriconToken, userId);
                     } catch (RemoteException e) {
-                        Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
+                        Slog.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
                     }
                 }
             });
@@ -2012,7 +2011,7 @@
                 try {
                     runningUsers = ActivityManager.getService().getRunningUserIds();
                 } catch (RemoteException e) {
-                    Log.w(LOG_TAG, "Unable to access ActivityManagerService");
+                    Slog.w(LOG_TAG, "Unable to access ActivityManagerService");
                     return;
                 }
                 // Then re-calculate the effective restrictions and apply, only for running users.
@@ -2596,7 +2595,7 @@
                 }
             }
         } catch (Resources.NotFoundException e) {
-            Log.e(LOG_TAG, "Couldn't find resource: config_defaultFirstUserRestrictions", e);
+            Slog.e(LOG_TAG, "Couldn't find resource: config_defaultFirstUserRestrictions", e);
         }
 
         if (!restrictions.isEmpty()) {
@@ -3056,7 +3055,7 @@
                 ? UserManager.DISALLOW_ADD_MANAGED_PROFILE
                 : UserManager.DISALLOW_ADD_USER;
         if (hasUserRestriction(restriction, UserHandle.getCallingUserId())) {
-            Log.w(LOG_TAG, "Cannot add user. " + restriction + " is enabled.");
+            Slog.w(LOG_TAG, "Cannot add user. " + restriction + " is enabled.");
             return null;
         }
         return createUserInternalUnchecked(name, userType, flags, parentId,
@@ -3115,7 +3114,7 @@
         DeviceStorageMonitorInternal dsm = LocalServices
                 .getService(DeviceStorageMonitorInternal.class);
         if (dsm.isMemoryLow()) {
-            Log.w(LOG_TAG, "Cannot add user. Not enough space on disk.");
+            Slog.w(LOG_TAG, "Cannot add user. Not enough space on disk.");
             return null;
         }
 
@@ -3138,36 +3137,36 @@
                     if (parent == null) return null;
                 }
                 if (!preCreate && !canAddMoreUsersOfType(userTypeDetails)) {
-                    Log.e(LOG_TAG, "Cannot add more users of type " + userType
+                    Slog.e(LOG_TAG, "Cannot add more users of type " + userType
                             + ". Maximum number of that type already exists.");
                     return null;
                 }
                 // TODO(b/142482943): Perhaps let the following code apply to restricted users too.
                 if (isProfile && !canAddMoreProfilesToUser(userType, parentId, false)) {
-                    Log.e(LOG_TAG, "Cannot add more profiles of type " + userType
+                    Slog.e(LOG_TAG, "Cannot add more profiles of type " + userType
                             + " for user " + parentId);
                     return null;
                 }
                 if (!isGuest && !isProfile && !isDemo && isUserLimitReached()) {
                     // If we're not adding a guest/demo user or a profile and the 'user limit' has
                     // been reached, cannot add a user.
-                    Log.e(LOG_TAG, "Cannot add user. Maximum user limit is reached.");
+                    Slog.e(LOG_TAG, "Cannot add user. Maximum user limit is reached.");
                     return null;
                 }
                 // In legacy mode, restricted profile's parent can only be the owner user
                 if (isRestricted && !UserManager.isSplitSystemUser()
                         && (parentId != UserHandle.USER_SYSTEM)) {
-                    Log.w(LOG_TAG, "Cannot add restricted profile - parent user must be owner");
+                    Slog.w(LOG_TAG, "Cannot add restricted profile - parent user must be owner");
                     return null;
                 }
                 if (isRestricted && UserManager.isSplitSystemUser()) {
                     if (parent == null) {
-                        Log.w(LOG_TAG, "Cannot add restricted profile - parent user must be "
+                        Slog.w(LOG_TAG, "Cannot add restricted profile - parent user must be "
                                 + "specified");
                         return null;
                     }
                     if (!parent.info.canHaveProfile()) {
-                        Log.w(LOG_TAG, "Cannot add restricted profile - profiles cannot be "
+                        Slog.w(LOG_TAG, "Cannot add restricted profile - profiles cannot be "
                                 + "created for the specified parent user id " + parentId);
                         return null;
                     }
@@ -3318,7 +3317,7 @@
                     + Integer.toHexString(preCreatedUser.flags) + ").");
             return null;
         }
-        Log.i(LOG_TAG, "Reusing pre-created user " + preCreatedUser.id + " of type "
+        Slog.i(LOG_TAG, "Reusing pre-created user " + preCreatedUser.id + " of type "
                 + userType + " and bestowing on it flags " + UserInfo.flagsToString(flags));
         preCreatedUser.name = name;
         preCreatedUser.flags = newFlags;
@@ -3483,7 +3482,7 @@
         checkManageUsersPermission("Only the system can remove users");
         if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(
                 UserManager.DISALLOW_REMOVE_USER, false)) {
-            Log.w(LOG_TAG, "Cannot remove user. DISALLOW_REMOVE_USER is enabled.");
+            Slog.w(LOG_TAG, "Cannot remove user. DISALLOW_REMOVE_USER is enabled.");
             return false;
         }
 
@@ -3535,7 +3534,7 @@
         String restriction = isManagedProfile
                 ? UserManager.DISALLOW_REMOVE_MANAGED_PROFILE : UserManager.DISALLOW_REMOVE_USER;
         if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(restriction, false)) {
-            Log.w(LOG_TAG, "Cannot remove user. " + restriction + " is enabled.");
+            Slog.w(LOG_TAG, "Cannot remove user. " + restriction + " is enabled.");
             return false;
         }
         return removeUserUnchecked(userId);
@@ -3553,25 +3552,25 @@
             final UserData userData;
             int currentUser = ActivityManager.getCurrentUser();
             if (currentUser == userId) {
-                Log.w(LOG_TAG, "Current user cannot be removed.");
+                Slog.w(LOG_TAG, "Current user cannot be removed.");
                 return false;
             }
             synchronized (mPackagesLock) {
                 synchronized (mUsersLock) {
                     userData = mUsers.get(userId);
                     if (userId == UserHandle.USER_SYSTEM) {
-                        Log.e(LOG_TAG, "System user cannot be removed.");
+                        Slog.e(LOG_TAG, "System user cannot be removed.");
                         return false;
                     }
 
                     if (userData == null) {
-                        Log.e(LOG_TAG, String.format(
+                        Slog.e(LOG_TAG, String.format(
                                 "Cannot remove user %d, invalid user id provided.", userId));
                         return false;
                     }
 
                     if (mRemovingUserIds.get(userId)) {
-                        Log.e(LOG_TAG, String.format(
+                        Slog.e(LOG_TAG, String.format(
                                 "User %d is already scheduled for removal.", userId));
                         return false;
                     }
@@ -3591,7 +3590,7 @@
             try {
                 mAppOpsService.removeUser(userId);
             } catch (RemoteException e) {
-                Log.w(LOG_TAG, "Unable to notify AppOpsService of removing user.", e);
+                Slog.w(LOG_TAG, "Unable to notify AppOpsService of removing user.", e);
             }
 
             // TODO(b/142482943): Send some sort of broadcast for profiles even if non-managed?
@@ -3616,7 +3615,7 @@
                             }
                         });
             } catch (RemoteException e) {
-                Log.w(LOG_TAG, "Failed to stop user during removal.", e);
+                Slog.w(LOG_TAG, "Failed to stop user during removal.", e);
                 return false;
             }
             return res == ActivityManager.USER_OP_SUCCESS;
@@ -3828,7 +3827,7 @@
                 readEntry(restrictions, values, parser);
             }
         } catch (IOException|XmlPullParserException e) {
-            Log.w(LOG_TAG, "Error parsing " + restrictionsFile.getBaseFile(), e);
+            Slog.w(LOG_TAG, "Error parsing " + restrictionsFile.getBaseFile(), e);
         } finally {
             IoUtils.closeQuietly(fis);
         }
@@ -4862,8 +4861,8 @@
     }
 
     private static void debug(String message) {
-        Log.d(LOG_TAG, message +
-                (DBG_WITH_STACKTRACE ? " called at\n" + Debug.getCallers(10, "  ") : ""));
+        Slog.d(LOG_TAG, message
+                + (DBG_WITH_STACKTRACE ? " called at\n" + Debug.getCallers(10, "  ") : ""));
     }
 
     /** @see #getMaxUsersOfTypePerParent(UserTypeDetails) */
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index e0bd0b4..90bd947 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -208,13 +208,6 @@
     );
 
     /**
-     * User restrictions that default to {@code true} for device owners.
-     */
-    private static final Set<String> DEFAULT_ENABLED_FOR_DEVICE_OWNERS = Sets.newArraySet(
-            UserManager.DISALLOW_ADD_MANAGED_PROFILE
-    );
-
-    /**
      * User restrictions that default to {@code true} for managed profile owners.
      *
      * NB: {@link UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES} is also set by default but it is
@@ -418,14 +411,6 @@
     }
 
     /**
-     * Returns the user restrictions that default to {@code true} for device owners.
-     * These user restrictions are local, though. ie only for the device owner's user id.
-     */
-    public static @NonNull Set<String> getDefaultEnabledForDeviceOwner() {
-        return DEFAULT_ENABLED_FOR_DEVICE_OWNERS;
-    }
-
-    /**
      * Returns the user restrictions that default to {@code true} for managed profile owners.
      */
     public static @NonNull Set<String> getDefaultEnabledForManagedProfiles() {
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index c36b993..77bb48e 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -67,10 +67,11 @@
  * then:
  * <ul>
  *     <li>If {@link #isImplicitWhitelistMode()}, the package is implicitly treated as whitelisted
- *          for all users</li>
- *     <li>Otherwise, the package is implicitly treated as blacklisted for all non-SYSTEM users</li>
- *     <li>Either way, for {@link UserHandle#USER_SYSTEM}, the package will be implicitly
- *          whitelisted so that it can be used for local development purposes.</li>
+ *          for <b>all</b> users</li>
+ *     <li>Otherwise, if {@link #isImplicitWhitelistSystemMode()}, the package is implicitly treated
+ *          as whitelisted for the <b>{@link UserHandle#USER_SYSTEM}</b> user (not other users),
+ *          which is useful for local development purposes</li>
+ *     <li>Otherwise, the package is implicitly treated as blacklisted for all users</li>
  * </ul>
  *
  * <p><b>NOTE:</b> the {@code SystemConfig} state is only updated on first boot or after a system
@@ -86,22 +87,24 @@
      * System Property whether to only install system packages on a user if they're whitelisted for
      * that user type. These are flags and can be freely combined.
      * <ul>
-     * <li> 0 (0b0000) - disable whitelist (install all system packages; no logging)</li>
-     * <li> 1 (0b0001) - enforce (only install system packages if they are whitelisted)</li>
-     * <li> 2 (0b0010) - log (log when a non-whitelisted package is run)</li>
-     * <li> 4 (0b0100) - implicitly whitelist any package not mentioned in the whitelist</li>
-     * <li> 8 (0b1000) - ignore OTAs (don't install system packages during OTAs)</li>
-     * <li>-1          - use device default (as defined in res/res/values/config.xml)</li>
+     * <li> 0  - disable whitelist (install all system packages; no logging)</li>
+     * <li> 1  - enforce (only install system packages if they are whitelisted)</li>
+     * <li> 2  - log (log when a non-whitelisted package is run)</li>
+     * <li> 4  - for all users: implicitly whitelist any package not mentioned in the whitelist</li>
+     * <li> 8  - for SYSTEM: implicitly whitelist any package not mentioned in the whitelist</li>
+     * <li> 16 - ignore OTAs (don't install system packages during OTAs)</li>
+     * <li>-1  - use device default (as defined in res/res/values/config.xml)</li>
      * </ul>
      * Note: This list must be kept current with config_userTypePackageWhitelistMode in
      * frameworks/base/core/res/res/values/config.xml
      */
     static final String PACKAGE_WHITELIST_MODE_PROP = "persist.debug.user.package_whitelist_mode";
-    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0;
-    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b0001;
-    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0b0010;
-    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b0100;
-    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA = 0b1000;
+    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0x00;
+    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0x01;
+    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0x02;
+    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0x04;
+    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM = 0x08;
+    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA = 0x10;
     static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1;
 
     @IntDef(flag = true, prefix = "USER_TYPE_PACKAGE_WHITELIST_MODE_", value = {
@@ -281,6 +284,14 @@
         return isImplicitWhitelistMode(getWhitelistMode());
     }
 
+    /**
+     * Whether to treat all packages that are not mentioned at all in the whitelist to be implicitly
+     * whitelisted for the SYSTEM user.
+     */
+    boolean isImplicitWhitelistSystemMode() {
+        return isImplicitWhitelistSystemMode(getWhitelistMode());
+    }
+
     /** See {@link #isEnforceMode()}. */
     private static boolean isEnforceMode(int whitelistMode) {
         return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE) != 0;
@@ -301,6 +312,11 @@
         return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST) != 0;
     }
 
+    /** See {@link #isImplicitWhitelistSystemMode()}. */
+    private static boolean isImplicitWhitelistSystemMode(int whitelistMode) {
+        return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM) != 0;
+    }
+
     /** Gets the PackageWhitelistMode for use of {@link #mWhitelistedPackagesForUserTypes}. */
     private @PackageWhitelistMode int getWhitelistMode() {
         final int runtimeMode = SystemProperties.getInt(
@@ -332,8 +348,8 @@
         if (!isEnforceMode(mode)) {
             return null;
         }
-        final boolean isSystemUser = mUm.isUserTypeSubtypeOfSystem(userType);
-        final boolean isImplicitWhitelistMode = isImplicitWhitelistMode(mode);
+        final boolean implicitlyWhitelist = isImplicitWhitelistMode(mode)
+                || (isImplicitWhitelistSystemMode(mode) && mUm.isUserTypeSubtypeOfSystem(userType));
         final Set<String> whitelistedPackages = getWhitelistedPackagesForUserType(userType);
 
         final Set<String> installPackages = new ArraySet<>();
@@ -343,7 +359,7 @@
                 return;
             }
             if (shouldInstallPackage(pkg, mWhitelistedPackagesForUserTypes,
-                    whitelistedPackages, isImplicitWhitelistMode, isSystemUser)) {
+                    whitelistedPackages, implicitlyWhitelist)) {
                 // Although the whitelist uses manifest names, this function returns packageNames.
                 installPackages.add(pkg.getPackageName());
             }
@@ -360,31 +376,18 @@
      *                          installed. This is only used for overriding the userWhitelist in
      *                          certain situations (based on its keyset).
      * @param userWhitelist set of package manifest names that should be installed on this
-     *                      particular user. This must be consistent with userTypeWhitelist, but is
-     *                      passed in separately to avoid repeatedly calculating it from
+     *                      <b>particular</b> user. This must be consistent with userTypeWhitelist,
+     *                      but is passed in separately to avoid repeatedly calculating it from
      *                      userTypeWhitelist.
-     * @param isImplicitWhitelistMode whether non-mentioned packages are implicitly whitelisted.
-     * @param isSystemUser whether the user is USER_SYSTEM (which gets special treatment).
+     * @param implicitlyWhitelist whether non-mentioned packages are implicitly whitelisted.
      */
     @VisibleForTesting
     static boolean shouldInstallPackage(AndroidPackage sysPkg,
             @NonNull ArrayMap<String, Long> userTypeWhitelist,
-            @NonNull Set<String> userWhitelist, boolean isImplicitWhitelistMode,
-            boolean isSystemUser) {
-
+            @NonNull Set<String> userWhitelist, boolean implicitlyWhitelist) {
         final String pkgName = sysPkg.getManifestPackageName();
-        boolean install = (isImplicitWhitelistMode && !userTypeWhitelist.containsKey(pkgName))
+        return (implicitlyWhitelist && !userTypeWhitelist.containsKey(pkgName))
                 || userWhitelist.contains(pkgName);
-
-        // For the purposes of local development, any package that isn't even mentioned in the
-        // whitelist at all is implicitly treated as whitelisted for the SYSTEM user.
-        if (!install && isSystemUser && !userTypeWhitelist.containsKey(pkgName)) {
-            install = true;
-            Slog.e(TAG, "System package " + pkgName + " is not mentioned "
-                    + "in SystemConfig's 'install-in-user-type' but we are "
-                    + "implicitly treating it as whitelisted for the SYSTEM user.");
-        }
-        return install;
     }
 
     /**
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index c779ebf..5271493 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -62,7 +62,6 @@
 import com.android.internal.globalactions.ToggleAction;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.util.EmergencyAffordanceManager;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
@@ -133,7 +132,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
+        filter.addAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
         context.registerReceiver(mBroadcastReceiver, filter);
 
         ConnectivityManager cm = (ConnectivityManager)
@@ -231,7 +230,7 @@
                     mIsWaitingForEcmExit = true;
                     // Launch ECM exit dialog
                     Intent ecmDialogIntent =
-                            new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
+                            new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
                     ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                     mContext.startActivity(ecmDialogIntent);
                 } else {
@@ -741,7 +740,7 @@
                 if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
                     mHandler.sendEmptyMessage(MESSAGE_DISMISS);
                 }
-            } else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
+            } else if (TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
                 // Airplane mode can be changed after ECM exits if airplane toggle button
                 // is pressed during ECM mode
                 if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) &&
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index f608642..a2425a3 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -336,13 +336,6 @@
         boolean isAnimatingLw();
 
         /**
-         * @return Whether the window can affect SystemUI flags, meaning that SystemUI (system bars,
-         *         for example) will be  affected by the flags specified in this window. This is the
-         *         case when the surface is on screen but not exiting.
-         */
-        boolean canAffectSystemUiFlags();
-
-        /**
          * Is this window considered to be gone for purposes of layout?
          */
         boolean isGoneForLayoutLw();
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 1b1ac6d..d99e03b 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -23,6 +23,7 @@
 import android.app.timedetector.ManualTimeSuggestion;
 import android.app.timedetector.PhoneTimeSuggestion;
 import android.content.Intent;
+import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.LocalLog;
 import android.util.Slog;
@@ -30,7 +31,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.PrintWriter;
@@ -512,12 +512,12 @@
             mLastAutoSystemClockTimeSet = null;
         }
 
-        // Historically, Android has sent a TelephonyIntents.ACTION_NETWORK_SET_TIME broadcast only
+        // Historically, Android has sent a TelephonyManager.ACTION_NETWORK_SET_TIME broadcast only
         // when setting the time using NITZ.
         if (origin == ORIGIN_PHONE) {
             // Send a broadcast that telephony code used to send after setting the clock.
             // TODO Remove this broadcast as soon as there are no remaining listeners.
-            Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
+            Intent intent = new Intent(TelephonyManager.ACTION_NETWORK_SET_TIME);
             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
             intent.putExtra("time", newSystemClockMillis);
             mCallback.sendStickyBroadcast(intent);
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index b4d8053..b3013c7 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -385,7 +385,7 @@
     }
 
     private static boolean isOriginAutomatic(@Origin int origin) {
-        return origin == ORIGIN_PHONE;
+        return origin != ORIGIN_MANUAL;
     }
 
     @GuardedBy("this")
@@ -456,15 +456,17 @@
      * Dumps internal state such as field values.
      */
     public synchronized void dumpState(PrintWriter pw, String[] args) {
-        pw.println("TimeZoneDetectorStrategy:");
-        pw.println("mCallback.isTimeZoneDetectionEnabled()="
+        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+        ipw.println("TimeZoneDetectorStrategy:");
+
+        ipw.increaseIndent(); // level 1
+        ipw.println("mCallback.isTimeZoneDetectionEnabled()="
                 + mCallback.isAutoTimeZoneDetectionEnabled());
-        pw.println("mCallback.isDeviceTimeZoneInitialized()="
+        ipw.println("mCallback.isDeviceTimeZoneInitialized()="
                 + mCallback.isDeviceTimeZoneInitialized());
-        pw.println("mCallback.getDeviceTimeZone()="
+        ipw.println("mCallback.getDeviceTimeZone()="
                 + mCallback.getDeviceTimeZone());
 
-        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
         ipw.println("Time zone change log:");
         ipw.increaseIndent(); // level 2
         mTimeZoneChangesLog.dump(ipw);
@@ -485,8 +487,6 @@
         ipw.decreaseIndent(); // level 2
         ipw.decreaseIndent(); // level 1
         ipw.flush();
-
-        pw.flush();
     }
 
     /**
diff --git a/services/core/java/com/android/server/utils/quota/Categorizer.java b/services/core/java/com/android/server/utils/quota/Categorizer.java
new file mode 100644
index 0000000..bf24991
--- /dev/null
+++ b/services/core/java/com/android/server/utils/quota/Categorizer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils.quota;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * Identifies the {@link Category} that each UPTC belongs in.
+ *
+ * @see Uptc
+ */
+public interface Categorizer {
+    /**
+     * Return the {@link Category} that this UPTC belongs to.
+     *
+     * @see Uptc
+     */
+    @NonNull
+    Category getCategory(int userId, @NonNull String packageName, @Nullable String tag);
+}
diff --git a/services/core/java/com/android/server/utils/quota/Category.java b/services/core/java/com/android/server/utils/quota/Category.java
new file mode 100644
index 0000000..d8459d7
--- /dev/null
+++ b/services/core/java/com/android/server/utils/quota/Category.java
@@ -0,0 +1,71 @@
+/*
+ * 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.utils.quota;
+
+import android.annotation.NonNull;
+import android.util.proto.ProtoOutputStream;
+import android.util.quota.CategoryProto;
+
+/**
+ * A category as defined by the (system) client. Categories are used to put UPTCs in different
+ * groups. A sample group of Categories could be the various App Standby buckets or foreground vs
+ * background.
+ *
+ * @see Uptc
+ */
+public final class Category {
+    @NonNull
+    private final String mName;
+
+    private final int mHash;
+
+    /** Construct a new Category with the specified name. */
+    public Category(@NonNull String name) {
+        mName = name;
+        mHash = name.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (other instanceof Category) {
+            return this.mName.equals(((Category) other).mName);
+        }
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return mHash;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "Category{" + mName + "}";
+    }
+
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(CategoryProto.NAME, mName);
+        proto.end(token);
+    }
+}
diff --git a/services/core/java/com/android/server/utils/quota/QuotaChangeListener.java b/services/core/java/com/android/server/utils/quota/QuotaChangeListener.java
new file mode 100644
index 0000000..b673050
--- /dev/null
+++ b/services/core/java/com/android/server/utils/quota/QuotaChangeListener.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils.quota;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * Listener that is notified when a UPTC goes in and out of quota.
+ *
+ * @see Uptc
+ */
+public interface QuotaChangeListener {
+    /**
+     * Called when the UPTC reaches its quota or comes back into quota.
+     *
+     * @see Uptc
+     */
+    void onQuotaStateChanged(int userId, @NonNull String packageName, @Nullable String tag);
+}
diff --git a/services/core/java/com/android/server/utils/quota/Uptc.java b/services/core/java/com/android/server/utils/quota/Uptc.java
new file mode 100644
index 0000000..4077544
--- /dev/null
+++ b/services/core/java/com/android/server/utils/quota/Uptc.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils.quota;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.proto.ProtoOutputStream;
+import android.util.quota.UptcProto;
+
+import java.util.Objects;
+
+/**
+ * A data object that represents a userId-packageName-tag combination (UPTC). The tag can be any
+ * desired String.
+ */
+final class Uptc {
+    public final int userId;
+    @NonNull
+    public final String packageName;
+    @Nullable
+    public final String tag;
+
+    private final int mHash;
+
+    /** Construct a new Uptc with the specified values. */
+    Uptc(int userId, @NonNull String packageName, @Nullable String tag) {
+        this.userId = userId;
+        this.packageName = packageName;
+        this.tag = tag;
+
+        mHash = 31 * userId
+                + 31 * packageName.hashCode()
+                + tag == null ? 0 : (31 * tag.hashCode());
+    }
+
+    @Override
+    public String toString() {
+        return string(userId, packageName, tag);
+    }
+
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+
+        proto.write(UptcProto.USER_ID, userId);
+        proto.write(UptcProto.NAME, packageName);
+        proto.write(UptcProto.TAG, tag);
+
+        proto.end(token);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof Uptc) {
+            final Uptc other = (Uptc) obj;
+            return userId == other.userId
+                    && Objects.equals(packageName, other.packageName)
+                    && Objects.equals(tag, other.tag);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return mHash;
+    }
+
+    /** Standardize the output of a UPTC. */
+    static String string(int userId, @NonNull String packageName, @Nullable String tag) {
+        return "<" + userId + ">" + packageName + (tag == null ? "" : ("::" + tag));
+    }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6bfa1ae..bfc6268 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5576,12 +5576,12 @@
 
     /**
      * @return The to top most child window for which {@link LayoutParams#isFullscreen()} returns
-     *         true.
+     *         true and isn't fully transparent.
      */
-    WindowState getTopFullscreenWindow() {
+    WindowState getTopFullscreenOpaqueWindow() {
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final WindowState win = mChildren.get(i);
-            if (win != null && win.mAttrs.isFullscreen()) {
+            if (win != null && win.mAttrs.isFullscreen() && !win.isFullyTransparent()) {
                 return win;
             }
         }
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 6f124ac..a741d45 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -3664,8 +3664,9 @@
         }
 
         final DisplayContent display = getDisplay();
-        final boolean topFocused = mRootActivityContainer.isTopDisplayFocusedStack(this);
-        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeChild: task=" + child);
+        if (DEBUG_TASK_MOVEMENT) {
+            Slog.d(TAG_WM, "removeChild: task=" + child + " reason=" + reason);
+        }
 
         super.removeChild(child);
 
@@ -3681,8 +3682,6 @@
             // Stack is now empty...
           removeIfPossible();
         }
-
-        moveHomeStackToFrontIfNeeded(topFocused, display, reason);
     }
 
     @Override
@@ -3690,18 +3689,6 @@
         removeChild(child, "removeChild");
     }
 
-    void moveHomeStackToFrontIfNeeded(
-            boolean wasTopFocusedStack, DisplayContent display, String reason) {
-        if (!hasChild() && wasTopFocusedStack) {
-            // We only need to adjust focused stack if this stack is in focus and we are not in the
-            // process of moving the task to the top of the stack that will be focused.
-            String myReason = reason + " leftTaskHistoryEmpty";
-            if (!inMultiWindowMode() || adjustFocusToNextFocusableStack(myReason) == null) {
-                display.moveHomeStackToFront(myReason);
-            }
-        }
-    }
-
     Task createTask(int taskId, ActivityInfo info, Intent intent,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             boolean toTop) {
@@ -3986,6 +3973,7 @@
             final PooledConsumer c = PooledLambda.obtainConsumer(Task::alignToAdjustedBounds,
                     PooledLambda.__(Task.class), adjusted ? mAdjustedBounds : getRawBounds(),
                     insetBounds, alignBottom);
+            forAllTasks(c);
             c.recycle();
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index b2fb93d..be3a613 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -301,7 +301,8 @@
                 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
         final KeyguardManager km = (KeyguardManager) mServiceContext
                 .getSystemService(KEYGUARD_SERVICE);
-        final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId);
+        final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId,
+                true /* disallowBiometricsIfPolicyExists */);
         if (newIntent == null) {
             return null;
         }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f0bc412..e02456e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4176,6 +4176,10 @@
 
                 final Runnable enterPipRunnable = () -> {
                     synchronized (mGlobalLock) {
+                        if (r.getParent() == null) {
+                            Slog.e(TAG, "Skip enterPictureInPictureMode, destroyed " + r);
+                            return;
+                        }
                         // Only update the saved args from the args that are set
                         r.pictureInPictureArgs.copyOnlySet(params);
                         final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4667eab..5bf8e05 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -166,6 +166,7 @@
 import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
 import android.app.WindowConfiguration;
+import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.ScreenOrientation;
 import android.content.res.CompatibilityInfo;
@@ -6640,4 +6641,22 @@
             }
         }
     }
+
+    /**
+     * Similar to {@link RootWindowContainer#isAnyNonToastWindowVisibleForUid(int)}, but
+     * used for pid.
+     */
+    boolean isAnyNonToastWindowVisibleForPid(int pid) {
+        final PooledPredicate p = PooledLambda.obtainPredicate(
+                WindowState::isNonToastWindowVisibleForPid,
+                PooledLambda.__(WindowState.class), pid);
+
+        final WindowState w = getWindow(p);
+        p.recycle();
+        return w != null;
+    }
+
+    Context getDisplayUiContext() {
+        return mDisplayPolicy.getSystemUiContext();
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 667e713..fbbc941 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -232,6 +232,7 @@
 
     private final WindowManagerService mService;
     private final Context mContext;
+    private final Context mUiContext;
     private final DisplayContent mDisplayContent;
     private final Object mLock;
     private final Handler mHandler;
@@ -449,6 +450,9 @@
         mService = service;
         mContext = displayContent.isDefaultDisplay ? service.mContext
                 : service.mContext.createDisplayContext(displayContent.getDisplay());
+        mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.mUiContext
+                : service.mAtmService.mSystemThread
+                        .createSystemUiContext(displayContent.getDisplayId());
         mDisplayContent = displayContent;
         mLock = service.getWindowManagerLock();
 
@@ -2765,10 +2769,8 @@
         return mContext;
     }
 
-    private Context getSystemUiContext() {
-        final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
-        return mDisplayContent.isDefaultDisplay
-                ? uiContext : uiContext.createDisplayContext(mDisplayContent.getDisplay());
+    Context getSystemUiContext() {
+        return mUiContext;
     }
 
     private int getNavigationBarWidth(int rotation, int uiMode) {
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index c7c3f8a..b59c4e3 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -442,13 +442,17 @@
         final int lastOrientation = mLastOrientation;
         final int rotation = rotationForOrientation(lastOrientation, oldRotation);
         ProtoLog.v(WM_DEBUG_ORIENTATION,
-                "Computed rotation=%d for display id=%d based on lastOrientation=%d and "
-                        + "oldRotation=%d",
-                rotation, displayId, lastOrientation, oldRotation);
+                "Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and "
+                        + "oldRotation=%s (%d)",
+                Surface.rotationToString(rotation), rotation,
+                displayId,
+                ActivityInfo.screenOrientationToString(lastOrientation), lastOrientation,
+                Surface.rotationToString(oldRotation), oldRotation);
 
         ProtoLog.v(WM_DEBUG_ORIENTATION,
-                "Display id=%d selected orientation %d, got rotation %d", displayId,
-                        lastOrientation, rotation);
+                "Display id=%d selected orientation %s (%d), got rotation %s (%d)", displayId,
+                ActivityInfo.screenOrientationToString(lastOrientation), lastOrientation,
+                Surface.rotationToString(rotation), rotation);
 
         if (oldRotation == rotation) {
             // No change.
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 0821873..184e7d6 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -24,6 +24,8 @@
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
 import static android.view.ViewRootImpl.sNewInsetsMode;
 
+import static com.android.server.wm.WindowManagerService.H.LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Point;
@@ -36,7 +38,6 @@
 import android.view.SurfaceControl.Transaction;
 
 import com.android.internal.util.function.TriConsumer;
-import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 
 import java.io.PrintWriter;
@@ -222,8 +223,8 @@
             return;
         }
         mClientVisible = clientVisible;
-        mDisplayContent.mWmService.mH.sendMessage(PooledLambda.obtainMessage(
-                DisplayContent::layoutAndAssignWindowLayersIfNeeded, mDisplayContent));
+        mDisplayContent.mWmService.mH.obtainMessage(
+                LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED, mDisplayContent).sendToTarget();
         updateVisibility();
     }
 
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 361bbe4..8b08344 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -22,10 +22,8 @@
 import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -54,6 +52,8 @@
 
 import android.annotation.CallSuper;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
 import android.content.res.Configuration;
 import android.hardware.power.V1_0.PowerHint;
 import android.os.Binder;
@@ -74,11 +74,14 @@
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
 import com.android.server.protolog.common.ProtoLog;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.function.Consumer;
 
 /** Root {@link WindowContainer} for the device. */
@@ -286,14 +289,19 @@
     }
 
     /**
-     * Returns true if the callingUid has any non-toast window currently visible to the user.
-     * Also ignores TYPE_APPLICATION_STARTING, since those windows don't belong to apps.
+     * Returns {@code true} if the callingUid has any non-toast window currently visible to the
+     * user. Also ignores {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_STARTING},
+     * since those windows don't belong to apps.
+     * @see WindowState#isNonToastOrStarting()
      */
     boolean isAnyNonToastWindowVisibleForUid(int callingUid) {
-        return forAllWindows(w ->
-                        w.getOwningUid() == callingUid && w.mAttrs.type != TYPE_TOAST
-                        && w.mAttrs.type != TYPE_APPLICATION_STARTING && w.isVisibleNow(),
-                true /* traverseTopToBottom */);
+        final PooledPredicate p = PooledLambda.obtainPredicate(
+                WindowState::isNonToastWindowVisibleForUid,
+                PooledLambda.__(WindowState.class), callingUid);
+
+        final WindowState w = getWindow(p);
+        p.recycle();
+        return w != null;
     }
 
     /**
@@ -1085,4 +1093,21 @@
         }
         return null;
     }
+
+    void getDisplayContextsWithNonToastVisibleWindows(int pid, List<Context> outContexts) {
+        if (outContexts == null) {
+            return;
+        }
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            DisplayContent dc = mChildren.get(i);
+            if (dc.isAnyNonToastWindowVisibleForPid(pid)) {
+                outContexts.add(dc.getDisplayUiContext());
+            }
+        }
+    }
+
+    @Nullable Context getDisplayUiContext(int displayId) {
+        return getDisplayContent(displayId) != null
+                ? getDisplayContent(displayId).getDisplayUiContext() : null;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1b2274a..fd95ac5 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2182,22 +2182,12 @@
     void reparent(ActivityStack stack, int position, boolean moveParents, String reason) {
         if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
                 + " from stack=" + getTaskStack());
-        EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask");
-
-        final ActivityStack prevStack = getTaskStack();
-        final boolean wasTopFocusedStack =
-                mAtmService.mRootActivityContainer.isTopDisplayFocusedStack(prevStack);
-        final DisplayContent prevStackDisplay = prevStack.getDisplay();
+        EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask:" + reason);
 
         position = stack.findPositionForTask(this, position, showForAllUsers());
 
         reparent(stack, position);
 
-        if (!moveParents) {
-            // Only move home stack forward if we are not going to move the new parent forward.
-            prevStack.moveHomeStackToFrontIfNeeded(wasTopFocusedStack, prevStackDisplay, reason);
-        }
-
         stack.positionChildAt(position, this, moveParents);
 
         // If we are moving from the fullscreen stack to the pinned stack then we want to preserve
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index dee9e9f..456068c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -89,6 +89,14 @@
     @VisibleForTesting
     static final int SNAPSHOT_MODE_NONE = 2;
 
+    /**
+     * Constant for <code>scaleFactor</code> when calling {@link #snapshotTask} which is
+     * interpreted as using the most appropriate scale ratio for the system.
+     * This may yield a smaller ratio on low memory devices.
+     */
+    @VisibleForTesting
+    static final float SNAPSHOT_SCALE_AUTO = -1f;
+
     private final WindowManagerService mService;
 
     private final TaskSnapshotCache mCache;
@@ -260,6 +268,84 @@
         });
     }
 
+    /**
+     * Validates the state of the Task is appropriate to capture a snapshot, collects
+     * information from the task and populates the builder.
+     *
+     * @param task the task to capture
+     * @param scaleFraction the scale fraction between 0-1.0, or {@link #SNAPSHOT_SCALE_AUTO}
+     *                      to automatically select
+     * @param pixelFormat the desired pixel format, or {@link PixelFormat#UNKNOWN} to
+     *                    automatically select
+     * @param builder the snapshot builder to populate
+     *
+     * @return true if the state of the task is ok to proceed
+     */
+    private boolean prepareTaskSnapshot(Task task, float scaleFraction, int pixelFormat,
+            TaskSnapshot.Builder builder) {
+        if (!mService.mPolicy.isScreenOn()) {
+            if (DEBUG_SCREENSHOT) {
+                Slog.i(TAG_WM, "Attempted to take screenshot while display was off.");
+            }
+            return false;
+        }
+        final ActivityRecord activity = findAppTokenForSnapshot(task);
+        if (activity == null) {
+            if (DEBUG_SCREENSHOT) {
+                Slog.w(TAG_WM, "Failed to take screenshot. No visible windows for " + task);
+            }
+            return false;
+        }
+        if (activity.hasCommittedReparentToAnimationLeash()) {
+            if (DEBUG_SCREENSHOT) {
+                Slog.w(TAG_WM, "Failed to take screenshot. App is animating " + activity);
+            }
+            return false;
+        }
+
+        final WindowState mainWindow = activity.findMainWindow();
+        if (mainWindow == null) {
+            Slog.w(TAG_WM, "Failed to take screenshot. No main window for " + task);
+            return false;
+        }
+
+        builder.setIsRealSnapshot(true);
+        builder.setId(System.currentTimeMillis());
+        builder.setContentInsets(getInsets(mainWindow));
+
+        final boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
+
+        if (scaleFraction == SNAPSHOT_SCALE_AUTO) {
+            builder.setScaleFraction(isLowRamDevice
+                    ? mPersister.getReducedScale()
+                    : mFullSnapshotScale);
+            builder.setReducedResolution(isLowRamDevice);
+        } else {
+            builder.setScaleFraction(scaleFraction);
+            builder.setReducedResolution(scaleFraction < 1.0f);
+        }
+
+        final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE;
+        final boolean isShowWallpaper = (mainWindow.getAttrs().flags & FLAG_SHOW_WALLPAPER) != 0;
+
+        if (pixelFormat == PixelFormat.UNKNOWN) {
+            pixelFormat = mPersister.use16BitFormat() && activity.fillsParent()
+                    && !(isWindowTranslucent && isShowWallpaper)
+                    ? PixelFormat.RGB_565
+                    : PixelFormat.RGBA_8888;
+        }
+
+        final boolean isTranslucent = PixelFormat.formatHasAlpha(pixelFormat)
+                && (!activity.fillsParent() || isWindowTranslucent);
+
+        builder.setTopActivityComponent(activity.mActivityComponent);
+        builder.setIsTranslucent(isTranslucent);
+        builder.setOrientation(activity.getTask().getConfiguration().orientation);
+        builder.setWindowingMode(task.getWindowingMode());
+        builder.setSystemUiVisibility(getSystemUiVisibility(task));
+        return true;
+    }
+
     @Nullable
     SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task,
             float scaleFraction) {
@@ -288,63 +374,31 @@
         return screenshotBuffer;
     }
 
-    @Nullable private TaskSnapshot snapshotTask(Task task) {
-        if (!mService.mPolicy.isScreenOn()) {
-            if (DEBUG_SCREENSHOT) {
-                Slog.i(TAG_WM, "Attempted to take screenshot while display was off.");
-            }
+    @Nullable
+    TaskSnapshot snapshotTask(Task task) {
+        return snapshotTask(task, SNAPSHOT_SCALE_AUTO, PixelFormat.UNKNOWN);
+    }
+
+    @Nullable
+    TaskSnapshot snapshotTask(Task task, float scaleFraction, int pixelFormat) {
+        TaskSnapshot.Builder builder = new TaskSnapshot.Builder();
+
+        if (!prepareTaskSnapshot(task, scaleFraction, pixelFormat, builder)) {
+            // Failed some pre-req. Has been logged.
             return null;
         }
 
-        final ActivityRecord activity = findAppTokenForSnapshot(task);
-        if (activity == null) {
-            if (DEBUG_SCREENSHOT) {
-                Slog.w(TAG_WM, "Failed to take screenshot. No visible windows for " + task);
-            }
-            return null;
-        }
-        if (activity.hasCommittedReparentToAnimationLeash()) {
-            if (DEBUG_SCREENSHOT) {
-                Slog.w(TAG_WM, "Failed to take screenshot. App is animating " + activity);
-            }
-            return null;
-        }
-
-        final boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
-        final float scaleFraction = isLowRamDevice
-                ? mPersister.getReducedScale()
-                : mFullSnapshotScale;
-
-        final WindowState mainWindow = activity.findMainWindow();
-        if (mainWindow == null) {
-            Slog.w(TAG_WM, "Failed to take screenshot. No main window for " + task);
-            return null;
-        }
-        final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE;
-        final boolean isShowWallpaper = (mainWindow.getAttrs().flags & FLAG_SHOW_WALLPAPER) != 0;
-        final int pixelFormat = mPersister.use16BitFormat() && activity.fillsParent()
-                && !(isWindowTranslucent && isShowWallpaper)
-                ? PixelFormat.RGB_565
-                : PixelFormat.RGBA_8888;
         final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
-                createTaskSnapshot(task, scaleFraction, pixelFormat);
+                createTaskSnapshot(task, builder.getScaleFraction(),
+                builder.getPixelFormat());
 
         if (screenshotBuffer == null) {
-            if (DEBUG_SCREENSHOT) {
-                Slog.w(TAG_WM, "Failed to take screenshot for " + task);
-            }
+            // Failed to acquire image. Has been logged.
             return null;
         }
-        final boolean isTranslucent = PixelFormat.formatHasAlpha(pixelFormat)
-                && (!activity.fillsParent() || isWindowTranslucent);
-        return new TaskSnapshot(
-                System.currentTimeMillis() /* id */,
-                activity.mActivityComponent, screenshotBuffer.getGraphicBuffer(),
-                screenshotBuffer.getColorSpace(),
-                activity.getTask().getConfiguration().orientation,
-                getInsets(mainWindow), isLowRamDevice /* reduced */, scaleFraction /* scale */,
-                true /* isRealSnapshot */, task.getWindowingMode(), getSystemUiVisibility(task),
-                isTranslucent);
+        builder.setSnapshot(screenshotBuffer.getGraphicBuffer());
+        builder.setColorSpace(screenshotBuffer.getColorSpace());
+        return builder.build();
     }
 
     private boolean shouldDisableSnapshots() {
@@ -511,16 +565,16 @@
     }
 
     /**
-     * @return The SystemUI visibility flags for the top fullscreen window in the given
+     * @return The SystemUI visibility flags for the top fullscreen opaque window in the given
      *         {@param task}.
      */
     private int getSystemUiVisibility(Task task) {
         final ActivityRecord topFullscreenActivity = task.getTopFullscreenActivity();
-        final WindowState topFullscreenWindow = topFullscreenActivity != null
-                ? topFullscreenActivity.getTopFullscreenWindow()
+        final WindowState topFullscreenOpaqueWindow = topFullscreenActivity != null
+                ? topFullscreenActivity.getTopFullscreenOpaqueWindow()
                 : null;
-        if (topFullscreenWindow != null) {
-            return topFullscreenWindow.getSystemUiVisibility();
+        if (topFullscreenOpaqueWindow != null) {
+            return topFullscreenOpaqueWindow.getSystemUiVisibility();
         }
         return 0;
     }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 1484d6a..5b458d8 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -155,7 +155,7 @@
         final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
         final TaskDescription taskDescription = new TaskDescription();
         taskDescription.setBackgroundColor(WHITE);
-        final WindowState topFullscreenWindow;
+        final WindowState topFullscreenOpaqueWindow;
         final int sysUiVis;
         final int windowFlags;
         final int windowPrivateFlags;
@@ -175,15 +175,15 @@
                         + task);
                 return null;
             }
-            topFullscreenWindow = topFullscreenActivity.getTopFullscreenWindow();
-            if (mainWindow == null || topFullscreenWindow == null) {
+            topFullscreenOpaqueWindow = topFullscreenActivity.getTopFullscreenOpaqueWindow();
+            if (mainWindow == null || topFullscreenOpaqueWindow == null) {
                 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for activity="
                         + activity);
                 return null;
             }
-            sysUiVis = topFullscreenWindow.getSystemUiVisibility();
-            windowFlags = topFullscreenWindow.getAttrs().flags;
-            windowPrivateFlags = topFullscreenWindow.getAttrs().privateFlags;
+            sysUiVis = topFullscreenOpaqueWindow.getSystemUiVisibility();
+            windowFlags = topFullscreenOpaqueWindow.getAttrs().flags;
+            windowPrivateFlags = topFullscreenOpaqueWindow.getAttrs().privateFlags;
 
             layoutParams.packageName = mainWindow.getAttrs().packageName;
             layoutParams.windowAnimations = mainWindow.getAttrs().windowAnimations;
@@ -202,11 +202,11 @@
 
             final TaskDescription td = task.getTaskDescription();
             if (td != null) {
-                taskDescription.copyFrom(td);
+                taskDescription.copyFromPreserveHiddenFields(td);
             }
             taskBounds = new Rect();
             task.getBounds(taskBounds);
-            currentOrientation = topFullscreenWindow.getConfiguration().orientation;
+            currentOrientation = topFullscreenOpaqueWindow.getConfiguration().orientation;
         }
         try {
             final int res = session.addToDisplay(window, window.mSeq, layoutParams,
@@ -222,7 +222,7 @@
         final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
                 surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, sysUiVis,
                 windowFlags, windowPrivateFlags, taskBounds,
-                currentOrientation, topFullscreenWindow.getClientInsetsState());
+                currentOrientation, topFullscreenOpaqueWindow.getClientInsetsState());
         window.setOuter(snapshotSurface);
         try {
             session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 06cea37..ce8e6dd 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -30,6 +30,7 @@
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -41,7 +42,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.logWithStack;
-import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 
 import android.annotation.CallSuper;
@@ -70,7 +70,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ToBooleanFunction;
-import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.protolog.common.ProtoLog;
 import com.android.server.wm.SurfaceAnimator.Animatable;
 
@@ -132,6 +131,7 @@
     protected final WindowList<E> mChildren = new WindowList<E>();
 
     // The specified orientation for this window container.
+    @ActivityInfo.ScreenOrientation
     protected int mOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
 
     private final Pools.SynchronizedPool<ForAllWindowsConsumerWrapper> mConsumerWrapperPool =
@@ -986,6 +986,7 @@
         }
     }
 
+    @ActivityInfo.ScreenOrientation
     int getOrientation() {
         return getOrientation(mOrientation);
     }
@@ -1038,6 +1039,8 @@
             if (wc.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
                 // Use the orientation if the container fills its parent or requested an explicit
                 // orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED.
+                ProtoLog.v(WM_DEBUG_ORIENTATION, "%s is requesting orientation %d (%s)", toString(),
+                        orientation, ActivityInfo.screenOrientationToString(orientation));
                 return orientation;
             }
         }
@@ -1730,6 +1733,7 @@
                     .setPosition(mSurfaceControl, spec.offsetX, spec.offsetY);
             mLastMagnificationSpec = spec;
         } else {
+            clearMagnificationSpec(t);
             for (int i = 0; i < mChildren.size(); i++) {
                 mChildren.get(i).applyMagnificationSpec(t, spec);
             }
@@ -2165,15 +2169,8 @@
     }
 
     void waitForAllWindowsDrawn() {
-        final WindowManagerPolicy policy = mWmService.mPolicy;
         forAllWindows(w -> {
-            final boolean keyguard = policy.isKeyguardHostWindow(w.mAttrs);
-            if (w.isVisibleLw() && (w.mActivityRecord != null || keyguard)) {
-                w.mWinAnimator.mDrawState = DRAW_PENDING;
-                // Force add to mResizingWindows.
-                w.resetLastContentInsets();
-                mWaitingForDrawn.add(w);
-            }
+            w.requestDrawIfNeeded(mWaitingForDrawn);
         }, true /* traverseTopToBottom */);
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index ea90e49..6e243f0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ClipData;
+import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.hardware.display.DisplayManagerInternal;
@@ -494,6 +495,11 @@
     public abstract int getTopFocusedDisplayId();
 
     /**
+     * @return The UI context of top focused display.
+     */
+    public abstract Context getTopFocusedDisplayUiContext();
+
+    /**
      * Checks if this display is configured and allowed to show system decorations.
      */
     public abstract boolean shouldShowSystemDecorOnDisplay(int displayId);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index acaaed9..ba9e9ce 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4511,6 +4511,7 @@
         public static final int ANIMATION_FAILSAFE = 60;
         public static final int RECOMPUTE_FOCUS = 61;
         public static final int ON_POINTER_DOWN_OUTSIDE_FOCUS = 62;
+        public static final int LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED = 63;
 
         /**
          * Used to denote that an integer field in a message will not be used.
@@ -4885,6 +4886,13 @@
                     }
                     break;
                 }
+                case LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED: {
+                    synchronized (mGlobalLock) {
+                        final DisplayContent displayContent = (DisplayContent) msg.obj;
+                        displayContent.layoutAndAssignWindowLayersIfNeeded();
+                    }
+                    break;
+                }
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG_WM, "handleMessage: exit");
@@ -7363,6 +7371,13 @@
         }
 
         @Override
+        public Context getTopFocusedDisplayUiContext() {
+            synchronized (mGlobalLock) {
+                return mRoot.getTopFocusedDisplayContent().getDisplayUiContext();
+            }
+        }
+
+        @Override
         public boolean shouldShowSystemDecorOnDisplay(int displayId) {
             synchronized (mGlobalLock) {
                 return WindowManagerService.this.shouldShowSystemDecors(displayId);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 1a41006..f6dd71b 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -44,6 +44,7 @@
 import android.app.IApplicationThread;
 import android.app.ProfilerInfo;
 import android.app.servertransaction.ConfigurationChangeItem;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -67,6 +68,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * The Activity Manager (AM) package manages the lifecycle of processes in the system through
@@ -767,6 +769,30 @@
         }
     }
 
+    /**
+     * Returns display UI context list which there is any app window shows or starting activities
+     * int this process.
+     */
+    public void getDisplayContextsWithErrorDialogs(List<Context> displayContexts) {
+        if (displayContexts == null) {
+            return;
+        }
+        synchronized (mAtm.mGlobalLock) {
+            final RootWindowContainer root = mAtm.mWindowManager.mRoot;
+            root.getDisplayContextsWithNonToastVisibleWindows(mPid, displayContexts);
+
+            for (int i = mActivities.size() - 1; i >= 0; --i) {
+                final ActivityRecord r = mActivities.get(i);
+                final int displayId = r.getDisplayId();
+                final Context c = root.getDisplayUiContext(displayId);
+
+                if (r.mVisibleRequested && !displayContexts.contains(c)) {
+                    displayContexts.add(c);
+                }
+            }
+        }
+    }
+
     public interface ComputeOomAdjCallback {
         void onVisibleActivity();
         void onPausedActivity();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 6918c96..5771f2c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1642,11 +1642,17 @@
                 && (parentAndClientVisible || isAnimating(TRANSITION | PARENTS));
     }
 
-    // TODO: Another visibility method that was added late in the release to minimize risk.
-    @Override
-    public boolean canAffectSystemUiFlags() {
-        final boolean translucent = mAttrs.alpha == 0.0f;
-        if (translucent) {
+    boolean isFullyTransparent() {
+        return mAttrs.alpha == 0f;
+    }
+
+    /**
+     * @return Whether the window can affect SystemUI flags, meaning that SystemUI (system bars,
+     *         for example) will be  affected by the flags specified in this window. This is the
+     *         case when the surface is on screen but not exiting.
+     */
+    boolean canAffectSystemUiFlags() {
+        if (isFullyTransparent()) {
             return false;
         }
         if (mActivityRecord == null) {
@@ -1726,6 +1732,39 @@
                 && isDrawnLw() && !isAnimating(TRANSITION | PARENTS);
     }
 
+    /** @see WindowManagerInternal#waitForAllWindowsDrawn */
+    void requestDrawIfNeeded(List<WindowState> outWaitingForDrawn) {
+        if (!isVisible()) {
+            return;
+        }
+        if (mActivityRecord != null) {
+            if (mActivityRecord.allDrawn) {
+                // The allDrawn of activity is reset when the visibility is changed to visible, so
+                // the content should be ready if allDrawn is set.
+                return;
+            }
+            if (mAttrs.type == TYPE_APPLICATION_STARTING) {
+                if (isDrawnLw()) {
+                    // Unnecessary to redraw a drawn starting window.
+                    return;
+                }
+            } else if (mActivityRecord.startingWindow != null) {
+                // If the activity has an active starting window, there is no need to wait for the
+                // main window.
+                return;
+            }
+        } else if (!mPolicy.isKeyguardHostWindow(mAttrs)) {
+            return;
+            // Always invalidate keyguard host window to make sure it shows the latest content
+            // because its visibility may not be changed.
+        }
+
+        mWinAnimator.mDrawState = DRAW_PENDING;
+        // Force add to {@link WindowManagerService#mResizingWindows}.
+        resetLastContentInsets();
+        outWaitingForDrawn.add(this);
+    }
+
     @Override
     void onMovedByResize() {
         ProtoLog.d(WM_DEBUG_RESIZE, "onMovedByResize: Moving %s", this);
@@ -5447,4 +5486,21 @@
         getContentInsets(outInsets);
         getStableInsets(outStableInsets);
     }
+
+    /**
+     * Returns {@code true} if this window is not {@link WindowManager.LayoutParams#TYPE_TOAST}
+     * or {@link WindowManager.LayoutParams#TYPE_APPLICATION_STARTING},
+     * since this window doesn't belong to apps.
+     */
+    boolean isNonToastOrStarting() {
+        return mAttrs.type != TYPE_TOAST && mAttrs.type != TYPE_APPLICATION_STARTING;
+    }
+
+    boolean isNonToastWindowVisibleForUid(int callingUid) {
+        return getOwningUid() == callingUid && isNonToastOrStarting() && isVisibleNow();
+    }
+
+    boolean isNonToastWindowVisibleForPid(int pid) {
+        return mSession.mPid == pid && isNonToastOrStarting() && isVisibleNow();
+    }
 }
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 9344a9b..2e8e5e7 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -485,8 +485,8 @@
     // Received data: ['inputPort1', '1', 'inputPort2', '2']
     // So we unpack accordingly here.
     outConfig->portAssociations.clear();
-    jobjectArray portAssociations = jobjectArray(env->CallStaticObjectMethod(
-            gServiceClassInfo.clazz, gServiceClassInfo.getInputPortAssociations));
+    jobjectArray portAssociations = jobjectArray(env->CallObjectMethod(mServiceObj,
+            gServiceClassInfo.getInputPortAssociations));
     if (!checkAndClearExceptionFromCallback(env, "getInputPortAssociations") && portAssociations) {
         jsize length = env->GetArrayLength(portAssociations);
         for (jsize i = 0; i < length / 2; i++) {
@@ -1920,7 +1920,7 @@
     GET_STATIC_METHOD_ID(gServiceClassInfo.getExcludedDeviceNames, clazz,
             "getExcludedDeviceNames", "()[Ljava/lang/String;");
 
-    GET_STATIC_METHOD_ID(gServiceClassInfo.getInputPortAssociations, clazz,
+    GET_METHOD_ID(gServiceClassInfo.getInputPortAssociations, clazz,
             "getInputPortAssociations", "()[Ljava/lang/String;");
 
     GET_METHOD_ID(gServiceClassInfo.getKeyRepeatTimeout, clazz,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d91ec42..8cd803c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -430,6 +430,8 @@
     private static final Set<String> GLOBAL_SETTINGS_DEPRECATED;
     private static final Set<String> SYSTEM_SETTINGS_WHITELIST;
     private static final Set<Integer> DA_DISALLOWED_POLICIES;
+    // A collection of user restrictions that are deprecated and should simply be ignored.
+    private static final Set<String> DEPRECATED_USER_RESTRICTIONS;
     private static final String AB_DEVICE_KEY = "ro.build.ab_update";
 
     static {
@@ -471,6 +473,10 @@
         DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
         DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
         DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+
+        DEPRECATED_USER_RESTRICTIONS = Sets.newHashSet(
+                UserManager.DISALLOW_ADD_MANAGED_PROFILE,
+                UserManager.DISALLOW_REMOVE_MANAGED_PROFILE);
     }
 
     /**
@@ -2400,7 +2406,6 @@
             setDeviceOwnerSystemPropertyLocked();
             findOwnerComponentIfNecessaryLocked();
             migrateUserRestrictionsIfNecessaryLocked();
-            maybeSetDefaultDeviceOwnerUserRestrictionsLocked();
 
             // TODO PO may not have a class name either due to b/17652534.  Address that too.
 
@@ -2408,15 +2413,6 @@
         }
     }
 
-    /** Apply default restrictions that haven't been applied to device owners yet. */
-    private void maybeSetDefaultDeviceOwnerUserRestrictionsLocked() {
-        final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
-        if (deviceOwner != null) {
-            maybeSetDefaultRestrictionsForAdminLocked(mOwners.getDeviceOwnerUserId(),
-                    deviceOwner, UserRestrictionsUtils.getDefaultEnabledForDeviceOwner());
-        }
-    }
-
     /** Apply default restrictions that haven't been applied to profile owners yet. */
     private void maybeSetDefaultProfileOwnerUserRestrictions() {
         synchronized (getLockObject()) {
@@ -8030,18 +8026,6 @@
             updateDeviceOwnerLocked();
             setDeviceOwnerSystemPropertyLocked();
 
-            final Set<String> restrictions =
-                    UserRestrictionsUtils.getDefaultEnabledForDeviceOwner();
-            if (!restrictions.isEmpty()) {
-                for (String restriction : restrictions) {
-                    activeAdmin.ensureUserRestrictions().putBoolean(restriction, true);
-                }
-                activeAdmin.defaultEnabledRestrictionsAlreadySet.addAll(restrictions);
-                Slog.i(LOG_TAG, "Enabled the following restrictions by default: " + restrictions);
-
-                saveUserRestrictionsLocked(userId, /* parent = */ false);
-            }
-
             long ident = mInjector.binderClearCallingIdentity();
             try {
                 // TODO Send to system too?
@@ -8717,9 +8701,15 @@
         // Allow access to the profile owner for the specified user, or delegate cert installer
         // But only if this is an organization-owned device.
         ComponentName profileOwner = getProfileOwnerAsUser(userId);
-        if (profileOwner != null && canProfileOwnerAccessDeviceIds(userId)
+        final boolean isCallerProfileOwnerOrDelegate = profileOwner != null
                 && (profileOwner.getPackageName().equals(packageName)
-                || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
+                        || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL));
+        if (isCallerProfileOwnerOrDelegate && canProfileOwnerAccessDeviceIds(userId)) {
+            return true;
+        }
+        //TODO(b/130844684): Temporarily allow profile owner on non-organization-owned devices
+        //to read device identifiers.
+        if (isCallerProfileOwnerOrDelegate) {
             return true;
         }
 
@@ -10384,8 +10374,8 @@
                 if (deviceOwner == null) {
                     return; // Shouldn't happen.
                 }
-                userRestrictions = deviceOwner.userRestrictions;
-                addOrRemoveDisableCameraRestriction(userRestrictions, deviceOwner);
+                userRestrictions = addOrRemoveDisableCameraRestriction(
+                        deviceOwner.userRestrictions, deviceOwner);
                 restrictionOwnerType = UserManagerInternal.OWNER_TYPE_DEVICE_OWNER;
                 originatingUserId = deviceOwner.getUserHandle().getIdentifier();
             } else {
@@ -10419,6 +10409,10 @@
                             userRestrictions, userId);
                 }
             }
+            // Remove deprecated restrictions.
+            for (String deprecatedRestriction: DEPRECATED_USER_RESTRICTIONS) {
+                userRestrictions.remove(deprecatedRestriction);
+            }
             mUserManagerInternal.setDevicePolicyUserRestrictions(originatingUserId,
                     userRestrictions, restrictionOwnerType);
         }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a1e0237..f05bbe2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -210,8 +210,8 @@
             "com.android.server.print.PrintManagerService";
     private static final String COMPANION_DEVICE_MANAGER_SERVICE_CLASS =
             "com.android.server.companion.CompanionDeviceManagerService";
-    private static final String STATS_COMPANION_SERVICE_LIFECYCLE_CLASS =
-            "com.android.server.stats.StatsCompanionService$Lifecycle";
+    private static final String STATS_COMPANION_LIFECYCLE_CLASS =
+            "com.android.server.stats.StatsCompanion$Lifecycle";
     private static final String USB_SERVICE_CLASS =
             "com.android.server.usb.UsbService$Lifecycle";
     private static final String MIDI_SERVICE_CLASS =
@@ -1962,8 +1962,8 @@
         }
 
         // Statsd helper
-        t.traceBegin("StartStatsCompanionService");
-        mSystemServiceManager.startService(STATS_COMPANION_SERVICE_LIFECYCLE_CLASS);
+        t.traceBegin("StartStatsCompanion");
+        mSystemServiceManager.startService(STATS_COMPANION_LIFECYCLE_CLASS);
         t.traceEnd();
 
         // Incidentd and dumpstated helper
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 3910993..015e574f2 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -28,6 +28,7 @@
         "services.net",
         "services.usage",
         "guava",
+        "androidx.test.core",
         "androidx.test.runner",
         "androidx.test.rules",
         "mockito-target-minus-junit4",
diff --git a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
index 192c50c..e9c5ce7 100644
--- a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -11,28 +11,48 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
 package com.android.server;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.doAnswer;
+
 import android.content.Context;
 import android.location.Country;
 import android.location.CountryListener;
 import android.location.ICountryListener;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.os.RemoteException;
-import android.test.AndroidTestCase;
 
-public class CountryDetectorServiceTest extends AndroidTestCase {
-    private class CountryListenerTester extends ICountryListener.Stub {
+import androidx.test.core.app.ApplicationProvider;
+
+import com.google.common.truth.Expect;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CountryDetectorServiceTest {
+
+    private static class CountryListenerTester extends ICountryListener.Stub {
         private Country mCountry;
 
         @Override
-        public void onCountryDetected(Country country) throws RemoteException {
+        public void onCountryDetected(Country country) {
             mCountry = country;
         }
 
-        public Country getCountry() {
+        Country getCountry() {
             return mCountry;
         }
 
@@ -41,12 +61,11 @@
         }
     }
 
-    private class CountryDetectorServiceTester extends CountryDetectorService {
-
+    private static class CountryDetectorServiceTester extends CountryDetectorService {
         private CountryListener mListener;
 
-        public CountryDetectorServiceTester(Context context) {
-            super(context);
+        CountryDetectorServiceTester(Context context, Handler handler) {
+            super(context, handler);
         }
 
         @Override
@@ -59,51 +78,77 @@
             mListener = listener;
         }
 
-        public boolean isListenerSet() {
+        boolean isListenerSet() {
             return mListener != null;
         }
     }
 
-    public void testAddRemoveListener() throws RemoteException {
-        CountryDetectorServiceTester serviceTester = new CountryDetectorServiceTester(getContext());
-        serviceTester.systemRunning();
-        waitForSystemReady(serviceTester);
-        CountryListenerTester listenerTester = new CountryListenerTester();
-        serviceTester.addCountryListener(listenerTester);
-        assertTrue(serviceTester.isListenerSet());
-        serviceTester.removeCountryListener(listenerTester);
-        assertFalse(serviceTester.isListenerSet());
-    }
+    @Rule
+    public final Expect expect = Expect.create();
+    @Spy
+    private Context mContext = ApplicationProvider.getApplicationContext();
+    @Spy
+    private Handler mHandler = new Handler(Looper.myLooper());
+    private CountryDetectorServiceTester mCountryDetectorService;
 
-    public void testNotifyListeners() throws RemoteException {
-        CountryDetectorServiceTester serviceTester = new CountryDetectorServiceTester(getContext());
-        CountryListenerTester listenerTesterA = new CountryListenerTester();
-        CountryListenerTester listenerTesterB = new CountryListenerTester();
-        Country country = new Country("US", Country.COUNTRY_SOURCE_NETWORK);
-        serviceTester.systemRunning();
-        waitForSystemReady(serviceTester);
-        serviceTester.addCountryListener(listenerTesterA);
-        serviceTester.addCountryListener(listenerTesterB);
-        serviceTester.notifyReceivers(country);
-        assertTrue(serviceTester.isListenerSet());
-        assertTrue(listenerTesterA.isNotified());
-        assertTrue(listenerTesterB.isNotified());
-        serviceTester.removeCountryListener(listenerTesterA);
-        serviceTester.removeCountryListener(listenerTesterB);
-        assertFalse(serviceTester.isListenerSet());
-    }
-
-    private void waitForSystemReady(CountryDetectorService service) {
-        int count = 5;
-        while (count-- > 0) {
-            try {
-                Thread.sleep(500);
-            } catch (Exception e) {
-            }
-            if (service.isSystemReady()) {
-                return;
-            }
+    @BeforeClass
+    public static void oneTimeInitialization() {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
         }
-        throw new RuntimeException("Wait System Ready timeout");
+    }
+
+    @Before
+    public void setUp() {
+        mCountryDetectorService = new CountryDetectorServiceTester(mContext, mHandler);
+
+        // Immediately invoke run on the Runnable posted to the handler
+        doAnswer(invocation -> {
+            Message message = invocation.getArgument(0);
+            message.getCallback().run();
+            return true;
+        }).when(mHandler).sendMessageAtTime(any(Message.class), anyLong());
+    }
+
+    @Test
+    public void countryListener_add_successful() throws RemoteException {
+        CountryListenerTester countryListener = new CountryListenerTester();
+
+        mCountryDetectorService.systemRunning();
+        expect.that(mCountryDetectorService.isListenerSet()).isFalse();
+        mCountryDetectorService.addCountryListener(countryListener);
+
+        expect.that(mCountryDetectorService.isListenerSet()).isTrue();
+    }
+
+    @Test
+    public void countryListener_remove_successful() throws RemoteException {
+        CountryListenerTester countryListener = new CountryListenerTester();
+
+        mCountryDetectorService.systemRunning();
+        mCountryDetectorService.addCountryListener(countryListener);
+        expect.that(mCountryDetectorService.isListenerSet()).isTrue();
+        mCountryDetectorService.removeCountryListener(countryListener);
+
+        expect.that(mCountryDetectorService.isListenerSet()).isFalse();
+    }
+
+    @Test
+    public void countryListener_notify_successful() throws RemoteException {
+        CountryListenerTester countryListenerA = new CountryListenerTester();
+        CountryListenerTester countryListenerB = new CountryListenerTester();
+        Country country = new Country("US", Country.COUNTRY_SOURCE_NETWORK);
+
+        mCountryDetectorService.systemRunning();
+        mCountryDetectorService.addCountryListener(countryListenerA);
+        mCountryDetectorService.addCountryListener(countryListenerB);
+        expect.that(countryListenerA.isNotified()).isFalse();
+        expect.that(countryListenerB.isNotified()).isFalse();
+        mCountryDetectorService.notifyReceivers(country);
+
+        expect.that(countryListenerA.isNotified()).isTrue();
+        expect.that(countryListenerB.isNotified()).isTrue();
+        expect.that(countryListenerA.getCountry().equalsIgnoreSource(country)).isTrue();
+        expect.that(countryListenerB.getCountry().equalsIgnoreSource(country)).isTrue();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 211fc4d..f96d996 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -36,6 +36,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.IActivityManager;
+import android.app.admin.DevicePolicyManager;
 import android.app.trust.ITrustManager;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -104,6 +105,8 @@
     IBiometricAuthenticator mFaceAuthenticator;
     @Mock
     ITrustManager mTrustManager;
+    @Mock
+    DevicePolicyManager mDevicePolicyManager;
 
     @Before
     public void setUp() {
@@ -111,6 +114,8 @@
 
         when(mContext.getContentResolver()).thenReturn(mContentResolver);
         when(mContext.getResources()).thenReturn(mResources);
+        when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE))
+                .thenReturn(mDevicePolicyManager);
 
         when(mInjector.getActivityManagerService()).thenReturn(mock(IActivityManager.class));
         when(mInjector.getStatusBarService()).thenReturn(mock(IStatusBarService.class));
@@ -1198,10 +1203,71 @@
         for (String s : mInjector.getConfiguration(null)) {
             SensorConfig config = new SensorConfig(s);
             mBiometricService.mImpl.registerAuthenticator(config.mId, config.mModality,
-                    config.mStrength, mFingerprintAuthenticator);
+                config.mStrength, mFingerprintAuthenticator);
         }
     }
 
+    @Test
+    public void testWorkAuthentication_fingerprintWorksIfNotDisabledByDevicePolicyManager()
+            throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
+        when(mDevicePolicyManager
+                .getKeyguardDisabledFeatures(any() /* admin */, anyInt() /* userHandle */))
+                .thenReturn(~DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+        invokeAuthenticateForWorkApp(mBiometricService.mImpl, mReceiver1);
+        waitForIdle();
+        assertEquals(mBiometricService.mPendingAuthSession.mState,
+                BiometricService.STATE_AUTH_CALLED);
+        startPendingAuthSession(mBiometricService);
+        waitForIdle();
+        assertEquals(mBiometricService.mCurrentAuthSession.mState,
+                BiometricService.STATE_AUTH_STARTED);
+    }
+
+    @Test
+    public void testWorkAuthentication_faceWorksIfNotDisabledByDevicePolicyManager()
+            throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
+        when(mDevicePolicyManager
+                .getKeyguardDisabledFeatures(any() /* admin*/, anyInt() /* userHandle */))
+                .thenReturn(~DevicePolicyManager.KEYGUARD_DISABLE_FACE);
+        invokeAuthenticateForWorkApp(mBiometricService.mImpl, mReceiver1);
+        waitForIdle();
+        assertEquals(mBiometricService.mPendingAuthSession.mState,
+                BiometricService.STATE_AUTH_CALLED);
+        startPendingAuthSession(mBiometricService);
+        waitForIdle();
+        assertEquals(mBiometricService.mCurrentAuthSession.mState,
+                BiometricService.STATE_AUTH_STARTED);
+    }
+
+    @Test
+    public void testWorkAuthentication_fingerprintFailsIfDisabledByDevicePolicyManager()
+            throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
+        when(mDevicePolicyManager
+                .getKeyguardDisabledFeatures(any() /* admin */, anyInt() /* userHandle */))
+                .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+        invokeAuthenticateForWorkApp(mBiometricService.mImpl, mReceiver1);
+        waitForIdle();
+        assertNotNull(mBiometricService.mCurrentAuthSession);
+        assertEquals(mBiometricService.mCurrentAuthSession.mState,
+                BiometricService.STATE_SHOWING_DEVICE_CREDENTIAL);
+    }
+
+    @Test
+    public void testWorkAuthentication_faceFailsIfDisabledByDevicePolicyManager() throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
+        when(mDevicePolicyManager
+                .getKeyguardDisabledFeatures(any() /* admin */, anyInt() /* userHandle */))
+                .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE);
+        invokeAuthenticateForWorkApp(mBiometricService.mImpl, mReceiver1);
+        waitForIdle();
+        assertNotNull(mBiometricService.mCurrentAuthSession);
+        assertEquals(mBiometricService.mCurrentAuthSession.mState,
+                BiometricService.STATE_SHOWING_DEVICE_CREDENTIAL);
+    }
+
     // Helper methods
 
     private int invokeCanAuthenticate(BiometricService service, int authenticators)
@@ -1311,6 +1377,21 @@
                 createTestBiometricPromptBundle(requireConfirmation, authenticators));
     }
 
+    private static void invokeAuthenticateForWorkApp(IBiometricService.Stub service,
+            IBiometricServiceReceiver receiver) throws Exception {
+        final Bundle bundle = new Bundle();
+        bundle.putBoolean(BiometricPrompt.EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS, true);
+        bundle.putBoolean(BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true);
+        bundle.putBoolean(BiometricPrompt.KEY_ALLOW_DEVICE_CREDENTIAL, true);
+        service.authenticate(
+                new Binder() /* token */,
+                0 /* sessionId */,
+                0 /* userId */,
+                receiver,
+                TEST_PACKAGE_NAME /* packageName */,
+                bundle);
+    }
+
     private static Bundle createTestBiometricPromptBundle(
             boolean requireConfirmation,
             Integer authenticators) {
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 f97c887..4fcfa32 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -100,7 +100,6 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.devicepolicy.DevicePolicyManagerService.RestrictionsListener;
-import com.android.server.pm.UserRestrictionsUtils;
 
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
@@ -1163,7 +1162,7 @@
 
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                eq(null),
+                MockUtils.checkUserRestrictions(),
                 eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
 
         verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
@@ -1719,28 +1718,6 @@
         assertTrue(dpm.setDeviceOwner(admin1, "owner-name",
                 UserHandle.USER_SYSTEM));
 
-        // Check that the user restrictions that are enabled by default are set. Then unset them.
-        final String[] defaultRestrictions = UserRestrictionsUtils
-                .getDefaultEnabledForDeviceOwner().toArray(new String[0]);
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions(defaultRestrictions),
-                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
-        );
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions(defaultRestrictions),
-                dpm.getUserRestrictions(admin1)
-        );
-        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
-                eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(defaultRestrictions),
-                eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)
-        );
-        reset(getServices().userManagerInternal);
-
-        for (String restriction : defaultRestrictions) {
-            dpm.clearUserRestriction(admin1, restriction);
-        }
-
         assertNoDeviceOwnerRestrictions();
         reset(getServices().userManagerInternal);
 
@@ -2004,7 +1981,7 @@
         reset(getServices().userManagerInternal);
     }
 
-    public void testDefaultEnabledUserRestrictions() throws Exception {
+    public void testNoDefaultEnabledUserRestrictions() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
         mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
@@ -2022,29 +1999,6 @@
         assertTrue(dpm.setDeviceOwner(admin1, "owner-name",
                 UserHandle.USER_SYSTEM));
 
-        // Check that the user restrictions that are enabled by default are set. Then unset them.
-        String[] defaultRestrictions = UserRestrictionsUtils
-                .getDefaultEnabledForDeviceOwner().toArray(new String[0]);
-        assertTrue(defaultRestrictions.length > 0);
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions(defaultRestrictions),
-                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
-        );
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions(defaultRestrictions),
-                dpm.getUserRestrictions(admin1)
-        );
-        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
-                eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(defaultRestrictions),
-                eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)
-        );
-        reset(getServices().userManagerInternal);
-
-        for (String restriction : defaultRestrictions) {
-            dpm.clearUserRestriction(admin1, restriction);
-        }
-
         assertNoDeviceOwnerRestrictions();
 
         // Initialize DPMS again and check that the user restriction wasn't enabled again.
@@ -2054,47 +2008,6 @@
         assertNotNull(dpms.getDeviceOwnerAdminLocked());
 
         assertNoDeviceOwnerRestrictions();
-
-        // Add a new restriction to the default set, initialize DPMS, and check that the restriction
-        // is set as it wasn't enabled during setDeviceOwner.
-        final String newDefaultEnabledRestriction = UserManager.DISALLOW_REMOVE_MANAGED_PROFILE;
-        assertFalse(UserRestrictionsUtils
-                .getDefaultEnabledForDeviceOwner().contains(newDefaultEnabledRestriction));
-        UserRestrictionsUtils
-                .getDefaultEnabledForDeviceOwner().add(newDefaultEnabledRestriction);
-        try {
-            reset(getServices().userManagerInternal);
-            initializeDpms();
-            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
-            assertNotNull(dpms.getDeviceOwnerAdminLocked());
-
-            DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions(newDefaultEnabledRestriction),
-                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
-            );
-            DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions(newDefaultEnabledRestriction),
-                dpm.getUserRestrictions(admin1)
-            );
-            verify(getServices().userManagerInternal, atLeast(1)).setDevicePolicyUserRestrictions(
-                    eq(UserHandle.USER_SYSTEM),
-                    MockUtils.checkUserRestrictions(newDefaultEnabledRestriction),
-                    eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)
-            );
-            reset(getServices().userManagerInternal);
-
-            // Remove the restriction.
-            dpm.clearUserRestriction(admin1, newDefaultEnabledRestriction);
-
-            // Initialize DPMS again. The restriction shouldn't be enabled for a second time.
-            initializeDpms();
-            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
-            assertNotNull(dpms.getDeviceOwnerAdminLocked());
-            assertNoDeviceOwnerRestrictions();
-        } finally {
-            UserRestrictionsUtils
-                .getDefaultEnabledForDeviceOwner().remove(newDefaultEnabledRestriction);
-        }
     }
 
     private void assertNoDeviceOwnerRestrictions() {
diff --git a/services/tests/servicestests/src/com/android/server/input/ConfigurationProcessorTest.java b/services/tests/servicestests/src/com/android/server/input/ConfigurationProcessorTest.java
index 636aa37..2bd4a3a 100644
--- a/services/tests/servicestests/src/com/android/server/input/ConfigurationProcessorTest.java
+++ b/services/tests/servicestests/src/com/android/server/input/ConfigurationProcessorTest.java
@@ -18,11 +18,9 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.content.Context;
-import android.util.Pair;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -32,7 +30,7 @@
 import org.junit.runner.RunWith;
 
 import java.io.InputStream;
-import java.util.List;
+import java.util.Map;
 
 /**
  * Build/Install/Run:
@@ -52,7 +50,7 @@
     public void testGetInputPortAssociations() {
         final int res = com.android.frameworks.servicestests.R.raw.input_port_associations;
         InputStream xml = mContext.getResources().openRawResource(res);
-        List<Pair<String, String>> associations = null;
+        Map<String, Integer> associations = null;
         try {
             associations = ConfigurationProcessor.processInputPortAssociations(xml);
         } catch (Exception e) {
@@ -60,8 +58,8 @@
         }
         assertNotNull(associations);
         assertEquals(2, associations.size());
-        assertTrue(associations.contains(Pair.create("USB1", "0")));
-        assertTrue(associations.contains(Pair.create("USB2", "1")));
+        assertEquals(0, associations.get("USB1").intValue());
+        assertEquals(1, associations.get("USB2").intValue());
     }
 
     @Test
@@ -69,7 +67,7 @@
         final int res =
                 com.android.frameworks.servicestests.R.raw.input_port_associations_bad_displayport;
         InputStream xml = mContext.getResources().openRawResource(res);
-        List<Pair<String, String>> associations = null;
+        Map<String, Integer> associations = null;
         try {
             associations = ConfigurationProcessor.processInputPortAssociations(xml);
         } catch (Exception e) {
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexTypeIdentifierTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexTypeIdentifierTest.java
deleted file mode 100644
index 18b91b0..0000000
--- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexTypeIdentifierTest.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.integrity.serializer;
-
-import static com.android.server.testutils.TestUtils.assertExpectException;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.integrity.AppInstallMetadata;
-import android.content.integrity.AtomicFormula;
-import android.content.integrity.CompoundFormula;
-import android.content.integrity.Formula;
-import android.content.integrity.Rule;
-
-import androidx.annotation.NonNull;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.Arrays;
-
-/** Unit tests for {@link RuleIndexTypeIdentifier}. */
-@RunWith(JUnit4.class)
-public class RuleIndexTypeIdentifierTest {
-
-    @Test
-    public void getIndexType_nullRule() {
-        Rule rule = null;
-
-        assertExpectException(
-                IllegalArgumentException.class,
-                /* expectedExceptionMessageRegex= */
-                "Indexing type cannot be determined for null rule.",
-                () -> RuleIndexTypeIdentifier.getIndexType(rule));
-    }
-
-    @Test
-    public void getIndexType_invalidFormula() {
-        Rule rule = new Rule(getInvalidFormula(), Rule.DENY);
-
-        assertExpectException(
-                IllegalArgumentException.class,
-                /* expectedExceptionMessageRegex= */ "Invalid formula tag type.",
-                () -> RuleIndexTypeIdentifier.getIndexType(rule));
-    }
-
-    @Test
-    public void getIndexType_ruleContainingPackageNameFormula() {
-        String packageName = "com.test.app";
-        String installerName = "com.test.installer";
-        Rule rule =
-                new Rule(
-                        new CompoundFormula(
-                                CompoundFormula.AND,
-                                Arrays.asList(
-                                        new AtomicFormula.StringAtomicFormula(
-                                                AtomicFormula.PACKAGE_NAME,
-                                                packageName,
-                                                /* isHashedValue= */ false),
-                                        new AtomicFormula.StringAtomicFormula(
-                                                AtomicFormula.INSTALLER_NAME,
-                                                installerName,
-                                                /* isHashedValue= */ false))),
-                        Rule.DENY);
-
-        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
-                .isEqualTo(RuleIndexTypeIdentifier.PACKAGE_NAME_INDEXED);
-    }
-
-    @Test
-    public void getIndexType_ruleContainingAppCertificateFormula() {
-        String appCertificate = "cert1";
-        String installerName = "com.test.installer";
-        Rule rule =
-                new Rule(
-                        new CompoundFormula(
-                                CompoundFormula.AND,
-                                Arrays.asList(
-                                        new AtomicFormula.StringAtomicFormula(
-                                                AtomicFormula.APP_CERTIFICATE,
-                                                appCertificate,
-                                                /* isHashedValue= */ false),
-                                        new AtomicFormula.StringAtomicFormula(
-                                                AtomicFormula.INSTALLER_NAME,
-                                                installerName,
-                                                /* isHashedValue= */ false))),
-                        Rule.DENY);
-
-        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
-                .isEqualTo(RuleIndexTypeIdentifier.APP_CERTIFICATE_INDEXED);
-    }
-
-    @Test
-    public void getIndexType_ruleWithUnindexedCompoundFormula() {
-        String installerCertificate = "cert1";
-        String installerName = "com.test.installer";
-        Rule rule =
-                new Rule(
-                        new CompoundFormula(
-                                CompoundFormula.AND,
-                                Arrays.asList(
-                                        new AtomicFormula.StringAtomicFormula(
-                                                AtomicFormula.INSTALLER_CERTIFICATE,
-                                                installerCertificate,
-                                                /* isHashedValue= */ false),
-                                        new AtomicFormula.StringAtomicFormula(
-                                                AtomicFormula.INSTALLER_NAME,
-                                                installerName,
-                                                /* isHashedValue= */ false))),
-                        Rule.DENY);
-
-        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
-                .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED);
-    }
-
-    @Test
-    public void getIndexType_rulContainingCompoundFormulaWithIntAndBoolean() {
-        int appVersion = 12;
-        Rule rule =
-                new Rule(
-                        new CompoundFormula(
-                                CompoundFormula.AND,
-                                Arrays.asList(
-                                        new AtomicFormula.BooleanAtomicFormula(
-                                                AtomicFormula.PRE_INSTALLED,
-                                                /* booleanValue= */ true),
-                                        new AtomicFormula.IntAtomicFormula(
-                                                AtomicFormula.VERSION_CODE,
-                                                AtomicFormula.EQ,
-                                                appVersion))),
-                        Rule.DENY);
-
-        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
-                .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED);
-    }
-
-    @Test
-    public void getIndexType_negatedRuleContainingPackageNameFormula() {
-        String packageName = "com.test.app";
-        String installerName = "com.test.installer";
-        Rule rule =
-                new Rule(
-                        new CompoundFormula(
-                                CompoundFormula.NOT,
-                                Arrays.asList(
-                                        new CompoundFormula(
-                                                CompoundFormula.AND,
-                                                Arrays.asList(
-                                                        new AtomicFormula.StringAtomicFormula(
-                                                                AtomicFormula.PACKAGE_NAME,
-                                                                packageName,
-                                                                /* isHashedValue= */ false),
-                                                        new AtomicFormula.StringAtomicFormula(
-                                                                AtomicFormula.INSTALLER_NAME,
-                                                                installerName,
-                                                                /* isHashedValue= */ false))))),
-                        Rule.DENY);
-
-        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
-                .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED);
-    }
-
-    private Formula getInvalidFormula() {
-        return new Formula() {
-            @Override
-            public boolean isSatisfied(AppInstallMetadata appInstallMetadata) {
-                return false;
-            }
-
-            @Override
-            public int getTag() {
-                return 4;
-            }
-
-            @Override
-            public int hashCode() {
-                return super.hashCode();
-            }
-
-            @Override
-            public boolean equals(Object obj) {
-                return super.equals(obj);
-            }
-
-            @NonNull
-            @Override
-            protected Object clone() throws CloneNotSupportedException {
-                return super.clone();
-            }
-
-            @Override
-            public String toString() {
-                return super.toString();
-            }
-
-            @Override
-            protected void finalize() throws Throwable {
-                super.finalize();
-            }
-        };
-    }
-}
-
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java
new file mode 100644
index 0000000..90ec19e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java
@@ -0,0 +1,323 @@
+/*
+ * 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.integrity.serializer;
+
+import static com.android.server.integrity.serializer.RuleIndexingDetails.APP_CERTIFICATE_INDEXED;
+import static com.android.server.integrity.serializer.RuleIndexingDetails.NOT_INDEXED;
+import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAGE_NAME_INDEXED;
+import static com.android.server.integrity.serializer.RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets;
+import static com.android.server.testutils.TestUtils.assertExpectException;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.integrity.AppInstallMetadata;
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Formula;
+import android.content.integrity.Rule;
+
+import androidx.annotation.NonNull;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/** Unit tests for {@link RuleIndexingDetailsIdentifier}. */
+@RunWith(JUnit4.class)
+public class RuleIndexingDetailsIdentifierTest {
+
+    private static final String SAMPLE_APP_CERTIFICATE = "testcert";
+    private static final String SAMPLE_INSTALLER_NAME = "com.test.installer";
+    private static final String SAMPLE_INSTALLER_CERTIFICATE = "installercert";
+    private static final String SAMPLE_PACKAGE_NAME = "com.test.package";
+
+    private static final AtomicFormula ATOMIC_FORMULA_WITH_PACKAGE_NAME =
+            new AtomicFormula.StringAtomicFormula(
+                    AtomicFormula.PACKAGE_NAME,
+                    SAMPLE_PACKAGE_NAME,
+                    /* isHashedValue= */ false);
+    private static final AtomicFormula ATOMIC_FORMULA_WITH_APP_CERTIFICATE =
+            new AtomicFormula.StringAtomicFormula(
+                    AtomicFormula.APP_CERTIFICATE,
+                    SAMPLE_APP_CERTIFICATE,
+                    /* isHashedValue= */ false);
+    private static final AtomicFormula ATOMIC_FORMULA_WITH_INSTALLER_NAME =
+            new AtomicFormula.StringAtomicFormula(
+                    AtomicFormula.INSTALLER_NAME,
+                    SAMPLE_INSTALLER_NAME,
+                    /* isHashedValue= */ false);
+    private static final AtomicFormula ATOMIC_FORMULA_WITH_INSTALLER_CERTIFICATE =
+            new AtomicFormula.StringAtomicFormula(
+                    AtomicFormula.INSTALLER_CERTIFICATE,
+                    SAMPLE_INSTALLER_CERTIFICATE,
+                    /* isHashedValue= */ false);
+    private static final AtomicFormula ATOMIC_FORMULA_WITH_VERSION_CODE =
+            new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 12);
+    private static final AtomicFormula ATOMIC_FORMULA_WITH_ISPREINSTALLED =
+            new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, /* booleanValue= */
+                    true);
+
+
+    private static final Rule RULE_WITH_PACKAGE_NAME =
+            new Rule(
+                    new CompoundFormula(
+                            CompoundFormula.AND,
+                            Arrays.asList(
+                                    ATOMIC_FORMULA_WITH_PACKAGE_NAME,
+                                    ATOMIC_FORMULA_WITH_INSTALLER_NAME)),
+                    Rule.DENY);
+    private static final Rule RULE_WITH_APP_CERTIFICATE =
+            new Rule(
+                    new CompoundFormula(
+                            CompoundFormula.AND,
+                            Arrays.asList(
+                                    ATOMIC_FORMULA_WITH_APP_CERTIFICATE,
+                                    ATOMIC_FORMULA_WITH_INSTALLER_NAME)),
+                    Rule.DENY);
+    private static final Rule RULE_WITH_INSTALLER_RESTRICTIONS =
+            new Rule(
+                    new CompoundFormula(
+                            CompoundFormula.AND,
+                            Arrays.asList(
+                                    ATOMIC_FORMULA_WITH_INSTALLER_NAME,
+                                    ATOMIC_FORMULA_WITH_INSTALLER_CERTIFICATE)),
+                    Rule.DENY);
+
+    private static final Rule RULE_WITH_NONSTRING_RESTRICTIONS =
+            new Rule(
+                    new CompoundFormula(
+                            CompoundFormula.AND,
+                            Arrays.asList(
+                                    ATOMIC_FORMULA_WITH_VERSION_CODE,
+                                    ATOMIC_FORMULA_WITH_ISPREINSTALLED)),
+                    Rule.DENY);
+
+    @Test
+    public void getIndexType_nullRule() {
+        List<Rule> ruleList = null;
+
+        assertExpectException(
+                IllegalArgumentException.class,
+                /* expectedExceptionMessageRegex= */
+                "Index buckets cannot be created for null rule list.",
+                () -> splitRulesIntoIndexBuckets(ruleList));
+    }
+
+    @Test
+    public void getIndexType_invalidFormula() {
+        List<Rule> ruleList = new ArrayList();
+        ruleList.add(new Rule(getInvalidFormula(), Rule.DENY));
+
+        assertExpectException(
+                IllegalArgumentException.class,
+                /* expectedExceptionMessageRegex= */ "Invalid formula tag type.",
+                () -> splitRulesIntoIndexBuckets(ruleList));
+    }
+
+    @Test
+    public void getIndexType_ruleContainingPackageNameFormula() {
+        List<Rule> ruleList = new ArrayList();
+        ruleList.add(RULE_WITH_PACKAGE_NAME);
+
+        Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList);
+
+        // Verify the resulting map content.
+        assertThat(result.keySet())
+                .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
+        assertThat(result.get(NOT_INDEXED)).isEmpty();
+        assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty();
+        assertThat(result.get(PACKAGE_NAME_INDEXED)).containsExactly(RULE_WITH_PACKAGE_NAME);
+    }
+
+    @Test
+    public void getIndexType_ruleContainingAppCertificateFormula() {
+        List<Rule> ruleList = new ArrayList();
+        ruleList.add(RULE_WITH_APP_CERTIFICATE);
+
+        Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList);
+
+        assertThat(result.keySet())
+                .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
+        assertThat(result.get(NOT_INDEXED)).isEmpty();
+        assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty();
+        assertThat(result.get(APP_CERTIFICATE_INDEXED)).containsExactly(RULE_WITH_APP_CERTIFICATE);
+    }
+
+    @Test
+    public void getIndexType_ruleWithUnindexedCompoundFormula() {
+        List<Rule> ruleList = new ArrayList();
+        ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS);
+
+        Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList);
+
+        assertThat(result.keySet())
+                .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
+        assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty();
+        assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty();
+        assertThat(result.get(NOT_INDEXED)).containsExactly(RULE_WITH_INSTALLER_RESTRICTIONS);
+    }
+
+    @Test
+    public void getIndexType_ruleContainingCompoundFormulaWithIntAndBoolean() {
+        List<Rule> ruleList = new ArrayList();
+        ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS);
+
+        Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList);
+
+        assertThat(result.keySet())
+                .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
+        assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty();
+        assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty();
+        assertThat(result.get(NOT_INDEXED)).containsExactly(RULE_WITH_NONSTRING_RESTRICTIONS);
+    }
+
+    @Test
+    public void getIndexType_negatedRuleContainingPackageNameFormula() {
+        Rule negatedRule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.NOT,
+                                Arrays.asList(
+                                        new CompoundFormula(
+                                                CompoundFormula.AND,
+                                                Arrays.asList(
+                                                        ATOMIC_FORMULA_WITH_PACKAGE_NAME,
+                                                        ATOMIC_FORMULA_WITH_APP_CERTIFICATE)))),
+                        Rule.DENY);
+        List<Rule> ruleList = new ArrayList();
+        ruleList.add(negatedRule);
+
+        Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList);
+
+        assertThat(result.keySet())
+                .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
+        assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty();
+        assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty();
+        assertThat(result.get(NOT_INDEXED)).containsExactly(negatedRule);
+    }
+
+    @Test
+    public void getIndexType_allRulesTogetherInValidOrder() {
+        Rule packageNameRuleA = getRuleWithPackageName("aaa");
+        Rule packageNameRuleB = getRuleWithPackageName("bbb");
+        Rule packageNameRuleC = getRuleWithPackageName("ccc");
+        Rule certificateRule1 = getRuleWithAppCertificate("cert1");
+        Rule certificateRule2 = getRuleWithAppCertificate("cert2");
+        Rule certificateRule3 = getRuleWithAppCertificate("cert3");
+
+        List<Rule> ruleList = new ArrayList();
+        ruleList.add(packageNameRuleB);
+        ruleList.add(packageNameRuleC);
+        ruleList.add(packageNameRuleA);
+        ruleList.add(certificateRule3);
+        ruleList.add(certificateRule2);
+        ruleList.add(certificateRule1);
+        ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS);
+        ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS);
+
+        Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList);
+
+        assertThat(result.keySet())
+                .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
+
+        // We check asserts this way to ensure ordering based on package name.
+        assertThat(result.get(PACKAGE_NAME_INDEXED).get(0)).isEqualTo(packageNameRuleA);
+        assertThat(result.get(PACKAGE_NAME_INDEXED).get(1)).isEqualTo(packageNameRuleB);
+        assertThat(result.get(PACKAGE_NAME_INDEXED).get(2)).isEqualTo(packageNameRuleC);
+
+        // We check asserts this way to ensure ordering based on app certificate.
+        assertThat(result.get(APP_CERTIFICATE_INDEXED).get(0)).isEqualTo(certificateRule1);
+        assertThat(result.get(APP_CERTIFICATE_INDEXED).get(1)).isEqualTo(certificateRule2);
+        assertThat(result.get(APP_CERTIFICATE_INDEXED).get(2)).isEqualTo(certificateRule3);
+
+        assertThat(result.get(NOT_INDEXED))
+                .containsExactly(
+                        RULE_WITH_INSTALLER_RESTRICTIONS,
+                        RULE_WITH_NONSTRING_RESTRICTIONS);
+    }
+
+    private Rule getRuleWithPackageName(String packageName) {
+        return new Rule(
+                new CompoundFormula(
+                        CompoundFormula.AND,
+                        Arrays.asList(
+                                new AtomicFormula.StringAtomicFormula(
+                                        AtomicFormula.PACKAGE_NAME,
+                                        packageName,
+                                        /* isHashedValue= */ false),
+                                ATOMIC_FORMULA_WITH_INSTALLER_NAME)),
+                Rule.DENY);
+    }
+
+    private Rule getRuleWithAppCertificate(String certificate) {
+        return new Rule(
+                new CompoundFormula(
+                        CompoundFormula.AND,
+                        Arrays.asList(
+                                new AtomicFormula.StringAtomicFormula(
+                                        AtomicFormula.APP_CERTIFICATE,
+                                        certificate,
+                                        /* isHashedValue= */ false),
+                                ATOMIC_FORMULA_WITH_INSTALLER_NAME)),
+                Rule.DENY);
+    }
+
+    private Formula getInvalidFormula() {
+        return new Formula() {
+            @Override
+            public boolean isSatisfied(AppInstallMetadata appInstallMetadata) {
+                return false;
+            }
+
+            @Override
+            public int getTag() {
+                return 4;
+            }
+
+            @Override
+            public int hashCode() {
+                return super.hashCode();
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                return super.equals(obj);
+            }
+
+            @NonNull
+            @Override
+            protected Object clone() throws CloneNotSupportedException {
+                return super.clone();
+            }
+
+            @Override
+            public String toString() {
+                return super.toString();
+            }
+
+            @Override
+            protected void finalize() throws Throwable {
+                super.finalize();
+            }
+        };
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index b3f1bcd6..06b3dc1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -16,6 +16,12 @@
 
 package com.android.server.pm;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
@@ -29,15 +35,21 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.internal.util.ArrayUtils;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.collect.Range;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -45,7 +57,8 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 /** Test {@link UserManager} functionality. */
-public class UserManagerTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public final class UserManagerTest {
     // Taken from UserManagerService
     private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // 30 years
 
@@ -58,6 +71,8 @@
             "com.android.egg"
     };
 
+    private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+
     private final Object mUserRemoveLock = new Object();
     private final Object mUserSwitchLock = new Object();
 
@@ -65,15 +80,14 @@
     private PackageManager mPackageManager;
     private List<Integer> usersToRemove;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
-        mUserManager = UserManager.get(getContext());
-        mPackageManager = getContext().getPackageManager();
+        mUserManager = UserManager.get(mContext);
+        mPackageManager = mContext.getPackageManager();
 
         IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
-        getContext().registerReceiver(new BroadcastReceiver() {
+        mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
                 switch (intent.getAction()) {
@@ -95,36 +109,35 @@
         usersToRemove = new ArrayList<>();
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void tearDown() throws Exception {
         for (Integer userId : usersToRemove) {
             removeUser(userId);
         }
-        super.tearDown();
     }
 
     private void removeExistingUsers() {
+        int currentUser = ActivityManager.getCurrentUser();
         List<UserInfo> list = mUserManager.getUsers();
         for (UserInfo user : list) {
-            // Keep system and primary user.
-            // We do not have to keep primary user, but in split system user mode, we need it
-            // until http://b/22976637 is fixed.  Right now in split system user mode, you need to
-            // switch to primary user and run tests under primary user.
-            if (user.id != UserHandle.USER_SYSTEM && !user.isPrimary()) {
+            // Keep system and current user
+            if (user.id != UserHandle.USER_SYSTEM && user.id != currentUser) {
                 removeUser(user.id);
             }
         }
     }
 
     @SmallTest
+    @Test
     public void testHasSystemUser() throws Exception {
-        assertTrue(findUser(UserHandle.USER_SYSTEM));
+        assertThat(findUser(UserHandle.USER_SYSTEM)).isTrue();
     }
 
     @MediumTest
-    public void testAddUser() throws Exception {
+    @Test
+    public void testAddGuest() throws Exception {
         UserInfo userInfo = createUser("Guest 1", UserInfo.FLAG_GUEST);
-        assertTrue(userInfo != null);
+        assertThat(userInfo).isNotNull();
 
         List<UserInfo> list = mUserManager.getUsers();
         boolean found = false;
@@ -135,35 +148,39 @@
                     && !user.isPrimary()) {
                 found = true;
                 Bundle restrictions = mUserManager.getUserRestrictions(user.getUserHandle());
-                assertTrue("Guest user should have DISALLOW_CONFIG_WIFI=true by default",
-                        restrictions.getBoolean(UserManager.DISALLOW_CONFIG_WIFI));
+                assertWithMessage("Guest user should have DISALLOW_CONFIG_WIFI=true by default")
+                        .that(restrictions.getBoolean(UserManager.DISALLOW_CONFIG_WIFI))
+                        .isTrue();
             }
         }
-        assertTrue(found);
+        assertThat(found).isTrue();
     }
 
     @MediumTest
+    @Test
     public void testAdd2Users() throws Exception {
         UserInfo user1 = createUser("Guest 1", UserInfo.FLAG_GUEST);
         UserInfo user2 = createUser("User 2", UserInfo.FLAG_ADMIN);
 
-        assertTrue(user1 != null);
-        assertTrue(user2 != null);
+        assertThat(user1).isNotNull();
+        assertThat(user2).isNotNull();
 
-        assertTrue(findUser(0));
-        assertTrue(findUser(user1.id));
-        assertTrue(findUser(user2.id));
+        assertThat(findUser(UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(findUser(user1.id)).isTrue();
+        assertThat(findUser(user2.id)).isTrue();
     }
 
     @MediumTest
+    @Test
     public void testRemoveUser() throws Exception {
         UserInfo userInfo = createUser("Guest 1", UserInfo.FLAG_GUEST);
         removeUser(userInfo.id);
 
-        assertFalse(findUser(userInfo.id));
+        assertThat(findUser(userInfo.id)).isFalse();
     }
 
     @MediumTest
+    @Test
     public void testRemoveUserByHandle() {
         UserInfo userInfo = createUser("Guest 1", UserInfo.FLAG_GUEST);
         final UserHandle user = userInfo.getUserHandle();
@@ -183,10 +200,11 @@
             }
         }
 
-        assertFalse(findUser(userInfo.id));
+        assertThat(findUser(userInfo.id)).isFalse();
     }
 
     @MediumTest
+    @Test
     public void testRemoveUserByHandle_ThrowsException() {
         synchronized (mUserRemoveLock) {
             try {
@@ -200,6 +218,7 @@
 
     /** Tests creating a FULL user via specifying userType. */
     @MediumTest
+    @Test
     public void testCreateUserViaTypes() throws Exception {
         createUserWithTypeAndCheckFlags(UserManager.USER_TYPE_FULL_GUEST,
                 UserInfo.FLAG_GUEST | UserInfo.FLAG_FULL);
@@ -213,6 +232,7 @@
 
     /** Tests creating a FULL user via specifying user flags. */
     @MediumTest
+    @Test
     public void testCreateUserViaFlags() throws Exception {
         createUserWithFlagsAndCheckType(UserInfo.FLAG_GUEST, UserManager.USER_TYPE_FULL_GUEST,
                 UserInfo.FLAG_FULL);
@@ -231,10 +251,9 @@
     private void createUserWithTypeAndCheckFlags(String userType,
             @UserIdInt int requiredFlags) {
         final UserInfo userInfo = createUser("Name", userType, 0);
-        assertEquals("Wrong user type", userType, userInfo.userType);
-        assertEquals(
-                "Flags " + userInfo.flags + " did not contain expected " + requiredFlags,
-                requiredFlags, userInfo.flags & requiredFlags);
+        assertWithMessage("Wrong user type").that(userInfo.userType).isEqualTo(userType);
+        assertWithMessage("Flags %s did not contain expected %s", userInfo.flags, requiredFlags)
+                .that(userInfo.flags & requiredFlags).isEqualTo(requiredFlags);
         removeUser(userInfo.id);
     }
 
@@ -245,131 +264,140 @@
     private void createUserWithFlagsAndCheckType(@UserIdInt int flags, String expectedUserType,
             @UserIdInt int additionalRequiredFlags) {
         final UserInfo userInfo = createUser("Name", flags);
-        assertEquals("Wrong user type", expectedUserType, userInfo.userType);
+        assertWithMessage("Wrong user type").that(userInfo.userType).isEqualTo(expectedUserType);
         additionalRequiredFlags |= flags;
-        assertEquals(
-                "Flags " + userInfo.flags + " did not contain expected " + additionalRequiredFlags,
-                additionalRequiredFlags, userInfo.flags & additionalRequiredFlags);
+        assertWithMessage("Flags %s did not contain expected %s", userInfo.flags,
+                additionalRequiredFlags).that(userInfo.flags & additionalRequiredFlags)
+                        .isEqualTo(additionalRequiredFlags);
         removeUser(userInfo.id);
     }
 
 
     @MediumTest
-    public void testAddGuest() throws Exception {
+    @Test
+    public void testThereCanBeOnlyOneGuest() throws Exception {
         UserInfo userInfo1 = createUser("Guest 1", UserInfo.FLAG_GUEST);
+        assertThat(userInfo1).isNotNull();
         UserInfo userInfo2 = createUser("Guest 2", UserInfo.FLAG_GUEST);
-        assertNotNull(userInfo1);
-        assertNull(userInfo2);
+        assertThat(userInfo2).isNull();
     }
 
     @MediumTest
+    @Test
     public void testFindExistingGuest_guestExists() throws Exception {
         UserInfo userInfo1 = createUser("Guest", UserInfo.FLAG_GUEST);
+        assertThat(userInfo1).isNotNull();
         UserInfo foundGuest = mUserManager.findCurrentGuestUser();
-        assertNotNull(foundGuest);
+        assertThat(foundGuest).isNotNull();
     }
 
     @SmallTest
+    @Test
     public void testFindExistingGuest_guestDoesNotExist() throws Exception {
         UserInfo foundGuest = mUserManager.findCurrentGuestUser();
-        assertNull(foundGuest);
+        assertThat(foundGuest).isNull();
     }
 
     @MediumTest
+    @Test
     public void testSetUserAdmin() throws Exception {
         UserInfo userInfo = createUser("SecondaryUser", /*flags=*/ 0);
-        assertFalse(userInfo.isAdmin());
+        assertThat(userInfo.isAdmin()).isFalse();
 
         mUserManager.setUserAdmin(userInfo.id);
 
         userInfo = mUserManager.getUserInfo(userInfo.id);
-        assertTrue(userInfo.isAdmin());
+        assertThat(userInfo.isAdmin()).isTrue();
     }
 
     @MediumTest
+    @Test
     public void testGetProfileParent() throws Exception {
+        assumeManagedUsersSupported();
         final int primaryUserId = mUserManager.getPrimaryUser().id;
 
         UserInfo userInfo = createProfileForUser("Profile",
                 UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
-        assertNotNull(userInfo);
-        assertNull(mUserManager.getProfileParent(primaryUserId));
+        assertThat(userInfo).isNotNull();
+        assertThat(mUserManager.getProfileParent(primaryUserId)).isNull();
         UserInfo parentProfileInfo = mUserManager.getProfileParent(userInfo.id);
-        assertNotNull(parentProfileInfo);
-        assertEquals(parentProfileInfo.id, primaryUserId);
+        assertThat(parentProfileInfo).isNotNull();
+        assertThat(primaryUserId).isEqualTo(parentProfileInfo.id);
         removeUser(userInfo.id);
-        assertNull(mUserManager.getProfileParent(primaryUserId));
+        assertThat(mUserManager.getProfileParent(primaryUserId)).isNull();
     }
 
     /** Test that UserManager returns the correct badge information for a managed profile. */
     @MediumTest
+    @Test
     public void testProfileTypeInformation() throws Exception {
+        assumeManagedUsersSupported();
         final UserTypeDetails userTypeDetails =
                 UserTypeFactory.getUserTypes().get(UserManager.USER_TYPE_PROFILE_MANAGED);
-        assertNotNull("No " + UserManager.USER_TYPE_PROFILE_MANAGED + " type on device",
-                userTypeDetails);
-        assertEquals(UserManager.USER_TYPE_PROFILE_MANAGED, userTypeDetails.getName());
+        assertWithMessage("No %s type on device", UserManager.USER_TYPE_PROFILE_MANAGED)
+                .that(userTypeDetails).isNotNull();
+        assertThat(userTypeDetails.getName()).isEqualTo(UserManager.USER_TYPE_PROFILE_MANAGED);
 
         final int primaryUserId = mUserManager.getPrimaryUser().id;
         UserInfo userInfo = createProfileForUser("Managed",
                 UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
-        assertNotNull(userInfo);
+        assertThat(userInfo).isNotNull();
         final int userId = userInfo.id;
         final UserHandle userHandle = new UserHandle(userId);
 
-        assertEquals(userTypeDetails.hasBadge(),
-                mUserManager.hasBadge(userId));
-        assertEquals(userTypeDetails.getIconBadge(),
-                mUserManager.getUserIconBadgeResId(userId));
-        assertEquals(userTypeDetails.getBadgePlain(),
-                mUserManager.getUserBadgeResId(userId));
-        assertEquals(userTypeDetails.getBadgeNoBackground(),
-                mUserManager.getUserBadgeNoBackgroundResId(userId));
-        assertEquals(userTypeDetails.isProfile(),
-                mUserManager.isProfile(userId));
-        assertEquals(userTypeDetails.getName(),
-                mUserManager.getUserTypeForUser(userHandle));
+        assertThat(mUserManager.hasBadge(userId)).isEqualTo(userTypeDetails.hasBadge());
+        assertThat(mUserManager.getUserIconBadgeResId(userId))
+                .isEqualTo(userTypeDetails.getIconBadge());
+        assertThat(mUserManager.getUserBadgeResId(userId))
+                .isEqualTo(userTypeDetails.getBadgePlain());
+        assertThat(mUserManager.getUserBadgeNoBackgroundResId(userId))
+                .isEqualTo(userTypeDetails.getBadgeNoBackground());
+        assertThat(mUserManager.isProfile(userId)).isEqualTo(userTypeDetails.isProfile());
+        assertThat(mUserManager.getUserTypeForUser(userHandle))
+                .isEqualTo(userTypeDetails.getName());
 
         final int badgeIndex = userInfo.profileBadge;
-        assertEquals(
-                Resources.getSystem().getColor(userTypeDetails.getBadgeColor(badgeIndex), null),
-                mUserManager.getUserBadgeColor(userId));
-        assertEquals(
-                Resources.getSystem().getString(userTypeDetails.getBadgeLabel(badgeIndex), "Test"),
-                mUserManager.getBadgedLabelForUser("Test", userHandle));
+        assertThat(mUserManager.getUserBadgeColor(userId)).isEqualTo(
+                Resources.getSystem().getColor(userTypeDetails.getBadgeColor(badgeIndex), null));
+        assertThat(mUserManager.getBadgedLabelForUser("Test", userHandle)).isEqualTo(
+                Resources.getSystem().getString(userTypeDetails.getBadgeLabel(badgeIndex), "Test"));
     }
 
     // Make sure only one managed profile can be created
     @MediumTest
+    @Test
     public void testAddManagedProfile() throws Exception {
+        assumeManagedUsersSupported();
         final int primaryUserId = mUserManager.getPrimaryUser().id;
         UserInfo userInfo1 = createProfileForUser("Managed 1",
                 UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
         UserInfo userInfo2 = createProfileForUser("Managed 2",
                 UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
 
-        assertNotNull(userInfo1);
-        assertNull(userInfo2);
+        assertThat(userInfo1).isNotNull();
+        assertThat(userInfo2).isNull();
 
-        assertEquals(userInfo1.userType, UserManager.USER_TYPE_PROFILE_MANAGED);
+        assertThat(userInfo1.userType).isEqualTo(UserManager.USER_TYPE_PROFILE_MANAGED);
         int requiredFlags = UserInfo.FLAG_MANAGED_PROFILE | UserInfo.FLAG_PROFILE;
-        assertEquals("Wrong flags " + userInfo1.flags, requiredFlags,
-                userInfo1.flags & requiredFlags);
+        assertWithMessage("Wrong flags %s", userInfo1.flags).that(userInfo1.flags & requiredFlags)
+                .isEqualTo(requiredFlags);
 
         // Verify that current user is not a managed profile
-        assertFalse(mUserManager.isManagedProfile());
+        assertThat(mUserManager.isManagedProfile()).isFalse();
     }
 
     // Verify that disallowed packages are not installed in the managed profile.
     @MediumTest
+    @Test
     public void testAddManagedProfile_withDisallowedPackages() throws Exception {
+        assumeManagedUsersSupported();
         final int primaryUserId = mUserManager.getPrimaryUser().id;
         UserInfo userInfo1 = createProfileForUser("Managed1",
                 UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
         // Verify that the packagesToVerify are installed by default.
         for (String pkg : PACKAGES) {
-            assertTrue("Package should be installed in managed profile: " + pkg,
-                    isPackageInstalledForUser(pkg, userInfo1.id));
+            assertWithMessage("Package should be installed in managed profile: %s", pkg)
+                    .that(isPackageInstalledForUser(pkg, userInfo1.id)).isTrue();
         }
         removeUser(userInfo1.id);
 
@@ -377,50 +405,57 @@
                 UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId, PACKAGES);
         // Verify that the packagesToVerify are not installed by default.
         for (String pkg : PACKAGES) {
-            assertFalse("Package should not be installed in managed profile when disallowed: "
-                    + pkg, isPackageInstalledForUser(pkg, userInfo2.id));
+            assertWithMessage(
+                    "Package should not be installed in managed profile when disallowed: %s", pkg)
+                            .that(isPackageInstalledForUser(pkg, userInfo2.id)).isFalse();
         }
     }
 
     // Verify that if any packages are disallowed to install during creation of managed profile can
     // still be installed later.
     @MediumTest
+    @Test
     public void testAddManagedProfile_disallowedPackagesInstalledLater() throws Exception {
+        assumeManagedUsersSupported();
         final int primaryUserId = mUserManager.getPrimaryUser().id;
         UserInfo userInfo = createProfileForUser("Managed",
                 UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId, PACKAGES);
         // Verify that the packagesToVerify are not installed by default.
         for (String pkg : PACKAGES) {
-            assertFalse("Package should not be installed in managed profile when disallowed: "
-                    + pkg, isPackageInstalledForUser(pkg, userInfo.id));
+            assertWithMessage("Pkg should not be installed in managed profile when disallowed: %s",
+                    pkg).that(isPackageInstalledForUser(pkg, userInfo.id)).isFalse();
         }
 
         // Verify that the disallowed packages during profile creation can be installed now.
         for (String pkg : PACKAGES) {
-            assertEquals("Package could not be installed: " + pkg,
-                    PackageManager.INSTALL_SUCCEEDED,
-                    mPackageManager.installExistingPackageAsUser(pkg, userInfo.id));
+            assertWithMessage("Package could not be installed: %s", pkg)
+                    .that(mPackageManager.installExistingPackageAsUser(pkg, userInfo.id))
+                    .isEqualTo(PackageManager.INSTALL_SUCCEEDED);
         }
     }
 
     // Make sure createUser would fail if we have DISALLOW_ADD_USER.
     @MediumTest
+    @Test
     public void testCreateUser_disallowAddUser() throws Exception {
-        final int primaryUserId = mUserManager.getPrimaryUser().id;
-        final UserHandle primaryUserHandle = new UserHandle(primaryUserId);
-        mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true, primaryUserHandle);
+        final int creatorId = isAutomotive() ? ActivityManager.getCurrentUser()
+                : mUserManager.getPrimaryUser().id;
+        final UserHandle creatorHandle = new UserHandle(creatorId);
+        mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true, creatorHandle);
         try {
-            UserInfo userInfo = createUser("SecondaryUser", /*flags=*/ 0);
-            assertNull(userInfo);
+            UserInfo createadInfo = createUser("SecondaryUser", /*flags=*/ 0);
+            assertThat(createadInfo).isNull();
         } finally {
             mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false,
-                    primaryUserHandle);
+                    creatorHandle);
         }
     }
 
     // Make sure createProfile would fail if we have DISALLOW_ADD_MANAGED_PROFILE.
     @MediumTest
+    @Test
     public void testCreateProfileForUser_disallowAddManagedProfile() throws Exception {
+        assumeManagedUsersSupported();
         final int primaryUserId = mUserManager.getPrimaryUser().id;
         final UserHandle primaryUserHandle = new UserHandle(primaryUserId);
         mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
@@ -428,7 +463,7 @@
         try {
             UserInfo userInfo = createProfileForUser("Managed",
                     UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
-            assertNull(userInfo);
+            assertThat(userInfo).isNull();
         } finally {
             mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false,
                     primaryUserHandle);
@@ -437,7 +472,9 @@
 
     // Make sure createProfileEvenWhenDisallowedForUser bypass DISALLOW_ADD_MANAGED_PROFILE.
     @MediumTest
+    @Test
     public void testCreateProfileForUserEvenWhenDisallowed() throws Exception {
+        assumeManagedUsersSupported();
         final int primaryUserId = mUserManager.getPrimaryUser().id;
         final UserHandle primaryUserHandle = new UserHandle(primaryUserId);
         mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
@@ -445,7 +482,7 @@
         try {
             UserInfo userInfo = createProfileEvenWhenDisallowedForUser("Managed",
                     UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
-            assertNotNull(userInfo);
+            assertThat(userInfo).isNotNull();
         } finally {
             mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false,
                     primaryUserHandle);
@@ -454,14 +491,16 @@
 
     // createProfile succeeds even if DISALLOW_ADD_USER is set
     @MediumTest
+    @Test
     public void testCreateProfileForUser_disallowAddUser() throws Exception {
+        assumeManagedUsersSupported();
         final int primaryUserId = mUserManager.getPrimaryUser().id;
         final UserHandle primaryUserHandle = new UserHandle(primaryUserId);
         mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true, primaryUserHandle);
         try {
             UserInfo userInfo = createProfileForUser("Managed",
                     UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
-            assertNotNull(userInfo);
+            assertThat(userInfo).isNotNull();
         } finally {
             mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false,
                     primaryUserHandle);
@@ -469,73 +508,85 @@
     }
 
     @MediumTest
+    @Test
     public void testAddRestrictedProfile() throws Exception {
-        assertFalse("There should be no associated restricted profiles before the test",
-                mUserManager.hasRestrictedProfiles());
+        if (isAutomotive()) return;
+        assertWithMessage("There should be no associated restricted profiles before the test")
+                .that(mUserManager.hasRestrictedProfiles()).isFalse();
         UserInfo userInfo = createRestrictedProfile("Profile");
-        assertNotNull(userInfo);
+        assertThat(userInfo).isNotNull();
 
         Bundle restrictions = mUserManager.getUserRestrictions(UserHandle.of(userInfo.id));
-        assertTrue("Restricted profile should have DISALLOW_MODIFY_ACCOUNTS restriction by default",
-                restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS));
-        assertTrue("Restricted profile should have DISALLOW_SHARE_LOCATION restriction by default",
-                restrictions.getBoolean(UserManager.DISALLOW_SHARE_LOCATION));
+        assertWithMessage(
+                "Restricted profile should have DISALLOW_MODIFY_ACCOUNTS restriction by default")
+                        .that(restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS))
+                        .isTrue();
+        assertWithMessage(
+                "Restricted profile should have DISALLOW_SHARE_LOCATION restriction by default")
+                        .that(restrictions.getBoolean(UserManager.DISALLOW_SHARE_LOCATION))
+                        .isTrue();
 
-        int locationMode = Settings.Secure.getIntForUser(getContext().getContentResolver(),
+        int locationMode = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.LOCATION_MODE,
                 Settings.Secure.LOCATION_MODE_HIGH_ACCURACY,
                 userInfo.id);
-        assertEquals("Restricted profile should have setting LOCATION_MODE set to "
-                + "LOCATION_MODE_OFF by default", locationMode, Settings.Secure.LOCATION_MODE_OFF);
+        assertWithMessage("Restricted profile should have setting LOCATION_MODE set to "
+                + "LOCATION_MODE_OFF by default").that(locationMode)
+                        .isEqualTo(Settings.Secure.LOCATION_MODE_OFF);
 
-        assertTrue("Newly created profile should be associated with the current user",
-                mUserManager.hasRestrictedProfiles());
+        assertWithMessage("Newly created profile should be associated with the current user")
+                .that(mUserManager.hasRestrictedProfiles()).isTrue();
     }
 
     @MediumTest
+    @Test
     public void testGetUserCreationTime() throws Exception {
+        // TODO: should add a regular user instead of a profile, so it can be tested everywhere
+        assumeManagedUsersSupported();
         final int primaryUserId = mUserManager.getPrimaryUser().id;
         final long startTime = System.currentTimeMillis();
         UserInfo profile = createProfileForUser("Managed 1",
                 UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
         final long endTime = System.currentTimeMillis();
-        assertNotNull(profile);
+        assertThat(profile).isNotNull();
         if (System.currentTimeMillis() > EPOCH_PLUS_30_YEARS) {
-            assertTrue("creationTime must be set when the profile is created",
-                    profile.creationTime >= startTime && profile.creationTime <= endTime);
+            assertWithMessage("creationTime must be set when the profile is created")
+                    .that(profile.creationTime).isIn(Range.closed(startTime, endTime));
         } else {
-            assertTrue("creationTime must be 0 if the time is not > EPOCH_PLUS_30_years",
-                    profile.creationTime == 0);
+            assertWithMessage("creationTime must be 0 if the time is not > EPOCH_PLUS_30_years")
+                    .that(profile.creationTime).isEqualTo(0);
         }
-        assertEquals(profile.creationTime, mUserManager.getUserCreationTime(
-                new UserHandle(profile.id)));
+        assertThat(mUserManager.getUserCreationTime(
+                new UserHandle(profile.id))).isEqualTo(profile.creationTime);
 
         long ownerCreationTime = mUserManager.getUserInfo(primaryUserId).creationTime;
-        assertEquals(ownerCreationTime, mUserManager.getUserCreationTime(
-                new UserHandle(primaryUserId)));
+        assertThat(mUserManager.getUserCreationTime(
+                new UserHandle(primaryUserId))).isEqualTo(ownerCreationTime);
     }
 
     @SmallTest
+    @Test
     public void testGetUserCreationTime_nonExistentUser() throws Exception {
         try {
             int noSuchUserId = 100500;
             mUserManager.getUserCreationTime(new UserHandle(noSuchUserId));
             fail("SecurityException should be thrown for nonexistent user");
         } catch (Exception e) {
-            assertTrue("SecurityException should be thrown for nonexistent user, but was: " + e,
-                    e instanceof SecurityException);
+            assertWithMessage("SecurityException should be thrown for nonexistent user").that(e)
+                    .isInstanceOf(SecurityException.class);
         }
     }
 
     @SmallTest
+    @Test
     public void testGetUserCreationTime_otherUser() throws Exception {
         UserInfo user = createUser("User 1", 0);
         try {
             mUserManager.getUserCreationTime(new UserHandle(user.id));
             fail("SecurityException should be thrown for other user");
         } catch (Exception e) {
-            assertTrue("SecurityException should be thrown for other user, but was: " + e,
-                    e instanceof SecurityException);
+            assertWithMessage("SecurityException should be thrown for other user").that(e)
+                    .isInstanceOf(SecurityException.class);
         }
     }
 
@@ -551,56 +602,58 @@
     }
 
     @MediumTest
+    @Test
     public void testSerialNumber() {
         UserInfo user1 = createUser("User 1", 0);
         int serialNumber1 = user1.serialNumber;
-        assertEquals(serialNumber1, mUserManager.getUserSerialNumber(user1.id));
-        assertEquals(user1.id, mUserManager.getUserHandle(serialNumber1));
+        assertThat(mUserManager.getUserSerialNumber(user1.id)).isEqualTo(serialNumber1);
+        assertThat(mUserManager.getUserHandle(serialNumber1)).isEqualTo(user1.id);
         UserInfo user2 = createUser("User 2", 0);
         int serialNumber2 = user2.serialNumber;
-        assertFalse(serialNumber1 == serialNumber2);
-        assertEquals(serialNumber2, mUserManager.getUserSerialNumber(user2.id));
-        assertEquals(user2.id, mUserManager.getUserHandle(serialNumber2));
+        assertThat(serialNumber1 == serialNumber2).isFalse();
+        assertThat(mUserManager.getUserSerialNumber(user2.id)).isEqualTo(serialNumber2);
+        assertThat(mUserManager.getUserHandle(serialNumber2)).isEqualTo(user2.id);
     }
 
     @MediumTest
+    @Test
     public void testGetSerialNumbersOfUsers() {
         UserInfo user1 = createUser("User 1", 0);
         UserInfo user2 = createUser("User 2", 0);
         long[] serialNumbersOfUsers = mUserManager.getSerialNumbersOfUsers(false);
-        String errMsg = "Array " + Arrays.toString(serialNumbersOfUsers) + " should contain ";
-        assertTrue(errMsg + user1.serialNumber,
-                ArrayUtils.contains(serialNumbersOfUsers, user1.serialNumber));
-        assertTrue(errMsg + user2.serialNumber,
-                ArrayUtils.contains(serialNumbersOfUsers, user2.serialNumber));
+        assertThat(serialNumbersOfUsers).asList().containsAllOf(
+                (long) user1.serialNumber, (long) user2.serialNumber);
     }
 
     @MediumTest
+    @Test
     public void testMaxUsers() {
         int N = UserManager.getMaxSupportedUsers();
         int count = mUserManager.getUsers().size();
         // Create as many users as permitted and make sure creation passes
         while (count < N) {
             UserInfo ui = createUser("User " + count, 0);
-            assertNotNull(ui);
+            assertThat(ui).isNotNull();
             count++;
         }
         // Try to create one more user and make sure it fails
         UserInfo extra = createUser("One more", 0);
-        assertNull(extra);
+        assertThat(extra).isNull();
     }
 
     @MediumTest
+    @Test
     public void testGetUserCount() {
         int count = mUserManager.getUsers().size();
         UserInfo user1 = createUser("User 1", 0);
-        assertNotNull(user1);
+        assertThat(user1).isNotNull();
         UserInfo user2 = createUser("User 2", 0);
-        assertNotNull(user2);
-        assertEquals(count + 2, mUserManager.getUserCount());
+        assertThat(user2).isNotNull();
+        assertThat(mUserManager.getUserCount()).isEqualTo(count + 2);
     }
 
     @MediumTest
+    @Test
     public void testRestrictions() {
         UserInfo testUser = createUser("User 1", 0);
 
@@ -611,12 +664,13 @@
 
         Bundle stored = mUserManager.getUserRestrictions(new UserHandle(testUser.id));
         // Note this will fail if DO already sets those restrictions.
-        assertEquals(stored.getBoolean(UserManager.DISALLOW_CONFIG_WIFI), false);
-        assertEquals(stored.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS), false);
-        assertEquals(stored.getBoolean(UserManager.DISALLOW_INSTALL_APPS), true);
+        assertThat(stored.getBoolean(UserManager.DISALLOW_CONFIG_WIFI)).isFalse();
+        assertThat(stored.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS)).isFalse();
+        assertThat(stored.getBoolean(UserManager.DISALLOW_INSTALL_APPS)).isTrue();
     }
 
     @MediumTest
+    @Test
     public void testDefaultRestrictionsApplied() throws Exception {
         final UserInfo userInfo = createUser("Useroid", UserManager.USER_TYPE_FULL_SECONDARY, 0);
         final UserTypeDetails userTypeDetails =
@@ -625,13 +679,14 @@
         // Note this can fail if DO unset those restrictions.
         for (String restriction : expectedRestrictions.keySet()) {
             if (expectedRestrictions.getBoolean(restriction)) {
-                assertTrue(
-                        mUserManager.hasUserRestriction(restriction, UserHandle.of(userInfo.id)));
+                assertThat(mUserManager.hasUserRestriction(restriction, UserHandle.of(userInfo.id)))
+                        .isTrue();
             }
         }
     }
 
     @MediumTest
+    @Test
     public void testSetDefaultGuestRestrictions() {
         final Bundle origGuestRestrictions = mUserManager.getDefaultGuestRestrictions();
         Bundle restrictions = new Bundle();
@@ -640,26 +695,28 @@
 
         try {
             UserInfo guest = createUser("Guest", UserInfo.FLAG_GUEST);
-            assertNotNull(guest);
-            assertTrue(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN,
-                    guest.getUserHandle()));
+            assertThat(guest).isNotNull();
+            assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN,
+                    guest.getUserHandle())).isTrue();
         } finally {
             mUserManager.setDefaultGuestRestrictions(origGuestRestrictions);
         }
     }
 
+    @Test
     public void testGetUserSwitchability() {
         int userSwitchable = mUserManager.getUserSwitchability();
-        assertEquals("Expected users to be switchable", UserManager.SWITCHABILITY_STATUS_OK,
-                userSwitchable);
+        assertWithMessage("Expected users to be switchable").that(userSwitchable)
+                .isEqualTo(UserManager.SWITCHABILITY_STATUS_OK);
     }
 
     @LargeTest
+    @Test
     public void testSwitchUser() {
-        ActivityManager am = getContext().getSystemService(ActivityManager.class);
+        ActivityManager am = mContext.getSystemService(ActivityManager.class);
         final int startUser = am.getCurrentUser();
         UserInfo user = createUser("User", 0);
-        assertNotNull(user);
+        assertThat(user).isNotNull();
         // Switch to the user just created.
         switchUser(user.id, null, true);
         // Switch back to the starting user.
@@ -667,21 +724,23 @@
     }
 
     @LargeTest
+    @Test
     public void testSwitchUserByHandle() {
-        ActivityManager am = getContext().getSystemService(ActivityManager.class);
+        ActivityManager am = mContext.getSystemService(ActivityManager.class);
         final int startUser = am.getCurrentUser();
         UserInfo user = createUser("User", 0);
-        assertNotNull(user);
+        assertThat(user).isNotNull();
         // Switch to the user just created.
         switchUser(-1, user.getUserHandle(), false);
         // Switch back to the starting user.
         switchUser(-1, UserHandle.of(startUser), false);
     }
 
+    @Test
     public void testSwitchUserByHandle_ThrowsException() {
         synchronized (mUserSwitchLock) {
             try {
-                ActivityManager am = getContext().getSystemService(ActivityManager.class);
+                ActivityManager am = mContext.getSystemService(ActivityManager.class);
                 am.switchUser(null);
                 fail("Expected IllegalArgumentException on passing in a null UserHandle.");
             } catch (IllegalArgumentException expected) {
@@ -691,6 +750,7 @@
     }
 
     @MediumTest
+    @Test
     public void testConcurrentUserCreate() throws Exception {
         int userCount = mUserManager.getUserCount();
         int maxSupportedUsers = UserManager.getMaxSupportedUsers();
@@ -713,11 +773,12 @@
         }
         es.shutdown();
         es.awaitTermination(20, TimeUnit.SECONDS);
-        assertEquals(maxSupportedUsers, mUserManager.getUserCount());
-        assertEquals(canBeCreatedCount, created.get());
+        assertThat(mUserManager.getUserCount()).isEqualTo(maxSupportedUsers);
+        assertThat(created.get()).isEqualTo(canBeCreatedCount);
     }
 
     @MediumTest
+    @Test
     public void testGetUserHandles_createNewUser_shouldFindNewUser() {
         UserInfo user = createUser("Guest 1", UserManager.USER_TYPE_FULL_GUEST, /*flags*/ 0);
 
@@ -729,7 +790,7 @@
             }
         }
 
-        assertTrue(found);
+        assertThat(found).isTrue();
     }
 
     private boolean isPackageInstalledForUser(String packageName, int userId) {
@@ -748,7 +809,7 @@
      */
     private void switchUser(int userId, UserHandle user, boolean ignoreHandle) {
         synchronized (mUserSwitchLock) {
-            ActivityManager am = getContext().getSystemService(ActivityManager.class);
+            ActivityManager am = mContext.getSystemService(ActivityManager.class);
             if (ignoreHandle) {
                 am.switchUser(userId);
             } else {
@@ -834,4 +895,12 @@
         return profile;
     }
 
+    private void assumeManagedUsersSupported() {
+        assumeTrue("device doesn't support managed users",
+                mPackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS));
+    }
+
+    private boolean isAutomotive() {
+        return mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index 683278b..3db832b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -26,6 +26,7 @@
 import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE;
 import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA;
 import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST;
+import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM;
 import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_LOG;
 
 import static org.junit.Assert.assertEquals;
@@ -262,39 +263,25 @@
 
         // No implicit whitelist, so only install pkg1.
         boolean implicit = false;
-        boolean isSysUser = false;
         assertTrue(UserSystemPackageInstaller.shouldInstallPackage(
-                pkg1, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+                pkg1, pkgBitSetMap, userWhitelist, implicit));
         assertFalse(UserSystemPackageInstaller.shouldInstallPackage(
-                pkg2, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+                pkg2, pkgBitSetMap, userWhitelist, implicit));
         assertFalse(UserSystemPackageInstaller.shouldInstallPackage(
-                pkg3, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+                pkg3, pkgBitSetMap, userWhitelist, implicit));
         assertFalse(UserSystemPackageInstaller.shouldInstallPackage(
-                pkg4, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+                pkg4, pkgBitSetMap, userWhitelist, implicit));
 
         // Use implicit whitelist, so install pkg1 and pkg4
         implicit = true;
-        isSysUser = false;
         assertTrue(UserSystemPackageInstaller.shouldInstallPackage(
-                pkg1, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+                pkg1, pkgBitSetMap, userWhitelist, implicit));
         assertFalse(UserSystemPackageInstaller.shouldInstallPackage(
-                pkg2, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+                pkg2, pkgBitSetMap, userWhitelist, implicit));
         assertFalse(UserSystemPackageInstaller.shouldInstallPackage(
-                pkg3, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+                pkg3, pkgBitSetMap, userWhitelist, implicit));
         assertTrue(UserSystemPackageInstaller.shouldInstallPackage(
-                pkg4, pkgBitSetMap, userWhitelist, implicit, isSysUser));
-
-        // For user 0 specifically, we always implicitly whitelist.
-        implicit = false;
-        isSysUser = true;
-        assertTrue(UserSystemPackageInstaller.shouldInstallPackage(
-                pkg1, pkgBitSetMap, userWhitelist, implicit, isSysUser));
-        assertFalse(UserSystemPackageInstaller.shouldInstallPackage(
-                pkg2, pkgBitSetMap, userWhitelist, implicit, isSysUser));
-        assertFalse(UserSystemPackageInstaller.shouldInstallPackage(
-                pkg3, pkgBitSetMap, userWhitelist, implicit, isSysUser));
-        assertTrue(UserSystemPackageInstaller.shouldInstallPackage(
-                pkg4, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+                pkg4, pkgBitSetMap, userWhitelist, implicit));
     }
 
     /**
@@ -400,30 +387,42 @@
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
         assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_LOG);
         assertTrue(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
         assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertTrue(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
         assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
+        assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
+
+        setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM);
+        assertFalse(mUserSystemPackageInstaller.isLogMode());
+        assertFalse(mUserSystemPackageInstaller.isEnforceMode());
+        assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
         assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
         assertTrue(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(
@@ -431,6 +430,7 @@
         assertTrue(mUserSystemPackageInstaller.isLogMode());
         assertTrue(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
         assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST
@@ -438,6 +438,7 @@
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertTrue(mUserSystemPackageInstaller.isEnforceMode());
         assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
         assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index d78e3af..4234720 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -24,6 +24,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
 
@@ -137,8 +138,8 @@
         // Mock KeyguardManager
         when(mContext.getSystemService(Context.KEYGUARD_SERVICE)).thenReturn(mKeyguardManager);
         when(mKeyguardManager.createConfirmDeviceCredentialIntent(
-                nullable(CharSequence.class), nullable(CharSequence.class), eq(TEST_USER_ID)))
-                .thenReturn(CONFIRM_CREDENTIALS_INTENT);
+                nullable(CharSequence.class), nullable(CharSequence.class), eq(TEST_USER_ID),
+                eq(true))).thenReturn(CONFIRM_CREDENTIALS_INTENT);
 
         // Mock PackageManager
         when(mService.getPackageManager()).thenReturn(mPackageManager);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 591ed51..f1de6e9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -19,15 +19,21 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
 
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.PictureInPictureParams;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.os.IBinder;
 import android.view.IDisplayWindowListener;
 import android.view.WindowContainerTransaction;
 
@@ -36,6 +42,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
 
 import java.util.ArrayList;
 
@@ -148,5 +155,43 @@
         assertEquals(0, changed.size());
         assertEquals(1, removed.size());
     }
+
+    /*
+        a test to verify b/144045134 - ignore PIP mode request for destroyed activity.
+        mocks r.getParent() to return null to cause NPE inside enterPipRunnable#run() in
+        ActivityTaskMangerservice#enterPictureInPictureMode(), which rebooted the device.
+        It doesn't fully simulate the issue's reproduce steps, but this should suffice.
+     */
+    @Test
+    public void testEnterPipModeWhenRecordParentChangesToNull() {
+        MockitoSession mockSession = mockitoSession()
+                .initMocks(this)
+                .mockStatic(ActivityRecord.class)
+                .startMocking();
+
+        ActivityRecord record = mock(ActivityRecord.class);
+        IBinder token = mock(IBinder.class);
+        PictureInPictureParams params = mock(PictureInPictureParams.class);
+        record.pictureInPictureArgs = params;
+
+        //mock operations in private method ensureValidPictureInPictureActivityParamsLocked()
+        when(ActivityRecord.forTokenLocked(token)).thenReturn(record);
+        doReturn(true).when(record).supportsPictureInPicture();
+        doReturn(false).when(params).hasSetAspectRatio();
+
+        //mock other operations
+        doReturn(true).when(record)
+                .checkEnterPictureInPictureState("enterPictureInPictureMode", false);
+        doReturn(false).when(mService).isInPictureInPictureMode(any());
+        doReturn(false).when(mService).isKeyguardLocked();
+
+        //to simulate NPE
+        doReturn(null).when(record).getParent();
+
+        mService.enterPictureInPictureMode(token, params);
+        //if record's null parent is not handled gracefully, test will fail with NPE
+
+        mockSession.finishMocking();
+    }
 }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
index c6203c5..a39be56 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
@@ -60,6 +60,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 144611135)
     public void testDeferring() {
         final ActivityRecord activity1 = createActivityRecord(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 0c7fad4..70e5ee7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -135,17 +135,19 @@
 
     @Test
     @Presubmit
-    public void testGetTopFullscreenWindow() {
-        assertNull(mActivity.getTopFullscreenWindow());
+    public void testGetTopFullscreenOpaqueWindow() {
+        assertNull(mActivity.getTopFullscreenOpaqueWindow());
 
         final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, mActivity, "window1");
         final WindowState window11 = createWindow(null, TYPE_APPLICATION, mActivity, "window11");
         final WindowState window12 = createWindow(null, TYPE_APPLICATION, mActivity, "window12");
-        assertEquals(window12, mActivity.getTopFullscreenWindow());
+        assertEquals(window12, mActivity.getTopFullscreenOpaqueWindow());
         window12.mAttrs.width = 500;
-        assertEquals(window11, mActivity.getTopFullscreenWindow());
+        assertEquals(window11, mActivity.getTopFullscreenOpaqueWindow());
         window11.mAttrs.width = 500;
-        assertEquals(window1, mActivity.getTopFullscreenWindow());
+        assertEquals(window1, mActivity.getTopFullscreenOpaqueWindow());
+        window1.mAttrs.alpha = 0f;
+        assertNull(mActivity.getTopFullscreenOpaqueWindow());
         mActivity.removeImmediately();
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
index 3008a75..e011280 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -88,6 +88,7 @@
         mFinishCallbackLatch.countDown();
     }
 
+    @FlakyTest(bugId = 144611135)
     @Test
     public void testAnimation() throws Exception {
         mSurfaceAnimationRunner
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 7174e5c..e17e0d8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -23,9 +23,20 @@
 import static com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_REAL;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
+import android.app.ActivityManager;
+import android.app.WindowConfiguration;
+import android.content.ComponentName;
+import android.content.res.Configuration;
+import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArraySet;
+import android.view.View;
 
 import androidx.test.filters.SmallTest;
 
@@ -33,6 +44,7 @@
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mockito;
 
 /**
  * Test class for {@link TaskSnapshotController}.
@@ -110,4 +122,57 @@
         assertEquals(SNAPSHOT_MODE_APP_THEME,
                 mWm.mTaskSnapshotController.getSnapshotMode(secureWindow.getTask()));
     }
+
+    @Test
+    public void testSnapshotBuilder() {
+        final GraphicBuffer buffer = Mockito.mock(GraphicBuffer.class);
+        final ColorSpace sRGB = ColorSpace.get(ColorSpace.Named.SRGB);
+        final long id = 1234L;
+        final ComponentName activityComponent = new ComponentName("package", ".Class");
+        final int windowingMode = WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+        final int systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN;
+        final int pixelFormat = PixelFormat.RGBA_8888;
+        final int orientation = Configuration.ORIENTATION_PORTRAIT;
+        final float scaleFraction = 0.25f;
+        final Rect contentInsets = new Rect(1, 2, 3, 4);
+
+        try {
+            ActivityManager.TaskSnapshot.Builder builder =
+                    new ActivityManager.TaskSnapshot.Builder();
+            builder.setId(id);
+            builder.setTopActivityComponent(activityComponent);
+            builder.setSystemUiVisibility(systemUiVisibility);
+            builder.setWindowingMode(windowingMode);
+            builder.setColorSpace(sRGB);
+            builder.setReducedResolution(true);
+            builder.setOrientation(orientation);
+            builder.setContentInsets(contentInsets);
+            builder.setIsTranslucent(true);
+            builder.setScaleFraction(0.25f);
+            builder.setSnapshot(buffer);
+            builder.setIsRealSnapshot(true);
+            builder.setPixelFormat(pixelFormat);
+
+            // Not part of TaskSnapshot itself, used in screenshot process
+            assertEquals(pixelFormat, builder.getPixelFormat());
+
+            ActivityManager.TaskSnapshot snapshot = builder.build();
+            assertEquals(id, snapshot.getId());
+            assertEquals(activityComponent, snapshot.getTopActivityComponent());
+            assertEquals(systemUiVisibility, snapshot.getSystemUiVisibility());
+            assertEquals(windowingMode, snapshot.getWindowingMode());
+            assertEquals(sRGB, snapshot.getColorSpace());
+            assertTrue(snapshot.isReducedResolution());
+            assertEquals(orientation, snapshot.getOrientation());
+            assertEquals(contentInsets, snapshot.getContentInsets());
+            assertTrue(snapshot.isTranslucent());
+            assertEquals(scaleFraction, builder.getScaleFraction(), 0.001f);
+            assertSame(buffer, snapshot.getSnapshot());
+            assertTrue(snapshot.isRealSnapshot());
+        } finally {
+            if (buffer != null) {
+                buffer.destroy();
+            }
+        }
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 8ade4d2..0018c63 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -32,7 +32,9 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 
@@ -82,7 +84,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
 import java.util.LinkedList;
+import java.util.List;
 
 /**
  * Tests for the {@link WindowState} class.
@@ -532,6 +536,31 @@
     }
 
     @Test
+    public void testRequestDrawIfNeeded() {
+        final WindowState startingApp = createWindow(null /* parent */,
+                TYPE_BASE_APPLICATION, "startingApp");
+        final WindowState startingWindow = createWindow(null /* parent */,
+                TYPE_APPLICATION_STARTING, startingApp.mToken, "starting");
+        startingApp.mActivityRecord.startingWindow = startingWindow;
+        final WindowState keyguardHostWindow = mStatusBarWindow;
+        final WindowState allDrawnApp = mAppWindow;
+        allDrawnApp.mActivityRecord.allDrawn = true;
+
+        // The waiting list is used to ensure the content is ready when turning on screen.
+        final List<WindowState> outWaitingForDrawn = mDisplayContent.mWaitingForDrawn;
+        final List<WindowState> visibleWindows = Arrays.asList(mChildAppWindowAbove,
+                keyguardHostWindow, allDrawnApp, startingApp, startingWindow);
+        visibleWindows.forEach(w -> {
+            w.mHasSurface = true;
+            w.requestDrawIfNeeded(outWaitingForDrawn);
+        });
+
+        // Keyguard host window should be always contained. The drawn app or app with starting
+        // window are unnecessary to draw.
+        assertEquals(Arrays.asList(keyguardHostWindow, startingWindow), outWaitingForDrawn);
+    }
+
+    @Test
     public void testGetTransformationMatrix() {
         final int PARENT_WINDOW_OFFSET = 1;
         final int DISPLAY_IN_PARENT_WINDOW_OFFSET = 2;
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 0f3050f..531a931 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -19,6 +19,9 @@
 import static com.android.internal.util.ArrayUtils.defeatNullable;
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.AppOpsManager;
 import android.app.usage.ExternalStorageStats;
 import android.app.usage.IStorageStatsManager;
@@ -30,6 +33,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageStats;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
 import android.net.Uri;
 import android.os.Binder;
@@ -44,10 +48,13 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.CrateInfo;
+import android.os.storage.CrateMetadata;
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.DataUnit;
@@ -67,6 +74,9 @@
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 public class StorageStatsService extends IStorageStatsManager.Stub {
     private static final String TAG = "StorageStatsService";
@@ -139,7 +149,7 @@
         }
     }
 
-    private void enforcePermission(int callingUid, String callingPackage) {
+    private void enforceStatsPermission(int callingUid, String callingPackage) {
         final int mode = mAppOps.noteOp(AppOpsManager.OP_GET_USAGE_STATS,
                 callingUid, callingPackage);
         switch (mode) {
@@ -222,7 +232,7 @@
 
     @Override
     public long getCacheBytes(String volumeUuid, String callingPackage) {
-        enforcePermission(Binder.getCallingUid(), callingPackage);
+        enforceStatsPermission(Binder.getCallingUid(), callingPackage);
 
         long cacheBytes = 0;
         for (UserInfo user : mUser.getUsers()) {
@@ -234,7 +244,7 @@
 
     @Override
     public long getCacheQuotaBytes(String volumeUuid, int uid, String callingPackage) {
-        enforcePermission(Binder.getCallingUid(), callingPackage);
+        enforceStatsPermission(Binder.getCallingUid(), callingPackage);
 
         if (mCacheQuotas.containsKey(volumeUuid)) {
             final SparseLongArray uidMap = mCacheQuotas.get(volumeUuid);
@@ -263,7 +273,7 @@
         if (Binder.getCallingUid() == appInfo.uid) {
             // No permissions required when asking about themselves
         } else {
-            enforcePermission(Binder.getCallingUid(), callingPackage);
+            enforceStatsPermission(Binder.getCallingUid(), callingPackage);
         }
 
         if (defeatNullable(mPackage.getPackagesForUid(appInfo.uid)).length == 1) {
@@ -307,7 +317,7 @@
         if (Binder.getCallingUid() == uid) {
             // No permissions required when asking about themselves
         } else {
-            enforcePermission(Binder.getCallingUid(), callingPackage);
+            enforceStatsPermission(Binder.getCallingUid(), callingPackage);
         }
 
         final String[] packageNames = defeatNullable(mPackage.getPackagesForUid(uid));
@@ -354,7 +364,7 @@
         }
 
         // Always require permission to see user-level stats
-        enforcePermission(Binder.getCallingUid(), callingPackage);
+        enforceStatsPermission(Binder.getCallingUid(), callingPackage);
 
         final int[] appIds = getAppIds(userId);
         final PackageStats stats = new PackageStats(TAG);
@@ -381,7 +391,7 @@
         }
 
         // Always require permission to see user-level stats
-        enforcePermission(Binder.getCallingUid(), callingPackage);
+        enforceStatsPermission(Binder.getCallingUid(), callingPackage);
 
         final int[] appIds = getAppIds(userId);
         final long[] stats;
@@ -556,4 +566,143 @@
         mContext.getContentResolver().notifyChange(
                 Uri.parse("content://com.android.externalstorage.documents/"), null, false);
     }
+
+    /**
+     * To enforce the calling or self to have the {@link android.Manifest.permission#MANAGE_CRATES}
+     * permission.
+     * @param callingUid the calling uid
+     * @param callingPackage the calling package name
+     */
+    private void enforceCratesPermission(int callingUid, String callingPackage) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_CRATES,
+                callingPackage);
+    }
+
+    /**
+     * To copy from CrateMetadata instances into CrateInfo instances.
+     */
+    @NonNull
+    private static List<CrateInfo> convertCrateInfoFrom(@Nullable CrateMetadata[] crateMetadatas) {
+        if (ArrayUtils.isEmpty(crateMetadatas)) {
+            return Collections.EMPTY_LIST;
+        }
+
+        ArrayList<CrateInfo> crateInfos = new ArrayList<>();
+        for (CrateMetadata crateMetadata : crateMetadatas) {
+            if (crateMetadata == null || TextUtils.isEmpty(crateMetadata.id)
+                    || TextUtils.isEmpty(crateMetadata.packageName)) {
+                continue;
+            }
+
+            CrateInfo crateInfo = CrateInfo.copyFrom(crateMetadata.uid,
+                    crateMetadata.packageName, crateMetadata.id);
+            if (crateInfo == null) {
+                continue;
+            }
+
+            crateInfos.add(crateInfo);
+        }
+
+        return crateInfos;
+    }
+
+    @NonNull
+    private ParceledListSlice<CrateInfo> getAppCrates(String volumeUuid, String[] packageNames,
+            @UserIdInt int userId) {
+        try {
+            CrateMetadata[] crateMetadatas = mInstaller.getAppCrates(volumeUuid,
+                    packageNames, userId);
+            return new ParceledListSlice<>(convertCrateInfoFrom(crateMetadatas));
+        } catch (InstallerException e) {
+            throw new ParcelableException(new IOException(e.getMessage()));
+        }
+    }
+
+    @NonNull
+    @Override
+    public ParceledListSlice<CrateInfo> queryCratesForPackage(String volumeUuid,
+            @NonNull String packageName, @UserIdInt int userId, @NonNull String callingPackage) {
+        if (userId != UserHandle.getCallingUserId()) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
+        }
+
+        final ApplicationInfo appInfo;
+        try {
+            appInfo = mPackage.getApplicationInfoAsUser(packageName,
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+        } catch (NameNotFoundException e) {
+            throw new ParcelableException(e);
+        }
+
+        if (Binder.getCallingUid() == appInfo.uid) {
+            // No permissions required when asking about themselves
+        } else {
+            enforceCratesPermission(Binder.getCallingUid(), callingPackage);
+        }
+
+        final String[] packageNames = new String[] { packageName };
+        return getAppCrates(volumeUuid, packageNames, userId);
+    }
+
+    @NonNull
+    @Override
+    public ParceledListSlice<CrateInfo> queryCratesForUid(String volumeUuid, int uid,
+            @NonNull String callingPackage) {
+        final int userId = UserHandle.getUserId(uid);
+        if (userId != UserHandle.getCallingUserId()) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
+        }
+
+        if (Binder.getCallingUid() == uid) {
+            // No permissions required when asking about themselves
+        } else {
+            enforceCratesPermission(Binder.getCallingUid(), callingPackage);
+        }
+
+        final String[] packageNames = defeatNullable(mPackage.getPackagesForUid(uid));
+        String[] validatedPackageNames = new String[0];
+
+        for (String packageName : packageNames) {
+            if (TextUtils.isEmpty(packageName)) {
+                continue;
+            }
+
+            try {
+                final ApplicationInfo appInfo = mPackage.getApplicationInfoAsUser(packageName,
+                        PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+                if (appInfo == null) {
+                    continue;
+                }
+
+                validatedPackageNames = ArrayUtils.appendElement(String.class,
+                        validatedPackageNames, packageName);
+            } catch (NameNotFoundException e) {
+                throw new ParcelableException(e);
+            }
+        }
+
+        return getAppCrates(volumeUuid, validatedPackageNames, userId);
+    }
+
+    @NonNull
+    @Override
+    public ParceledListSlice<CrateInfo> queryCratesForUser(String volumeUuid, int userId,
+            @NonNull String callingPackage) {
+        if (userId != UserHandle.getCallingUserId()) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
+        }
+
+        // Always require permission to see user-level stats
+        enforceCratesPermission(Binder.getCallingUid(), callingPackage);
+
+        try {
+            CrateMetadata[] crateMetadatas = mInstaller.getUserCrates(volumeUuid, userId);
+            return new ParceledListSlice<>(convertCrateInfoFrom(crateMetadatas));
+        } catch (InstallerException e) {
+            throw new ParcelableException(new IOException(e.getMessage()));
+        }
+    }
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 6132cc2..404346f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1291,6 +1291,7 @@
                 pw.println("  mCurUser: " + mCurUser);
                 pw.println("  mCurUserUnlocked: " + mCurUserUnlocked);
                 pw.println("  mCurUserSupported: " + mCurUserSupported);
+                dumpSupportedUsers(pw, "  ");
                 if (mImpl == null) {
                     pw.println("  (No active implementation)");
                     return;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 39d741c..af3c55a 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -485,6 +485,103 @@
             "android.telecom.extra.START_CALL_WITH_RTT";
 
     /**
+     * Start an activity indicating that the completion of an outgoing call or an incoming call
+     * which was not blocked by the {@link CallScreeningService}, and which was NOT terminated
+     * while the call was in {@link Call#STATE_AUDIO_PROCESSING}.
+     *
+     * The {@link Uri} extra {@link #EXTRA_HANDLE} will contain the uri handle(phone number) for the
+     * call which completed.
+     *
+     * The integer extra {@link #EXTRA_DISCONNECT_CAUSE} will indicate the reason for the call
+     * disconnection. See {@link #EXTRA_DISCONNECT_CAUSE} for more information.
+     *
+     * The integer extra {@link #EXTRA_CALL_DURATION} will indicate the duration of the call. See
+     * {@link #EXTRA_CALL_DURATION} for more information.
+     */
+    public static final String ACTION_POST_CALL = "android.telecom.action.POST_CALL";
+
+    /**
+     * A {@link Uri} extra, which when set on the {@link #ACTION_POST_CALL} intent, indicates the
+     * uri handle(phone number) of the completed call.
+     */
+    public static final String EXTRA_HANDLE = "android.telecom.extra.HANDLE";
+
+    /**
+     * A integer value provided for completed calls to indicate the reason for the call
+     * disconnection.
+     * <p>
+     * Allowed values:
+     * <ul>
+     * <li>{@link DisconnectCause#UNKNOWN}</li>
+     * <li>{@link DisconnectCause#LOCAL}</li>
+     * <li>{@link DisconnectCause#REMOTE}</li>
+     * <li>{@link DisconnectCause#REJECTED}</li>
+     * <li>{@link DisconnectCause#MISSED}</li>
+     * </ul>
+     * </p>
+     */
+    public static final String EXTRA_DISCONNECT_CAUSE = "android.telecom.extra.DISCONNECT_CAUSE";
+
+    /**
+     * A integer value provided for completed calls to indicate the duration of the call.
+     * <p>
+     * Allowed values:
+     * <ul>
+     * <li>{@link #DURATION_VERY_SHORT}</li>
+     * <li>{@link #DURATION_SHORT}</li>
+     * <li>{@link #DURATION_MEDIUM}</li>
+     * <li>{@link #DURATION_LONG}</li>
+     * </ul>
+     * </p>
+     */
+    public static final String EXTRA_CALL_DURATION = "android.telecom.extra.CALL_DURATION";
+
+    /**
+     * A integer value for {@link #EXTRA_CALL_DURATION}, indicates the duration of the completed
+     * call was < 3 seconds.
+     */
+    public static final int DURATION_VERY_SHORT = 0;
+
+    /**
+     * A integer value for {@link #EXTRA_CALL_DURATION}, indicates the duration of the completed
+     * call was >= 3 seconds and < 60 seconds.
+     */
+    public static final int DURATION_SHORT = 1;
+
+    /**
+     * A integer value for {@link #EXTRA_CALL_DURATION}, indicates the duration of the completed
+     * call was >= 60 seconds and < 120 seconds.
+     */
+    public static final int DURATION_MEDIUM = 2;
+
+    /**
+     * A integer value for {@link #EXTRA_CALL_DURATION}, indicates the duration of the completed
+     * call was >= 120 seconds.
+     */
+    public static final int DURATION_LONG = 3;
+
+    /**
+     * The threshold between {@link #DURATION_VERY_SHORT} calls and {@link #DURATION_SHORT} calls in
+     * milliseconds.
+     * @hide
+     */
+    public static final long VERY_SHORT_CALL_TIME_MS = 3000;
+
+    /**
+     * The threshold between {@link #DURATION_SHORT} calls and {@link #DURATION_MEDIUM} calls in
+     * milliseconds.
+     * @hide
+     */
+    public static final long SHORT_CALL_TIME_MS = 60000;
+
+    /**
+     * The threshold between {@link #DURATION_MEDIUM} calls and {@link #DURATION_LONG} calls in
+     * milliseconds.
+     * @hide
+     */
+    public static final long MEDIUM_CALL_TIME_MS = 120000;
+
+    /**
      * A boolean meta-data value indicating whether an {@link InCallService} implements an
      * in-call user interface. Dialer implementations (see {@link #getDefaultDialerPackage()}) which
      * would also like to replace the in-call interface should set this meta-data to {@code true} in
diff --git a/telephony/java/android/telephony/CbGeoUtils.java b/telephony/java/android/telephony/CbGeoUtils.java
index d4d4e13..7314edd 100644
--- a/telephony/java/android/telephony/CbGeoUtils.java
+++ b/telephony/java/android/telephony/CbGeoUtils.java
@@ -28,10 +28,15 @@
 
 
 /**
- * This utils class is specifically used for geo-targeting of CellBroadcast messages.
+ * This utils class is used for geo-fencing of CellBroadcast messages and is used by the cell
+ * broadcast module.
+ *
  * The coordinates used by this utils class are latitude and longitude, but some algorithms in this
  * class only use them as coordinates on plane, so the calculation will be inaccurate. So don't use
  * this class for anything other then geo-targeting of cellbroadcast messages.
+ *
+ * More information regarding cell broadcast geo-fencing logic is laid out in 3GPP TS 23.041 and
+ * ATIS-0700041.
  * @hide
  */
 @SystemApi
@@ -82,7 +87,7 @@
     /** @hide */
     private static final String POLYGON_SYMBOL = "polygon";
 
-    /** Point represent by (latitude, longitude). */
+    /** A point represented by (latitude, longitude). */
     public static class LatLng {
         public final double lat;
         public final double lng;
@@ -98,8 +103,8 @@
         }
 
         /**
-         * @param p the point use to calculate the subtraction result.
-         * @return the result of this point subtract the given point {@code p}.
+         * @param p the point to subtract
+         * @return the result of the subtraction
          */
         @NonNull
         public LatLng subtract(@NonNull LatLng p) {
@@ -107,9 +112,9 @@
         }
 
         /**
-         * Calculate the distance in meter between this point and the given point {@code p}.
-         * @param p the point use to calculate the distance.
-         * @return the distance in meter.
+         * Calculate the distance in meters between this point and the given point {@code p}.
+         * @param p the point used to calculate the distance.
+         * @return the distance in meters.
          */
         public double distance(@NonNull LatLng p) {
             double dlat = Math.sin(0.5 * Math.toRadians(lat - p.lat));
@@ -126,8 +131,9 @@
     }
 
     /**
-     * The class represents a simple polygon with at least 3 points.
-     * @hide
+     * A class representing a simple polygon with at least 3 points. This is used for geo-fencing
+     * logic with cell broadcasts. More information regarding cell broadcast geo-fencing logic is
+     * laid out in 3GPP TS 23.041 and ATIS-0700041.
      */
     public static class Polygon implements Geometry {
         /**
@@ -146,7 +152,7 @@
          * connected to form an edge of the polygon. The polygon has at least 3 vertices, and the
          * last vertices and the first vertices must be adjacent.
          *
-         * The longitude difference in the vertices should be less than 180 degree.
+         * The longitude difference in the vertices should be less than 180 degrees.
          */
         public Polygon(@NonNull List<LatLng> vertices) {
             mVertices = vertices;
@@ -165,19 +171,24 @@
                     .collect(Collectors.toList());
         }
 
-        public List<LatLng> getVertices() {
+        /**
+         * Return the list of vertices which compose the polygon.
+         */
+        public @NonNull List<LatLng> getVertices() {
             return mVertices;
         }
 
         /**
-         * Check if the given point {@code p} is inside the polygon. This method counts the number
-         * of times the polygon winds around the point P, A.K.A "winding number". The point is
-         * outside only when this "winding number" is 0.
+         * Check if the given LatLng is inside the polygon.
          *
-         * If a point is on the edge of the polygon, it is also considered to be inside the polygon.
+         * If a LatLng is on the edge of the polygon, it is also considered to be inside the
+         * polygon.
          */
         @Override
-        public boolean contains(LatLng latLng) {
+        public boolean contains(@NonNull LatLng latLng) {
+            // This method counts the number of times the polygon winds around the point P, A.K.A
+            // "winding number". The point is outside only when this "winding number" is 0.
+
             Point p = convertAndScaleLatLng(latLng);
 
             int n = mScaledVertices.size();
@@ -246,6 +257,7 @@
             return a.x * b.y - a.y * b.x;
         }
 
+        /** @hide */
         static final class Point {
             public final double x;
             public final double y;
@@ -271,29 +283,47 @@
     }
 
     /**
-     * The class represents a circle.
-     * @hide
+     * A class represents a {@link Geometry} in the shape of a Circle. This is used for handling
+     * geo-fenced cell broadcasts. More information regarding cell broadcast geo-fencing logic is
+     * laid out in 3GPP TS 23.041 and ATIS-0700041.
      */
     public static class Circle implements Geometry {
         private final LatLng mCenter;
         private final double mRadiusMeter;
 
-        public Circle(LatLng center, double radiusMeter) {
+        /**
+         * Construct a Circle given a center point and a radius in meters.
+         *
+         * @param center the latitude and longitude of the center of the circle
+         * @param radiusInMeters the radius of the circle in meters
+         */
+        public Circle(@NonNull LatLng center, double radiusInMeters) {
             this.mCenter = center;
-            this.mRadiusMeter = radiusMeter;
+            this.mRadiusMeter = radiusInMeters;
         }
 
-        public LatLng getCenter() {
+        /**
+         * Return the latitude and longitude of the center of the circle;
+         */
+        public @NonNull LatLng getCenter() {
             return mCenter;
         }
 
+        /**
+         * Return the radius of the circle in meters.
+         */
         public double getRadius() {
             return mRadiusMeter;
         }
 
+        /**
+         * Check if the given LatLng is inside the circle.
+         *
+         * If a LatLng is on the edge of the circle, it is also considered to be inside the circle.
+         */
         @Override
-        public boolean contains(LatLng p) {
-            return mCenter.distance(p) <= mRadiusMeter;
+        public boolean contains(@NonNull LatLng latLng) {
+            return mCenter.distance(latLng) <= mRadiusMeter;
         }
 
         @Override
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 78c5e43..60fda09 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -757,8 +757,10 @@
      * Retrieve with
      * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
      *
+     * @deprecated Should use the {@link TelecomManager#EXTRA_DISCONNECT_CAUSE} instead.
      * @hide
      */
+    @Deprecated
     public static final String EXTRA_DISCONNECT_CAUSE = "disconnect_cause";
 
     /**
@@ -1461,6 +1463,80 @@
      */
     public static final String EXTRA_SIM_COMBINATION_NAMES =
             "android.telephony.extra.SIM_COMBINATION_NAMES";
+
+    /**
+     * Broadcast Action: The time was set by the carrier (typically by the NITZ string).
+     * This is a sticky broadcast.
+     * The intent will have the following extra values:</p>
+     * <ul>
+     *   <li><em>time</em> - The time as a long in UTC milliseconds.</li>
+     * </ul>
+     *
+     * <p class="note">
+     * Requires the READ_PHONE_STATE permission.
+     *
+     * <p class="note">This is a protected intent that can only be sent by the system.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_NETWORK_SET_TIME = "android.telephony.action.NETWORK_SET_TIME";
+
+    /**
+     * <p>Broadcast Action: The emergency callback mode is changed.
+     * <ul>
+     *   <li><em>phoneinECMState</em> - A boolean value,true=phone in ECM, false=ECM off</li>
+     * </ul>
+     * <p class="note">
+     * You can <em>not</em> receive this through components declared
+     * in manifests, only by explicitly registering for it with
+     * {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver,
+     * android.content.IntentFilter) Context.registerReceiver()}.
+     *
+     * <p class="note">This is a protected intent that can only be sent by the system.
+     *
+     * @hide
+     */
+    @SystemApi
+    @SuppressLint("ActionValue")
+    public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
+            = "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED";
+
+    /**
+     * <p>Broadcast Action: The emergency call state is changed.
+     * <ul>
+     *   <li><em>phoneInEmergencyCall</em> - A boolean value, true if phone in emergency call,
+     *   false otherwise</li>
+     * </ul>
+     * <p class="note">
+     * You can <em>not</em> receive this through components declared
+     * in manifests, only by explicitly registering for it with
+     * {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver,
+     * android.content.IntentFilter) Context.registerReceiver()}.
+     *
+     * <p class="note">This is a protected intent that can only be sent by the system.
+     *
+     * @hide
+     */
+    @SystemApi
+    @SuppressLint("ActionValue")
+    public static final String ACTION_EMERGENCY_CALL_STATE_CHANGED
+            = "android.intent.action.EMERGENCY_CALL_STATE_CHANGED";
+
+    /**
+     * <p>Broadcast Action: It indicates the Emergency callback mode blocks datacall/sms
+     * <p class="note">.
+     * This is to pop up a notice to show user that the phone is in emergency callback mode
+     * and data calls and outgoing sms are blocked.
+     *
+     * <p class="note">This is a protected intent that can only be sent by the system.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS
+            = "android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS";
+
     //
     //
     // Device Info
@@ -11828,6 +11904,8 @@
      *
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public boolean isApnMetered(@ApnType int apnType) {
         try {
             ITelephony service = getITelephony();
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index b2c3fc7..024b640 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -18,6 +18,7 @@
 
 import android.content.Intent;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 
 /**
  * The intents that the telephony services broadcast.
@@ -99,7 +100,7 @@
      * by the system.
      */
     public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
-            = "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED";
+            = TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED;
 
     /**
      * <p>Broadcast Action: The emergency call state is changed.
@@ -120,7 +121,7 @@
      * by the system.
      */
     public static final String ACTION_EMERGENCY_CALL_STATE_CHANGED
-            = "android.intent.action.EMERGENCY_CALL_STATE_CHANGED";
+            = TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED;
 
     /**
      * Broadcast Action: The phone's signal strength has changed. The intent will have the
@@ -225,22 +226,6 @@
     public static final String EXTRA_REBROADCAST_ON_UNLOCK= "rebroadcastOnUnlock";
 
     /**
-     * Broadcast Action: The time was set by the carrier (typically by the NITZ string).
-     * This is a sticky broadcast.
-     * The intent will have the following extra values:</p>
-     * <ul>
-     *   <li><em>time</em> - The time as a long in UTC milliseconds.</li>
-     * </ul>
-     *
-     * <p class="note">
-     * Requires the READ_PHONE_STATE permission.
-     *
-     * <p class="note">This is a protected intent that can only be sent
-     * by the system.
-     */
-    public static final String ACTION_NETWORK_SET_TIME = "android.intent.action.NETWORK_SET_TIME";
-
-    /**
      * <p>Broadcast Action: It indicates the Emergency callback mode blocks datacall/sms
      * <p class="note">.
      * This is to pop up a notice to show user that the phone is in emergency callback mode
@@ -250,7 +235,7 @@
      * by the system.
      */
     public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS
-            = "com.android.internal.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS";
+            = TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS;
 
     /**
      * <p>Broadcast Action: Indicates that the action is forbidden by network.
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
deleted file mode 100644
index c16eafb..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
- * Copyright (C) 2012 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.telephony.gsm;
-
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE;
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI;
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_OTHER_EMERGENCY;
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_TEST_MESSAGE;
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_TSUNAMI;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.content.res.Resources;
-import android.telephony.CbGeoUtils;
-import android.telephony.CbGeoUtils.Circle;
-import android.telephony.CbGeoUtils.Geometry;
-import android.telephony.CbGeoUtils.LatLng;
-import android.telephony.CbGeoUtils.Polygon;
-import android.telephony.Rlog;
-import android.telephony.SmsCbLocation;
-import android.telephony.SmsCbMessage;
-import android.telephony.SubscriptionManager;
-import android.util.Pair;
-
-import com.android.internal.R;
-import com.android.internal.telephony.GsmAlphabet;
-import com.android.internal.telephony.SmsConstants;
-import com.android.internal.telephony.gsm.GsmSmsCbMessage.GeoFencingTriggerMessage.CellBroadcastIdentity;
-import com.android.internal.telephony.gsm.SmsCbHeader.DataCodingScheme;
-
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * Parses a GSM or UMTS format SMS-CB message into an {@link SmsCbMessage} object. The class is
- * public because {@link #createSmsCbMessage(SmsCbLocation, byte[][])} is used by some test cases.
- */
-public class GsmSmsCbMessage {
-    private static final String TAG = GsmSmsCbMessage.class.getSimpleName();
-
-    private static final char CARRIAGE_RETURN = 0x0d;
-
-    private static final int PDU_BODY_PAGE_LENGTH = 82;
-
-    /** Utility class with only static methods. */
-    private GsmSmsCbMessage() { }
-
-    /**
-     * Get built-in ETWS primary messages by category. ETWS primary message does not contain text,
-     * so we have to show the pre-built messages to the user.
-     *
-     * @param context Device context
-     * @param category ETWS message category defined in SmsCbConstants
-     * @return ETWS text message in string. Return an empty string if no match.
-     */
-    private static String getEtwsPrimaryMessage(Context context, int category) {
-        final Resources r = context.getResources();
-        switch (category) {
-            case ETWS_WARNING_TYPE_EARTHQUAKE:
-                return r.getString(R.string.etws_primary_default_message_earthquake);
-            case ETWS_WARNING_TYPE_TSUNAMI:
-                return r.getString(R.string.etws_primary_default_message_tsunami);
-            case ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI:
-                return r.getString(R.string.etws_primary_default_message_earthquake_and_tsunami);
-            case ETWS_WARNING_TYPE_TEST_MESSAGE:
-                return r.getString(R.string.etws_primary_default_message_test);
-            case ETWS_WARNING_TYPE_OTHER_EMERGENCY:
-                return r.getString(R.string.etws_primary_default_message_others);
-            default:
-                return "";
-        }
-    }
-
-    /**
-     * Create a new SmsCbMessage object from a header object plus one or more received PDUs.
-     *
-     * @param pdus PDU bytes
-     * @slotIndex slotIndex for which received sms cb message
-     */
-    public static SmsCbMessage createSmsCbMessage(Context context, SmsCbHeader header,
-            SmsCbLocation location, byte[][] pdus, int slotIndex)
-            throws IllegalArgumentException {
-        SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
-                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
-        int subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
-        int[] subIds = sm.getSubscriptionIds(slotIndex);
-        if (subIds != null && subIds.length > 0) {
-            subId = subIds[0];
-        }
-
-        long receivedTimeMillis = System.currentTimeMillis();
-        if (header.isEtwsPrimaryNotification()) {
-            // ETSI TS 23.041 ETWS Primary Notification message
-            // ETWS primary message only contains 4 fields including serial number,
-            // message identifier, warning type, and warning security information.
-            // There is no field for the content/text so we get the text from the resources.
-            return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP, header.getGeographicalScope(),
-                    header.getSerialNumber(), location, header.getServiceCategory(), null,
-                    getEtwsPrimaryMessage(context, header.getEtwsInfo().getWarningType()),
-                    SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, header.getEtwsInfo(),
-                    header.getCmasInfo(), 0, null /* geometries */, receivedTimeMillis, slotIndex,
-                    subId);
-        } else if (header.isUmtsFormat()) {
-            // UMTS format has only 1 PDU
-            byte[] pdu = pdus[0];
-            Pair<String, String> cbData = parseUmtsBody(header, pdu);
-            String language = cbData.first;
-            String body = cbData.second;
-            int priority = header.isEmergencyMessage() ? SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY
-                    : SmsCbMessage.MESSAGE_PRIORITY_NORMAL;
-            int nrPages = pdu[SmsCbHeader.PDU_HEADER_LENGTH];
-            int wacDataOffset = SmsCbHeader.PDU_HEADER_LENGTH
-                    + 1 // number of pages
-                    + (PDU_BODY_PAGE_LENGTH + 1) * nrPages; // cb data
-
-            // Has Warning Area Coordinates information
-            List<Geometry> geometries = null;
-            int maximumWaitingTimeSec = 255;
-            if (pdu.length > wacDataOffset) {
-                try {
-                    Pair<Integer, List<Geometry>> wac = parseWarningAreaCoordinates(pdu,
-                            wacDataOffset);
-                    maximumWaitingTimeSec = wac.first;
-                    geometries = wac.second;
-                } catch (Exception ex) {
-                    // Catch the exception here, the message will be considered as having no WAC
-                    // information which means the message will be broadcasted directly.
-                    Rlog.e(TAG, "Can't parse warning area coordinates, ex = " + ex.toString());
-                }
-            }
-
-            return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP,
-                    header.getGeographicalScope(), header.getSerialNumber(), location,
-                    header.getServiceCategory(), language, body, priority,
-                    header.getEtwsInfo(), header.getCmasInfo(), maximumWaitingTimeSec, geometries,
-                    receivedTimeMillis, slotIndex, subId);
-        } else {
-            String language = null;
-            StringBuilder sb = new StringBuilder();
-            for (byte[] pdu : pdus) {
-                Pair<String, String> p = parseGsmBody(header, pdu);
-                language = p.first;
-                sb.append(p.second);
-            }
-            int priority = header.isEmergencyMessage() ? SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY
-                    : SmsCbMessage.MESSAGE_PRIORITY_NORMAL;
-
-            return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP,
-                    header.getGeographicalScope(), header.getSerialNumber(), location,
-                    header.getServiceCategory(), language, sb.toString(), priority,
-                    header.getEtwsInfo(), header.getCmasInfo(), 0, null /* geometries */,
-                    receivedTimeMillis, slotIndex, subId);
-        }
-    }
-
-    /**
-     * Parse WEA Handset Action Message(WHAM) a.k.a geo-fencing trigger message.
-     *
-     * WEA Handset Action Message(WHAM) is a cell broadcast service message broadcast by the network
-     * to direct devices to perform a geo-fencing check on selected alerts.
-     *
-     * WEA Handset Action Message(WHAM) requirements from ATIS-0700041 section 4
-     * 1. The Warning Message contents of a WHAM shall be in Cell Broadcast(CB) data format as
-     * defined in TS 23.041.
-     * 2. The Warning Message Contents of WHAM shall be limited to one CB page(max 20 referenced
-     * WEA messages).
-     * 3. The broadcast area for a WHAM shall be the union of the broadcast areas of the referenced
-     * WEA message.
-     * @param pdu cell broadcast pdu, including the header
-     * @return {@link GeoFencingTriggerMessage} instance
-     */
-    public static GeoFencingTriggerMessage createGeoFencingTriggerMessage(byte[] pdu) {
-        try {
-            // Header length + 1(number of page). ATIS-0700041 define the number of page of
-            // geo-fencing trigger message is 1.
-            int whamOffset = SmsCbHeader.PDU_HEADER_LENGTH + 1;
-
-            BitStreamReader bitReader = new BitStreamReader(pdu, whamOffset);
-            int type = bitReader.read(4);
-            int length = bitReader.read(7);
-            // Skip the remained 5 bits
-            bitReader.skip();
-
-            int messageIdentifierCount = (length - 2) * 8 / 32;
-            List<CellBroadcastIdentity> cbIdentifiers = new ArrayList<>();
-            for (int i = 0; i < messageIdentifierCount; i++) {
-                // Both messageIdentifier and serialNumber are 16 bits integers.
-                // ATIS-0700041 Section 5.1.6
-                int messageIdentifier = bitReader.read(16);
-                int serialNumber = bitReader.read(16);
-                cbIdentifiers.add(new CellBroadcastIdentity(messageIdentifier, serialNumber));
-            }
-            return new GeoFencingTriggerMessage(type, cbIdentifiers);
-        } catch (Exception ex) {
-            Rlog.e(TAG, "create geo-fencing trigger failed, ex = " + ex.toString());
-            return null;
-        }
-    }
-
-    /**
-     * Parse the broadcast area and maximum wait time from the Warning Area Coordinates TLV.
-     *
-     * @param pdu Warning Area Coordinates TLV.
-     * @param wacOffset the offset of Warning Area Coordinates TLV.
-     * @return a pair with the first element is maximum wait time and the second is the broadcast
-     * area. The default value of the maximum wait time is 255 which means use the device default
-     * value.
-     */
-    private static Pair<Integer, List<Geometry>> parseWarningAreaCoordinates(
-            byte[] pdu, int wacOffset) {
-        // little-endian
-        int wacDataLength = ((pdu[wacOffset + 1] & 0xff) << 8) | (pdu[wacOffset] & 0xff);
-        int offset = wacOffset + 2;
-
-        if (offset + wacDataLength > pdu.length) {
-            throw new IllegalArgumentException("Invalid wac data, expected the length of pdu at"
-                    + "least " + offset + wacDataLength + ", actual is " + pdu.length);
-        }
-
-        BitStreamReader bitReader = new BitStreamReader(pdu, offset);
-
-        int maximumWaitTimeSec = SmsCbMessage.MAXIMUM_WAIT_TIME_NOT_SET;
-
-        List<Geometry> geo = new ArrayList<>();
-        int remainedBytes = wacDataLength;
-        while (remainedBytes > 0) {
-            int type = bitReader.read(4);
-            int length = bitReader.read(10);
-            remainedBytes -= length;
-            // Skip the 2 remained bits
-            bitReader.skip();
-
-            switch (type) {
-                case CbGeoUtils.GEO_FENCING_MAXIMUM_WAIT_TIME:
-                    maximumWaitTimeSec = bitReader.read(8);
-                    break;
-                case CbGeoUtils.GEOMETRY_TYPE_POLYGON:
-                    List<LatLng> latLngs = new ArrayList<>();
-                    // Each coordinate is represented by 44 bits integer.
-                    // ATIS-0700041 5.2.4 Coordinate coding
-                    int n = (length - 2) * 8 / 44;
-                    for (int i = 0; i < n; i++) {
-                        latLngs.add(getLatLng(bitReader));
-                    }
-                    // Skip the padding bits
-                    bitReader.skip();
-                    geo.add(new Polygon(latLngs));
-                    break;
-                case CbGeoUtils.GEOMETRY_TYPE_CIRCLE:
-                    LatLng center = getLatLng(bitReader);
-                    // radius = (wacRadius / 2^6). The unit of wacRadius is km, we use meter as the
-                    // distance unit during geo-fencing.
-                    // ATIS-0700041 5.2.5 radius coding
-                    double radius = (bitReader.read(20) * 1.0 / (1 << 6)) * 1000.0;
-                    geo.add(new Circle(center, radius));
-                    break;
-                default:
-                    throw new IllegalArgumentException("Unsupported geoType = " + type);
-            }
-        }
-        return new Pair(maximumWaitTimeSec, geo);
-    }
-
-    /**
-     * The coordinate is (latitude, longitude), represented by a 44 bits integer.
-     * The coding is defined in ATIS-0700041 5.2.4
-     * @param bitReader
-     * @return coordinate (latitude, longitude)
-     */
-    private static LatLng getLatLng(BitStreamReader bitReader) {
-        // wacLatitude = floor(((latitude + 90) / 180) * 2^22)
-        // wacLongitude = floor(((longitude + 180) / 360) * 2^22)
-        int wacLat = bitReader.read(22);
-        int wacLng = bitReader.read(22);
-
-        // latitude = wacLatitude * 180 / 2^22 - 90
-        // longitude = wacLongitude * 360 / 2^22 -180
-        return new LatLng((wacLat * 180.0 / (1 << 22)) - 90, (wacLng * 360.0 / (1 << 22) - 180));
-    }
-
-    /**
-     * Parse and unpack the UMTS body text according to the encoding in the data coding scheme.
-     *
-     * @param header the message header to use
-     * @param pdu the PDU to decode
-     * @return a pair of string containing the language and body of the message in order
-     */
-    private static Pair<String, String> parseUmtsBody(SmsCbHeader header, byte[] pdu) {
-        // Payload may contain multiple pages
-        int nrPages = pdu[SmsCbHeader.PDU_HEADER_LENGTH];
-        String language = header.getDataCodingSchemeStructedData().language;
-
-        if (pdu.length < SmsCbHeader.PDU_HEADER_LENGTH + 1 + (PDU_BODY_PAGE_LENGTH + 1)
-                * nrPages) {
-            throw new IllegalArgumentException("Pdu length " + pdu.length + " does not match "
-                    + nrPages + " pages");
-        }
-
-        StringBuilder sb = new StringBuilder();
-
-        for (int i = 0; i < nrPages; i++) {
-            // Each page is 82 bytes followed by a length octet indicating
-            // the number of useful octets within those 82
-            int offset = SmsCbHeader.PDU_HEADER_LENGTH + 1 + (PDU_BODY_PAGE_LENGTH + 1) * i;
-            int length = pdu[offset + PDU_BODY_PAGE_LENGTH];
-
-            if (length > PDU_BODY_PAGE_LENGTH) {
-                throw new IllegalArgumentException("Page length " + length
-                        + " exceeds maximum value " + PDU_BODY_PAGE_LENGTH);
-            }
-
-            Pair<String, String> p = unpackBody(pdu, offset, length,
-                    header.getDataCodingSchemeStructedData());
-            language = p.first;
-            sb.append(p.second);
-        }
-        return new Pair(language, sb.toString());
-
-    }
-
-    /**
-     * Parse and unpack the GSM body text according to the encoding in the data coding scheme.
-     * @param header the message header to use
-     * @param pdu the PDU to decode
-     * @return a pair of string containing the language and body of the message in order
-     */
-    private static Pair<String, String> parseGsmBody(SmsCbHeader header, byte[] pdu) {
-        // Payload is one single page
-        int offset = SmsCbHeader.PDU_HEADER_LENGTH;
-        int length = pdu.length - offset;
-        return unpackBody(pdu, offset, length, header.getDataCodingSchemeStructedData());
-    }
-
-    /**
-     * Unpack body text from the pdu using the given encoding, position and length within the pdu.
-     *
-     * @param pdu The pdu
-     * @param offset Position of the first byte to unpack
-     * @param length Number of bytes to unpack
-     * @param dcs data coding scheme
-     * @return a Pair of Strings containing the language and body of the message
-     */
-    private static Pair<String, String> unpackBody(byte[] pdu, int offset, int length,
-            DataCodingScheme dcs) {
-        String body = null;
-
-        String language = dcs.language;
-        switch (dcs.encoding) {
-            case SmsConstants.ENCODING_7BIT:
-                body = GsmAlphabet.gsm7BitPackedToString(pdu, offset, length * 8 / 7);
-
-                if (dcs.hasLanguageIndicator && body != null && body.length() > 2) {
-                    // Language is two GSM characters followed by a CR.
-                    // The actual body text is offset by 3 characters.
-                    language = body.substring(0, 2);
-                    body = body.substring(3);
-                }
-                break;
-
-            case SmsConstants.ENCODING_16BIT:
-                if (dcs.hasLanguageIndicator && pdu.length >= offset + 2) {
-                    // Language is two GSM characters.
-                    // The actual body text is offset by 2 bytes.
-                    language = GsmAlphabet.gsm7BitPackedToString(pdu, offset, 2);
-                    offset += 2;
-                    length -= 2;
-                }
-
-                try {
-                    body = new String(pdu, offset, (length & 0xfffe), "utf-16");
-                } catch (UnsupportedEncodingException e) {
-                    // Apparently it wasn't valid UTF-16.
-                    throw new IllegalArgumentException("Error decoding UTF-16 message", e);
-                }
-                break;
-
-            default:
-                break;
-        }
-
-        if (body != null) {
-            // Remove trailing carriage return
-            for (int i = body.length() - 1; i >= 0; i--) {
-                if (body.charAt(i) != CARRIAGE_RETURN) {
-                    body = body.substring(0, i + 1);
-                    break;
-                }
-            }
-        } else {
-            body = "";
-        }
-
-        return new Pair<String, String>(language, body);
-    }
-
-    /** A class use to facilitate the processing of bits stream data. */
-    private static final class BitStreamReader {
-        /** The bits stream represent by a bytes array. */
-        private final byte[] mData;
-
-        /** The offset of the current byte. */
-        private int mCurrentOffset;
-
-        /**
-         * The remained bits of the current byte which have not been read. The most significant
-         * will be read first, so the remained bits are always the least significant bits.
-         */
-        private int mRemainedBit;
-
-        /**
-         * Constructor
-         * @param data bit stream data represent by byte array.
-         * @param offset the offset of the first byte.
-         */
-        BitStreamReader(byte[] data, int offset) {
-            mData = data;
-            mCurrentOffset = offset;
-            mRemainedBit = 8;
-        }
-
-        /**
-         * Read the first {@code count} bits.
-         * @param count the number of bits need to read
-         * @return {@code bits} represent by an 32-bits integer, therefore {@code count} must be no
-         * greater than 32.
-         */
-        public int read(int count) throws IndexOutOfBoundsException {
-            int val = 0;
-            while (count > 0) {
-                if (count >= mRemainedBit) {
-                    val <<= mRemainedBit;
-                    val |= mData[mCurrentOffset] & ((1 << mRemainedBit) - 1);
-                    count -= mRemainedBit;
-                    mRemainedBit = 8;
-                    ++mCurrentOffset;
-                } else {
-                    val <<= count;
-                    val |= (mData[mCurrentOffset] & ((1 << mRemainedBit) - 1))
-                            >> (mRemainedBit - count);
-                    mRemainedBit -= count;
-                    count = 0;
-                }
-            }
-            return val;
-        }
-
-        /**
-         * Skip the current bytes if the remained bits is less than 8. This is useful when
-         * processing the padding or reserved bits.
-         */
-        public void skip() {
-            if (mRemainedBit < 8) {
-                mRemainedBit = 8;
-                ++mCurrentOffset;
-            }
-        }
-    }
-
-    /**
-     * Part of a GSM SMS cell broadcast message which may trigger geo-fencing logic.
-     * @hide
-     */
-    public static final class GeoFencingTriggerMessage {
-        /**
-         * Indicate the list of active alerts share their warning area coordinates which means the
-         * broadcast area is the union of the broadcast areas of the active alerts in this list.
-         */
-        public static final int TYPE_ACTIVE_ALERT_SHARE_WAC = 2;
-
-        public final int type;
-        public final List<CellBroadcastIdentity> cbIdentifiers;
-
-        GeoFencingTriggerMessage(int type, @NonNull List<CellBroadcastIdentity> cbIdentifiers) {
-            this.type = type;
-            this.cbIdentifiers = cbIdentifiers;
-        }
-
-        /**
-         * Whether the trigger message indicates that the broadcast areas are shared between all
-         * active alerts.
-         * @return true if broadcast areas are to be shared
-         */
-        boolean shouldShareBroadcastArea() {
-            return type == TYPE_ACTIVE_ALERT_SHARE_WAC;
-        }
-
-        static final class CellBroadcastIdentity {
-            public final int messageIdentifier;
-            public final int serialNumber;
-            CellBroadcastIdentity(int messageIdentifier, int serialNumber) {
-                this.messageIdentifier = messageIdentifier;
-                this.serialNumber = serialNumber;
-            }
-        }
-
-        @Override
-        public String toString() {
-            String identifiers = cbIdentifiers.stream()
-                    .map(cbIdentifier ->String.format("(msgId = %d, serial = %d)",
-                            cbIdentifier.messageIdentifier, cbIdentifier.serialNumber))
-                    .collect(Collectors.joining(","));
-            return "triggerType=" + type + " identifiers=" + identifiers;
-        }
-    }
-}
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index ae8285b..a7eef05 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -16,7 +16,9 @@
 
 package android.net;
 
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
 import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
+import static com.android.testutils.ParcelUtilsKt.parcelingRoundTrip;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -47,25 +49,22 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class LinkPropertiesTest {
-    private static final InetAddress ADDRV4 = InetAddresses.parseNumericAddress("75.208.6.1");
-    private static final InetAddress ADDRV6 = InetAddresses.parseNumericAddress(
-            "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
-    private static final InetAddress DNS1 = InetAddresses.parseNumericAddress("75.208.7.1");
-    private static final InetAddress DNS2 = InetAddresses.parseNumericAddress("69.78.7.1");
-    private static final InetAddress DNS6 = InetAddresses.parseNumericAddress(
-            "2001:4860:4860::8888");
-    private static final InetAddress PRIVDNS1 = InetAddresses.parseNumericAddress("1.1.1.1");
-    private static final InetAddress PRIVDNS2 = InetAddresses.parseNumericAddress("1.0.0.1");
-    private static final InetAddress PRIVDNS6 = InetAddresses.parseNumericAddress(
-            "2606:4700:4700::1111");
-    private static final InetAddress PCSCFV4 = InetAddresses.parseNumericAddress("10.77.25.37");
-    private static final InetAddress PCSCFV6 = InetAddresses.parseNumericAddress(
-            "2001:0db8:85a3:0000:0000:8a2e:0370:1");
-    private static final InetAddress GATEWAY1 = InetAddresses.parseNumericAddress("75.208.8.1");
-    private static final InetAddress GATEWAY2 = InetAddresses.parseNumericAddress("69.78.8.1");
-    private static final InetAddress GATEWAY61 = InetAddresses.parseNumericAddress(
-            "fe80::6:0000:613");
-    private static final InetAddress GATEWAY62 = InetAddresses.parseNumericAddress("fe80::6:2222");
+    private static final InetAddress ADDRV4 = address("75.208.6.1");
+    private static final InetAddress ADDRV6 = address("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+    private static final InetAddress DNS1 = address("75.208.7.1");
+    private static final InetAddress DNS2 = address("69.78.7.1");
+    private static final InetAddress DNS6 = address("2001:4860:4860::8888");
+    private static final InetAddress PRIVDNS1 = address("1.1.1.1");
+    private static final InetAddress PRIVDNS2 = address("1.0.0.1");
+    private static final InetAddress PRIVDNS6 = address("2606:4700:4700::1111");
+    private static final InetAddress PCSCFV4 = address("10.77.25.37");
+    private static final InetAddress PCSCFV6 = address("2001:0db8:85a3:0000:0000:8a2e:0370:1");
+    private static final InetAddress GATEWAY1 = address("75.208.8.1");
+    private static final InetAddress GATEWAY2 = address("69.78.8.1");
+    private static final InetAddress GATEWAY61 = address("fe80::6:0000:613");
+    private static final InetAddress GATEWAY62 = address("fe80::6:22%lo");
+    private static final InetAddress TESTIPV4ADDR = address("192.168.47.42");
+    private static final InetAddress TESTIPV6ADDR = address("fe80::7:33%43");
     private static final String NAME = "qmi0";
     private static final String DOMAINS = "google.com";
     private static final String PRIV_DNS_SERVER_NAME = "private.dns.com";
@@ -75,8 +74,7 @@
     private static final LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
     private static final LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
 
-    // TODO: replace all calls to NetworkUtils.numericToInetAddress with calls to this method.
-    private InetAddress Address(String addrString) {
+    private static InetAddress address(String addrString) {
         return InetAddresses.parseNumericAddress(addrString);
     }
 
@@ -228,7 +226,7 @@
         target.clear();
         target.setInterfaceName(NAME);
         // change link addresses
-        target.addLinkAddress(new LinkAddress(Address("75.208.6.2"), 32));
+        target.addLinkAddress(new LinkAddress(address("75.208.6.2"), 32));
         target.addLinkAddress(LINKADDRV6);
         target.addDnsServer(DNS1);
         target.addDnsServer(DNS2);
@@ -243,7 +241,7 @@
         target.addLinkAddress(LINKADDRV4);
         target.addLinkAddress(LINKADDRV6);
         // change dnses
-        target.addDnsServer(Address("75.208.7.2"));
+        target.addDnsServer(address("75.208.7.2"));
         target.addDnsServer(DNS2);
         target.addPcscfServer(PCSCFV6);
         target.addRoute(new RouteInfo(GATEWAY1));
@@ -255,10 +253,10 @@
         target.setInterfaceName(NAME);
         target.addLinkAddress(LINKADDRV4);
         target.addLinkAddress(LINKADDRV6);
-        target.addDnsServer(Address("75.208.7.2"));
+        target.addDnsServer(address("75.208.7.2"));
         target.addDnsServer(DNS2);
         // change pcscf
-        target.addPcscfServer(Address("2001::1"));
+        target.addPcscfServer(address("2001::1"));
         target.addRoute(new RouteInfo(GATEWAY1));
         target.addRoute(new RouteInfo(GATEWAY2));
         target.setMtu(MTU);
@@ -271,9 +269,9 @@
         target.addDnsServer(DNS1);
         target.addDnsServer(DNS2);
         // change gateway
-        target.addRoute(new RouteInfo(Address("75.208.8.2")));
-        target.addRoute(new RouteInfo(GATEWAY2));
+        target.addRoute(new RouteInfo(address("75.208.8.2")));
         target.setMtu(MTU);
+        target.addRoute(new RouteInfo(GATEWAY2));
         assertFalse(source.equals(target));
 
         target.clear();
@@ -349,7 +347,7 @@
 
     @Test
     public void testRouteInterfaces() {
-        LinkAddress prefix = new LinkAddress(Address("2001:db8::"), 32);
+        LinkAddress prefix = new LinkAddress(address("2001:db8::"), 32);
         InetAddress address = ADDRV6;
 
         // Add a route with no interface to a LinkProperties with no interface. No errors.
@@ -739,8 +737,7 @@
 
         // Add an on-link route, making the on-link DNS server reachable,
         // but there is still no IPv4 address.
-        assertTrue(v4lp.addRoute(new RouteInfo(
-                new IpPrefix(NetworkUtils.numericToInetAddress("75.208.0.0"), 16))));
+        assertTrue(v4lp.addRoute(new RouteInfo(new IpPrefix(address("75.208.0.0"), 16))));
         assertFalse(v4lp.isReachable(DNS1));
         assertFalse(v4lp.isReachable(DNS2));
 
@@ -756,9 +753,9 @@
         assertTrue(v4lp.isReachable(DNS2));
 
         final LinkProperties v6lp = new LinkProperties();
-        final InetAddress kLinkLocalDns = Address("fe80::6:1");
-        final InetAddress kLinkLocalDnsWithScope = Address("fe80::6:2%43");
-        final InetAddress kOnLinkDns = Address("2001:db8:85a3::53");
+        final InetAddress kLinkLocalDns = address("fe80::6:1");
+        final InetAddress kLinkLocalDnsWithScope = address("fe80::6:2%43");
+        final InetAddress kOnLinkDns = address("2001:db8:85a3::53");
         assertFalse(v6lp.isReachable(kLinkLocalDns));
         assertFalse(v6lp.isReachable(kLinkLocalDnsWithScope));
         assertFalse(v6lp.isReachable(kOnLinkDns));
@@ -767,7 +764,7 @@
         // Add a link-local route, making the link-local DNS servers reachable. Because
         // we assume the presence of an IPv6 link-local address, link-local DNS servers
         // are considered reachable, but only those with a non-zero scope identifier.
-        assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(Address("fe80::"), 64))));
+        assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(address("fe80::"), 64))));
         assertFalse(v6lp.isReachable(kLinkLocalDns));
         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
         assertFalse(v6lp.isReachable(kOnLinkDns));
@@ -783,7 +780,7 @@
         // Add a global route on link, but no global address yet. DNS servers reachable
         // via a route that doesn't require a gateway: give them the benefit of the
         // doubt and hope the link-local source address suffices for communication.
-        assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(Address("2001:db8:85a3::"), 64))));
+        assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(address("2001:db8:85a3::"), 64))));
         assertFalse(v6lp.isReachable(kLinkLocalDns));
         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
         assertTrue(v6lp.isReachable(kOnLinkDns));
@@ -812,7 +809,7 @@
         stacked.setInterfaceName("v4-test0");
         v6lp.addStackedLink(stacked);
 
-        InetAddress stackedAddress = Address("192.0.0.4");
+        InetAddress stackedAddress = address("192.0.0.4");
         LinkAddress stackedLinkAddress = new LinkAddress(stackedAddress, 32);
         assertFalse(v6lp.isReachable(stackedAddress));
         stacked.addLinkAddress(stackedLinkAddress);
@@ -845,7 +842,7 @@
         LinkProperties rmnet1 = new LinkProperties();
         rmnet1.setInterfaceName("rmnet1");
         rmnet1.addLinkAddress(new LinkAddress("10.0.0.3/8"));
-        RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null, Address("10.0.0.1"),
+        RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null, address("10.0.0.1"),
                 rmnet1.getInterfaceName());
         RouteInfo directRoute1 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
                 rmnet1.getInterfaceName());
@@ -864,7 +861,7 @@
         rmnet2.setInterfaceName("rmnet2");
         rmnet2.addLinkAddress(new LinkAddress("fe80::cafe/64"));
         rmnet2.addLinkAddress(new LinkAddress("2001:db8::2/64"));
-        RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null, Address("2001:db8::1"),
+        RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null, address("2001:db8::1"),
                 rmnet2.getInterfaceName());
         RouteInfo directRoute2 = new RouteInfo(new IpPrefix("2001:db8::/64"), null,
                 rmnet2.getInterfaceName());
@@ -930,24 +927,54 @@
     public void testLinkPropertiesParcelable() throws Exception {
         LinkProperties source = new LinkProperties();
         source.setInterfaceName(NAME);
-        // set 2 link addresses
+
         source.addLinkAddress(LINKADDRV4);
         source.addLinkAddress(LINKADDRV6);
-        // set 2 dnses
+
         source.addDnsServer(DNS1);
         source.addDnsServer(DNS2);
-        // set 2 gateways
+        source.addDnsServer(GATEWAY62);
+
+        source.addPcscfServer(TESTIPV4ADDR);
+        source.addPcscfServer(TESTIPV6ADDR);
+
+        source.setUsePrivateDns(true);
+        source.setPrivateDnsServerName(PRIV_DNS_SERVER_NAME);
+
+        source.setDomains(DOMAINS);
+
         source.addRoute(new RouteInfo(GATEWAY1));
         source.addRoute(new RouteInfo(GATEWAY2));
-        // set 2 validated private dnses
+
         source.addValidatedPrivateDnsServer(DNS6);
         source.addValidatedPrivateDnsServer(GATEWAY61);
+        source.addValidatedPrivateDnsServer(TESTIPV6ADDR);
+
+        source.setHttpProxy(ProxyInfo.buildDirectProxy("test", 8888));
 
         source.setMtu(MTU);
 
+        source.setTcpBufferSizes(TCP_BUFFER_SIZES);
+
         source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
 
-        assertParcelingIsLossless(source);
+        source.setWakeOnLanSupported(true);
+
+        final LinkProperties stacked = new LinkProperties();
+        stacked.setInterfaceName("test-stacked");
+        source.addStackedLink(stacked);
+
+        assertParcelSane(source, 15 /* fieldCount */);
+    }
+
+    @Test
+    public void testLinkLocalDnsServerParceling() throws Exception {
+        final String strAddress = "fe80::1%lo";
+        final LinkProperties lp = new LinkProperties();
+        lp.addDnsServer(address(strAddress));
+        final LinkProperties unparceled = parcelingRoundTrip(lp);
+        // Inet6Address#equals does not test for the scope id
+        assertEquals(strAddress, unparceled.getDnsServers().get(0).getHostAddress());
     }
 
     @Test
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index bd2ab53..03009aa 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -738,7 +738,13 @@
                                           const android::Res_value& res_value,
                                           StringPool* dst_pool) {
   if (type == ResourceType::kId) {
-    return util::make_unique<Id>();
+    if (res_value.dataType != android::Res_value::TYPE_REFERENCE &&
+        res_value.dataType != android::Res_value::TYPE_DYNAMIC_REFERENCE) {
+      // plain "id" resources are actually encoded as dummy values (aapt1 uses an empty string,
+      // while aapt2 uses a false boolean).
+      return util::make_unique<Id>();
+    }
+    // fall through to regular reference deserialization logic
   }
 
   const uint32_t data = util::DeviceToHost32(res_value.data);
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 729ef61..83a1800 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -103,6 +103,12 @@
 
     /**
      * @hide
+     * Security protocol type: WAPI.
+     */
+    public static final int PROTOCOL_WAPI = 4;
+
+    /**
+     * @hide
      * No security key management scheme.
      */
     public static final int KEY_MGMT_NONE = 0;
@@ -169,6 +175,18 @@
     public static final int KEY_MGMT_OWE_TRANSITION = 12;
     /**
      * @hide
+     * Security key management scheme: WAPI_PSK.
+     */
+    @SystemApi
+    public static final int KEY_MGMT_WAPI_PSK = 13;
+    /**
+     * @hide
+     * Security key management scheme: WAPI_CERT.
+     */
+    @SystemApi
+    public static final int KEY_MGMT_WAPI_CERT = 14;
+    /**
+     * @hide
      * No cipher suite.
      */
     public static final int CIPHER_NONE = 0;
@@ -192,6 +210,11 @@
      * Cipher suite: GCMP
      */
     public static final int CIPHER_GCMP_256 = 4;
+    /**
+     * @hide
+     * Cipher suite: SMS4
+     */
+    public static final int CIPHER_SMS4 = 5;
 
     /**
      * The detected signal level in dBm, also known as the RSSI.
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index d755053..fd8a924 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -60,32 +60,77 @@
      * @hide
      */
     @SystemApi
-    public static final int BAND_2GHZ = 0;
+    public static final int BAND_2GHZ = 1 << 0;
 
     /**
      * 5GHz band.
      * @hide
      */
     @SystemApi
-    public static final int BAND_5GHZ = 1;
+    public static final int BAND_5GHZ = 1 << 1;
 
     /**
-     * Device is allowed to choose the optimal band (2Ghz or 5Ghz) based on device capability,
+     * 6GHz band.
+     * @hide
+     */
+    @SystemApi
+    public static final int BAND_6GHZ = 1 << 2;
+
+    /**
+     * Device is allowed to choose the optimal band (2Ghz, 5Ghz, 6Ghz) based on device capability,
      * operating country code and current radio conditions.
      * @hide
      */
     @SystemApi
-    public static final int BAND_ANY = -1;
+    public static final int BAND_ANY = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "BAND_TYPE_" }, value = {
+    @IntDef(flag = true, prefix = { "BAND_TYPE_" }, value = {
             BAND_2GHZ,
             BAND_5GHZ,
-            BAND_ANY,
+            BAND_6GHZ,
     })
     public @interface BandType {}
 
+    private static boolean isBandValid(@BandType int band) {
+        return ((band != 0) && ((band & ~BAND_ANY) == 0));
+    }
+
+    private static final int MIN_CH_2G_BAND = 1;
+    private static final int MAX_CH_2G_BAND = 14;
+    private static final int MIN_CH_5G_BAND = 34;
+    private static final int MAX_CH_5G_BAND = 196;
+    private static final int MIN_CH_6G_BAND = 1;
+    private static final int MAX_CH_6G_BAND = 253;
+
+
+
+    private static boolean isChannelBandPairValid(int channel, @BandType int band) {
+        switch (band) {
+            case BAND_2GHZ:
+                if (channel < MIN_CH_2G_BAND || channel >  MAX_CH_2G_BAND) {
+                    return false;
+                }
+                break;
+
+            case BAND_5GHZ:
+                if (channel < MIN_CH_5G_BAND || channel >  MAX_CH_5G_BAND) {
+                    return false;
+                }
+                break;
+
+            case BAND_6GHZ:
+                if (channel < MIN_CH_6G_BAND || channel >  MAX_CH_6G_BAND) {
+                    return false;
+                }
+                break;
+            default:
+                return false;
+        }
+        return true;
+    }
+
     /**
      * SSID for the AP, or null for a framework-determined SSID.
      */
@@ -439,39 +484,42 @@
          * <p>
          * <li>If not set, defaults to BAND_2GHZ {@link @BandType}.</li>
          *
-         * @param band One of the band types from {@link @BandType}.
+         * @param band One or combination of the band types from {@link @BandType}.
          * @return Builder for chaining.
          */
         @NonNull
         public Builder setBand(@BandType int band) {
-            switch (band) {
-                case BAND_2GHZ:
-                    break;
-                case BAND_5GHZ:
-                    break;
-                case BAND_ANY:
-                    break;
-                default:
-                    throw new IllegalArgumentException("Invalid band type");
+            if (!isBandValid(band)) {
+                throw new IllegalArgumentException("Invalid band type");
             }
             mBand = band;
+            // Since band preference is specified, no specific channel is selected.
+            mChannel = 0;
             return this;
         }
 
         /**
-         * Specifies the channel for the AP.
+         * Specifies the channel and associated band for the AP.
          *
          * The channel which AP resides on. Valid channels are country dependent.
-         * Use the special channel value 0 to have the framework auto-select a valid channel
-         * from the band configured with {@link #setBand(@BandType int)}.
+         * The default for the channel is a the special value 0 to have the framework
+         * auto-select a valid channel from the band configured with
+         * {@link #setBand(@BandType int)}.
+         * Note, since 6GHz band use the same channel numbering of 2.4GHz and 5GHZ bands,
+         * the caller needs to pass the band containing the selected channel.
          *
          * <p>
          * <li>If not set, defaults to 0.</li>
          * @param channel operating channel of the AP.
+         * @param band containing this channel.
          * @return Builder for chaining.
          */
         @NonNull
-        public Builder setChannel(int channel) {
+        public Builder setChannel(int channel, @BandType int band) {
+            if (!isChannelBandPairValid(channel, band)) {
+                throw new IllegalArgumentException("Invalid band type");
+            }
+            mBand = band;
             mChannel = channel;
             return this;
         }
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index d068fc6..e3a945d 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -36,14 +36,9 @@
 import android.os.UserHandle;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.util.BackupUtils;
 import android.util.Log;
 import android.util.SparseArray;
 
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
@@ -123,7 +118,9 @@
                 OWE,
                 SUITE_B_192,
                 WPA_PSK_SHA256,
-                WPA_EAP_SHA256})
+                WPA_EAP_SHA256,
+                WAPI_PSK,
+                WAPI_CERT})
         public @interface KeyMgmtScheme {}
 
         /** WPA is not used; plaintext or static WEP could be used. */
@@ -190,11 +187,26 @@
          */
         public static final int WPA_EAP_SHA256 = 12;
 
+        /**
+         * WAPI pre-shared key (requires {@code preSharedKey} to be specified).
+         * @hide
+         */
+        @SystemApi
+        public static final int WAPI_PSK = 13;
+
+        /**
+         * WAPI certificate to be specified.
+         * @hide
+         */
+        @SystemApi
+        public static final int WAPI_CERT = 14;
+
         public static final String varName = "key_mgmt";
 
         public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP",
                 "IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP",
-                "SAE", "OWE", "SUITE_B_192", "WPA_PSK_SHA256", "WPA_EAP_SHA256" };
+                "SAE", "OWE", "SUITE_B_192", "WPA_PSK_SHA256", "WPA_EAP_SHA256",
+                "WAPI_PSK", "WAPI_CERT" };
     }
 
     /**
@@ -215,9 +227,14 @@
          */
         public static final int OSEN = 2;
 
+        /**
+         * WAPI Protocol
+         */
+        public static final int WAPI = 3;
+
         public static final String varName = "proto";
 
-        public static final String[] strings = { "WPA", "RSN", "OSEN" };
+        public static final String[] strings = { "WPA", "RSN", "OSEN", "WAPI" };
     }
 
     /**
@@ -260,10 +277,14 @@
          * AES in Galois/Counter Mode
          */
         public static final int GCMP_256 = 3;
+        /**
+         * SMS4 cipher for WAPI
+         */
+        public static final int SMS4 = 4;
 
         public static final String varName = "pairwise";
 
-        public static final String[] strings = { "NONE", "TKIP", "CCMP", "GCMP_256" };
+        public static final String[] strings = { "NONE", "TKIP", "CCMP", "GCMP_256", "SMS4" };
     }
 
     /**
@@ -301,12 +322,17 @@
          * AES in Galois/Counter Mode
          */
         public static final int GCMP_256 = 5;
+        /**
+         * SMS4 cipher for WAPI
+         */
+        public static final int SMS4 = 6;
 
         public static final String varName = "group";
 
         public static final String[] strings =
                 { /* deprecated */ "WEP40", /* deprecated */ "WEP104",
-                        "TKIP", "CCMP", "GTK_NOT_USED", "GCMP_256" };
+                        "TKIP", "CCMP", "GTK_NOT_USED", "GCMP_256",
+                        "SMS4" };
     }
 
     /**
@@ -388,6 +414,10 @@
     public static final int SECURITY_TYPE_EAP_SUITE_B = 5;
     /** @hide */
     public static final int SECURITY_TYPE_OWE = 6;
+    /** @hide */
+    public static final int SECURITY_TYPE_WAPI_PSK = 7;
+    /** @hide */
+    public static final int SECURITY_TYPE_WAPI_CERT = 8;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -398,7 +428,9 @@
             SECURITY_TYPE_EAP,
             SECURITY_TYPE_SAE,
             SECURITY_TYPE_EAP_SUITE_B,
-            SECURITY_TYPE_OWE
+            SECURITY_TYPE_OWE,
+            SECURITY_TYPE_WAPI_PSK,
+            SECURITY_TYPE_WAPI_CERT
     })
     public @interface SecurityType {}
 
@@ -450,6 +482,18 @@
                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
                 requirePMF = true;
                 break;
+            case SECURITY_TYPE_WAPI_PSK:
+                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WAPI_PSK);
+                allowedProtocols.set(WifiConfiguration.Protocol.WAPI);
+                allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.SMS4);
+                allowedGroupCiphers.set(WifiConfiguration.GroupCipher.SMS4);
+                break;
+            case SECURITY_TYPE_WAPI_CERT:
+                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WAPI_CERT);
+                allowedProtocols.set(WifiConfiguration.Protocol.WAPI);
+                allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.SMS4);
+                allowedGroupCiphers.set(WifiConfiguration.GroupCipher.SMS4);
+                break;
             default:
                 throw new IllegalArgumentException("unknown security type " + securityType);
         }
@@ -2350,6 +2394,10 @@
             return KeyMgmt.OWE;
         } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
             return KeyMgmt.SUITE_B_192;
+        } else if (allowedKeyManagement.get(KeyMgmt.WAPI_PSK)) {
+            return KeyMgmt.WAPI_PSK;
+        } else if (allowedKeyManagement.get(KeyMgmt.WAPI_CERT)) {
+            return KeyMgmt.WAPI_CERT;
         }
         return KeyMgmt.NONE;
     }
@@ -2388,6 +2436,10 @@
             key = SSID + KeyMgmt.strings[KeyMgmt.SAE];
         } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
             key = SSID + KeyMgmt.strings[KeyMgmt.SUITE_B_192];
+        } else if (allowedKeyManagement.get(KeyMgmt.WAPI_PSK)) {
+            key = SSID + KeyMgmt.strings[KeyMgmt.WAPI_PSK];
+        } else if (allowedKeyManagement.get(KeyMgmt.WAPI_CERT)) {
+            key = SSID + KeyMgmt.strings[KeyMgmt.WAPI_CERT];
         } else {
             key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
         }
@@ -2768,54 +2820,4 @@
                 return new WifiConfiguration[size];
             }
         };
-
-    /**
-     * Serialize the Soft AP configuration contained in this object for backup.
-     * @hide
-     */
-    @NonNull
-    // TODO(b/144368124): this method should be removed once we migrate to SoftApConfiguration
-    public byte[] getBytesForBackup() throws IOException {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        DataOutputStream out = new DataOutputStream(baos);
-
-        out.writeInt(BACKUP_VERSION);
-        BackupUtils.writeString(out, SSID);
-        out.writeInt(apBand);
-        out.writeInt(apChannel);
-        BackupUtils.writeString(out, preSharedKey);
-        out.writeInt(getAuthType());
-        out.writeBoolean(hiddenSSID);
-        return baos.toByteArray();
-    }
-
-    /**
-     * Deserialize a byte array containing Soft AP configuration into a WifiConfiguration object.
-     * @return The deserialized WifiConfiguration containing Soft AP configuration, or null if
-     * the version contains a bad dataset e.g. Version 1
-     * @throws BackupUtils.BadVersionException if the version is unrecognized
-     * @hide
-     */
-    @Nullable
-    // TODO(b/144368124): this method should be removed once we migrate to SoftApConfiguration
-    public static WifiConfiguration getWifiConfigFromBackup(@NonNull DataInputStream in)
-            throws IOException, BackupUtils.BadVersionException {
-        WifiConfiguration config = new WifiConfiguration();
-        int version = in.readInt();
-        if (version < 1 || version > BACKUP_VERSION) {
-            throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
-        }
-
-        if (version == 1) return null; // Version 1 is a bad dataset.
-
-        config.SSID = BackupUtils.readString(in);
-        config.apBand = in.readInt();
-        config.apChannel = in.readInt();
-        config.preSharedKey = BackupUtils.readString(in);
-        config.allowedKeyManagement.set(in.readInt());
-        if (version >= 3) {
-            config.hiddenSSID = in.readBoolean();
-        }
-        return config;
-    }
 }
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 66b0590..7a59a4f 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -41,6 +41,36 @@
  */
 public class WifiEnterpriseConfig implements Parcelable {
 
+    /** Key prefix for WAPI AS certificates. */
+    public static final String WAPI_AS_CERTIFICATE = "WAPIAS_";
+
+    /** Key prefix for WAPI user certificates. */
+    public static final String WAPI_USER_CERTIFICATE = "WAPIUSR_";
+
+    /**
+     * Intent extra: name for WAPI AS certificates
+     */
+    public static final String EXTRA_WAPI_AS_CERTIFICATE_NAME =
+            "android.net.wifi.extra.WAPI_AS_CERTIFICATE_NAME";
+
+    /**
+     * Intent extra: data for WAPI AS certificates
+     */
+    public static final String EXTRA_WAPI_AS_CERTIFICATE_DATA =
+            "android.net.wifi.extra.WAPI_AS_CERTIFICATE_DATA";
+
+    /**
+     * Intent extra: name for WAPI AS certificates
+     */
+    public static final String EXTRA_WAPI_USER_CERTIFICATE_NAME =
+            "android.net.wifi.extra.WAPI_USER_CERTIFICATE_NAME";
+
+    /**
+     * Intent extra: data for WAPI AS certificates
+     */
+    public static final String EXTRA_WAPI_USER_CERTIFICATE_DATA =
+            "android.net.wifi.extra.WAPI_USER_CERTIFICATE_DATA";
+
     /** @hide */
     public static final String EMPTY_VALUE         = "NULL";
     /** @hide */
@@ -61,6 +91,7 @@
     public static final String DOM_SUFFIX_MATCH_KEY = "domain_suffix_match";
     /** @hide */
     public static final String OPP_KEY_CACHING     = "proactive_key_caching";
+
     /**
      * String representing the keystore OpenSSL ENGINE's ID.
      * @hide
@@ -130,6 +161,8 @@
     public static final String PLMN_KEY            = "plmn";
     /** @hide */
     public static final String CA_CERT_ALIAS_DELIMITER = " ";
+    /** @hide */
+    public static final String WAPI_CERT_SUITE_KEY = "wapi_cert_suite";
 
     /**
      * Do not use OCSP stapling (TLS certificate status extension)
@@ -348,9 +381,12 @@
         public static final int AKA_PRIME = 6;
         /** Hotspot 2.0 r2 OSEN */
         public static final int UNAUTH_TLS = 7;
+        /** WAPI Certificate */
+        public static final int WAPI_CERT = 8;
         /** @hide */
         public static final String[] strings =
-                { "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA", "AKA'", "WFA-UNAUTH-TLS" };
+                { "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA", "AKA'", "WFA-UNAUTH-TLS",
+                        "WAPI_CERT" };
 
         /** Prevent initialization */
         private Eap() {}
@@ -494,6 +530,10 @@
     public void setEapMethod(int eapMethod) {
         switch (eapMethod) {
             /** Valid methods */
+            case Eap.WAPI_CERT:
+                mEapMethod = eapMethod;
+                setPhase2Method(Phase2.NONE);
+                break;
             case Eap.TLS:
             case Eap.UNAUTH_TLS:
                 setPhase2Method(Phase2.NONE);
@@ -1313,4 +1353,29 @@
         }
         return false;
     }
+
+    /**
+     * Set the WAPI certificate suite name on wpa_supplicant.
+     *
+     * If this field is not specified, WAPI-CERT uses ASU ID from WAI packet
+     * as the certificate suite name automatically.
+     *
+     * @param wapiCertSuite The name for WAPI certificate suite, or null/empty string to clear.
+     * @hide
+     */
+    @SystemApi
+    public void setWapiCertSuite(@Nullable String wapiCertSuite) {
+        setFieldValue(WAPI_CERT_SUITE_KEY, wapiCertSuite);
+    }
+
+    /**
+     * Get the WAPI certificate suite name
+     * @return the certificate suite name
+     * @hide
+     */
+    @Nullable
+    @SystemApi
+    public String getWapiCertSuite() {
+        return getFieldValue(WAPI_CERT_SUITE_KEY);
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 9691bda..b98d64d 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1153,6 +1153,7 @@
     @UnsupportedAppUsage
     public static final int RSSI_LEVELS = 5;
 
+    //TODO (b/146346676): This needs to be removed, not used in the code.
     /**
      * Auto settings in the driver. The driver could choose to operate on both
      * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
@@ -2225,6 +2226,8 @@
     public static final long WIFI_FEATURE_MBO              = 0x800000000L; // MBO Support
     /** @hide */
     public static final long WIFI_FEATURE_OCE              = 0x1000000000L; // OCE Support
+    /** @hide */
+    public static final long WIFI_FEATURE_WAPI             = 0x2000000000L; // WAPI
 
     private long getSupportedFeatures() {
         try {
@@ -2600,10 +2603,10 @@
      * Check if the device is dual mode capable i.e. supports concurrent STA + Soft AP.
      *
      * If the device is dual mode capable, it may require conversion of the user's Soft AP band
-     * selection {@link WifiConfiguration#apBand} from {@link WifiConfiguration#AP_BAND_5GHZ} to
-     * {@link WifiConfiguration#AP_BAND_ANY}, since if the device is connected to a 5GHz DFS
-     * channel as a STA, it may be unable to honor a request to start Soft AP on the same DFS
-     * channel.
+     * selection {@link SoftApConfiguration#mBand} from {@link SoftApConfiguration#BAND_5GHZ} to
+     * include also {@link SoftApConfiguration#BAND_2GHZ}, since if the device is connected to a
+     * 5GHz DFS channel as a STA, it may be unable to honor a request to start Soft AP on the same
+     * DFS channel.
      *
      * @return {@code true} if dual mode STA + AP is supported by this device, {@code false}
      * otherwise.
@@ -4961,6 +4964,13 @@
     }
 
     /**
+     * @return true if this device supports WAPI.
+     */
+    public boolean isWapiSupported() {
+        return isFeatureSupported(WIFI_FEATURE_WAPI);
+    }
+
+    /**
      * Gets the factory Wi-Fi MAC addresses.
      * @return Array of String representing Wi-Fi MAC addresses sorted lexically or an empty Array
      * if failed.
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 9fd29ae..9c1475f 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -122,6 +122,16 @@
          * Whether the setIsUserAllowedToManuallyConnect have been called.
          */
         private boolean mIsUserAllowedBeenSet;
+        /**
+         * Pre-shared key for use with WAPI-PSK networks.
+         */
+        private @Nullable String mWapiPskPassphrase;
+
+        /**
+         * The enterprise configuration details specifying the EAP method,
+         * certificates and other settings associated with the WAPI networks.
+         */
+        private @Nullable WifiEnterpriseConfig mWapiEnterpriseConfig;
 
         public Builder() {
             mSsid = null;
@@ -140,6 +150,8 @@
             mIsUserAllowedBeenSet = false;
             mPriority = UNASSIGNED_PRIORITY;
             mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
+            mWapiPskPassphrase = null;
+            mWapiEnterpriseConfig = null;
         }
 
         /**
@@ -294,6 +306,39 @@
         }
 
         /**
+         * Set the ASCII WAPI passphrase for this network. Needed for authenticating to
+         * WAPI-PSK networks.
+         *
+         * @param passphrase passphrase of the network.
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         * @throws IllegalArgumentException if the passphrase is not ASCII encodable.
+         *
+         */
+        public @NonNull Builder setWapiPassphrase(@NonNull String passphrase) {
+            checkNotNull(passphrase);
+            final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
+            if (!asciiEncoder.canEncode(passphrase)) {
+                throw new IllegalArgumentException("passphrase not ASCII encodable");
+            }
+            mWapiPskPassphrase = passphrase;
+            return this;
+        }
+
+        /**
+         * Set the associated enterprise configuration for this network. Needed for authenticating
+         * to WAPI-CERT networks. See {@link WifiEnterpriseConfig} for description.
+         *
+         * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         */
+        public @NonNull Builder setWapiEnterpriseConfig(
+                @NonNull WifiEnterpriseConfig enterpriseConfig) {
+            checkNotNull(enterpriseConfig);
+            mWapiEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+            return this;
+        }
+
+        /**
          * Specifies whether this represents a hidden network.
          * <p>
          * <li>If not set, defaults to false (i.e not a hidden network).</li>
@@ -413,6 +458,13 @@
                 configuration.enterpriseConfig = mWpa3EnterpriseConfig;
             } else if (mIsEnhancedOpen) { // OWE network
                 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE);
+            } else if (!TextUtils.isEmpty(mWapiPskPassphrase)) { // WAPI-PSK network.
+                configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WAPI_PSK);
+                // WifiConfiguration.preSharedKey needs quotes around ASCII password.
+                configuration.preSharedKey = "\"" + mWapiPskPassphrase + "\"";
+            } else if (mWapiEnterpriseConfig != null) { // WAPI-CERT network
+                configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WAPI_CERT);
+                configuration.enterpriseConfig = mWapiEnterpriseConfig;
             } else { // Open network
                 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
             }
@@ -446,13 +498,16 @@
             numSecurityTypes += mIsEnhancedOpen ? 1 : 0;
             numSecurityTypes += !TextUtils.isEmpty(mWpa2PskPassphrase) ? 1 : 0;
             numSecurityTypes += !TextUtils.isEmpty(mWpa3SaePassphrase) ? 1 : 0;
+            numSecurityTypes += !TextUtils.isEmpty(mWapiPskPassphrase) ? 1 : 0;
             numSecurityTypes += mWpa2EnterpriseConfig != null ? 1 : 0;
             numSecurityTypes += mWpa3EnterpriseConfig != null ? 1 : 0;
+            numSecurityTypes += mWapiEnterpriseConfig != null ? 1 : 0;
             numSecurityTypes += mPasspointConfiguration != null ? 1 : 0;
             if (numSecurityTypes > 1) {
                 throw new IllegalStateException("only one of setIsEnhancedOpen, setWpa2Passphrase,"
-                        + "setWpa3Passphrase, setWpa2EnterpriseConfig, setWpa3EnterpriseConfig"
-                        + "or setPasspointConfig can be invoked for network suggestion");
+                        + " setWpa3Passphrase, setWpa2EnterpriseConfig, setWpa3EnterpriseConfig"
+                        + " setWapiPassphrase, setWapiCertSuite, setIsWapiCertSuiteAuto"
+                        + " or setPasspointConfig can be invoked for network suggestion");
             }
         }
 
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index 495b1bb..c9bca4f 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -48,21 +48,29 @@
      */
     public WpsInfo wps;
 
-    /**
-     * The network name of a group, should be configured by helper method
-     */
+    /** Get the network name of this P2P configuration, or null if unset. */
+    @Nullable
+    public String getNetworkName() {
+        return networkName;
+    }
+
     /** @hide */
     public String networkName = "";
 
-    /**
-     * The passphrase of a group, should be configured by helper method
-     */
+    /** Get the passphrase of this P2P configuration, or null if unset. */
+    @Nullable
+    public String getPassphrase() {
+        return passphrase;
+    }
+
     /** @hide */
     public String passphrase = "";
 
-    /**
-     * The required band for Group Owner
-     */
+    /** Get the required band for the group owner. */
+    public int getGroupOwnerBand() {
+        return groupOwnerBand;
+    }
+
     /** @hide */
     public int groupOwnerBand = GROUP_OWNER_BAND_AUTO;
 
@@ -123,6 +131,15 @@
     @UnsupportedAppUsage
     public int netId = WifiP2pGroup.PERSISTENT_NET_ID;
 
+    /**
+     * Get the network ID of this P2P configuration.
+     * @return either a non-negative network ID, or one of {@link WifiP2pGroup#PERSISTENT_NET_ID} or
+     * {@link WifiP2pGroup#TEMPORARY_NET_ID}.
+     */
+    public int getNetworkId() {
+        return netId;
+    }
+
     public WifiP2pConfig() {
         //set defaults
         wps = new WpsInfo();
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index f9d1266..d8c50f2 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -39,18 +39,15 @@
 
     /**
      * The temporary network id.
-     *
-     * @hide
+     * @see #getNetworkId()
      */
-    @UnsupportedAppUsage
     public static final int TEMPORARY_NET_ID = -1;
 
     /**
      * The persistent network id.
      * If a matching persistent profile is found, use it.
      * Otherwise, create a new persistent profile.
-     *
-     * @hide
+     * @see #getNetworkId()
      */
     public static final int PERSISTENT_NET_ID = -2;
 
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
index b8d3e41..60125e3 100644
--- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -91,13 +91,13 @@
         SoftApConfiguration original = new SoftApConfiguration.Builder()
                 .setWpa2Passphrase("secretsecret")
                 .setBand(SoftApConfiguration.BAND_ANY)
-                .setChannel(149)
+                .setChannel(149, SoftApConfiguration.BAND_5GHZ)
                 .setHiddenSsid(true)
                 .build();
         assertThat(original.getWpa2Passphrase()).isEqualTo("secretsecret");
         assertThat(original.getSecurityType()).isEqualTo(
                 SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
-        assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_ANY);
+        assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
         assertThat(original.getChannel()).isEqualTo(149);
         assertThat(original.isHiddenSsid()).isEqualTo(true);
 
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 7e38e14..5d6549e 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -32,9 +32,6 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
-
 /**
  * Unit tests for {@link android.net.wifi.WifiConfiguration}.
  */
@@ -196,33 +193,6 @@
     }
 
     /**
-     * Verifies that the serialization/de-serialization for softap config works.
-     */
-    @Test
-    public void testSoftApConfigBackupAndRestore() throws Exception {
-        WifiConfiguration config = new WifiConfiguration();
-        config.SSID = "TestAP";
-        config.apBand = WifiConfiguration.AP_BAND_5GHZ;
-        config.apChannel = 40;
-        config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
-        config.preSharedKey = "TestPsk";
-        config.hiddenSSID = true;
-
-        byte[] data = config.getBytesForBackup();
-        ByteArrayInputStream bais = new ByteArrayInputStream(data);
-        DataInputStream in = new DataInputStream(bais);
-        WifiConfiguration restoredConfig = WifiConfiguration.getWifiConfigFromBackup(in);
-
-        assertEquals(config.SSID, restoredConfig.SSID);
-        assertEquals(config.preSharedKey, restoredConfig.preSharedKey);
-        assertEquals(config.getAuthType(), restoredConfig.getAuthType());
-        assertEquals(config.apBand, restoredConfig.apBand);
-        assertEquals(config.apChannel, restoredConfig.apChannel);
-        assertEquals(config.hiddenSSID, restoredConfig.hiddenSSID);
-    }
-
-
-    /**
      * Verifies that getKeyIdForCredentials returns the expected string for Enterprise networks
      * @throws Exception
      */
@@ -317,6 +287,16 @@
         config.allowedKeyManagement.clear();
         config.allowedKeyManagement.set(KeyMgmt.NONE);
         assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.NONE], config.getSsidAndSecurityTypeString());
+
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.WAPI_PSK);
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WAPI_PSK],
+                config.getSsidAndSecurityTypeString());
+
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.WAPI_CERT);
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WAPI_CERT],
+                config.getSsidAndSecurityTypeString());
     }
 
     /**
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 62ff9f6..4a46744 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -2075,4 +2075,18 @@
         verify(mWifiService).calculateSignalLevel(Integer.MAX_VALUE);
         assertEquals(4, actual);
     }
+
+    /*
+     * Test behavior of isWapiSupported
+     * @throws Exception
+     */
+    @Test
+    public void testIsWapiSupported() throws Exception {
+        when(mWifiService.getSupportedFeatures())
+                .thenReturn(new Long(WifiManager.WIFI_FEATURE_WAPI));
+        assertTrue(mWifiManager.isWapiSupported());
+        when(mWifiService.getSupportedFeatures())
+                .thenReturn(new Long(~WifiManager.WIFI_FEATURE_WAPI));
+        assertFalse(mWifiManager.isWapiSupported());
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 04aaa0b..4cdc4bc 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -39,6 +39,7 @@
     private static final String TEST_SSID_1 = "\"Test1234\"";
     private static final String TEST_PRESHARED_KEY = "Test123";
     private static final String TEST_FQDN = "fqdn";
+    private static final String TEST_WAPI_CERT_SUITE = "suite";
 
     /**
      * Validate correctness of WifiNetworkSuggestion object created by
@@ -194,6 +195,87 @@
 
     /**
      * Validate correctness of WifiNetworkSuggestion object created by
+     * {@link WifiNetworkSuggestion.Builder#build()} for WAPI-PSK network.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderForWapiPskNetwork() {
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWapiPassphrase(TEST_PRESHARED_KEY)
+                .build();
+
+        assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.WAPI_PSK));
+        assertTrue(suggestion.wifiConfiguration.allowedPairwiseCiphers
+                .get(WifiConfiguration.PairwiseCipher.SMS4));
+        assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.SMS4));
+        assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+                suggestion.wifiConfiguration.preSharedKey);
+    }
+
+
+    /**
+     * Validate correctness of WifiNetworkSuggestion object created by
+     * {@link WifiNetworkSuggestion.Builder#build()} for WAPI-CERT network.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderForWapiCertNetwork() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.WAPI_CERT);
+        enterpriseConfig.setWapiCertSuite(TEST_WAPI_CERT_SUITE);
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWapiEnterpriseConfig(enterpriseConfig)
+                .build();
+
+        assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.WAPI_CERT));
+        assertTrue(suggestion.wifiConfiguration.allowedPairwiseCiphers
+                .get(WifiConfiguration.PairwiseCipher.SMS4));
+        assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.SMS4));
+        assertNull(suggestion.wifiConfiguration.preSharedKey);
+        assertNotNull(suggestion.wifiConfiguration.enterpriseConfig);
+        assertEquals(WifiEnterpriseConfig.Eap.WAPI_CERT,
+                suggestion.wifiConfiguration.enterpriseConfig.getEapMethod());
+        assertEquals(TEST_WAPI_CERT_SUITE,
+                suggestion.wifiConfiguration.enterpriseConfig.getWapiCertSuite());
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSuggestion object created by
+     * {@link WifiNetworkSuggestion.Builder#build()} for WAPI-CERT network
+     * which selects the certificate suite automatically.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderForWapiCertAutoNetwork() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.WAPI_CERT);
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWapiEnterpriseConfig(enterpriseConfig)
+                .build();
+
+        assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.WAPI_CERT));
+        assertTrue(suggestion.wifiConfiguration.allowedPairwiseCiphers
+                .get(WifiConfiguration.PairwiseCipher.SMS4));
+        assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.SMS4));
+        assertNull(suggestion.wifiConfiguration.preSharedKey);
+        assertNotNull(suggestion.wifiConfiguration.enterpriseConfig);
+        assertEquals(WifiEnterpriseConfig.Eap.WAPI_CERT,
+                suggestion.wifiConfiguration.enterpriseConfig.getEapMethod());
+        assertEquals("",
+                suggestion.wifiConfiguration.enterpriseConfig.getWapiCertSuite());
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSuggestion object created by
      * {@link WifiNetworkSuggestion.Builder#build()} for Passpoint network which requires
      *  app interaction and metered.
      */