Merge "Move ImsManager registery to TelephonyFrameworkInitializer"
diff --git a/Android.bp b/Android.bp
index 787b48b..eef9f80 100644
--- a/Android.bp
+++ b/Android.bp
@@ -265,6 +265,7 @@
         ":framework-sdkext-sources",
         ":framework-statsd-sources",
         ":updatable-media-srcs",
+        ":framework-mediaprovider-sources",
         ":framework-wifi-updatable-sources",
     ]
 }
@@ -380,6 +381,7 @@
         "ext",
         "unsupportedappusage",
         "updatable_media_stubs",
+        "framework_mediaprovider_stubs",
     ],
 
     jarjar_rules: ":framework-jarjar-rules",
@@ -467,6 +469,8 @@
     installable: false, // this lib is a build-only library
     static_libs: [
         "framework-minus-apex",
+        "updatable_media_stubs",
+        "framework_mediaprovider_stubs",
         "framework-appsearch", // TODO(b/146218515): should be framework-appsearch-stubs
         "framework-sdkext-stubs-systemapi",
         // TODO(b/146167933): Use framework-statsd-stubs instead.
@@ -582,11 +586,14 @@
 filegroup {
     name: "framework-annotations",
     srcs: [
-        "core/java/android/annotation/NonNull.java",
-        "core/java/android/annotation/Nullable.java",
         "core/java/android/annotation/IntDef.java",
         "core/java/android/annotation/IntRange.java",
+        "core/java/android/annotation/NonNull.java",
+        "core/java/android/annotation/Nullable.java",
+        "core/java/android/annotation/RequiresPermission.java",
+        "core/java/android/annotation/SdkConstant.java",
         "core/java/android/annotation/SystemApi.java",
+        "core/java/android/annotation/TestApi.java",
         "core/java/android/annotation/UnsupportedAppUsage.java",
         "core/java/com/android/internal/annotations/GuardedBy.java",
         "core/java/com/android/internal/annotations/VisibleForTesting.java",
@@ -966,6 +973,7 @@
         "core/java/android/os/RemoteException.java",
         "core/java/android/util/AndroidException.java",
     ],
+    libs: [ "unsupportedappusage" ],
 
     dxflags: ["--core-library"],
     installable: false,
@@ -1646,20 +1654,23 @@
 filegroup {
     name: "framework-media-annotation-srcs",
     srcs: [
+        ":framework-annotations",
         "core/java/android/annotation/CallbackExecutor.java",
         "core/java/android/annotation/CallSuper.java",
         "core/java/android/annotation/DrawableRes.java",
-        "core/java/android/annotation/IntDef.java",
         "core/java/android/annotation/LongDef.java",
-        "core/java/android/annotation/NonNull.java",
-        "core/java/android/annotation/Nullable.java",
-        "core/java/android/annotation/RequiresPermission.java",
-        "core/java/android/annotation/SdkConstant.java",
         "core/java/android/annotation/StringDef.java",
-        "core/java/android/annotation/SystemApi.java",
-        "core/java/android/annotation/TestApi.java",
-        "core/java/android/annotation/UnsupportedAppUsage.java",
-        "core/java/com/android/internal/annotations/GuardedBy.java",
+    ],
+}
+
+filegroup {
+    name: "framework-mediaprovider-annotation-sources",
+    srcs: [
+        ":framework-annotations",
+        "core/java/android/annotation/BytesLong.java",
+        "core/java/android/annotation/CurrentTimeMillisLong.java",
+        "core/java/android/annotation/CurrentTimeSecondsLong.java",
+        "core/java/android/annotation/DurationMillisLong.java",
     ],
 }
 
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index 278a786..661f32f 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -146,7 +146,8 @@
 
             final CountDownLatch latch = new CountDownLatch(1);
             registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
-            // Don't use this.startUserInBackground() since only waiting until ACTION_USER_STARTED.
+            // Don't use this.startUserInBackgroundAndWaitForUnlock() since only waiting until
+            // ACTION_USER_STARTED.
             mIam.startUserInBackground(userId);
             latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
 
@@ -156,6 +157,48 @@
         }
     }
 
+    /**
+     * Measures the time until ACTION_USER_STARTED is received.
+     */
+    @Test
+    public void startUser() throws Exception {
+        while (mRunner.keepRunning()) {
+            mRunner.pauseTiming();
+            final int userId = createUserNoFlags();
+            final CountDownLatch latch = new CountDownLatch(1);
+            registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
+            mRunner.resumeTiming();
+
+            mIam.startUserInBackground(userId);
+            latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+
+            mRunner.pauseTiming();
+            removeUser(userId);
+            mRunner.resumeTiming();
+        }
+    }
+
+    /**
+     * Measures the time until unlock listener is triggered and user is unlocked.
+     */
+    @Test
+    public void startAndUnlockUser() throws Exception {
+        while (mRunner.keepRunning()) {
+            mRunner.pauseTiming();
+            final int userId = createUserNoFlags();
+            mRunner.resumeTiming();
+
+            // Waits for UserState.mUnlockProgress.finish().
+            startUserInBackgroundAndWaitForUnlock(userId);
+
+            mRunner.pauseTiming();
+            removeUser(userId);
+            mRunner.resumeTiming();
+        }
+    }
+
+
+
     @Test
     public void switchUser() throws Exception {
         while (mRunner.keepRunning()) {
@@ -309,7 +352,7 @@
             final int userId = createManagedProfile();
             mRunner.resumeTiming();
 
-            startUserInBackground(userId);
+            startUserInBackgroundAndWaitForUnlock(userId);
 
             mRunner.pauseTiming();
             removeUser(userId);
@@ -326,11 +369,11 @@
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
             // Start the profile initially, then stop it. Similar to setQuietModeEnabled.
-            startUserInBackground(userId);
+            startUserInBackgroundAndWaitForUnlock(userId);
             stopUser(userId, true);
             mRunner.resumeTiming();
 
-            startUserInBackground(userId);
+            startUserInBackgroundAndWaitForUnlock(userId);
 
             mRunner.pauseTiming();
             removeUser(userId);
@@ -352,7 +395,7 @@
             installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
             mRunner.resumeTiming();
 
-            startUserInBackground(userId);
+            startUserInBackgroundAndWaitForUnlock(userId);
             startApp(userId, DUMMY_PACKAGE_NAME);
 
             mRunner.pauseTiming();
@@ -376,13 +419,13 @@
             final int userId = createManagedProfile();
             WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
             installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
-            startUserInBackground(userId);
+            startUserInBackgroundAndWaitForUnlock(userId);
             startApp(userId, DUMMY_PACKAGE_NAME);
             stopUser(userId, true);
             TimeUnit.SECONDS.sleep(1); // Brief cool-down before re-starting profile.
             mRunner.resumeTiming();
 
-            startUserInBackground(userId);
+            startUserInBackgroundAndWaitForUnlock(userId);
             startApp(userId, DUMMY_PACKAGE_NAME);
 
             mRunner.pauseTiming();
@@ -423,7 +466,7 @@
             mRunner.resumeTiming();
 
             final int userId = createManagedProfile();
-            startUserInBackground(userId);
+            startUserInBackgroundAndWaitForUnlock(userId);
             installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
             startApp(userId, DUMMY_PACKAGE_NAME);
 
@@ -441,7 +484,7 @@
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
-            startUserInBackground(userId);
+            startUserInBackgroundAndWaitForUnlock(userId);
             mRunner.resumeTiming();
 
             stopUser(userId, true);
@@ -467,7 +510,7 @@
                 final int userId = createManagedProfile();
                 mRunner.resumeTiming();
 
-                startUserInBackground(userId);
+                startUserInBackgroundAndWaitForUnlock(userId);
 
                 mRunner.pauseTiming();
                 removeUser(userId);
@@ -490,7 +533,7 @@
                 final int userId = createManagedProfile();
                 mRunner.resumeTiming();
 
-                startUserInBackground(userId);
+                startUserInBackgroundAndWaitForUnlock(userId);
 
                 mRunner.pauseTiming();
                 removeUser(userId);
@@ -526,18 +569,19 @@
     }
 
     /**
-     * Start user in background and wait for it to unlock (equivalent to ACTION_USER_UNLOCKED).
-     * To start in foreground instead, see {@link #switchUser(int)}.
-     * This should always be used for profiles since profiles cannot be started in foreground.
+     * Start user in background and wait for it to unlock by waiting for
+     * UserState.mUnlockProgress.finish().
+     * <p> To start in foreground instead, see {@link #switchUser(int)}.
+     * <p> This should always be used for profiles since profiles cannot be started in foreground.
      */
-    private void startUserInBackground(int userId) {
+    private void startUserInBackgroundAndWaitForUnlock(int userId) {
         final ProgressWaiter waiter = new ProgressWaiter();
         try {
             mIam.startUserInBackgroundWithListener(userId, waiter);
             boolean success = waiter.waitForFinish(TIMEOUT_IN_SECOND);
             attestTrue("Failed to start user " + userId + " in background.", success);
         } catch (RemoteException e) {
-            Log.e(TAG, "startUserInBackground failed", e);
+            Log.e(TAG, "startUserInBackgroundAndWaitForUnlock failed", e);
         }
     }
 
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 157da63..c5fd3f2 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -112,7 +112,6 @@
 import android.util.Slog;
 import android.util.StatsLog;
 import android.util.proto.ProtoOutputStream;
-import android.util.proto.ProtoStream;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.procstats.IProcessStats;
@@ -172,6 +171,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;
 
@@ -542,9 +542,9 @@
     private void informAllUidsLocked(Context context) throws RemoteException {
         UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
         PackageManager pm = context.getPackageManager();
-        final List<UserInfo> users = um.getUsers(true);
+        final List<UserHandle> users = um.getUserHandles(true);
         if (DEBUG) {
-            Slog.d(TAG, "Iterating over " + users.size() + " profiles.");
+            Slog.d(TAG, "Iterating over " + users.size() + " userHandles.");
         }
 
         ParcelFileDescriptor[] fds;
@@ -571,11 +571,11 @@
                 ProtoOutputStream output = new ProtoOutputStream(fout);
                 int numRecords = 0;
                 // Add in all the apps for every user/profile.
-                for (UserInfo profile : users) {
+                for (UserHandle userHandle : users) {
                     List<PackageInfo> pi =
                             pm.getInstalledPackagesAsUser(PackageManager.MATCH_UNINSTALLED_PACKAGES
                                             | PackageManager.MATCH_ANY_USER,
-                                    profile.id);
+                                    userHandle.getIdentifier());
                     for (int j = 0; j < pi.size(); j++) {
                         if (pi.get(j).applicationInfo != null) {
                             String installer;
@@ -585,23 +585,24 @@
                                 installer = "";
                             }
                             long applicationInfoToken =
-                                    output.start(ProtoStream.FIELD_TYPE_MESSAGE
-                                            | ProtoStream.FIELD_COUNT_REPEATED
+                                    output.start(ProtoOutputStream.FIELD_TYPE_MESSAGE
+                                            | ProtoOutputStream.FIELD_COUNT_REPEATED
                                                     | APPLICATION_INFO_FIELD_ID);
-                            output.write(ProtoStream.FIELD_TYPE_INT32
-                                    | ProtoStream.FIELD_COUNT_SINGLE | UID_FIELD_ID,
+                            output.write(ProtoOutputStream.FIELD_TYPE_INT32
+                                    | ProtoOutputStream.FIELD_COUNT_SINGLE | UID_FIELD_ID,
                                             pi.get(j).applicationInfo.uid);
-                            output.write(ProtoStream.FIELD_TYPE_INT64
-                                    | ProtoStream.FIELD_COUNT_SINGLE
+                            output.write(ProtoOutputStream.FIELD_TYPE_INT64
+                                    | ProtoOutputStream.FIELD_COUNT_SINGLE
                                             | VERSION_FIELD_ID, pi.get(j).getLongVersionCode());
-                            output.write(ProtoStream.FIELD_TYPE_STRING
-                                    | ProtoStream.FIELD_COUNT_SINGLE | VERSION_STRING_FIELD_ID,
+                            output.write(ProtoOutputStream.FIELD_TYPE_STRING
+                                    | ProtoOutputStream.FIELD_COUNT_SINGLE
+                                    | VERSION_STRING_FIELD_ID,
                                             pi.get(j).versionName);
-                            output.write(ProtoStream.FIELD_TYPE_STRING
-                                    | ProtoStream.FIELD_COUNT_SINGLE
+                            output.write(ProtoOutputStream.FIELD_TYPE_STRING
+                                    | ProtoOutputStream.FIELD_COUNT_SINGLE
                                             | PACKAGE_NAME_FIELD_ID, pi.get(j).packageName);
-                            output.write(ProtoStream.FIELD_TYPE_STRING
-                                    | ProtoStream.FIELD_COUNT_SINGLE
+                            output.write(ProtoOutputStream.FIELD_TYPE_STRING
+                                    | ProtoOutputStream.FIELD_COUNT_SINGLE
                                             | INSTALLER_FIELD_ID,
                                                     installer == null ? "" : installer);
                             numRecords++;
@@ -2136,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 {
@@ -2166,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];
@@ -2175,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;
@@ -2186,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);
@@ -2640,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: {
diff --git a/api/current.txt b/api/current.txt
index 36374bb..6014e1f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -99,6 +99,7 @@
     field public static final String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
     field public static final String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
     field public static final String NFC = "android.permission.NFC";
+    field public static final String NFC_PREFERRED_PAYMENT_INFO = "android.permission.NFC_PREFERRED_PAYMENT_INFO";
     field public static final String NFC_TRANSACTION_EVENT = "android.permission.NFC_TRANSACTION_EVENT";
     field public static final String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
     field @Deprecated public static final String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
@@ -4308,7 +4309,7 @@
     method public static String permissionToOp(String);
     method public void setNotedAppOpsCollector(@Nullable android.app.AppOpsManager.AppOpsCollector);
     method @Deprecated public int startOp(@NonNull String, int, @NonNull String);
-    method public int startOp(@NonNull String, int, @Nullable String, @NonNull String, @Nullable String);
+    method public int startOp(@NonNull String, int, @Nullable String, @Nullable String, @Nullable String);
     method @Deprecated public int startOpNoThrow(@NonNull String, int, @NonNull String);
     method public int startOpNoThrow(@NonNull String, int, @NonNull String, @NonNull String, @Nullable String);
     method public void startWatchingActive(@NonNull String[], @NonNull java.util.concurrent.Executor, @NonNull android.app.AppOpsManager.OnOpActiveChangedListener);
@@ -16934,7 +16935,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 +16946,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 +17359,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 +17446,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 +17536,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 {
@@ -23236,10 +23241,10 @@
   }
 
   public interface LocationListener {
-    method public void onLocationChanged(android.location.Location);
-    method public void onProviderDisabled(String);
-    method public void onProviderEnabled(String);
-    method @Deprecated public void onStatusChanged(String, int, android.os.Bundle);
+    method public void onLocationChanged(@NonNull android.location.Location);
+    method public default void onProviderDisabled(@NonNull String);
+    method public default void onProviderEnabled(@NonNull String);
+    method @Deprecated public default void onStatusChanged(String, int, android.os.Bundle);
   }
 
   public class LocationManager {
@@ -27639,6 +27644,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 +30047,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 +30077,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 +30085,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 +30132,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 +30150,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 +30222,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 +30379,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);
@@ -30399,8 +30418,11 @@
     method public int getMaxMatchFilterLength();
     method public int getMaxServiceNameLength();
     method public int getMaxServiceSpecificInfoLength();
+    method public int getSupportedCipherSuites();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.Characteristics> CREATOR;
+    field public static final int WIFI_AWARE_CIPHER_SUITE_NCS_SK_128 = 1; // 0x1
+    field public static final int WIFI_AWARE_CIPHER_SUITE_NCS_SK_256 = 2; // 0x2
   }
 
   public class DiscoverySession implements java.lang.AutoCloseable {
@@ -31112,6 +31134,7 @@
     method @Deprecated public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...);
     field public static final String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
     field public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
+    field @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public static final String ACTION_PREFERRED_PAYMENT_CHANGED = "android.nfc.action.PREFERRED_PAYMENT_CHANGED";
     field public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
     field public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED";
     field @RequiresPermission(android.Manifest.permission.NFC_TRANSACTION_EVENT) public static final String ACTION_TRANSACTION_DETECTED = "android.nfc.action.TRANSACTION_DETECTED";
@@ -31120,6 +31143,7 @@
     field public static final String EXTRA_DATA = "android.nfc.extra.DATA";
     field public static final String EXTRA_ID = "android.nfc.extra.ID";
     field public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
+    field public static final String EXTRA_PREFERRED_PAYMENT_CHANGED_REASON = "android.nfc.extra.PREFERRED_PAYMENT_CHANGED_REASON";
     field public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
     field public static final String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME";
     field public static final String EXTRA_TAG = "android.nfc.extra.TAG";
@@ -31130,6 +31154,9 @@
     field public static final int FLAG_READER_NFC_V = 8; // 0x8
     field public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 256; // 0x100
     field public static final int FLAG_READER_SKIP_NDEF_CHECK = 128; // 0x80
+    field public static final int PREFERRED_PAYMENT_CHANGED = 2; // 0x2
+    field public static final int PREFERRED_PAYMENT_LOADED = 1; // 0x1
+    field public static final int PREFERRED_PAYMENT_UPDATED = 3; // 0x3
     field public static final int STATE_OFF = 1; // 0x1
     field public static final int STATE_ON = 3; // 0x3
     field public static final int STATE_TURNING_OFF = 4; // 0x4
@@ -31185,8 +31212,11 @@
 
   public final class CardEmulation {
     method public boolean categoryAllowsForegroundPreference(String);
+    method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public java.util.List<java.lang.String> getAidsForPreferredPaymentService();
     method public java.util.List<java.lang.String> getAidsForService(android.content.ComponentName, String);
+    method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public String getDescriptionForPreferredPaymentService();
     method public static android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter);
+    method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public String getRouteDestinationForPreferredPaymentService();
     method public int getSelectionModeForCategory(String);
     method public boolean isDefaultServiceForAid(android.content.ComponentName, String);
     method public boolean isDefaultServiceForCategory(android.content.ComponentName, String);
@@ -35424,11 +35454,12 @@
     method public boolean isIgnoringBatteryOptimizations(String);
     method public boolean isInteractive();
     method public boolean isPowerSaveMode();
+    method public boolean isRebootingUserspaceSupported();
     method @Deprecated public boolean isScreenOn();
     method public boolean isSustainedPerformanceModeSupported();
     method public boolean isWakeLockLevelSupported(int);
     method public android.os.PowerManager.WakeLock newWakeLock(int, String);
-    method public void reboot(String);
+    method public void reboot(@Nullable String);
     method public void removeThermalStatusListener(@NonNull android.os.PowerManager.OnThermalStatusChangedListener);
     field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
     field public static final String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
@@ -35759,7 +35790,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";
@@ -35798,7 +35829,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";
@@ -39042,6 +39073,8 @@
     field public static final String GENRE = "genre";
     field public static final String HEIGHT = "height";
     field public static final String INSTANCE_ID = "instance_id";
+    field public static final String IS_DOWNLOAD = "is_download";
+    field public static final String IS_DRM = "is_drm";
     field public static final String IS_FAVORITE = "is_favorite";
     field public static final String IS_PENDING = "is_pending";
     field public static final String IS_TRASHED = "is_trashed";
@@ -44821,6 +44854,11 @@
     field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
 
+  public static final class CarrierConfigManager.Gps {
+    field public static final String KEY_PERSIST_LPP_MODE_BOOL = "gps.persist_lpp_mode_bool";
+    field public static final String KEY_PREFIX = "gps.";
+  }
+
   public static final class CarrierConfigManager.Ims {
     field public static final String KEY_PREFIX = "ims.";
   }
@@ -49457,6 +49495,71 @@
 
 }
 
+package android.util.proto {
+
+  public final class ProtoOutputStream {
+    ctor public ProtoOutputStream();
+    ctor public ProtoOutputStream(int);
+    ctor public ProtoOutputStream(@NonNull java.io.OutputStream);
+    method public static int checkFieldId(long, long);
+    method public void dump(@NonNull String);
+    method public void end(long);
+    method public void flush();
+    method @NonNull public byte[] getBytes();
+    method @Nullable public static String getFieldCountString(long);
+    method @NonNull public static String getFieldIdString(long);
+    method @Nullable public static String getFieldTypeString(long);
+    method public int getRawSize();
+    method @Nullable public static String getWireTypeString(int);
+    method public static long makeFieldId(int, long);
+    method public static long makeToken(int, boolean, int, int, int);
+    method public long start(long);
+    method @NonNull public static String token2String(long);
+    method public void write(long, double);
+    method public void write(long, float);
+    method public void write(long, int);
+    method public void write(long, long);
+    method public void write(long, boolean);
+    method public void write(long, @Nullable String);
+    method public void write(long, @Nullable byte[]);
+    method public void writeTag(int, int);
+    field public static final long FIELD_COUNT_MASK = 16492674416640L; // 0xf0000000000L
+    field public static final long FIELD_COUNT_PACKED = 5497558138880L; // 0x50000000000L
+    field public static final long FIELD_COUNT_REPEATED = 2199023255552L; // 0x20000000000L
+    field public static final int FIELD_COUNT_SHIFT = 40; // 0x28
+    field public static final long FIELD_COUNT_SINGLE = 1099511627776L; // 0x10000000000L
+    field public static final long FIELD_COUNT_UNKNOWN = 0L; // 0x0L
+    field public static final int FIELD_ID_SHIFT = 3; // 0x3
+    field public static final long FIELD_TYPE_BOOL = 34359738368L; // 0x800000000L
+    field public static final long FIELD_TYPE_BYTES = 51539607552L; // 0xc00000000L
+    field public static final long FIELD_TYPE_DOUBLE = 4294967296L; // 0x100000000L
+    field public static final long FIELD_TYPE_ENUM = 60129542144L; // 0xe00000000L
+    field public static final long FIELD_TYPE_FIXED32 = 30064771072L; // 0x700000000L
+    field public static final long FIELD_TYPE_FIXED64 = 25769803776L; // 0x600000000L
+    field public static final long FIELD_TYPE_FLOAT = 8589934592L; // 0x200000000L
+    field public static final long FIELD_TYPE_INT32 = 21474836480L; // 0x500000000L
+    field public static final long FIELD_TYPE_INT64 = 12884901888L; // 0x300000000L
+    field public static final long FIELD_TYPE_MASK = 1095216660480L; // 0xff00000000L
+    field public static final long FIELD_TYPE_MESSAGE = 47244640256L; // 0xb00000000L
+    field public static final long FIELD_TYPE_SFIXED32 = 64424509440L; // 0xf00000000L
+    field public static final long FIELD_TYPE_SFIXED64 = 68719476736L; // 0x1000000000L
+    field public static final int FIELD_TYPE_SHIFT = 32; // 0x20
+    field public static final long FIELD_TYPE_SINT32 = 73014444032L; // 0x1100000000L
+    field public static final long FIELD_TYPE_SINT64 = 77309411328L; // 0x1200000000L
+    field public static final long FIELD_TYPE_STRING = 38654705664L; // 0x900000000L
+    field public static final long FIELD_TYPE_UINT32 = 55834574848L; // 0xd00000000L
+    field public static final long FIELD_TYPE_UINT64 = 17179869184L; // 0x400000000L
+    field public static final int WIRE_TYPE_END_GROUP = 4; // 0x4
+    field public static final int WIRE_TYPE_FIXED32 = 5; // 0x5
+    field public static final int WIRE_TYPE_FIXED64 = 1; // 0x1
+    field public static final int WIRE_TYPE_LENGTH_DELIMITED = 2; // 0x2
+    field public static final int WIRE_TYPE_MASK = 7; // 0x7
+    field public static final int WIRE_TYPE_START_GROUP = 3; // 0x3
+    field public static final int WIRE_TYPE_VARINT = 0; // 0x0
+  }
+
+}
+
 package android.view {
 
   public abstract class AbsSavedState implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index b2bf2c6..1a74f4b 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -15,6 +15,7 @@
     field public static final String ACCESS_SHARED_LIBRARIES = "android.permission.ACCESS_SHARED_LIBRARIES";
     field public static final String ACCESS_SHORTCUTS = "android.permission.ACCESS_SHORTCUTS";
     field public static final String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
+    field public static final String ACCESS_TV_TUNER = "android.permission.ACCESS_TV_TUNER";
     field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
     field public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = "android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY";
     field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
@@ -365,6 +366,7 @@
     field public static final String OPSTR_GPS = "android:gps";
     field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
     field public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
+    field public static final String OPSTR_MANAGE_EXTERNAL_STORAGE = "android:manage_external_storage";
     field public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
     field public static final String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
     field public static final String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
@@ -473,15 +475,20 @@
 
   public static final class AppOpsManager.OpEntry implements android.os.Parcelable {
     method public int describeContents();
-    method public long getDuration();
+    method @Deprecated public long getDuration();
     method @NonNull public java.util.Map<java.lang.String,android.app.AppOpsManager.OpFeatureEntry> getFeatures();
     method public long getLastAccessBackgroundTime(int);
     method public long getLastAccessForegroundTime(int);
     method public long getLastAccessTime(int);
     method public long getLastAccessTime(int, int, int);
     method public long getLastBackgroundDuration(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastBackgroundProxyInfo(int);
+    method public long getLastDuration(int);
     method public long getLastDuration(int, int, int);
     method public long getLastForegroundDuration(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastForegroundProxyInfo(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int, int, int);
     method public long getLastRejectBackgroundTime(int);
     method public long getLastRejectForegroundTime(int);
     method public long getLastRejectTime(int);
@@ -489,34 +496,44 @@
     method public int getMode();
     method @NonNull public String getOpStr();
     method @Deprecated @Nullable public String getProxyPackageName();
-    method @Nullable public String getProxyPackageName(int, int);
+    method @Deprecated @Nullable public String getProxyPackageName(int, int);
     method @Deprecated public int getProxyUid();
-    method public int getProxyUid(int, int);
+    method @Deprecated public int getProxyUid(int, int);
     method public boolean isRunning();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpEntry> CREATOR;
   }
 
-  public static final class AppOpsManager.OpFeatureEntry {
-    method public long getDuration();
+  public static final class AppOpsManager.OpEventProxyInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public String getFeatureId();
+    method @Nullable public String getPackageName();
+    method @IntRange(from=0) public int getUid();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpEventProxyInfo> CREATOR;
+  }
+
+  public static final class AppOpsManager.OpFeatureEntry implements android.os.Parcelable {
+    method public int describeContents();
     method public long getLastAccessBackgroundTime(int);
     method public long getLastAccessForegroundTime(int);
     method public long getLastAccessTime(int);
     method public long getLastAccessTime(int, int, int);
     method public long getLastBackgroundDuration(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastBackgroundProxyInfo(int);
+    method public long getLastDuration(int);
     method public long getLastDuration(int, int, int);
     method public long getLastForegroundDuration(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastForegroundProxyInfo(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int, int, int);
     method public long getLastRejectBackgroundTime(int);
     method public long getLastRejectForegroundTime(int);
     method public long getLastRejectTime(int);
     method public long getLastRejectTime(int, int, int);
-    method @Nullable public String getProxyFeatureId();
-    method @Nullable public String getProxyFeatureId(int, int);
-    method @Nullable public String getProxyPackageName();
-    method @Nullable public String getProxyPackageName(int, int);
-    method public int getProxyUid();
-    method public int getProxyUid(int, int);
     method public boolean isRunning();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpFeatureEntry> CREATOR;
   }
 
   public static final class AppOpsManager.PackageOps implements android.os.Parcelable {
@@ -524,7 +541,7 @@
     method @NonNull public java.util.List<android.app.AppOpsManager.OpEntry> getOps();
     method @NonNull public String getPackageName();
     method public int getUid();
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.PackageOps> CREATOR;
   }
 
@@ -1915,6 +1932,13 @@
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_PROFILES) public void startActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
   }
 
+  public class DataLoaderParams {
+    ctor public DataLoaderParams(@NonNull String, @NonNull String, @Nullable java.util.Map<java.lang.String,android.os.ParcelFileDescriptor>);
+    method @NonNull public final java.util.Map<java.lang.String,android.os.ParcelFileDescriptor> getDynamicArgs();
+    method @NonNull public final String getPackageName();
+    method @NonNull public final String getStaticArgs();
+  }
+
   public final class InstantAppInfo implements android.os.Parcelable {
     ctor public InstantAppInfo(android.content.pm.ApplicationInfo, String[], String[]);
     ctor public InstantAppInfo(String, CharSequence, String[], String[]);
@@ -2004,6 +2028,7 @@
   }
 
   public static class PackageInstaller.Session implements java.io.Closeable {
+    method public void addFile(@NonNull String, long, @NonNull byte[]);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void commitTransferred(@NonNull android.content.IntentSender);
   }
 
@@ -2026,6 +2051,7 @@
     method public void setDontKillApp(boolean);
     method public void setEnableRollback(boolean);
     method @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) public void setGrantedRuntimePermissions(String[]);
+    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setIncrementalParams(@NonNull android.content.pm.DataLoaderParams);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
     method public void setInstallAsInstantApp(boolean);
     method public void setInstallAsVirtualPreload();
@@ -2088,6 +2114,7 @@
     field public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 16384; // 0x4000
     field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20
     field public static final int FLAG_PERMISSION_GRANTED_BY_ROLE = 32768; // 0x8000
+    field public static final int FLAG_PERMISSION_ONE_TIME = 65536; // 0x10000
     field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4
     field public static final int FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT = 2048; // 0x800
     field public static final int FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT = 4096; // 0x1000
@@ -2162,7 +2189,7 @@
     method public void onPermissionsChanged(int);
   }
 
-  @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
+  @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
   }
 
   public class PermissionGroupInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
@@ -2175,6 +2202,7 @@
   public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
     field public static final int FLAG_REMOVED = 2; // 0x2
     field public static final int PROTECTION_FLAG_APP_PREDICTOR = 2097152; // 0x200000
+    field public static final int PROTECTION_FLAG_COMPANION = 8388608; // 0x800000
     field public static final int PROTECTION_FLAG_CONFIGURATOR = 524288; // 0x80000
     field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
     field public static final int PROTECTION_FLAG_INCIDENT_REPORT_APPROVER = 1048576; // 0x100000
@@ -4015,6 +4043,7 @@
     field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
     field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
     field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
+    field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int STREAM_ASSISTANT = 11; // 0xb
     field public static final int SUCCESS = 0; // 0x0
   }
 
@@ -4477,6 +4506,20 @@
 
 }
 
+package android.media.tv.tuner {
+
+  public abstract class FrontendSettings {
+    method public final int getFrequency();
+    method public abstract int getType();
+  }
+
+  public final class Tuner implements java.lang.AutoCloseable {
+    ctor public Tuner(@NonNull android.content.Context);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int tune(@NonNull android.media.tv.tuner.FrontendSettings);
+  }
+
+}
+
 package android.metrics {
 
   public class LogMaker {
@@ -4652,12 +4695,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 +5593,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 +5608,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 +5623,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 +5696,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 +5734,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
@@ -6605,6 +6666,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.USER_ACTIVITY}) public void userActivity(long, int, int);
     field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1
     field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0
+    field public static final String REBOOT_USERSPACE = "userspace";
     field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
     field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
     field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0
@@ -6798,6 +6860,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isSameProfileGroup(@NonNull android.os.UserHandle, @NonNull android.os.UserHandle);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public boolean isUserNameSet();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public boolean isUserUnlockingOrUnlocked(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean removeUser(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap);
@@ -6997,6 +7060,7 @@
     method @BinderThread public abstract void onGetPermissionUsages(boolean, long, @NonNull java.util.function.Consumer<java.util.List<android.permission.RuntimePermissionUsageInfo>>);
     method @BinderThread public abstract void onGetRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.OutputStream, @NonNull Runnable);
     method @BinderThread public abstract void onGrantOrUpgradeDefaultRuntimePermissions(@NonNull Runnable);
+    method @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String);
     method @Deprecated @BinderThread public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @Deprecated @BinderThread public void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
     method @BinderThread public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String, @NonNull Runnable);
@@ -7013,6 +7077,8 @@
     method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToLuiApp(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromLuiApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
+    method @RequiresPermission(allOf={android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void startOneTimePermissionSession(@NonNull String, long, int, int);
+    method @RequiresPermission(allOf={android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void stopOneTimePermissionSession(@NonNull String);
   }
 
   public static final class PermissionManager.SplitPermissionInfo {
@@ -7254,8 +7320,12 @@
   }
 
   public final class MediaStore {
+    method @NonNull public static android.net.Uri rewriteToLegacy(@NonNull android.net.Uri);
     method @NonNull public static android.net.Uri scanFile(@NonNull android.content.ContentResolver, @NonNull java.io.File);
     method public static void scanVolume(@NonNull android.content.ContentResolver, @NonNull String);
+    method public static void waitForIdle(@NonNull android.content.ContentResolver);
+    field public static final String AUTHORITY_LEGACY = "media_legacy";
+    field @NonNull public static final android.net.Uri AUTHORITY_LEGACY_URI;
   }
 
   public abstract class SearchIndexableData {
@@ -7886,6 +7956,14 @@
 
 }
 
+package android.service.dataloader {
+
+  public abstract class DataLoaderService extends android.app.Service {
+    ctor public DataLoaderService();
+  }
+
+}
+
 package android.service.euicc {
 
   public final class DownloadSubscriptionResult implements android.os.Parcelable {
@@ -9647,6 +9725,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultVoiceSubscriptionId(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPreferredDataSubscriptionId(int, boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSubscriptionEnabled(int, boolean);
+    field @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS) public static final String ACTION_SUBSCRIPTION_PLANS_CHANGED = "android.telephony.action.SUBSCRIPTION_PLANS_CHANGED";
     field @NonNull public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI;
     field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff
     field public static final int PROFILE_CLASS_OPERATIONAL = 2; // 0x2
@@ -9748,6 +9827,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);
@@ -9801,7 +9881,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..b020ee6 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";
@@ -157,6 +158,7 @@
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void getHistoricalOpsFromDiskRaw(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
     method public static int getNumOps();
     method public static String[] getOpStrs();
+    method @NonNull @RequiresPermission("android.permission.GET_APP_OPS_STATS") public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable java.lang.String...);
     method public boolean isOperationActive(int, int, String);
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void offsetHistory(long);
     method public static int opToDefaultMode(@NonNull String);
@@ -307,15 +309,20 @@
 
   public static final class AppOpsManager.OpEntry implements android.os.Parcelable {
     method public int describeContents();
-    method public long getDuration();
+    method @Deprecated public long getDuration();
     method @NonNull public java.util.Map<java.lang.String,android.app.AppOpsManager.OpFeatureEntry> getFeatures();
     method public long getLastAccessBackgroundTime(int);
     method public long getLastAccessForegroundTime(int);
     method public long getLastAccessTime(int);
     method public long getLastAccessTime(int, int, int);
     method public long getLastBackgroundDuration(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastBackgroundProxyInfo(int);
+    method public long getLastDuration(int);
     method public long getLastDuration(int, int, int);
     method public long getLastForegroundDuration(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastForegroundProxyInfo(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int, int, int);
     method public long getLastRejectBackgroundTime(int);
     method public long getLastRejectForegroundTime(int);
     method public long getLastRejectTime(int);
@@ -323,34 +330,53 @@
     method public int getMode();
     method @NonNull public String getOpStr();
     method @Deprecated @Nullable public String getProxyPackageName();
-    method @Nullable public String getProxyPackageName(int, int);
+    method @Deprecated @Nullable public String getProxyPackageName(int, int);
     method @Deprecated public int getProxyUid();
-    method public int getProxyUid(int, int);
+    method @Deprecated public int getProxyUid(int, int);
     method public boolean isRunning();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpEntry> CREATOR;
   }
 
-  public static final class AppOpsManager.OpFeatureEntry {
-    method public long getDuration();
+  public static final class AppOpsManager.OpEventProxyInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public String getFeatureId();
+    method @Nullable public String getPackageName();
+    method @IntRange(from=0) public int getUid();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpEventProxyInfo> CREATOR;
+  }
+
+  public static final class AppOpsManager.OpFeatureEntry implements android.os.Parcelable {
+    method public int describeContents();
     method public long getLastAccessBackgroundTime(int);
     method public long getLastAccessForegroundTime(int);
     method public long getLastAccessTime(int);
     method public long getLastAccessTime(int, int, int);
     method public long getLastBackgroundDuration(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastBackgroundProxyInfo(int);
+    method public long getLastDuration(int);
     method public long getLastDuration(int, int, int);
     method public long getLastForegroundDuration(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastForegroundProxyInfo(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int, int, int);
     method public long getLastRejectBackgroundTime(int);
     method public long getLastRejectForegroundTime(int);
     method public long getLastRejectTime(int);
     method public long getLastRejectTime(int, int, int);
-    method @Nullable public String getProxyFeatureId();
-    method @Nullable public String getProxyFeatureId(int, int);
-    method @Nullable public String getProxyPackageName();
-    method @Nullable public String getProxyPackageName(int, int);
-    method public int getProxyUid();
-    method public int getProxyUid(int, int);
     method public boolean isRunning();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpFeatureEntry> CREATOR;
+  }
+
+  public static final class AppOpsManager.PackageOps implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.List<android.app.AppOpsManager.OpEntry> getOps();
+    method @NonNull public String getPackageName();
+    method public int getUid();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.PackageOps> CREATOR;
   }
 
   public class DownloadManager {
@@ -629,6 +655,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 {
@@ -809,6 +838,7 @@
   public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
     field public static final int FLAG_REMOVED = 2; // 0x2
     field public static final int PROTECTION_FLAG_APP_PREDICTOR = 2097152; // 0x200000
+    field public static final int PROTECTION_FLAG_COMPANION = 8388608; // 0x800000
     field public static final int PROTECTION_FLAG_CONFIGURATOR = 524288; // 0x80000
     field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
     field public static final int PROTECTION_FLAG_INCIDENT_REPORT_APPROVER = 1048576; // 0x100000
@@ -2314,6 +2344,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();
   }
@@ -4232,138 +4273,10 @@
     method public void writeRawZigZag64(long);
   }
 
-  public final class ProtoOutputStream extends android.util.proto.ProtoStream {
-    ctor public ProtoOutputStream();
-    ctor public ProtoOutputStream(int);
-    ctor public ProtoOutputStream(java.io.OutputStream);
-    ctor public ProtoOutputStream(java.io.FileDescriptor);
-    method public static int checkFieldId(long, long);
-    method public void dump(String);
-    method public void end(long);
-    method @Deprecated public void endObject(long);
-    method @Deprecated public void endRepeatedObject(long);
-    method public void flush();
-    method public byte[] getBytes();
-    method public int getRawSize();
-    method public static long makeFieldId(int, long);
-    method public long start(long);
-    method @Deprecated public long startObject(long);
-    method @Deprecated public long startRepeatedObject(long);
-    method public void write(long, double);
-    method public void write(long, float);
-    method public void write(long, int);
-    method public void write(long, long);
-    method public void write(long, boolean);
-    method public void write(long, String);
-    method public void write(long, byte[]);
-    method @Deprecated public void writeBool(long, boolean);
-    method @Deprecated public void writeBytes(long, byte[]);
-    method @Deprecated public void writeDouble(long, double);
-    method @Deprecated public void writeEnum(long, int);
-    method @Deprecated public void writeFixed32(long, int);
-    method @Deprecated public void writeFixed64(long, long);
-    method @Deprecated public void writeFloat(long, float);
-    method @Deprecated public void writeInt32(long, int);
-    method @Deprecated public void writeInt64(long, long);
-    method @Deprecated public void writeObject(long, byte[]);
-    method @Deprecated public void writePackedBool(long, boolean[]);
-    method @Deprecated public void writePackedDouble(long, double[]);
-    method @Deprecated public void writePackedEnum(long, int[]);
-    method @Deprecated public void writePackedFixed32(long, int[]);
-    method @Deprecated public void writePackedFixed64(long, long[]);
-    method @Deprecated public void writePackedFloat(long, float[]);
-    method @Deprecated public void writePackedInt32(long, int[]);
-    method @Deprecated public void writePackedInt64(long, long[]);
-    method @Deprecated public void writePackedSFixed32(long, int[]);
-    method @Deprecated public void writePackedSFixed64(long, long[]);
-    method @Deprecated public void writePackedSInt32(long, int[]);
-    method @Deprecated public void writePackedSInt64(long, long[]);
-    method @Deprecated public void writePackedUInt32(long, int[]);
-    method @Deprecated public void writePackedUInt64(long, long[]);
-    method @Deprecated public void writeRepeatedBool(long, boolean);
-    method @Deprecated public void writeRepeatedBytes(long, byte[]);
-    method @Deprecated public void writeRepeatedDouble(long, double);
-    method @Deprecated public void writeRepeatedEnum(long, int);
-    method @Deprecated public void writeRepeatedFixed32(long, int);
-    method @Deprecated public void writeRepeatedFixed64(long, long);
-    method @Deprecated public void writeRepeatedFloat(long, float);
-    method @Deprecated public void writeRepeatedInt32(long, int);
-    method @Deprecated public void writeRepeatedInt64(long, long);
-    method @Deprecated public void writeRepeatedObject(long, byte[]);
-    method @Deprecated public void writeRepeatedSFixed32(long, int);
-    method @Deprecated public void writeRepeatedSFixed64(long, long);
-    method @Deprecated public void writeRepeatedSInt32(long, int);
-    method @Deprecated public void writeRepeatedSInt64(long, long);
-    method @Deprecated public void writeRepeatedString(long, String);
-    method @Deprecated public void writeRepeatedUInt32(long, int);
-    method @Deprecated public void writeRepeatedUInt64(long, long);
-    method @Deprecated public void writeSFixed32(long, int);
-    method @Deprecated public void writeSFixed64(long, long);
-    method @Deprecated public void writeSInt32(long, int);
-    method @Deprecated public void writeSInt64(long, long);
-    method @Deprecated public void writeString(long, String);
-    method public void writeTag(int, int);
-    method @Deprecated public void writeUInt32(long, int);
-    method @Deprecated public void writeUInt64(long, long);
-  }
-
   public class ProtoParseException extends java.lang.RuntimeException {
     ctor public ProtoParseException(String);
   }
 
-  public abstract class ProtoStream {
-    ctor public ProtoStream();
-    method public static int convertObjectIdToOrdinal(int);
-    method public static int getDepthFromToken(long);
-    method public static String getFieldCountString(long);
-    method public static String getFieldIdString(long);
-    method public static String getFieldTypeString(long);
-    method public static int getObjectIdFromToken(long);
-    method public static int getOffsetFromToken(long);
-    method public static boolean getRepeatedFromToken(long);
-    method public static int getTagSizeFromToken(long);
-    method public static String getWireTypeString(int);
-    method public static long makeFieldId(int, long);
-    method public static long makeToken(int, boolean, int, int, int);
-    method public static String token2String(long);
-    field public static final long FIELD_COUNT_MASK = 16492674416640L; // 0xf0000000000L
-    field public static final long FIELD_COUNT_PACKED = 5497558138880L; // 0x50000000000L
-    field public static final long FIELD_COUNT_REPEATED = 2199023255552L; // 0x20000000000L
-    field public static final int FIELD_COUNT_SHIFT = 40; // 0x28
-    field public static final long FIELD_COUNT_SINGLE = 1099511627776L; // 0x10000000000L
-    field public static final long FIELD_COUNT_UNKNOWN = 0L; // 0x0L
-    field public static final int FIELD_ID_MASK = -8; // 0xfffffff8
-    field public static final int FIELD_ID_SHIFT = 3; // 0x3
-    field public static final long FIELD_TYPE_BOOL = 34359738368L; // 0x800000000L
-    field public static final long FIELD_TYPE_BYTES = 51539607552L; // 0xc00000000L
-    field public static final long FIELD_TYPE_DOUBLE = 4294967296L; // 0x100000000L
-    field public static final long FIELD_TYPE_ENUM = 60129542144L; // 0xe00000000L
-    field public static final long FIELD_TYPE_FIXED32 = 30064771072L; // 0x700000000L
-    field public static final long FIELD_TYPE_FIXED64 = 25769803776L; // 0x600000000L
-    field public static final long FIELD_TYPE_FLOAT = 8589934592L; // 0x200000000L
-    field public static final long FIELD_TYPE_INT32 = 21474836480L; // 0x500000000L
-    field public static final long FIELD_TYPE_INT64 = 12884901888L; // 0x300000000L
-    field public static final long FIELD_TYPE_MASK = 1095216660480L; // 0xff00000000L
-    field public static final long FIELD_TYPE_MESSAGE = 47244640256L; // 0xb00000000L
-    field protected static final String[] FIELD_TYPE_NAMES;
-    field public static final long FIELD_TYPE_SFIXED32 = 64424509440L; // 0xf00000000L
-    field public static final long FIELD_TYPE_SFIXED64 = 68719476736L; // 0x1000000000L
-    field public static final int FIELD_TYPE_SHIFT = 32; // 0x20
-    field public static final long FIELD_TYPE_SINT32 = 73014444032L; // 0x1100000000L
-    field public static final long FIELD_TYPE_SINT64 = 77309411328L; // 0x1200000000L
-    field public static final long FIELD_TYPE_STRING = 38654705664L; // 0x900000000L
-    field public static final long FIELD_TYPE_UINT32 = 55834574848L; // 0xd00000000L
-    field public static final long FIELD_TYPE_UINT64 = 17179869184L; // 0x400000000L
-    field public static final long FIELD_TYPE_UNKNOWN = 0L; // 0x0L
-    field public static final int WIRE_TYPE_END_GROUP = 4; // 0x4
-    field public static final int WIRE_TYPE_FIXED32 = 5; // 0x5
-    field public static final int WIRE_TYPE_FIXED64 = 1; // 0x1
-    field public static final int WIRE_TYPE_LENGTH_DELIMITED = 2; // 0x2
-    field public static final int WIRE_TYPE_MASK = 7; // 0x7
-    field public static final int WIRE_TYPE_START_GROUP = 3; // 0x3
-    field public static final int WIRE_TYPE_VARINT = 0; // 0x0
-  }
-
   public class WireTypeMismatchException extends android.util.proto.ProtoParseException {
     ctor public WireTypeMismatchException(String);
   }
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/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
index a545fc5..4385964 100644
--- a/cmds/statsd/src/FieldValue.cpp
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -435,6 +435,25 @@
     return eq;
 }
 
+bool subsetDimensions(const std::vector<Matcher>& dimension_a,
+                      const std::vector<Matcher>& dimension_b) {
+    if (dimension_a.size() > dimension_b.size()) {
+        return false;
+    }
+    for (size_t i = 0; i < dimension_a.size(); ++i) {
+        bool found = false;
+        for (size_t j = 0; j < dimension_b.size(); ++j) {
+            if (dimension_a[i] == dimension_b[j]) {
+                found = true;
+            }
+        }
+        if (!found) {
+            return false;
+        }
+    }
+    return true;
+}
+
 bool HasPositionANY(const FieldMatcher& matcher) {
     if (matcher.has_position() && matcher.position() == Position::ANY) {
         return true;
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index 0e033e0..6fc1e23 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -396,6 +396,10 @@
 
 bool equalDimensions(const std::vector<Matcher>& dimension_a,
                      const std::vector<Matcher>& dimension_b);
+
+// Returns true if dimension_a is a subset of dimension_b.
+bool subsetDimensions(const std::vector<Matcher>& dimension_a,
+                      const std::vector<Matcher>& dimension_b);
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
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/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp
index f1cad92..f4a59ed 100644
--- a/cmds/statsd/tests/FieldValue_test.cpp
+++ b/cmds/statsd/tests/FieldValue_test.cpp
@@ -480,6 +480,137 @@
     EXPECT_EQ(999, atom.num_results());
 }
 
+/*
+ * Test two Matchers is not a subset of one Matcher.
+ * Test one Matcher is subset of two Matchers.
+ */
+TEST(AtomMatcherTest, TestSubsetDimensions1) {
+    // Initialize first set of matchers
+    FieldMatcher matcher1;
+    matcher1.set_field(10);
+
+    FieldMatcher* child = matcher1.add_child();
+    child->set_field(1);
+    child->set_position(Position::ALL);
+    child->add_child()->set_field(1);
+    child->add_child()->set_field(2);
+
+    vector<Matcher> matchers1;
+    translateFieldMatcher(matcher1, &matchers1);
+    EXPECT_EQ(2, matchers1.size());
+
+    // Initialize second set of matchers
+    FieldMatcher matcher2;
+    matcher2.set_field(10);
+
+    child = matcher2.add_child();
+    child->set_field(1);
+    child->set_position(Position::ALL);
+    child->add_child()->set_field(1);
+
+    vector<Matcher> matchers2;
+    translateFieldMatcher(matcher2, &matchers2);
+    EXPECT_EQ(1, matchers2.size());
+
+    EXPECT_FALSE(subsetDimensions(matchers1, matchers2));
+    EXPECT_TRUE(subsetDimensions(matchers2, matchers1));
+}
+/*
+ * Test not a subset with one matching Matcher, one non-matching Matcher.
+ */
+TEST(AtomMatcherTest, TestSubsetDimensions2) {
+    // Initialize first set of matchers
+    FieldMatcher matcher1;
+    matcher1.set_field(10);
+
+    FieldMatcher* child = matcher1.add_child();
+    child->set_field(1);
+
+    child = matcher1.add_child();
+    child->set_field(2);
+
+    vector<Matcher> matchers1;
+    translateFieldMatcher(matcher1, &matchers1);
+
+    // Initialize second set of matchers
+    FieldMatcher matcher2;
+    matcher2.set_field(10);
+
+    child = matcher2.add_child();
+    child->set_field(1);
+
+    child = matcher2.add_child();
+    child->set_field(3);
+
+    vector<Matcher> matchers2;
+    translateFieldMatcher(matcher2, &matchers2);
+
+    EXPECT_FALSE(subsetDimensions(matchers1, matchers2));
+}
+
+/*
+ * Test not a subset if parent field is not equal.
+ */
+TEST(AtomMatcherTest, TestSubsetDimensions3) {
+    // Initialize first set of matchers
+    FieldMatcher matcher1;
+    matcher1.set_field(10);
+
+    FieldMatcher* child = matcher1.add_child();
+    child->set_field(1);
+
+    vector<Matcher> matchers1;
+    translateFieldMatcher(matcher1, &matchers1);
+
+    // Initialize second set of matchers
+    FieldMatcher matcher2;
+    matcher2.set_field(5);
+
+    child = matcher2.add_child();
+    child->set_field(1);
+
+    vector<Matcher> matchers2;
+    translateFieldMatcher(matcher2, &matchers2);
+
+    EXPECT_FALSE(subsetDimensions(matchers1, matchers2));
+}
+
+/*
+ * Test is subset with two matching Matchers.
+ */
+TEST(AtomMatcherTest, TestSubsetDimensions4) {
+    // Initialize first set of matchers
+    FieldMatcher matcher1;
+    matcher1.set_field(10);
+
+    FieldMatcher* child = matcher1.add_child();
+    child->set_field(1);
+
+    child = matcher1.add_child();
+    child->set_field(2);
+
+    vector<Matcher> matchers1;
+    translateFieldMatcher(matcher1, &matchers1);
+
+    // Initialize second set of matchers
+    FieldMatcher matcher2;
+    matcher2.set_field(10);
+
+    child = matcher2.add_child();
+    child->set_field(1);
+
+    child = matcher2.add_child();
+    child->set_field(2);
+
+    child = matcher2.add_child();
+    child->set_field(3);
+
+    vector<Matcher> matchers2;
+    translateFieldMatcher(matcher2, &matchers2);
+
+    EXPECT_TRUE(subsetDimensions(matchers1, matchers2));
+    EXPECT_FALSE(subsetDimensions(matchers2, matchers1));
+}
 
 }  // namespace statsd
 }  // namespace os
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/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 3e6388b..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;
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.aidl b/core/java/android/app/AppOpsManager.aidl
index 2240302..b4dee2e 100644
--- a/core/java/android/app/AppOpsManager.aidl
+++ b/core/java/android/app/AppOpsManager.aidl
@@ -17,6 +17,9 @@
 package android.app;
 
 parcelable AppOpsManager.PackageOps;
+parcelable AppOpsManager.NoteOpEventProxyInfo;
+parcelable AppOpsManager.NoteOpEvent;
+parcelable AppOpsManager.OpFeatureEntry;
 parcelable AppOpsManager.OpEntry;
 
 parcelable AppOpsManager.HistoricalOp;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index f2fa4fd..86a5c76 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;
@@ -48,9 +48,9 @@
 import android.os.RemoteException;
 import android.os.UserManager;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.LongSparseArray;
 import android.util.LongSparseLongArray;
-import android.util.Pair;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
@@ -63,6 +63,8 @@
 import com.android.internal.os.RuntimeInit;
 import com.android.internal.os.ZygoteInit;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.ElementType;
@@ -83,7 +85,6 @@
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
-import java.util.function.ToLongFunction;
 
 /**
  * API for interacting with "application operation" tracking.
@@ -138,7 +139,7 @@
     @GuardedBy("sLock")
     private static @Nullable AppOpsCollector sNotedAppOpsCollector;
 
-    static IBinder sToken;
+    static IBinder sClientId;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -846,10 +847,12 @@
     public static final int OP_ACCESS_MEDIA_LOCATION = 90;
     /** @hide Query all apps on device, regardless of declarations in the calling app manifest */
     public static final int OP_QUERY_ALL_PACKAGES = 91;
+    /** @hide Access all external storage */
+    public static final int OP_MANAGE_EXTERNAL_STORAGE = 92;
 
     /** @hide */
     @UnsupportedAppUsage
-    public static final int _NUM_OP = 92;
+    public static final int _NUM_OP = 93;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1135,6 +1138,10 @@
     public static final String OPSTR_READ_DEVICE_IDENTIFIERS = "android:read_device_identifiers";
     /** @hide Query all packages on device */
     public static final String OPSTR_QUERY_ALL_PACKAGES = "android:query_all_packages";
+    /** @hide Access all external storage */
+    @SystemApi
+    public static final String OPSTR_MANAGE_EXTERNAL_STORAGE =
+            "android:manage_external_storage";
 
 
     /** {@link #sAppOpsToNote} not initialized yet for this op */
@@ -1317,6 +1324,7 @@
             OP_READ_DEVICE_IDENTIFIERS,         // READ_DEVICE_IDENTIFIERS
             OP_ACCESS_MEDIA_LOCATION,           // ACCESS_MEDIA_LOCATION
             OP_QUERY_ALL_PACKAGES,              // QUERY_ALL_PACKAGES
+            OP_MANAGE_EXTERNAL_STORAGE,         // MANAGE_EXTERNAL_STORAGE
     };
 
     /**
@@ -1415,6 +1423,7 @@
             OPSTR_READ_DEVICE_IDENTIFIERS,
             OPSTR_ACCESS_MEDIA_LOCATION,
             OPSTR_QUERY_ALL_PACKAGES,
+            OPSTR_MANAGE_EXTERNAL_STORAGE,
     };
 
     /**
@@ -1514,6 +1523,7 @@
             "READ_DEVICE_IDENTIFIERS",
             "ACCESS_MEDIA_LOCATION",
             "QUERY_ALL_PACKAGES",
+            "MANAGE_EXTERNAL_STORAGE"
     };
 
     /**
@@ -1614,6 +1624,7 @@
             null, // no direct permission for OP_READ_DEVICE_IDENTIFIERS
             Manifest.permission.ACCESS_MEDIA_LOCATION,
             null, // no permission for OP_QUERY_ALL_PACKAGES
+            null, // no permission for OP_MANAGE_EXTERNAL_STORAGE
     };
 
     /**
@@ -1714,6 +1725,7 @@
             null, // READ_DEVICE_IDENTIFIERS
             null, // ACCESS_MEDIA_LOCATION
             null, // QUERY_ALL_PACKAGES
+            null, // MANAGE_EXTERNAL_STORAGE
     };
 
     /**
@@ -1813,6 +1825,7 @@
             false, // READ_DEVICE_IDENTIFIERS
             false, // ACCESS_MEDIA_LOCATION
             false, // QUERY_ALL_PACKAGES
+            false, // MANAGE_EXTERNAL_STORAGE
     };
 
     /**
@@ -1911,6 +1924,7 @@
             AppOpsManager.MODE_ERRORED, // READ_DEVICE_IDENTIFIERS
             AppOpsManager.MODE_ALLOWED, // ALLOW_MEDIA_LOCATION
             AppOpsManager.MODE_DEFAULT, // QUERY_ALL_PACKAGES
+            AppOpsManager.MODE_DEFAULT, // MANAGE_EXTERNAL_STORAGE
     };
 
     /**
@@ -2013,6 +2027,7 @@
             false, // READ_DEVICE_IDENTIFIERS
             false, // ACCESS_MEDIA_LOCATION
             false, // QUERY_ALL_PACKAGES
+            false, // MANAGE_EXTERNAL_STORAGE
     };
 
     /**
@@ -2245,6 +2260,7 @@
      * Class holding all of the operation information associated with an app.
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final class PackageOps implements Parcelable {
         private final String mPackageName;
@@ -2288,7 +2304,7 @@
         }
 
         @Override
-        public void writeToParcel(Parcel dest, int flags) {
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
             dest.writeString(mPackageName);
             dest.writeInt(mUid);
             dest.writeInt(mEntries.size());
@@ -2319,537 +2335,878 @@
     }
 
     /**
-     * Class holding the information about one unique operation of a
-     * {@link Context#createFeatureContext(String) feature}.
+     * Proxy information for a {@link #noteOp} event
+     *
+     * @hide
+     */
+    @TestApi
+    @SystemApi
+    @Immutable
+    @DataClass(genHiddenConstructor = true)
+    public static final class OpEventProxyInfo implements Parcelable {
+        /** UID of the proxy app that noted the op */
+        private final @IntRange(from = 0) int mUid;
+        /** Package of the proxy that noted the op */
+        private final @Nullable String mPackageName;
+        /** ID of the feature of the proxy that noted the op */
+        private final @Nullable String mFeatureId;
+
+
+
+        // Code below generated by codegen v1.0.14.
+        //
+        // DO NOT MODIFY!
+        // CHECKSTYLE:OFF Generated code
+        //
+        // To regenerate run:
+        // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/AppOpsManager.java
+        //
+        // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+        //   Settings > Editor > Code Style > Formatter Control
+        //@formatter:off
+
+
+        /**
+         * Creates a new OpEventProxyInfo.
+         *
+         * @param uid
+         *   UID of the proxy app that noted the op
+         * @param packageName
+         *   Package of the proxy that noted the op
+         * @param featureId
+         *   ID of the feature of the proxy that noted the op
+         * @hide
+         */
+        @DataClass.Generated.Member
+        public OpEventProxyInfo(
+                @IntRange(from = 0) int uid,
+                @Nullable String packageName,
+                @Nullable String featureId) {
+            this.mUid = uid;
+            com.android.internal.util.AnnotationValidations.validate(
+                    IntRange.class, null, mUid,
+                    "from", 0);
+            this.mPackageName = packageName;
+            this.mFeatureId = featureId;
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        /**
+         * UID of the proxy app that noted the op
+         */
+        @DataClass.Generated.Member
+        public @IntRange(from = 0) int getUid() {
+            return mUid;
+        }
+
+        /**
+         * Package of the proxy that noted the op
+         */
+        @DataClass.Generated.Member
+        public @Nullable String getPackageName() {
+            return mPackageName;
+        }
+
+        /**
+         * ID of the feature of the proxy that noted the op
+         */
+        @DataClass.Generated.Member
+        public @Nullable String getFeatureId() {
+            return mFeatureId;
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            // You can override field parcelling by defining methods like:
+            // void parcelFieldName(Parcel dest, int flags) { ... }
+
+            byte flg = 0;
+            if (mPackageName != null) flg |= 0x2;
+            if (mFeatureId != null) flg |= 0x4;
+            dest.writeByte(flg);
+            dest.writeInt(mUid);
+            if (mPackageName != null) dest.writeString(mPackageName);
+            if (mFeatureId != null) dest.writeString(mFeatureId);
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public int describeContents() { return 0; }
+
+        /** @hide */
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        @DataClass.Generated.Member
+        /* package-private */ OpEventProxyInfo(@NonNull Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            byte flg = in.readByte();
+            int uid = in.readInt();
+            String packageName = (flg & 0x2) == 0 ? null : in.readString();
+            String featureId = (flg & 0x4) == 0 ? null : in.readString();
+
+            this.mUid = uid;
+            com.android.internal.util.AnnotationValidations.validate(
+                    IntRange.class, null, mUid,
+                    "from", 0);
+            this.mPackageName = packageName;
+            this.mFeatureId = featureId;
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @DataClass.Generated.Member
+        public static final @NonNull Parcelable.Creator<OpEventProxyInfo> CREATOR
+                = new Parcelable.Creator<OpEventProxyInfo>() {
+            @Override
+            public OpEventProxyInfo[] newArray(int size) {
+                return new OpEventProxyInfo[size];
+            }
+
+            @Override
+            public OpEventProxyInfo createFromParcel(@NonNull Parcel in) {
+                return new OpEventProxyInfo(in);
+            }
+        };
+
+        @DataClass.Generated(
+                time = 1576194071700L,
+                codegenVersion = "1.0.14",
+                sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
+                inputSignatures = "private final @android.annotation.IntRange(from=0L) int mUid\nprivate final @android.annotation.Nullable java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nclass OpEventProxyInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+        @Deprecated
+        private void __metadata() {}
+
+
+        //@formatter:on
+        // End of generated code
+
+    }
+
+    /**
+     * Description of a {@link #noteOp} or {@link #startOp} event
+     *
+     * @hide
+     */
+    @Immutable
+    //@DataClass codegen verifier is broken
+    public static final class NoteOpEvent implements Parcelable {
+        /** Time of noteOp event */
+        public final @IntRange(from = 0) long noteTime;
+        /** The duration of this event (in case this is a startOp event, -1 otherwise). */
+        public final @IntRange(from = -1) long duration;
+        /** Proxy information of the noteOp event */
+        public final @Nullable OpEventProxyInfo proxy;
+
+
+        // Code below generated by codegen v1.0.14.
+        //
+        // DO NOT MODIFY!
+        // CHECKSTYLE:OFF Generated code
+        //
+        // To regenerate run:
+        // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/AppOpsManager.java
+        //
+        // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+        //   Settings > Editor > Code Style > Formatter Control
+        //@formatter:off
+
+
+        /**
+         * Creates a new NoteOpEvent.
+         *
+         * @param noteTime
+         *   Time of noteOp event
+         * @param duration
+         *   The duration of this event (in case this is a startOp event, -1 otherwise).
+         * @param proxy
+         *   Proxy information of the noteOp event
+         */
+        @DataClass.Generated.Member
+        public NoteOpEvent(
+                @IntRange(from = 0) long noteTime,
+                @IntRange(from = -1) long duration,
+                @Nullable OpEventProxyInfo proxy) {
+            this.noteTime = noteTime;
+            com.android.internal.util.AnnotationValidations.validate(
+                    IntRange.class, null, noteTime,
+                    "from", 0);
+            this.duration = duration;
+            com.android.internal.util.AnnotationValidations.validate(
+                    IntRange.class, null, duration,
+                    "from", -1);
+            this.proxy = proxy;
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            // You can override field parcelling by defining methods like:
+            // void parcelFieldName(Parcel dest, int flags) { ... }
+
+            byte flg = 0;
+            if (proxy != null) flg |= 0x4;
+            dest.writeByte(flg);
+            dest.writeLong(noteTime);
+            dest.writeLong(duration);
+            if (proxy != null) dest.writeTypedObject(proxy, flags);
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public int describeContents() { return 0; }
+
+        /** @hide */
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        @DataClass.Generated.Member
+        /* package-private */ NoteOpEvent(@NonNull Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            byte flg = in.readByte();
+            long _noteTime = in.readLong();
+            long _duration = in.readLong();
+            OpEventProxyInfo _proxy = (flg & 0x4) == 0 ? null : (OpEventProxyInfo) in.readTypedObject(
+                    OpEventProxyInfo.CREATOR);
+
+            this.noteTime = _noteTime;
+            com.android.internal.util.AnnotationValidations.validate(
+                    IntRange.class, null, noteTime,
+                    "from", 0);
+            this.duration = _duration;
+            com.android.internal.util.AnnotationValidations.validate(
+                    IntRange.class, null, duration,
+                    "from", -1);
+            this.proxy = _proxy;
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @DataClass.Generated.Member
+        public static final @NonNull Parcelable.Creator<NoteOpEvent> CREATOR
+                = new Parcelable.Creator<NoteOpEvent>() {
+            @Override
+            public NoteOpEvent[] newArray(int size) {
+                return new NoteOpEvent[size];
+            }
+
+            @Override
+            public NoteOpEvent createFromParcel(@NonNull Parcel in) {
+                return new NoteOpEvent(in);
+            }
+        };
+
+        /*
+        @DataClass.Generated(
+                time = 1574809856220L,
+                codegenVersion = "1.0.14",
+                sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
+                inputSignatures = "public final @android.annotation.IntRange(from=0L) long noteTime\npublic final @android.annotation.IntRange(from=-1) long duration\npublic final @android.annotation.Nullable android.app.NoteOpEventProxyInfo proxy\nclass NoteOpEvent extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
+        @Deprecated
+        private void __metadata() {}
+         */
+
+
+        //@formatter:on
+        // End of generated code
+
+    }
+
+    /**
+     * Last {@link #noteOp} and {@link #startOp} events performed for a single op and a specific
+     * {@link Context#createFeatureContext(String) feature} for all uidModes and opFlags.
+     *
+     * @hide
+     */
+    @TestApi
+    @SystemApi
+    @Immutable
+    // @DataClass(genHiddenConstructor = true) codegen verifier is broken
+    @DataClass.Suppress({"getAccessEvents", "getRejectEvents", "getOp"})
+    public static final class OpFeatureEntry implements Parcelable {
+        /** The code of the op */
+        private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp;
+        /** Whether the op is running */
+        private final boolean mRunning;
+        /** The access events */
+        @DataClass.ParcelWith(LongSparseArrayParceling.class)
+        private final @Nullable LongSparseArray<NoteOpEvent> mAccessEvents;
+        /** The rejection events */
+        @DataClass.ParcelWith(LongSparseArrayParceling.class)
+        private final @Nullable LongSparseArray<NoteOpEvent> mRejectEvents;
+
+        /**
+         * Returns all keys for which we have events.
+         *
+         * @hide
+         */
+        public @NonNull ArraySet<Long> collectKeys() {
+            ArraySet<Long> keys = new ArraySet<>();
+
+            if (mAccessEvents != null) {
+                int numEvents = mAccessEvents.size();
+                for (int i = 0; i < numEvents; i++) {
+                    keys.add(mAccessEvents.keyAt(i));
+                }
+            }
+
+            if (mRejectEvents != null) {
+                int numEvents = mRejectEvents.size();
+                for (int i = 0; i < numEvents; i++) {
+                    keys.add(mRejectEvents.keyAt(i));
+                }
+            }
+
+            return keys;
+        }
+
+        /**
+         * Return the last access time.
+         *
+         * @param flags The op flags
+         *
+         * @return the last access time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
+         * @see #getLastAccessForegroundTime(int)
+         * @see #getLastAccessBackgroundTime(int)
+         * @see #getLastAccessTime(int, int, int)
+         * @see OpEntry#getLastAccessTime(int)
+         */
+        public long getLastAccessTime(@OpFlags int flags) {
+            return getLastAccessTime(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
+        }
+
+        /**
+         * Return the last foreground access time.
+         *
+         * @param flags The op flags
+         *
+         * @return the last access time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
+         * @see #getLastAccessTime(int)
+         * @see #getLastAccessBackgroundTime(int)
+         * @see #getLastAccessTime(int, int, int)
+         * @see OpEntry#getLastAccessForegroundTime(int)
+         */
+        public long getLastAccessForegroundTime(@OpFlags int flags) {
+            return getLastAccessTime(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
+                    flags);
+        }
+
+        /**
+         * Return the last background access time.
+         *
+         * @param flags The op flags
+         *
+         * @return the last access time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
+         * @see #getLastAccessTime(int)
+         * @see #getLastAccessForegroundTime(int)
+         * @see #getLastAccessTime(int, int, int)
+         * @see OpEntry#getLastAccessBackgroundTime(int)
+         */
+        public long getLastAccessBackgroundTime(@OpFlags int flags) {
+            return getLastAccessTime(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
+                    flags);
+        }
+
+        /**
+         * Return the last access event.
+         *
+         * @param flags The op flags
+         *
+         * @return the last access event of {@code null}
+         */
+        private @Nullable NoteOpEvent getLastAccessEvent(@UidState int fromUidState,
+                @UidState int toUidState, @OpFlags int flags) {
+            return getLastEvent(mAccessEvents, fromUidState, toUidState, flags);
+        }
+
+        /**
+         * Return the last access time.
+         *
+         * @param fromUidState The lowest UID state for which to query
+         * @param toUidState The highest UID state for which to query (inclusive)
+         * @param flags The op flags
+         *
+         * @return the last access time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
+         * @see #getLastAccessTime(int)
+         * @see #getLastAccessForegroundTime(int)
+         * @see #getLastAccessBackgroundTime(int)
+         * @see OpEntry#getLastAccessTime(int, int, int)
+         */
+        public long getLastAccessTime(@UidState int fromUidState, @UidState int toUidState,
+                @OpFlags int flags) {
+            NoteOpEvent lastEvent = getLastAccessEvent(fromUidState, toUidState, flags);
+            if (lastEvent == null) {
+                return -1;
+            }
+
+            return lastEvent.noteTime;
+        }
+
+        /**
+         * Return the last rejection time.
+         *
+         * @param flags The op flags
+         *
+         * @return the last rejection time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
+         * @see #getLastRejectForegroundTime(int)
+         * @see #getLastRejectBackgroundTime(int)
+         * @see #getLastRejectTime(int, int, int)
+         * @see OpEntry#getLastRejectTime(int)
+         */
+        public long getLastRejectTime(@OpFlags int flags) {
+            return getLastRejectTime(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
+        }
+
+        /**
+         * Return the last foreground rejection time.
+         *
+         * @param flags The op flags
+         *
+         * @return the last rejection time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
+         * @see #getLastRejectTime(int)
+         * @see #getLastRejectBackgroundTime(int)
+         * @see #getLastRejectTime(int, int, int)
+         * @see OpEntry#getLastRejectForegroundTime(int)
+         */
+        public long getLastRejectForegroundTime(@OpFlags int flags) {
+            return getLastRejectTime(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
+                    flags);
+        }
+
+        /**
+         * Return the last background rejection time.
+         *
+         * @param flags The op flags
+         *
+         * @return the last rejection time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
+         * @see #getLastRejectTime(int)
+         * @see #getLastRejectForegroundTime(int)
+         * @see #getLastRejectTime(int, int, int)
+         * @see OpEntry#getLastRejectBackgroundTime(int)
+         */
+        public long getLastRejectBackgroundTime(@OpFlags int flags) {
+            return getLastRejectTime(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
+                    flags);
+        }
+
+        /**
+         * Return the last background rejection event.
+         *
+         * @param flags The op flags
+         *
+         * @return the last rejection time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
+         * @see #getLastRejectTime(int)
+         * @see #getLastRejectForegroundTime(int)
+         * @see #getLastRejectBackgroundTime(int)
+         * @see OpEntry#getLastRejectTime(int, int, int)
+         */
+        private @Nullable NoteOpEvent getLastRejectEvent(@UidState int fromUidState,
+                @UidState int toUidState, @OpFlags int flags) {
+            return getLastEvent(mRejectEvents, fromUidState, toUidState, flags);
+        }
+
+        /**
+         * Return the last rejection time.
+         *
+         * @param fromUidState The lowest UID state for which to query
+         * @param toUidState The highest UID state for which to query (inclusive)
+         * @param flags The op flags
+         *
+         * @return the last access time (in milliseconds since epoch) or {@code -1}
+         *
+         * @see #getLastRejectTime(int)
+         * @see #getLastRejectForegroundTime(int)
+         * @see #getLastRejectForegroundTime(int)
+         * @see #getLastRejectTime(int, int, int)
+         * @see OpEntry#getLastRejectTime(int, int, int)
+         */
+        public long getLastRejectTime(@UidState int fromUidState, @UidState int toUidState,
+                @OpFlags int flags) {
+            NoteOpEvent lastEvent = getLastRejectEvent(fromUidState, toUidState, flags);
+            if (lastEvent == null) {
+                return -1;
+            }
+
+            return lastEvent.noteTime;
+        }
+
+        /**
+         * Return the duration in milliseconds of the last the access.
+         *
+         * @param flags The op flags
+         *
+         * @return the duration in milliseconds or {@code -1}
+         *
+         * @see #getLastForegroundDuration(int)
+         * @see #getLastBackgroundDuration(int)
+         * @see #getLastDuration(int, int, int)
+         * @see OpEntry#getLastDuration(int)
+         */
+        public long getLastDuration(@OpFlags int flags) {
+            return getLastDuration(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
+        }
+
+        /**
+         * Return the duration in milliseconds of the last foreground access.
+         *
+         * @param flags The op flags
+         *
+         * @return the duration in milliseconds or {@code -1}
+         *
+         * @see #getLastDuration(int)
+         * @see #getLastBackgroundDuration(int)
+         * @see #getLastDuration(int, int, int)
+         * @see OpEntry#getLastForegroundDuration(int)
+         */
+        public long getLastForegroundDuration(@OpFlags int flags) {
+            return getLastDuration(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
+                    flags);
+        }
+
+        /**
+         * Return the duration in milliseconds of the last background access.
+         *
+         * @param flags The op flags
+         *
+         * @return the duration in milliseconds or {@code -1}
+         *
+         * @see #getLastDuration(int)
+         * @see #getLastForegroundDuration(int)
+         * @see #getLastDuration(int, int, int)
+         * @see OpEntry#getLastBackgroundDuration(int)
+         */
+        public long getLastBackgroundDuration(@OpFlags int flags) {
+            return getLastDuration(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
+                    flags);
+        }
+
+        /**
+         * Return the duration in milliseconds of the last access.
+         *
+         * @param fromUidState The lowest UID state for which to query
+         * @param toUidState The highest UID state for which to query (inclusive)
+         * @param flags The op flags
+         *
+         * @return the duration in milliseconds or {@code -1}
+         *
+         * @see #getLastDuration(int)
+         * @see #getLastForegroundDuration(int)
+         * @see #getLastBackgroundDuration(int)
+         * @see #getLastDuration(int, int, int)
+         * @see OpEntry#getLastDuration(int, int, int)
+         */
+        public long getLastDuration(@UidState int fromUidState, @UidState int toUidState,
+                @OpFlags int flags) {
+            NoteOpEvent lastEvent = getLastAccessEvent(fromUidState, toUidState, flags);;
+            if (lastEvent == null) {
+                return -1;
+            }
+
+            return lastEvent.duration;
+        }
+
+        /**
+         * Gets the proxy info of the app that performed the last access on behalf of this feature
+         * and as a result blamed the op on this app.
+         *
+         * @param flags The op flags
+         *
+         * @return The proxy name or {@code null}
+         *
+         * @see #getLastForegroundProxyInfo(int)
+         * @see #getLastBackgroundProxyInfo(int)
+         * @see #getLastProxyInfo(int, int, int)
+         * @see OpEntry#getLastProxyInfo(int)
+         */
+        public @Nullable OpEventProxyInfo getLastProxyInfo(@OpFlags int flags) {
+            return getLastProxyInfo(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
+        }
+
+        /**
+         * Gets the proxy info of the app that performed the last foreground access on behalf of
+         * this feature and as a result blamed the op on this app.
+         *
+         * @param flags The op flags
+         *
+         * @return The proxy name or {@code null}
+         *
+         * @see #getLastProxyInfo(int)
+         * @see #getLastBackgroundProxyInfo(int)
+         * @see #getLastProxyInfo(int, int, int)
+         * @see OpEntry#getLastForegroundProxyInfo(int)
+         */
+        public @Nullable OpEventProxyInfo getLastForegroundProxyInfo(@OpFlags int flags) {
+            return getLastProxyInfo(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
+                    flags);
+        }
+
+        /**
+         * Gets the proxy info of the app that performed the last background access on behalf of
+         * this feature and as a result blamed the op on this app.
+         *
+         * @param flags The op flags
+         *
+         * @return The proxy name or {@code null}
+         *
+         * @see #getLastProxyInfo(int)
+         * @see #getLastForegroundProxyInfo(int)
+         * @see #getLastProxyInfo(int, int, int)
+         * @see OpEntry#getLastBackgroundProxyInfo(int)
+         */
+        public @Nullable OpEventProxyInfo getLastBackgroundProxyInfo(@OpFlags int flags) {
+            return getLastProxyInfo(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
+                    flags);
+        }
+
+        /**
+         * Gets the proxy info of the app that performed the last access on behalf of this feature
+         * and as a result blamed the op on this app.
+         *
+         * @param fromUidState The lowest UID state for which to query
+         * @param toUidState The highest UID state for which to query (inclusive)
+         * @param flags The op flags
+         *
+         * @return The proxy name or {@code null}
+         *
+         * @see #getLastProxyInfo(int)
+         * @see #getLastForegroundProxyInfo(int)
+         * @see #getLastBackgroundProxyInfo(int)
+         * @see OpEntry#getLastProxyInfo(int, int, int)
+         */
+        public @Nullable OpEventProxyInfo getLastProxyInfo(@UidState int fromUidState,
+                @UidState int toUidState, @OpFlags int flags) {
+            NoteOpEvent lastEvent = getLastAccessEvent(fromUidState, toUidState, flags);
+            if (lastEvent == null) {
+                return null;
+            }
+
+            return lastEvent.proxy;
+        }
+
+        private static class LongSparseArrayParceling implements
+                Parcelling<LongSparseArray<NoteOpEvent>> {
+            @Override
+            public void parcel(@Nullable LongSparseArray<NoteOpEvent> array, @NonNull Parcel dest,
+                    int parcelFlags) {
+                if (array == null) {
+                    dest.writeInt(-1);
+                    return;
+                }
+
+                int numEntries = array.size();
+                dest.writeInt(numEntries);
+
+                for (int i = 0; i < numEntries; i++) {
+                    dest.writeLong(array.keyAt(i));
+                    dest.writeParcelable(array.valueAt(i), parcelFlags);
+                }
+            }
+
+            @Override
+            public @Nullable LongSparseArray<NoteOpEvent> unparcel(@NonNull Parcel source) {
+                int numEntries = source.readInt();
+                if (numEntries == -1) {
+                    return null;
+                }
+
+                LongSparseArray<NoteOpEvent> array = new LongSparseArray<>(numEntries);
+
+                for (int i = 0; i < numEntries; i++) {
+                    array.put(source.readLong(), source.readParcelable(null));
+                }
+
+                return array;
+            }
+        }
+
+
+
+        // Code below generated by codegen v1.0.14.
+        //
+        // DO NOT MODIFY!
+        // CHECKSTYLE:OFF Generated code
+        //
+        // To regenerate run:
+        // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/AppOpsManager.java
+        //
+        // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+        //   Settings > Editor > Code Style > Formatter Control
+        //@formatter:off
+
+
+        /**
+         * Creates a new OpFeatureEntry.
+         *
+         * @param op
+         *   The code of the op
+         * @param running
+         *   Whether the op is running
+         * @param accessEvents
+         *   The access events
+         * @param rejectEvents
+         *   The rejection events
+         * @hide
+         */
+        @DataClass.Generated.Member
+        public OpFeatureEntry(
+                @IntRange(from = 0, to = _NUM_OP - 1) int op,
+                boolean running,
+                @Nullable LongSparseArray<NoteOpEvent> accessEvents,
+                @Nullable LongSparseArray<NoteOpEvent> rejectEvents) {
+            this.mOp = op;
+            com.android.internal.util.AnnotationValidations.validate(
+                    IntRange.class, null, mOp,
+                    "from", 0,
+                    "to", _NUM_OP - 1);
+            this.mRunning = running;
+            this.mAccessEvents = accessEvents;
+            this.mRejectEvents = rejectEvents;
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        /**
+         * Whether the op is running
+         */
+        @DataClass.Generated.Member
+        public boolean isRunning() {
+            return mRunning;
+        }
+
+        @DataClass.Generated.Member
+        static Parcelling<LongSparseArray<NoteOpEvent>> sParcellingForAccessEvents =
+                Parcelling.Cache.get(
+                        LongSparseArrayParceling.class);
+        static {
+            if (sParcellingForAccessEvents == null) {
+                sParcellingForAccessEvents = Parcelling.Cache.put(
+                        new LongSparseArrayParceling());
+            }
+        }
+
+        @DataClass.Generated.Member
+        static Parcelling<LongSparseArray<NoteOpEvent>> sParcellingForRejectEvents =
+                Parcelling.Cache.get(
+                        LongSparseArrayParceling.class);
+        static {
+            if (sParcellingForRejectEvents == null) {
+                sParcellingForRejectEvents = Parcelling.Cache.put(
+                        new LongSparseArrayParceling());
+            }
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            // You can override field parcelling by defining methods like:
+            // void parcelFieldName(Parcel dest, int flags) { ... }
+
+            byte flg = 0;
+            if (mRunning) flg |= 0x2;
+            if (mAccessEvents != null) flg |= 0x4;
+            if (mRejectEvents != null) flg |= 0x8;
+            dest.writeByte(flg);
+            dest.writeInt(mOp);
+            sParcellingForAccessEvents.parcel(mAccessEvents, dest, flags);
+            sParcellingForRejectEvents.parcel(mRejectEvents, dest, flags);
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public int describeContents() { return 0; }
+
+        /** @hide */
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        @DataClass.Generated.Member
+        /* package-private */ OpFeatureEntry(@NonNull Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            byte flg = in.readByte();
+            boolean running = (flg & 0x2) != 0;
+            int op = in.readInt();
+            LongSparseArray<NoteOpEvent> accessEvents = sParcellingForAccessEvents.unparcel(in);
+            LongSparseArray<NoteOpEvent> rejectEvents = sParcellingForRejectEvents.unparcel(in);
+
+            this.mOp = op;
+            com.android.internal.util.AnnotationValidations.validate(
+                    IntRange.class, null, mOp,
+                    "from", 0,
+                    "to", _NUM_OP - 1);
+            this.mRunning = running;
+            this.mAccessEvents = accessEvents;
+            this.mRejectEvents = rejectEvents;
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @DataClass.Generated.Member
+        public static final @NonNull Parcelable.Creator<OpFeatureEntry> CREATOR
+                = new Parcelable.Creator<OpFeatureEntry>() {
+            @Override
+            public OpFeatureEntry[] newArray(int size) {
+                return new OpFeatureEntry[size];
+            }
+
+            @Override
+            public OpFeatureEntry createFromParcel(@NonNull Parcel in) {
+                return new OpFeatureEntry(in);
+            }
+        };
+
+        /*
+        @DataClass.Generated(
+                time = 1574809856239L,
+                codegenVersion = "1.0.14",
+                sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
+                inputSignatures = "private final @android.annotation.IntRange(from=0L, to=_NUM_OP - 1) int mOp\nprivate final  boolean mRunning\nprivate final @com.android.internal.util.DataClass.ParcelWith(android.app.OpFeatureEntry.LongSparseArrayParceling.class) @android.annotation.Nullable android.util.LongSparseArray<android.app.NoteOpEvent> mAccessEvents\nprivate final @com.android.internal.util.DataClass.ParcelWith(android.app.OpFeatureEntry.LongSparseArrayParceling.class) @android.annotation.Nullable android.util.LongSparseArray<android.app.NoteOpEvent> mRejectEvents\npublic @android.annotation.NonNull android.util.ArraySet<java.lang.Long> collectKeys()\npublic @android.app.UidState int getLastAccessUidState(int)\npublic @android.app.UidState int getLastForegroundAccessUidState(int)\npublic @android.app.UidState int getLastBackgroundAccessUidState(int)\npublic @android.app.UidState int getLastRejectUidState(int)\npublic @android.app.UidState int getLastForegroundRejectUidState(int)\npublic @android.app.UidState int getLastBackgroundRejectUidState(int)\npublic  long getAccessTime(int,int)\npublic  long getRejectTime(int,int)\npublic  long getDuration(int,int)\npublic  int getProxyUid(int,int)\npublic @android.annotation.Nullable java.lang.String getProxyPackageName(int,int)\npublic @android.annotation.Nullable java.lang.String getProxyFeatureId(int,int)\nclass OpFeatureEntry extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+        @Deprecated
+        private void __metadata() {}
+         */
+
+
+        //@formatter:on
+        // End of generated code
+
+    }
+
+    /**
+     * Last {@link #noteOp} and {@link #startOp} events performed for a single op for all uidModes
+     * and opFlags.
      *
      * @hide
      */
     @TestApi
     @Immutable
     @SystemApi
-    public static final class OpFeatureEntry {
-        private final @NonNull OpEntry mParent;
-        private final boolean mRunning;
-
-        private final @Nullable LongSparseLongArray mAccessTimes;
-        private final @Nullable LongSparseLongArray mRejectTimes;
-        private final @Nullable LongSparseLongArray mDurations;
-        private final @Nullable LongSparseLongArray mProxyUids;
-        private final @Nullable LongSparseArray<String> mProxyPackageNames;
-        private final @Nullable LongSparseArray<String> mProxyFeatureIds;
-
-        /**
-         * @hide
-         */
-        public OpFeatureEntry(@NonNull OpEntry parent, boolean running,
-                @Nullable LongSparseLongArray accessTimes,
-                @Nullable LongSparseLongArray rejectTimes,
-                @Nullable LongSparseLongArray durations, @Nullable LongSparseLongArray proxyUids,
-                @Nullable LongSparseArray<String> proxyPackageNames,
-                @Nullable LongSparseArray<String> proxyFeatureIds) {
-            mParent = Preconditions.checkNotNull(parent);
-            mRunning = running;
-            mAccessTimes = accessTimes;
-            mRejectTimes = rejectTimes;
-            mDurations = durations;
-            mProxyUids = proxyUids;
-            mProxyPackageNames = proxyPackageNames;
-            mProxyFeatureIds = proxyFeatureIds;
-        }
-
-        /**
-         * Returns all keys for which we have mapped state in any of the data buckets -
-         * access time, reject time, duration.
-         * @hide */
-        public @Nullable LongSparseArray<Object> collectKeys() {
-            LongSparseArray<Object> result = AppOpsManager.collectKeys(mAccessTimes, null);
-            result = AppOpsManager.collectKeys(mRejectTimes, result);
-            result = AppOpsManager.collectKeys(mDurations, result);
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public long getTime() {
-            return getLastAccessTime(OP_FLAGS_ALL);
-        }
-
-        /**
-         * Return the last wall clock time in milliseconds this op was accessed.
-         *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the last access time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
-         *
-         * @see #getLastAccessForegroundTime(int)
-         * @see #getLastAccessBackgroundTime(int)
-         * @see #getLastAccessTime(int, int, int)
-         */
-        public long getLastAccessTime(@OpFlags int flags) {
-            return maxForFlagsInStates(mAccessTimes, MAX_PRIORITY_UID_STATE,
-                    MIN_PRIORITY_UID_STATE, flags);
-        }
-
-        /**
-         * Return the last wall clock time in milliseconds this op was accessed
-         * by the app while in the foreground.
-         *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the last foreground access time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
-         *
-         * @see #getLastAccessBackgroundTime(int)
-         * @see #getLastAccessTime(int)
-         * @see #getLastAccessTime(int, int, int)
-         */
-        public long getLastAccessForegroundTime(@OpFlags int flags) {
-            return maxForFlagsInStates(mAccessTimes, MAX_PRIORITY_UID_STATE,
-                    resolveFirstUnrestrictedUidState(mParent.mOp), flags);
-        }
-
-        /**
-         * Return the last wall clock time in milliseconds this op was accessed
-         * by the app while in the background.
-         *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the last foreground access time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
-         *
-         * @see #getLastAccessForegroundTime(int)
-         * @see #getLastAccessTime(int)
-         * @see #getLastAccessTime(int, int, int)
-         */
-        public long getLastAccessBackgroundTime(@OpFlags int flags) {
-            return maxForFlagsInStates(mAccessTimes, resolveLastRestrictedUidState(mParent.mOp),
-                    MIN_PRIORITY_UID_STATE, flags);
-        }
-
-        /**
-         * Return the last wall clock time  in milliseconds this op was accessed
-         * by the app for a given range of UID states.
-         *
-         * @param fromUidState The UID state for which to query. Could be one of
-         * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
-         * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
-         * @param toUidState The UID state for which to query.
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         *
-         * @return the last foreground access time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
-         *
-         * @see #getLastAccessForegroundTime(int)
-         * @see #getLastAccessBackgroundTime(int)
-         * @see #getLastAccessTime(int)
-         */
-        public long getLastAccessTime(@UidState int fromUidState, @UidState int toUidState,
-                @OpFlags int flags) {
-            return maxForFlagsInStates(mAccessTimes, fromUidState, toUidState, flags);
-        }
-
-        /**
-         * @hide
-         */
-        public long getRejectTime() {
-            return getLastRejectTime(OP_FLAGS_ALL);
-        }
-
-        /**
-         * Return the last wall clock time in milliseconds the app made an attempt
-         * to access this op but was rejected.
-         *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the last reject time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
-         *
-         * @see #getLastRejectBackgroundTime(int)
-         * @see #getLastRejectForegroundTime(int)
-         * @see #getLastRejectTime(int, int, int)
-         */
-        public long getLastRejectTime(@OpFlags int flags) {
-            return maxForFlagsInStates(mRejectTimes, MAX_PRIORITY_UID_STATE,
-                    MIN_PRIORITY_UID_STATE, flags);
-        }
-
-        /**
-         * Return the last wall clock time in milliseconds the app made an attempt
-         * to access this op while in the foreground but was rejected.
-         *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the last foreground reject time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
-         *
-         * @see #getLastRejectBackgroundTime(int)
-         * @see #getLastRejectTime(int, int, int)
-         * @see #getLastRejectTime(int)
-         */
-        public long getLastRejectForegroundTime(@OpFlags int flags) {
-            return maxForFlagsInStates(mRejectTimes, MAX_PRIORITY_UID_STATE,
-                    resolveFirstUnrestrictedUidState(mParent.mOp), flags);
-        }
-
-        /**
-         * Return the last wall clock time in milliseconds the app made an attempt
-         * to access this op while in the background but was rejected.
-         *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the last background reject time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
-         *
-         * @see #getLastRejectForegroundTime(int)
-         * @see #getLastRejectTime(int, int, int)
-         * @see #getLastRejectTime(int)
-         */
-        public long getLastRejectBackgroundTime(@OpFlags int flags) {
-            return maxForFlagsInStates(mRejectTimes, resolveLastRestrictedUidState(mParent.mOp),
-                    MIN_PRIORITY_UID_STATE, flags);
-        }
-
-        /**
-         * Return the last wall clock time state in milliseconds the app made an
-         * attempt to access this op for a given range of UID states.
-         *
-         * @param fromUidState The UID state from which to query. Could be one of
-         * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
-         * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
-         * @param toUidState The UID state to which to query.
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the last foreground access time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
-         *
-         * @see #getLastRejectForegroundTime(int)
-         * @see #getLastRejectBackgroundTime(int)
-         * @see #getLastRejectTime(int)
-         */
-        public long getLastRejectTime(@UidState int fromUidState, @UidState int toUidState,
-                @OpFlags int flags) {
-            return maxForFlagsInStates(mRejectTimes, fromUidState, toUidState, flags);
-        }
-
-        /**
-         * @return Whether the operation is running.
-         */
-        public boolean isRunning() {
-            return mRunning;
-        }
-
-        /**
-         * @return The duration of the operation in milliseconds. The duration is in wall time.
-         */
-        public long getDuration() {
-            return getLastDuration(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL);
-        }
-
-        /**
-         * Return the duration in milliseconds the app accessed this op while
-         * in the foreground. The duration is in wall time.
-         *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the foreground access duration in milliseconds.
-         *
-         * @see #getLastBackgroundDuration(int)
-         * @see #getLastDuration(int, int, int)
-         */
-        public long getLastForegroundDuration(@OpFlags int flags) {
-            return sumForFlagsInStates(mDurations, MAX_PRIORITY_UID_STATE,
-                    resolveFirstUnrestrictedUidState(mParent.mOp), flags);
-        }
-
-        /**
-         * Return the duration in milliseconds the app accessed this op while
-         * in the background. The duration is in wall time.
-         *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the background access duration in milliseconds.
-         *
-         * @see #getLastForegroundDuration(int)
-         * @see #getLastDuration(int, int, int)
-         */
-        public long getLastBackgroundDuration(@OpFlags int flags) {
-            return sumForFlagsInStates(mDurations, resolveLastRestrictedUidState(mParent.mOp),
-                    MIN_PRIORITY_UID_STATE, flags);
-        }
-
-        /**
-         * Return the duration in milliseconds the app accessed this op for
-         * a given range of UID states. The duration is in wall time.
-         *
-         * @param fromUidState The UID state for which to query. Could be one of
-         * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
-         * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
-         * @param toUidState The UID state for which to query.
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the access duration in milliseconds.
-         */
-        public long getLastDuration(@UidState int fromUidState, @UidState int toUidState,
-                @OpFlags int flags) {
-            return sumForFlagsInStates(mDurations, fromUidState, toUidState, flags);
-        }
-
-        /**
-         * Gets the UID of the app that performed the op on behalf of this app and
-         * as a result blamed the op on this app or {@link Process#INVALID_UID} if
-         * there is no proxy.
-         *
-         * @return The proxy UID.
-         */
-        public int getProxyUid() {
-            return (int) findFirstNonNegativeForFlagsInStates(mProxyUids,
-                    MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL);
-        }
-
-        /**
-         * Gets the UID of the app that performed the op on behalf of this app and
-         * as a result blamed the op on this app or {@link Process#INVALID_UID} if
-         * there is no proxy.
-         *
-         * @param uidState The UID state for which to query. Could be one of
-         * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
-         * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         *
-         * @return The proxy UID.
-         */
-        public int getProxyUid(@UidState int uidState, @OpFlags int flags) {
-            return (int) findFirstNonNegativeForFlagsInStates(mProxyUids,
-                    uidState, uidState, flags);
-        }
-
-        /**
-         * Gets the package name of the app that performed the op on behalf of this
-         * app and as a result blamed the op on this app or {@code null}
-         * if there is no proxy.
-         *
-         * @return The proxy package name.
-         */
-        public @Nullable String getProxyPackageName() {
-            return findFirstNonNullForFlagsInStates(mProxyPackageNames, MAX_PRIORITY_UID_STATE,
-                    MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL);
-        }
-
-        /**
-         * Gets the package name of the app that performed the op on behalf of this
-         * app and as a result blamed the op on this app for a UID state or
-         * {@code null} if there is no proxy.
-         *
-         * @param uidState The UID state for which to query. Could be one of
-         * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
-         * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return The feature id.
-         */
-        public @Nullable String getProxyPackageName(@UidState int uidState, @OpFlags int flags) {
-            return findFirstNonNullForFlagsInStates(mProxyPackageNames, uidState, uidState, flags);
-        }
-
-        /**
-         * Gets the feature of the app that performed the op on behalf of this
-         * app and as a result blamed the op on this app or {@code null}
-         * if there is no proxy.
-         *
-         * @return The proxy package name.
-         */
-        public @Nullable String getProxyFeatureId() {
-            return findFirstNonNullForFlagsInStates(mProxyFeatureIds, MAX_PRIORITY_UID_STATE,
-                    MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL);
-        }
-
-        /**
-         * Gets the feature of the app that performed the op on behalf of this
-         * app and as a result blamed the op on this app for a UID state or
-         * {@code null} if there is no proxy.
-         *
-         * @param uidState The UID state for which to query. Could be one of
-         * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
-         * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return The feature id.
-         */
-        public @Nullable String getProxyFeatureId(@UidState int uidState, @OpFlags int flags) {
-            return findFirstNonNullForFlagsInStates(mProxyFeatureIds, uidState, uidState, flags);
-        }
-
-        /**
-         * @hide
-         */
-        public static class Builder {
-            private final boolean mRunning;
-
-            private final @Nullable LongSparseLongArray mAccessTimes;
-            private final @Nullable LongSparseLongArray mRejectTimes;
-            private final @Nullable LongSparseLongArray mDurations;
-            private final @Nullable LongSparseLongArray mProxyUids;
-            private final @Nullable LongSparseArray<String> mProxyPackageNames;
-            private final @Nullable LongSparseArray<String> mProxyFeatureIds;
-            private @NonNull OpEntry mParent;
-
-            public Builder(boolean running, @Nullable LongSparseLongArray accessTimes,
-                    @Nullable LongSparseLongArray rejectTimes,
-                    @Nullable LongSparseLongArray durations,
-                    @Nullable LongSparseLongArray proxyUids,
-                    @Nullable LongSparseArray<String> proxyPackageNames,
-                    @Nullable LongSparseArray<String> proxyFeatureIds) {
-                mRunning = running;
-                mAccessTimes = accessTimes;
-                mRejectTimes = rejectTimes;
-                mDurations = durations;
-                mProxyUids = proxyUids;
-                mProxyPackageNames = proxyPackageNames;
-                mProxyFeatureIds = proxyFeatureIds;
-            }
-
-            public Builder setParent(@NonNull OpEntry parent) {
-                mParent = parent;
-
-                return this;
-            }
-
-            /**
-             * Create OpFeatureEntry from builder
-             */
-            public OpFeatureEntry build() {
-                Preconditions.checkNotNull(mParent);
-
-                return new OpFeatureEntry(mParent, mRunning, mAccessTimes, mRejectTimes,
-                        mDurations, mProxyUids, mProxyPackageNames, mProxyFeatureIds);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public void writeToParcel(@NonNull Parcel dest, int flags) {
-            LongSparseLongArray.Parcelling longSparseLongArrayParcelling =
-                    LongSparseLongArray.Parcelling.Cache.getOrCreate(
-                            LongSparseLongArray.Parcelling.class);
-            LongSparseArray.StringParcelling longSparseStringArrayParcelling =
-                    LongSparseArray.StringParcelling.Cache.getOrCreate(
-                            LongSparseArray.StringParcelling.class);
-
-            dest.writeBoolean(mRunning);
-            longSparseLongArrayParcelling.parcel(mAccessTimes, dest, flags);
-            longSparseLongArrayParcelling.parcel(mRejectTimes, dest, flags);
-            longSparseLongArrayParcelling.parcel(mDurations, dest, flags);
-            longSparseLongArrayParcelling.parcel(mProxyUids, dest, flags);
-            longSparseStringArrayParcelling.parcel(mProxyPackageNames, dest, flags);
-            longSparseStringArrayParcelling.parcel(mProxyFeatureIds, dest, flags);
-        }
-
-        /**
-         * @hide
-         */
-        public static OpFeatureEntry.Builder createFromParcel(@NonNull Parcel source) {
-            LongSparseLongArray.Parcelling longSparseLongArrayParcelling =
-                    LongSparseLongArray.Parcelling.Cache.getOrCreate(
-                            LongSparseLongArray.Parcelling.class);
-            LongSparseArray.StringParcelling longSparseStringArrayParcelling =
-                    LongSparseArray.StringParcelling.Cache.getOrCreate(
-                            LongSparseArray.StringParcelling.class);
-
-            return new OpFeatureEntry.Builder(source.readBoolean(),
-                    longSparseLongArrayParcelling.unparcel(source),
-                    longSparseLongArrayParcelling.unparcel(source),
-                    longSparseLongArrayParcelling.unparcel(source),
-                    longSparseLongArrayParcelling.unparcel(source),
-                    longSparseStringArrayParcelling.unparcel(source),
-                    longSparseStringArrayParcelling.unparcel(source));
-        }
-    }
-
-    /**
-     * Class holding the information about one unique operation of an application.
-     * @hide
-     */
-    @TestApi
-    @Immutable
-    @SystemApi
+    // @DataClass(genHiddenConstructor = true) codegen verifier is broken
     public static final class OpEntry implements Parcelable {
+        /** The code of the op */
         private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp;
+        /** The mode of the op */
         private final @Mode int mMode;
-        private final @NonNull ArrayMap<String, OpFeatureEntry> mFeatures;
-
-        /**
-         * @hide
-         */
-        public OpEntry(@IntRange(from = 0, to = _NUM_OP - 1) int op, @Mode int mode,
-                @NonNull Pair<String, OpFeatureEntry.Builder>[] featureBuilders) {
-            mOp = Preconditions.checkArgumentInRange(op, 0, _NUM_OP - 1, "op");
-            mMode = Preconditions.checkArgumentInRange(mode, 0, MODE_FOREGROUND, "mode");
-
-            mFeatures = new ArrayMap<>(featureBuilders.length);
-            for (Pair<String, OpFeatureEntry.Builder> feature : featureBuilders) {
-                mFeatures.put(feature.first, feature.second.setParent(this).build());
-            }
-        }
-
-        /**
-         * @return The mapping from the feature ids to the feature state
-         */
-        public @NonNull Map<String, OpFeatureEntry> getFeatures() {
-            return mFeatures;
-        }
+        /** The features that have been used when checking the op */
+        private final @NonNull Map<String, OpFeatureEntry> mFeatures;
 
         /**
          * @hide
@@ -2868,16 +3225,9 @@
         }
 
         /**
-         * @return this entry's current mode, such as {@link #MODE_ALLOWED}.
-         */
-        public @Mode int getMode() {
-            return mMode;
-        }
-
-        /**
-         * @deprecated Use {@link OpEntry#getLastAccessTime(int)} instead
-         *
          * @hide
+         *
+         * @deprecated Use {@link #getLastAccessTime(int)} instead
          */
         @Deprecated
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@code "
@@ -2886,130 +3236,112 @@
             return getLastAccessTime(OP_FLAGS_ALL);
         }
 
-        private long getMaxOfFeatures(@NonNull ToLongFunction<OpFeatureEntry> timeGetter) {
-            long max = 0;
-
-            int numFeatures = mFeatures.size();
-            for (int i = 0; i < numFeatures; i++) {
-                max = Math.max(max, timeGetter.applyAsLong(mFeatures.valueAt(i)));
-            }
-
-            return max;
-        }
-
-        private long getSumOfFeatures(@NonNull ToLongFunction<OpFeatureEntry> getter) {
-            long sum = 0;
-
-            int numFeatures = mFeatures.size();
-            for (int i = 0; i < numFeatures; i++) {
-                sum += getter.applyAsLong(mFeatures.valueAt(i));
-            }
-
-            return sum;
-        }
-
         /**
-         * Return the last wall clock time  in milliseconds this op was accessed
-         * by the app for a given range of UID states.
+         * Return the last access time.
          *
-         * @param fromUidState The UID state for which to query. Could be one of
-         * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
-         * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
-         * @param toUidState The UID state for which to query.
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
+         * @param flags The op flags
          *
-         * @return the last foreground access time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+         * @return the last access time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
          *
          * @see #getLastAccessForegroundTime(int)
          * @see #getLastAccessBackgroundTime(int)
-         * @see #getLastAccessTime(int)
+         * @see #getLastAccessTime(int, int, int)
+         * @see OpFeatureEntry#getLastAccessTime(int)
          */
         public long getLastAccessTime(@OpFlags int flags) {
-            return getMaxOfFeatures(
-                    (featureEntry -> featureEntry.getLastAccessTime(flags)));
+            return getLastAccessTime(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
         }
 
         /**
-         * Return the last wall clock time in milliseconds this op was accessed
-         * by the app while in the foreground.
+         * Return the last foreground access time.
          *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the last foreground access time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+         * @param flags The op flags
          *
-         * @see #getLastAccessBackgroundTime(int)
+         * @return the last access time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
          * @see #getLastAccessTime(int)
+         * @see #getLastAccessBackgroundTime(int)
          * @see #getLastAccessTime(int, int, int)
+         * @see OpFeatureEntry#getLastAccessForegroundTime(int)
          */
         public long getLastAccessForegroundTime(@OpFlags int flags) {
-            return getMaxOfFeatures(
-                    (featureEntry -> featureEntry.getLastAccessForegroundTime(flags)));
+            return getLastAccessTime(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
+                    flags);
         }
 
         /**
-         * Return the last wall clock time in milliseconds this op was accessed
-         * by the app while in the background.
+         * Return the last background access time.
          *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the last foreground access time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+         * @param flags The op flags
          *
-         * @see #getLastAccessForegroundTime(int)
+         * @return the last access time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
          * @see #getLastAccessTime(int)
+         * @see #getLastAccessForegroundTime(int)
          * @see #getLastAccessTime(int, int, int)
+         * @see OpFeatureEntry#getLastAccessBackgroundTime(int)
          */
         public long getLastAccessBackgroundTime(@OpFlags int flags) {
-            return getMaxOfFeatures(
-                    (featureEntry -> featureEntry.getLastAccessBackgroundTime(flags)));
+            return getLastAccessTime(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
+                    flags);
         }
 
         /**
-         * Return the last wall clock time  in milliseconds this op was accessed
-         * by the app for a given range of UID states.
+         * Return the last access event.
          *
-         * @param fromUidState The UID state for which to query. Could be one of
-         * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
-         * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
-         * @param toUidState The UID state for which to query.
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
+         * @param flags The op flags
          *
-         * @return the last foreground access time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+         * @return the last access event of {@code null}
+         */
+        private @Nullable NoteOpEvent getLastAccessEvent(@UidState int fromUidState,
+                @UidState int toUidState, @OpFlags int flags) {
+            NoteOpEvent lastAccessEvent = null;
+            for (OpFeatureEntry featureEntry : mFeatures.values()) {
+                NoteOpEvent lastFeatureAccessEvent = featureEntry.getLastAccessEvent(fromUidState,
+                        toUidState, flags);
+
+                if (lastAccessEvent == null || (lastFeatureAccessEvent != null
+                        && lastFeatureAccessEvent.noteTime > lastAccessEvent.noteTime)) {
+                    lastAccessEvent = lastFeatureAccessEvent;
+                }
+            }
+
+            return lastAccessEvent;
+        }
+
+        /**
+         * Return the last access time.
          *
+         * @param fromUidState the lowest uid state to query
+         * @param toUidState the highest uid state to query (inclusive)
+         * @param flags The op flags
+         *
+         * @return the last access time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
+         * @see #getLastAccessTime(int)
          * @see #getLastAccessForegroundTime(int)
          * @see #getLastAccessBackgroundTime(int)
-         * @see #getLastAccessTime(int)
+         * @see OpFeatureEntry#getLastAccessTime(int, int, int)
          */
         public long getLastAccessTime(@UidState int fromUidState, @UidState int toUidState,
                 @OpFlags int flags) {
-            return getMaxOfFeatures(
-                    (featureEntry -> featureEntry.getLastAccessTime(fromUidState,
-                            toUidState, flags)));
+            NoteOpEvent lastEvent = getLastAccessEvent(fromUidState, toUidState, flags);;
+
+            if (lastEvent == null) {
+                return -1;
+            }
+
+            return lastEvent.noteTime;
         }
 
         /**
-         * @deprecated Use {@link OpEntry#getLastRejectTime(int)} instead
-         *
          * @hide
+         *
+         * @deprecated Use {@link #getLastRejectTime(int)} instead
          */
         @Deprecated
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@code "
@@ -3019,107 +3351,113 @@
         }
 
         /**
-         * Return the last wall clock time in milliseconds the app made an attempt
-         * to access this op but was rejected.
+         * Return the last rejection time.
          *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the last reject time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+         * @param flags The op flags
          *
-         * @see #getLastRejectBackgroundTime(int)
+         * @return the last rejection time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
          * @see #getLastRejectForegroundTime(int)
+         * @see #getLastRejectBackgroundTime(int)
          * @see #getLastRejectTime(int, int, int)
+         * @see OpFeatureEntry#getLastRejectTime(int)
          */
         public long getLastRejectTime(@OpFlags int flags) {
-            return getMaxOfFeatures(
-                    (featureEntry -> featureEntry.getLastRejectTime(flags)));
+            return getLastRejectTime(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
         }
 
         /**
-         * Return the last wall clock time in milliseconds the app made an attempt
-         * to access this op while in the foreground but was rejected.
+         * Return the last foreground rejection time.
          *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the last foreground reject time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+         * @param flags The op flags
          *
+         * @return the last rejection time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
+         * @see #getLastRejectTime(int)
          * @see #getLastRejectBackgroundTime(int)
          * @see #getLastRejectTime(int, int, int)
-         * @see #getLastRejectTime(int)
+         * @see OpFeatureEntry#getLastRejectForegroundTime(int)
          */
         public long getLastRejectForegroundTime(@OpFlags int flags) {
-            return getMaxOfFeatures(
-                    (featureEntry -> featureEntry.getLastRejectForegroundTime(flags)));
+            return getLastRejectTime(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
+                    flags);
         }
 
         /**
-         * Return the last wall clock time in milliseconds the app made an attempt
-         * to access this op while in the background but was rejected.
+         * Return the last background rejection time.
          *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the last background reject time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+         * @param flags The op flags
          *
+         * @return the last rejection time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
+         * @see #getLastRejectTime(int)
          * @see #getLastRejectForegroundTime(int)
          * @see #getLastRejectTime(int, int, int)
-         * @see #getLastRejectTime(int)
+         * @see OpFeatureEntry#getLastRejectBackgroundTime(int)
          */
         public long getLastRejectBackgroundTime(@OpFlags int flags) {
-            return getMaxOfFeatures(
-                    (featureEntry -> featureEntry.getLastRejectBackgroundTime(flags)));
+            return getLastRejectTime(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
+                    flags);
         }
 
         /**
-         * Return the last wall clock time state in milliseconds the app made an
-         * attempt to access this op for a given range of UID states.
+         * Return the last rejection event.
          *
-         * @param fromUidState The UID state from which to query. Could be one of
-         * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
-         * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
-         * @param toUidState The UID state to which to query.
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the last foreground access time in milliseconds since
-         * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+         * @param flags The op flags
          *
+         * @return the last reject event of {@code null}
+         */
+        private @Nullable NoteOpEvent getLastRejectEvent(@UidState int fromUidState,
+                @UidState int toUidState, @OpFlags int flags) {
+            NoteOpEvent lastAccessEvent = null;
+            for (OpFeatureEntry featureEntry : mFeatures.values()) {
+                NoteOpEvent lastFeatureAccessEvent = featureEntry.getLastRejectEvent(fromUidState,
+                        toUidState, flags);
+
+                if (lastAccessEvent == null || (lastFeatureAccessEvent != null
+                        && lastFeatureAccessEvent.noteTime > lastAccessEvent.noteTime)) {
+                    lastAccessEvent = lastFeatureAccessEvent;
+                }
+            }
+
+            return lastAccessEvent;
+        }
+
+        /**
+         * Return the last rejection time.
+         *
+         * @param fromUidState the lowest uid state to query
+         * @param toUidState the highest uid state to query (inclusive)
+         * @param flags The op flags
+         *
+         * @return the last rejection time (in milliseconds since epoch start (January 1, 1970
+         * 00:00:00.000 GMT - Gregorian)) or {@code -1}
+         *
+         * @see #getLastRejectTime(int)
          * @see #getLastRejectForegroundTime(int)
          * @see #getLastRejectBackgroundTime(int)
-         * @see #getLastRejectTime(int)
+         * @see #getLastRejectTime(int, int, int)
+         * @see OpFeatureEntry#getLastRejectTime(int, int, int)
          */
         public long getLastRejectTime(@UidState int fromUidState, @UidState int toUidState,
                 @OpFlags int flags) {
-            return getMaxOfFeatures(
-                    (featureEntry -> featureEntry.getLastRejectTime(fromUidState,
-                            toUidState, flags)));
+            NoteOpEvent lastEvent = getLastRejectEvent(fromUidState, toUidState, flags);
+            if (lastEvent == null) {
+                return -1;
+            }
+
+            return lastEvent.noteTime;
         }
 
         /**
          * @return Whether the operation is running.
          */
         public boolean isRunning() {
-            int numFeatures = mFeatures.size();
-            if (mFeatures.isEmpty()) {
-                return false;
-            }
-
-            for (int i = 0; i < numFeatures; i++) {
-                if (mFeatures.valueAt(i).mRunning) {
+            for (OpFeatureEntry opFeatureEntry : mFeatures.values()) {
+                if (opFeatureEntry.isRunning()) {
                     return true;
                 }
             }
@@ -3128,257 +3466,349 @@
         }
 
         /**
-         * @return The duration of the operation in milliseconds. The duration is in wall time.
+         * @deprecated Use {@link #getLastDuration(int)} instead
          */
+        @Deprecated
         public long getDuration() {
-            return getLastDuration(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL);
+            return getLastDuration(OP_FLAGS_ALL);
         }
 
         /**
-         * Return the duration in milliseconds the app accessed this op while
-         * in the foreground. The duration is in wall time.
+         * Return the duration in milliseconds of the last the access.
          *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the foreground access duration in milliseconds.
+         * @param flags The op flags
          *
-         * @see #getLastBackgroundDuration(int)
-         * @see #getLastDuration(int, int, int)
-         */
-        public long getLastForegroundDuration(@OpFlags int flags) {
-            return getSumOfFeatures((featureEntry) ->
-                    featureEntry.getLastForegroundDuration(flags));
-        }
-
-        /**
-         * Return the duration in milliseconds the app accessed this op while
-         * in the background. The duration is in wall time.
-         *
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the background access duration in milliseconds.
+         * @return the duration in milliseconds or {@code -1}
          *
          * @see #getLastForegroundDuration(int)
+         * @see #getLastBackgroundDuration(int)
          * @see #getLastDuration(int, int, int)
+         * @see OpFeatureEntry#getLastDuration(int)
          */
-        public long getLastBackgroundDuration(@OpFlags int flags) {
-            return getSumOfFeatures((featureEntry) ->
-                    featureEntry.getLastBackgroundDuration(flags));
+        public long getLastDuration(@OpFlags int flags) {
+            return getLastDuration(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
         }
 
         /**
-         * Return the duration in milliseconds the app accessed this op for
-         * a given range of UID states. The duration is in wall time.
+         * Return the duration in milliseconds of the last foreground access.
          *
-         * @param fromUidState The UID state for which to query. Could be one of
-         * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
-         * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
-         * @param toUidState The UID state for which to query.
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return the access duration in milliseconds.
+         * @param flags The op flags
+         *
+         * @return the duration in milliseconds or {@code -1}
+         *
+         * @see #getLastDuration(int)
+         * @see #getLastBackgroundDuration(int)
+         * @see #getLastDuration(int, int, int)
+         * @see OpFeatureEntry#getLastForegroundDuration(int)
+         */
+        public long getLastForegroundDuration(@OpFlags int flags) {
+            return getLastDuration(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
+                    flags);
+        }
+
+        /**
+         * Return the duration in milliseconds of the last background access.
+         *
+         * @param flags The op flags
+         *
+         * @return the duration in milliseconds or {@code -1}
+         *
+         * @see #getLastDuration(int)
+         * @see #getLastForegroundDuration(int)
+         * @see #getLastDuration(int, int, int)
+         * @see OpFeatureEntry#getLastBackgroundDuration(int)
+         */
+        public long getLastBackgroundDuration(@OpFlags int flags) {
+            return getLastDuration(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
+                    flags);
+        }
+
+        /**
+         * Return the duration in milliseconds of the last access.
+         *
+         * @param fromUidState The lowest UID state for which to query
+         * @param toUidState The highest UID state for which to query (inclusive)
+         * @param flags The op flags
+         *
+         * @return the duration in milliseconds or {@code -1}
+         *
+         * @see #getLastDuration(int)
+         * @see #getLastForegroundDuration(int)
+         * @see #getLastBackgroundDuration(int)
+         * @see OpFeatureEntry#getLastDuration(int, int, int)
          */
         public long getLastDuration(@UidState int fromUidState, @UidState int toUidState,
                 @OpFlags int flags) {
-            return getSumOfFeatures((featureEntry) ->
-                    featureEntry.getLastDuration(fromUidState, toUidState, flags));
-        }
-
-        /**
-         * Like {@link #findFirstNonNegativeForFlagsInStates(LongSparseLongArray, int, int, int)}
-         * but for all proxy uid in all features.
-         */
-        private long findFirstNonNegativeProxyUidInFeatureStates(@UidState int beginUidState,
-                @UidState int endUidState, @OpFlags int flags) {
-            int numFeatures = mFeatures.size();
-
-            if (numFeatures == 0) {
+            NoteOpEvent lastEvent = getLastAccessEvent(fromUidState, toUidState, flags);
+            if (lastEvent == null) {
                 return -1;
             }
 
-            while (flags != 0) {
-                final int flag = 1 << Integer.numberOfTrailingZeros(flags);
-                flags &= ~flag;
-                for (int uidState : UID_STATES) {
-                    if (uidState < beginUidState || uidState > endUidState) {
-                        continue;
-                    }
-
-                    final long key = makeKey(uidState, flag);
-
-                    for (int i = 0; i < numFeatures; i++) {
-                        OpFeatureEntry featureEntry = mFeatures.valueAt(i);
-
-                        if (featureEntry.mProxyUids == null) {
-                            continue;
-                        }
-
-                        final long proxyUid = featureEntry.mProxyUids.get(key);
-                        if (proxyUid >= 0) {
-                            return proxyUid;
-                        }
-                    }
-                }
-            }
-
-            return -1;
+            return lastEvent.duration;
         }
 
         /**
-         * Like {@link #findFirstNonNullForFlagsInStates(LongSparseArray, int, int, int)} but
-         * for all proxyPackageNames in all features.
-         */
-        private @Nullable String findFirstNonNullProxyPackageNameInFeatureStates(
-                @OpFlags int flags, @UidState int beginUidState, @UidState int endUidState) {
-            int numFeatures = mFeatures.size();
-
-            if (numFeatures == 0) {
-                return null;
-            }
-
-            while (flags != 0) {
-                final int flag = 1 << Integer.numberOfTrailingZeros(flags);
-                flags &= ~flag;
-                for (int uidState : UID_STATES) {
-                    if (uidState < beginUidState || uidState > endUidState) {
-                        continue;
-                    }
-                    final long key = makeKey(uidState, flag);
-
-                    for (int i = 0; i < numFeatures; i++) {
-                        OpFeatureEntry featureEntry = mFeatures.valueAt(i);
-
-                        if (featureEntry.mProxyPackageNames == null) {
-                            continue;
-                        }
-
-                        final String proxyName = featureEntry.mProxyPackageNames.get(key);
-                        if (proxyName != null) {
-                            return proxyName;
-                        }
-                    }
-                }
-            }
-            return null;
-        }
-
-        /**
-         * @deprecated Use {@link #getProxyUid(int, int)} instead
+         * @deprecated Use {@link #getLastProxyInfo(int)} instead
          */
         @Deprecated
         public int getProxyUid() {
-            return (int) findFirstNonNegativeProxyUidInFeatureStates(MAX_PRIORITY_UID_STATE,
-                    MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL);
+            OpEventProxyInfo proxy = getLastProxyInfo(OP_FLAGS_ALL);
+            if (proxy == null) {
+                return Process.INVALID_UID;
+            }
+
+            return proxy.getUid();
         }
 
         /**
-         * Gets the UID of the app that performed the op on behalf of this app and
-         * as a result blamed the op on this app or {@link Process#INVALID_UID} if
-         * there is no proxy.
-         *
-         * @param uidState The UID state for which to query. Could be one of
-         * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
-         * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         *
-         * @return The proxy UID.
+         * @deprecated Use {@link #getLastProxyInfo(int)} instead
          */
+        @Deprecated
         public int getProxyUid(@UidState int uidState, @OpFlags int flags) {
-            return (int) findFirstNonNegativeProxyUidInFeatureStates(uidState, uidState, flags);
+            OpEventProxyInfo proxy = getLastProxyInfo(uidState, uidState, flags);
+            if (proxy == null) {
+                return Process.INVALID_UID;
+            }
+
+            return proxy.getUid();
         }
 
         /**
-         * @deprecated Use {@link #getProxyPackageName(int, int)} instead
+         * @deprecated Use {@link #getLastProxyInfo(int)} instead
          */
         @Deprecated
         public @Nullable String getProxyPackageName() {
-            return findFirstNonNullProxyPackageNameInFeatureStates(MAX_PRIORITY_UID_STATE,
-                    MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL);
+            OpEventProxyInfo proxy = getLastProxyInfo(OP_FLAGS_ALL);
+            if (proxy == null) {
+                return null;
+            }
+
+            return proxy.getPackageName();
         }
 
         /**
-         * Gets the package name of the app that performed the op on behalf of this
-         * app and as a result blamed the op on this app for a UID state or
-         * {@code null} if there is no proxy.
-         *
-         * @param uidState The UID state for which to query. Could be one of
-         * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
-         * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
-         * @param flags The flags which are any combination of
-         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
-         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
-         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
-         * for any flag.
-         * @return The proxy package name.
+         * @deprecated Use {@link #getLastProxyInfo(int)} instead
          */
+        @Deprecated
         public @Nullable String getProxyPackageName(@UidState int uidState, @OpFlags int flags) {
-            return findFirstNonNullProxyPackageNameInFeatureStates(uidState, uidState, flags);
+            OpEventProxyInfo proxy = getLastProxyInfo(uidState, uidState, flags);
+            if (proxy == null) {
+                return null;
+            }
+
+            return proxy.getPackageName();
         }
 
         /**
-         * Create OpEntry from parcel.
+         * Gets the proxy info of the app that performed the last access on behalf of this app and
+         * as a result blamed the op on this app.
          *
+         * @param flags The op flags
+         *
+         * @return The proxy name or {@code null}
+         *
+         * @see #getLastForegroundProxyInfo(int)
+         * @see #getLastBackgroundProxyInfo(int)
+         * @see #getLastProxyInfo(int, int, int)
+         * @see OpFeatureEntry#getLastProxyInfo(int)
+         */
+        public @Nullable OpEventProxyInfo getLastProxyInfo(@OpFlags int flags) {
+            return getLastProxyInfo(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
+        }
+
+        /**
+         * Gets the proxy info of the app that performed the last foreground access on behalf of
+         * this app and as a result blamed the op on this app.
+         *
+         * @param flags The op flags
+         *
+         * @return The proxy name or {@code null}
+         *
+         * @see #getLastProxyInfo(int)
+         * @see #getLastBackgroundProxyInfo(int)
+         * @see #getLastProxyInfo(int, int, int)
+         * @see OpFeatureEntry#getLastForegroundProxyInfo(int)
+         */
+        public @Nullable OpEventProxyInfo getLastForegroundProxyInfo(@OpFlags int flags) {
+            return getLastProxyInfo(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
+                    flags);
+        }
+
+        /**
+         * Gets the proxy info of the app that performed the last background access on behalf of
+         * this app and as a result blamed the op on this app.
+         *
+         * @param flags The op flags
+         *
+         * @return The proxy name or {@code null}
+         *
+         * @see #getLastProxyInfo(int)
+         * @see #getLastForegroundProxyInfo(int)
+         * @see #getLastProxyInfo(int, int, int)
+         * @see OpFeatureEntry#getLastBackgroundProxyInfo(int)
+         */
+        public @Nullable OpEventProxyInfo getLastBackgroundProxyInfo(@OpFlags int flags) {
+            return getLastProxyInfo(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
+                    flags);
+        }
+
+        /**
+         * Gets the proxy info of the app that performed the last access on behalf of this app and
+         * as a result blamed the op on this app.
+         *
+         * @param fromUidState The lowest UID state for which to query
+         * @param toUidState The highest UID state for which to query (inclusive)
+         * @param flags The op flags
+         *
+         * @return The proxy name or {@code null}
+         *
+         * @see #getLastProxyInfo(int)
+         * @see #getLastForegroundProxyInfo(int)
+         * @see #getLastBackgroundProxyInfo(int)
+         * @see OpFeatureEntry#getLastProxyInfo(int, int, int)
+         */
+        public @Nullable OpEventProxyInfo getLastProxyInfo(@UidState int fromUidState,
+                @UidState int toUidState, @OpFlags int flags) {
+            NoteOpEvent lastEvent = getLastAccessEvent(fromUidState, toUidState, flags);
+            if (lastEvent == null) {
+                return null;
+            }
+
+            return lastEvent.proxy;
+        }
+
+
+
+        // Code below generated by codegen v1.0.14.
+        //
+        // DO NOT MODIFY!
+        // CHECKSTYLE:OFF Generated code
+        //
+        // To regenerate run:
+        // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/AppOpsManager.java
+        //
+        // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+        //   Settings > Editor > Code Style > Formatter Control
+        //@formatter:off
+
+
+        /**
+         * Creates a new OpEntry.
+         *
+         * @param op
+         *   The code of the op
+         * @param mode
+         *   The mode of the op
+         * @param features
+         *   The features that have been used when checking the op
          * @hide
          */
-        public static OpEntry createFromParcel(@NonNull Parcel source) {
-            int op = source.readInt();
-            int mode = source.readInt();
+        @DataClass.Generated.Member
+        public OpEntry(
+                @IntRange(from = 0, to = _NUM_OP - 1) int op,
+                @Mode int mode,
+                @NonNull Map<String,OpFeatureEntry> features) {
+            this.mOp = op;
+            com.android.internal.util.AnnotationValidations.validate(
+                    IntRange.class, null, mOp,
+                    "from", 0,
+                    "to", _NUM_OP - 1);
+            this.mMode = mode;
+            com.android.internal.util.AnnotationValidations.validate(
+                    Mode.class, null, mMode);
+            this.mFeatures = features;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mFeatures);
 
-            int numFeatures = source.readInt();
-            Pair<String, OpFeatureEntry.Builder>[] features = new Pair[numFeatures];
-            for (int i = 0; i < numFeatures; i++) {
-                features[i] = new Pair<>(source.readString(),
-                        OpFeatureEntry.createFromParcel(source));
-            }
+            // onConstructed(); // You can define this method to get a callback
+        }
 
-            return new OpEntry(op, mode, features);
+        /**
+         * The mode of the op
+         */
+        @DataClass.Generated.Member
+        public @Mode int getMode() {
+            return mMode;
+        }
+
+        /**
+         * The features that have been used when checking the op
+         */
+        @DataClass.Generated.Member
+        public @NonNull Map<String,OpFeatureEntry> getFeatures() {
+            return mFeatures;
         }
 
         @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
+        @DataClass.Generated.Member
         public void writeToParcel(Parcel dest, int flags) {
+            // You can override field parcelling by defining methods like:
+            // void parcelFieldName(Parcel dest, int flags) { ... }
+
             dest.writeInt(mOp);
             dest.writeInt(mMode);
-
-            int numFeatures = mFeatures.size();
-            dest.writeInt(numFeatures);
-            for (int i = 0; i < numFeatures; i++) {
-                dest.writeString(mFeatures.keyAt(i));
-                mFeatures.valueAt(i).writeToParcel(dest, flags);
-            }
+            dest.writeMap(mFeatures);
         }
 
-        public static final @NonNull Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
+        @Override
+        @DataClass.Generated.Member
+        public int describeContents() { return 0; }
+
+        /** @hide */
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        @DataClass.Generated.Member
+        /* package-private */ OpEntry(@NonNull Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            int op = in.readInt();
+            int mode = in.readInt();
+            Map<String,OpFeatureEntry> features = new java.util.LinkedHashMap<>();
+            in.readMap(features, OpFeatureEntry.class.getClassLoader());
+
+            this.mOp = op;
+            com.android.internal.util.AnnotationValidations.validate(
+                    IntRange.class, null, mOp,
+                    "from", 0,
+                    "to", _NUM_OP - 1);
+            this.mMode = mode;
+            com.android.internal.util.AnnotationValidations.validate(
+                    Mode.class, null, mMode);
+            this.mFeatures = features;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mFeatures);
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @DataClass.Generated.Member
+        public static final @NonNull Parcelable.Creator<OpEntry> CREATOR
+                = new Parcelable.Creator<OpEntry>() {
             @Override
-            public @NonNull OpEntry createFromParcel(@NonNull Parcel parcel) {
-                return OpEntry.createFromParcel(parcel);
+            public OpEntry[] newArray(int size) {
+                return new OpEntry[size];
             }
 
             @Override
-            public @NonNull OpEntry[] newArray(int size) {
-                return new OpEntry[size];
+            public OpEntry createFromParcel(@NonNull Parcel in) {
+                return new OpEntry(in);
             }
         };
+
+        /*
+        @DataClass.Generated(
+                time = 1574809856259L,
+                codegenVersion = "1.0.14",
+                sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
+                inputSignatures = "private final @android.annotation.IntRange(from=0L, to=_NUM_OP - 1) int mOp\nprivate final @android.app.Mode int mMode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,android.app.OpFeatureEntry> mFeatures\npublic @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getOpStr()}\") int getOp()\npublic @android.annotation.NonNull java.lang.String getOpStr()\npublic @java.lang.Deprecated @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getAccessTime(int, int)}\") long getTime()\npublic @java.lang.Deprecated long getLastAccessTime(int)\npublic @java.lang.Deprecated long getLastAccessForegroundTime(int)\npublic @java.lang.Deprecated long getLastAccessBackgroundTime(int)\npublic @java.lang.Deprecated long getLastAccessTime(int,int,int)\npublic @java.lang.Deprecated @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getLastRejectTime(int, int, int)}\") long getRejectTime()\npublic @java.lang.Deprecated long getLastRejectTime(int)\npublic @java.lang.Deprecated long getLastRejectForegroundTime(int)\npublic @java.lang.Deprecated long getLastRejectBackgroundTime(int)\npublic @java.lang.Deprecated long getLastRejectTime(int,int,int)\npublic  long getAccessTime(int,int)\npublic  long getRejectTime(int,int)\npublic  boolean isRunning()\nprivate  android.app.NoteOpEvent getLastAccessEvent(int,int,int)\npublic @java.lang.Deprecated long getDuration()\npublic @java.lang.Deprecated long getLastForegroundDuration(int)\npublic @java.lang.Deprecated long getLastBackgroundDuration(int)\npublic @java.lang.Deprecated long getLastDuration(int,int,int)\npublic @java.lang.Deprecated int getProxyUid()\npublic @java.lang.Deprecated @android.annotation.Nullable java.lang.String getProxyPackageName()\nprivate @android.app.UidState int getLastAccessUidStateForFlagsInStatesOfAllFeatures(int,int,int)\npublic @android.app.UidState int getLastAccessUidState(int)\npublic @android.app.UidState int getLastForegroundAccessUidState(int)\npublic @android.app.UidState int getLastBackgroundAccessUidState(int)\nprivate @android.app.UidState int getLastRejectUidStateForFlagsInStatesOfAllFeatures(int,int,int)\npublic @android.app.UidState int getLastRejectUidState(int)\npublic @android.app.UidState int getLastForegroundRejectUidState(int)\npublic @android.app.UidState int getLastBackgroundRejectUidState(int)\npublic  long getDuration(int,int)\npublic  int getProxyUid(int,int)\nprivate  int getProxyUid(int,int,int)\npublic @android.annotation.Nullable java.lang.String getProxyPackageName(int,int)\nprivate @android.annotation.Nullable java.lang.String getProxyPackageName(int,int,int)\nclass OpEntry extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+        @Deprecated
+        private void __metadata() {}
+         */
+
+
+        //@formatter:on
+        // End of generated code
+
     }
 
     /** @hide */
@@ -4890,71 +5320,6 @@
     }
 
     /**
-     * Finds the first non-negative value for the given flags in between the begin and
-     * end UID states.
-     *
-     * @param counts The data array.
-     * @param beginUidState The beginning UID state (inclusive).
-     * @param endUidState The end UID state (inclusive).
-     * @param flags The UID flags.
-     * @return The non-negative value or -1.
-     */
-    private static long findFirstNonNegativeForFlagsInStates(@Nullable LongSparseLongArray counts,
-            @UidState int beginUidState, @UidState int endUidState, @OpFlags int flags) {
-        if (counts == null) {
-            return -1;
-        }
-        while (flags != 0) {
-            final int flag = 1 << Integer.numberOfTrailingZeros(flags);
-            flags &= ~flag;
-            for (int uidState : UID_STATES) {
-                if (uidState < beginUidState || uidState > endUidState) {
-                    continue;
-                }
-                final long key = makeKey(uidState, flag);
-                final long value = counts.get(key);
-                if (value >= 0) {
-                    return value;
-                }
-            }
-        }
-        return -1;
-    }
-
-    /**
-     * Finds the first non-null value for the given flags in between the begin and
-     * end UID states.
-     *
-     * @param counts The data array.
-     * @param beginUidState The beginning UID state (inclusive).
-     * @param endUidState The end UID state (inclusive).
-     * @param flags The UID flags.
-     * @return The non-negative value or -1.
-     */
-    private static @Nullable String findFirstNonNullForFlagsInStates(
-            @Nullable LongSparseArray<String> counts, @UidState int beginUidState,
-            @UidState int endUidState, @OpFlags int flags) {
-        if (counts == null) {
-            return null;
-        }
-        while (flags != 0) {
-            final int flag = 1 << Integer.numberOfTrailingZeros(flags);
-            flags &= ~flag;
-            for (int uidState : UID_STATES) {
-                if (uidState < beginUidState || uidState > endUidState) {
-                    continue;
-                }
-                final long key = makeKey(uidState, flag);
-                final String value = counts.get(key);
-                if (value != null) {
-                    return value;
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
      * Callback for notification of changes to operation state.
      */
     public interface OnOpChangedListener {
@@ -5112,6 +5477,7 @@
      *
      * @hide
      */
+    @TestApi
     @SystemApi
     @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
     public @NonNull List<AppOpsManager.PackageOps> getOpsForPackage(int uid,
@@ -6135,22 +6501,28 @@
         }
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
+    /**
+     * @deprecated Use own local {@link android.os.Binder#Binder()}
+     *
+     * @hide
+     */
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Create own "
+            + "local {@link android.os.Binder}")
     public static IBinder getToken(IAppOpsService service) {
-        synchronized (AppOpsManager.class) {
-            if (sToken != null) {
-                return sToken;
-            }
-            try {
-                sToken = service.getToken(new Binder());
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-            return sToken;
-        }
+        return getClientId();
     }
 
+    /** @hide */
+    public static IBinder getClientId() {
+        synchronized (AppOpsManager.class) {
+            if (sClientId == null) {
+                sClientId = new Binder();
+            }
+
+            return sClientId;
+        }
+    }
 
     /**
      * @deprecated use {@link #startOp(String, int, String, String, String)} instead
@@ -6207,7 +6579,7 @@
      * the package is not in the passed in UID.
      */
     public int startOp(@NonNull String op, int uid, @Nullable String packageName,
-            @NonNull String featureId, @Nullable String message) {
+            @Nullable String featureId, @Nullable String message) {
         return startOp(strOpToOp(op), uid, packageName, false, featureId, message);
     }
 
@@ -6231,7 +6603,7 @@
      * @hide
      */
     public int startOp(int op, int uid, @Nullable String packageName, boolean startIfModeDefault,
-            @NonNull String featureId, @Nullable String message) {
+            @Nullable String featureId, @Nullable String message) {
         final int mode = startOpNoThrow(op, uid, packageName, startIfModeDefault, featureId,
                 message);
         if (mode == MODE_ERRORED) {
@@ -6307,7 +6679,7 @@
     public int startOpNoThrow(int op, int uid, @NonNull String packageName,
             boolean startIfModeDefault, @Nullable String featureId, @Nullable String message) {
         try {
-            int mode = mService.startOperation(getToken(mService), op, uid, packageName,
+            int mode = mService.startOperation(getClientId(), op, uid, packageName,
                     featureId, startIfModeDefault);
             if (mode == MODE_ALLOWED) {
                 markAppOpNoted(uid, packageName, op, featureId, message);
@@ -6367,7 +6739,7 @@
     public void finishOp(int op, int uid, @NonNull String packageName,
             @Nullable String featureId) {
         try {
-            mService.finishOperation(getToken(mService), op, uid, packageName, featureId);
+            mService.finishOperation(getClientId(), op, uid, packageName, featureId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -6932,22 +7304,23 @@
     }
 
     /**
-     * Computes the max for the given flags in between the begin and
-     * end UID states.
+     * Gets the last of the event.
      *
-     * @param counts The data array.
-     * @param flags The UID flags.
-     * @param beginUidState The beginning UID state (exclusive).
-     * @param endUidState The end UID state.
-     * @return The sum.
+     * @param events The events
+     * @param flags The UID flags
+     * @param beginUidState The maximum UID state (inclusive)
+     * @param endUidState The minimum UID state (inclusive)
+     *
+     * @return The last event of {@code null}
      */
-    private static long maxForFlagsInStates(@Nullable LongSparseLongArray counts,
-            @UidState int beginUidState, @UidState int endUidState,
-            @OpFlags int flags) {
-        if (counts == null) {
-            return 0;
+    private static @Nullable NoteOpEvent getLastEvent(
+            @Nullable LongSparseArray<NoteOpEvent> events, @UidState int beginUidState,
+            @UidState int endUidState, @OpFlags int flags) {
+        if (events == null) {
+            return null;
         }
-        long max = 0;
+
+        NoteOpEvent lastEvent = null;
         while (flags != 0) {
             final int flag = 1 << Integer.numberOfTrailingZeros(flags);
             flags &= ~flag;
@@ -6956,12 +7329,16 @@
                     continue;
                 }
                 final long key = makeKey(uidState, flag);
-                max = Math.max(max, counts.get(key));
+
+                NoteOpEvent event = events.get(key);
+                if (lastEvent == null || event != null && event.noteTime > lastEvent.noteTime) {
+                    lastEvent = event;
+                }
             }
         }
-        return max;
-    }
 
+        return lastEvent;
+    }
 
     private static void writeLongSparseLongArrayToParcel(
             @Nullable LongSparseLongArray array, @NonNull Parcel parcel) {
@@ -6990,33 +7367,6 @@
         return array;
     }
 
-    private static void writeLongSparseStringArrayToParcel(
-            @Nullable LongSparseArray<String> array, @NonNull Parcel parcel) {
-        if (array != null) {
-            final int size = array.size();
-            parcel.writeInt(size);
-            for (int i = 0; i < size; i++) {
-                parcel.writeLong(array.keyAt(i));
-                parcel.writeString(array.valueAt(i));
-            }
-        } else {
-            parcel.writeInt(-1);
-        }
-    }
-
-    private static @Nullable LongSparseArray<String> readLongSparseStringArrayFromParcel(
-            @NonNull Parcel parcel) {
-        final int size = parcel.readInt();
-        if (size < 0) {
-            return null;
-        }
-        final LongSparseArray<String> array = new LongSparseArray<>(size);
-        for (int i = 0; i < size; i++) {
-            array.append(parcel.readLong(), parcel.readString());
-        }
-        return array;
-    }
-
     /**
      * Collects the keys from an array to the result creating the result if needed.
      *
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/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java
index 958ebae..0e1f921 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -285,7 +285,7 @@
             time = 1571327470155L,
             codegenVersion = "1.0.9",
             sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
-            inputSignatures = "private final @android.annotation.IntRange(from=0L, to=91L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mNotingPackageName\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
+            inputSignatures = "private final @android.annotation.IntRange(from=0L, to=92L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mNotingPackageName\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
     @Deprecated
     private void __metadata() {}
 
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/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/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 85424119..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;
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/content/pm/DataLoaderParams.java b/core/java/android/content/pm/DataLoaderParams.java
index b163861..af4b99a 100644
--- a/core/java/android/content/pm/DataLoaderParams.java
+++ b/core/java/android/content/pm/DataLoaderParams.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.ParcelFileDescriptor;
 
 import java.util.Arrays;
@@ -26,9 +27,12 @@
 
 /**
  * This class represents the parameters used to configure an Incremental Data Loader.
- * Hide for now.
+ *
+ * WARNING: This is a system API to aid internal development.
+ * Use at your own risk. It will change or be removed without warning.
  * @hide
  */
+@SystemApi
 public class DataLoaderParams {
     @NonNull private final DataLoaderParamsParcel mData;
 
@@ -52,6 +56,9 @@
         mData = data;
     }
 
+    /**
+     * @hide
+     */
     public DataLoaderParams(@NonNull DataLoaderParamsParcel data) {
         mData = data;
     }
@@ -70,6 +77,9 @@
         return mData.packageName;
     }
 
+    /**
+     * @hide
+     */
     public final @NonNull DataLoaderParamsParcel getData() {
         return mData;
     }
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/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 218c876..1d07ec7 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;
@@ -1082,8 +1082,12 @@
          * @throws SecurityException if called after the session has been
          *             sealed or abandoned
          * @throws IllegalStateException if called for non-callback session
+         *
+         * WARNING: This is a system API to aid internal development.
+         * Use at your own risk. It will change or be removed without warning.
          * {@hide}
          */
+        @SystemApi
         public void addFile(@NonNull String name, long lengthBytes, @NonNull byte[] metadata) {
             try {
                 mSession.addFile(name, lengthBytes, metadata);
@@ -1857,9 +1861,11 @@
 
         /**
          * Set Incremental data loader params.
-         *
+         * WARNING: This is a system API to aid internal development.
+         * Use at your own risk. It will change or be removed without warning.
          * {@hide}
          */
+        @SystemApi
         @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
         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..ee27f4f 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;
@@ -3243,6 +3243,15 @@
     public static final int FLAG_PERMISSION_REVOKED_COMPAT =  FLAG_PERMISSION_REVOKE_ON_UPGRADE;
 
     /**
+     * Permission flag: The permission is one-time and should be revoked automatically on app
+     * inactivity
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int FLAG_PERMISSION_ONE_TIME = 1 << 16;
+
+    /**
      * Permission flags: Bitwise or of all permission flags allowing an
      * exemption for a restricted permission.
      * @hide
@@ -3283,7 +3292,8 @@
             | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT
             | FLAG_PERMISSION_APPLY_RESTRICTION
             | FLAG_PERMISSION_GRANTED_BY_ROLE
-            | FLAG_PERMISSION_REVOKED_COMPAT;
+            | FLAG_PERMISSION_REVOKED_COMPAT
+            | FLAG_PERMISSION_ONE_TIME;
 
     /**
      * Injected activity in app that forwards user to setting activity of that app.
@@ -4063,7 +4073,8 @@
             FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT,
             FLAG_PERMISSION_APPLY_RESTRICTION,
             FLAG_PERMISSION_GRANTED_BY_ROLE,
-            FLAG_PERMISSION_REVOKED_COMPAT
+            FLAG_PERMISSION_REVOKED_COMPAT,
+            FLAG_PERMISSION_ONE_TIME
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface PermissionFlags {}
@@ -7164,6 +7175,7 @@
             case FLAG_PERMISSION_APPLY_RESTRICTION: return "APPLY_RESTRICTION";
             case FLAG_PERMISSION_GRANTED_BY_ROLE: return "GRANTED_BY_ROLE";
             case FLAG_PERMISSION_REVOKED_COMPAT: return "REVOKED_COMPAT";
+            case FLAG_PERMISSION_ONE_TIME: return "ONE_TIME";
             default: return Integer.toString(flag);
         }
     }
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..a0f089b 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;
@@ -248,6 +248,17 @@
     @TestApi
     public static final int PROTECTION_FLAG_TELEPHONY = 0x400000;
 
+    /**
+     * Additional flag for {@link #protectionLevel}, corresponding
+     * to the <code>companion</code> value of
+     * {@link android.R.attr#protectionLevel}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final int PROTECTION_FLAG_COMPANION = 0x800000;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = {
             PROTECTION_FLAG_PRIVILEGED,
@@ -270,6 +281,7 @@
             PROTECTION_FLAG_INCIDENT_REPORT_APPROVER,
             PROTECTION_FLAG_APP_PREDICTOR,
             PROTECTION_FLAG_TELEPHONY,
+            PROTECTION_FLAG_COMPANION,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ProtectionFlags {}
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/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 39c1dac..f7137705 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -782,59 +782,42 @@
     private void enforceStrictGrammar(@Nullable String selection, @Nullable String groupBy,
             @Nullable String having, @Nullable String sortOrder, @Nullable String limit) {
         SQLiteTokenizer.tokenize(selection, SQLiteTokenizer.OPTION_NONE,
-                this::enforceStrictGrammarWhereHaving);
+                this::enforceStrictToken);
         SQLiteTokenizer.tokenize(groupBy, SQLiteTokenizer.OPTION_NONE,
-                this::enforceStrictGrammarGroupBy);
+                this::enforceStrictToken);
         SQLiteTokenizer.tokenize(having, SQLiteTokenizer.OPTION_NONE,
-                this::enforceStrictGrammarWhereHaving);
+                this::enforceStrictToken);
         SQLiteTokenizer.tokenize(sortOrder, SQLiteTokenizer.OPTION_NONE,
-                this::enforceStrictGrammarOrderBy);
+                this::enforceStrictToken);
         SQLiteTokenizer.tokenize(limit, SQLiteTokenizer.OPTION_NONE,
-                this::enforceStrictGrammarLimit);
+                this::enforceStrictToken);
     }
 
-    private void enforceStrictGrammarWhereHaving(@NonNull String token) {
+    private void enforceStrictToken(@NonNull String token) {
         if (isTableOrColumn(token)) return;
         if (SQLiteTokenizer.isFunction(token)) return;
         if (SQLiteTokenizer.isType(token)) return;
 
-        // NOTE: we explicitly don't allow SELECT subqueries, since they could
-        // leak data that should have been filtered by the trusted where clause
+        // Carefully block any tokens that are attempting to jump across query
+        // clauses or create subqueries, since they could leak data that should
+        // have been filtered by the trusted where clause
+        boolean isAllowedKeyword = SQLiteTokenizer.isKeyword(token);
         switch (token.toUpperCase(Locale.US)) {
-            case "AND": case "AS": case "BETWEEN": case "BINARY":
-            case "CASE": case "CAST": case "COLLATE": case "DISTINCT":
-            case "ELSE": case "END": case "ESCAPE": case "EXISTS":
-            case "GLOB": case "IN": case "IS": case "ISNULL":
-            case "LIKE": case "MATCH": case "NOCASE": case "NOT":
-            case "NOTNULL": case "NULL": case "OR": case "REGEXP":
-            case "RTRIM": case "THEN": case "WHEN":
-                return;
+            case "SELECT":
+            case "FROM":
+            case "WHERE":
+            case "GROUP":
+            case "HAVING":
+            case "WINDOW":
+            case "VALUES":
+            case "ORDER":
+            case "LIMIT":
+                isAllowedKeyword = false;
+                break;
         }
-        throw new IllegalArgumentException("Invalid token " + token);
-    }
-
-    private void enforceStrictGrammarGroupBy(@NonNull String token) {
-        if (isTableOrColumn(token)) return;
-        throw new IllegalArgumentException("Invalid token " + token);
-    }
-
-    private void enforceStrictGrammarOrderBy(@NonNull String token) {
-        if (isTableOrColumn(token)) return;
-        switch (token.toUpperCase(Locale.US)) {
-            case "COLLATE": case "ASC": case "DESC":
-            case "BINARY": case "RTRIM": case "NOCASE":
-            case "LOCALIZED": case "UNICODE":
-                return;
+        if (!isAllowedKeyword) {
+            throw new IllegalArgumentException("Invalid token " + token);
         }
-        throw new IllegalArgumentException("Invalid token " + token);
-    }
-
-    private void enforceStrictGrammarLimit(@NonNull String token) {
-        switch (token.toUpperCase(Locale.US)) {
-            case "OFFSET":
-                return;
-        }
-        throw new IllegalArgumentException("Invalid token " + token);
     }
 
     /**
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/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl
index dd2c0d4..848b6d5 100644
--- a/core/java/android/nfc/INfcCardEmulation.aidl
+++ b/core/java/android/nfc/INfcCardEmulation.aidl
@@ -39,4 +39,5 @@
     boolean setPreferredService(in ComponentName service);
     boolean unsetPreferredService();
     boolean supportsAidPrefixRegistration();
+    ApduServiceInfo getPreferredPaymentService(int userHandle);
 }
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..d320f61 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;
@@ -164,6 +164,18 @@
             "android.nfc.action.TRANSACTION_DETECTED";
 
     /**
+     * Broadcast Action: Intent to notify if the preferred payment service changed.
+     *
+     * <p>This intent will only be sent to the application has requested permission for
+     * {@link android.Manifest.permission#NFC_PREFERRED_PAYMENT_INFO} and if the application
+     * has the necessary access to Secure Element which witnessed the particular event.
+     */
+    @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO)
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PREFERRED_PAYMENT_CHANGED =
+            "android.nfc.action.PREFERRED_PAYMENT_CHANGED";
+
+    /**
      * Broadcast to only the activity that handles ACTION_TAG_DISCOVERED
      * @hide
      */
@@ -231,6 +243,17 @@
      */
     public static final String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME";
 
+    /**
+     * Mandatory String extra field in {@link #ACTION_PREFERRED_PAYMENT_CHANGED}
+     * Indicates the condition when trigger this event.
+     */
+    public static final String EXTRA_PREFERRED_PAYMENT_CHANGED_REASON =
+            "android.nfc.extra.PREFERRED_PAYMENT_CHANGED_REASON";
+
+    public static final int PREFERRED_PAYMENT_LOADED = 1;
+    public static final int PREFERRED_PAYMENT_CHANGED = 2;
+    public static final int PREFERRED_PAYMENT_UPDATED = 3;
+
     public static final int STATE_OFF = 1;
     public static final int STATE_TURNING_ON = 2;
     public static final int STATE_ON = 3;
@@ -1410,7 +1433,7 @@
     /**
      * Enable foreground dispatch to the given Activity.
      *
-     * <p>This will give give priority to the foreground activity when
+     * <p>This will give priority to the foreground activity when
      * dispatching a discovered {@link Tag} to an application.
      *
      * <p>If any IntentFilters are provided to this method they are used to match dispatch Intents
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/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index aa93611..f1c74a6 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -17,6 +17,7 @@
 package android.nfc.cardemulation;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -657,6 +658,109 @@
     }
 
     /**
+     * Retrieves the registered AIDs for the preferred payment service.
+     *
+     * @return The list of AIDs registered for this category, or null if it couldn't be found.
+     */
+    @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO)
+    @Nullable
+    public List<String> getAidsForPreferredPaymentService() {
+        try {
+            ApduServiceInfo serviceInfo = sService.getPreferredPaymentService(mContext.getUserId());
+            return (serviceInfo != null ? serviceInfo.getAids() : null);
+        } catch (RemoteException e) {
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return null;
+            }
+            try {
+                ApduServiceInfo serviceInfo =
+                        sService.getPreferredPaymentService(mContext.getUserId());
+                return (serviceInfo != null ? serviceInfo.getAids() : null);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return null;
+            }
+        }
+    }
+
+    /**
+     * Retrieves the route destination for the preferred payment service.
+     *
+     * @return The route destination secure element name of the preferred payment service.
+     *         HCE payment: "Host"
+     *         OffHost payment: prefix SIM or prefix eSE string.
+     *                          "OffHost" if the payment service does not specify secure element
+     *                          name.
+     */
+    @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO)
+    @Nullable
+    public String getRouteDestinationForPreferredPaymentService() {
+        try {
+            ApduServiceInfo serviceInfo = sService.getPreferredPaymentService(mContext.getUserId());
+            if (serviceInfo != null) {
+                if (!serviceInfo.isOnHost()) {
+                    return serviceInfo.getOffHostSecureElement() == null ?
+                            "OffHost" : serviceInfo.getOffHostSecureElement();
+                }
+                return "Host";
+            }
+            return null;
+        } catch (RemoteException e) {
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return null;
+            }
+            try {
+                ApduServiceInfo serviceInfo =
+                        sService.getPreferredPaymentService(mContext.getUserId());
+                if (serviceInfo != null) {
+                    if (!serviceInfo.isOnHost()) {
+                        return serviceInfo.getOffHostSecureElement() == null ?
+                                "Offhost" : serviceInfo.getOffHostSecureElement();
+                    }
+                    return "Host";
+                }
+                return null;
+
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return null;
+            }
+        }
+    }
+
+    /**
+     * Returns a user-visible description of the preferred payment service.
+     *
+     * @return the preferred payment service description
+     */
+    @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO)
+    @Nullable
+    public String getDescriptionForPreferredPaymentService() {
+        try {
+            ApduServiceInfo serviceInfo = sService.getPreferredPaymentService(mContext.getUserId());
+            return (serviceInfo != null ? serviceInfo.getDescription() : null);
+        } catch (RemoteException e) {
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return null;
+            }
+            try {
+                ApduServiceInfo serviceInfo =
+                        sService.getPreferredPaymentService(mContext.getUserId());
+                return (serviceInfo != null ? serviceInfo.getDescription() : null);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return null;
+            }
+        }
+    }
+
+    /**
      * @hide
      */
     public boolean setDefaultServiceForCategory(ComponentName service, String category) {
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..82b04a6 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -20,12 +20,13 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 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;
@@ -552,6 +553,13 @@
     public static final String REBOOT_SAFE_MODE = "safemode";
 
     /**
+     * The 'reason' value used for rebooting userspace.
+     * @hide
+     */
+    @SystemApi
+    public static final String REBOOT_USERSPACE = "userspace";
+
+    /**
      * The 'reason' value used when rebooting the device without turning on the screen.
      * @hide
      */
@@ -1326,6 +1334,14 @@
     }
 
     /**
+     * Returns {@code true} if this device supports rebooting userspace.
+     */
+    // TODO(b/138605180): add link to documentation once it's ready.
+    public boolean isRebootingUserspaceSupported() {
+        return SystemProperties.getBoolean("ro.init.userspace_reboot.is_supported", false);
+    }
+
+    /**
      * Reboot the device.  Will not return if the reboot is successful.
      * <p>
      * Requires the {@link android.Manifest.permission#REBOOT} permission.
@@ -1333,8 +1349,14 @@
      *
      * @param reason code to pass to the kernel (e.g., "recovery") to
      *               request special boot modes, or null.
+     * @throws UnsupportedOperationException if userspace reboot was requested on a device that
+     *                                       doesn't support it.
      */
-    public void reboot(String reason) {
+    public void reboot(@Nullable String reason) {
+        if (REBOOT_USERSPACE.equals(reason) && !isRebootingUserspaceSupported()) {
+            throw new UnsupportedOperationException(
+                    "Attempted userspace reboot on a device that doesn't support it");
+        }
         try {
             mService.reboot(false, reason, true);
         } catch (RemoteException e) {
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 6ae188a..94623bc 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.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.system.Os;
 import android.system.OsConstants;
 import android.util.Pair;
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..fa9569b 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";
 
     /**
@@ -1540,6 +1550,9 @@
      * set by the user and is not a placeholder string provided by the system.
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
+            Manifest.permission.GET_ACCOUNTS_PRIVILEGED})
     public boolean isUserNameSet() {
         try {
             return mService.isUserNameSet(getUserHandle());
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/VintfObject.java b/core/java/android/os/VintfObject.java
index 1c78b08..7af8f71 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.annotation.TestApi;
+import android.util.Slog;
 
 import java.util.Map;
 
@@ -28,6 +29,8 @@
 @TestApi
 public class VintfObject {
 
+    private static final String LOG_TAG = "VintfObject";
+
     /**
      * Slurps all device information (both manifests and both matrices)
      * and report them.
@@ -46,12 +49,33 @@
      * @param packageInfo a list of serialized form of HalManifest's /
      * CompatibilityMatri'ces (XML).
      * @return = 0 if success (compatible)
-     *         > 0 if incompatible
-     *         < 0 if any error (mount partition fails, illformed XML, etc.)
+     *         &gt; 0 if incompatible
+     *         &lt; 0 if any error (mount partition fails, illformed XML, etc.)
+     *
+     * @deprecated Checking compatibility against an OTA package is no longer
+     * supported because the format of VINTF metadata in the OTA package may not
+     * be recognized by the current system.
+     *
+     * <p>
+     * <ul>
+     * <li>This function always returns 0 for non-empty {@code packageInfo}.
+     * </li>
+     * <li>This function returns the result of {@link #verifyWithoutAvb} for
+     * null or empty {@code packageInfo}.</li>
+     * </ul>
      *
      * @hide
      */
-    public static native int verify(String[] packageInfo);
+    @Deprecated
+    public static int verify(String[] packageInfo) {
+        if (packageInfo != null && packageInfo.length > 0) {
+            Slog.w(LOG_TAG, "VintfObject.verify() with non-empty packageInfo is deprecated. "
+                    + "Skipping compatibility checks for update package.");
+            return 0;
+        }
+        Slog.w(LOG_TAG, "VintfObject.verify() is deprecated. Call verifyWithoutAvb() instead.");
+        return verifyWithoutAvb();
+    }
 
     /**
      * Verify Vintf compatibility on the device without checking AVB
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 d32bd26..62b8953 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.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.ApplicationInfo;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
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/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index c722287..9c6672d 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -328,7 +328,9 @@
      * Checks if path is mounted on Incremental File System.
      */
     public static boolean isIncrementalPath(@NonNull String path) {
-        // TODO(b/136132412): add jni implementation
-        return false;
+        return nativeIsIncrementalPath(path);
     }
+
+    /* Native methods */
+    private static native boolean nativeIsIncrementalPath(@NonNull String path);
 }
diff --git a/core/java/android/os/storage/CrateInfo.aidl b/core/java/android/os/storage/CrateInfo.aidl
new file mode 100644
index 0000000..dd91053
--- /dev/null
+++ b/core/java/android/os/storage/CrateInfo.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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;
+
+/**
+ * @hide
+ */
+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/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index 26c1ec1..0483514 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -43,4 +43,5 @@
                 String permission, int grantState, in AndroidFuture callback);
     void grantOrUpgradeDefaultRuntimePermissions(in AndroidFuture callback);
     void updateUserSensitive(in AndroidFuture callback);
+    void notifyOneTimePermissionSessionTimeout(String packageName);
 }
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 60c8811..2615c98 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -20,6 +20,7 @@
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
 import android.content.pm.permission.SplitPermissionInfoParcelable;
+import android.os.UserHandle;
 import android.permission.IOnPermissionsChangeListener;
 
 /**
@@ -100,4 +101,9 @@
     boolean isPermissionRevokedByPolicy(String permName, String packageName, int userId);
 
     List<SplitPermissionInfoParcelable> getSplitPermissions();
+
+    void startOneTimePermissionSession(String packageName, int userId, long timeout,
+            int importanceToResetTimer, int importanceToKeepSessionAlive);
+
+    void stopOneTimePermissionSession(String packageName, int userId);
 }
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 421e29e..2a1857f 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -636,4 +636,18 @@
             return future;
         });
     }
+
+    /**
+     * Called when a package that has permissions registered as "one-time" is considered
+     * inactive.
+     *
+     * @param packageName The package which became inactive
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
+    public void notifyOneTimePermissionSessionTimeout(@NonNull String packageName) {
+        mRemoteService.run(
+                service -> service.notifyOneTimePermissionSessionTimeout(packageName));
+    }
 }
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index f914663..5d4561c 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -240,6 +240,18 @@
             @NonNull String permission, @PermissionGrantState int grantState,
             @NonNull Consumer<Boolean> callback);
 
+    /**
+     * Called when a package is considered inactive based on the criteria given by
+     * {@link PermissionManager#startOneTimePermissionSession(String, long, int, int)}.
+     * This method is called at the end of a one-time permission session
+     *
+     * @param packageName The package that has been inactive
+     */
+    @BinderThread
+    public void onOneTimePermissionSessionTimeout(@NonNull String packageName) {
+        throw new AbstractMethodError("Must be overridden in implementing class");
+    }
+
     @Override
     public final @NonNull IBinder onBind(Intent intent) {
         return new IPermissionController.Stub() {
@@ -452,6 +464,15 @@
                 onUpdateUserSensitivePermissionFlags();
                 callback.complete(null);
             }
+
+            @Override
+            public void notifyOneTimePermissionSessionTimeout(String packageName) {
+                enforceSomePermissionsGrantedToCaller(
+                        Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
+                packageName = Preconditions.checkNotNull(packageName,
+                        "packageName cannot be null");
+                onOneTimePermissionSessionTimeout(packageName);
+            }
         };
     }
 }
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 09286fe..a3215a4 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -25,6 +25,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.content.Context;
 import android.content.pm.IPackageManager;
@@ -284,4 +285,69 @@
             mSplitPermissionInfoParcelable = parcelable;
         }
     }
+
+    /**
+     * Starts a one-time permission session for a given package. A one-time permission session is
+     * ended if app becomes inactive. Inactivity is defined as the package's uid importance level
+     * staying > importanceToResetTimer for timeoutMillis milliseconds. If the package's uid
+     * importance level goes <= importanceToResetTimer then the timer is reset and doesn't start
+     * until going > importanceToResetTimer.
+     * <p>
+     * When this timeoutMillis is reached if the importance level is <= importanceToKeepSessionAlive
+     * then the session is extended until either the importance goes above
+     * importanceToKeepSessionAlive which will end the session or <= importanceToResetTimer which
+     * will continue the session and reset the timer.
+     * </p>
+     * <p>
+     * Importance levels are defined in {@link android.app.ActivityManager.RunningAppProcessInfo}.
+     * </p>
+     * <p>
+     * Once the session ends
+     * {@link PermissionControllerService#onOneTimePermissionSessionTimeout(String)} is invoked.
+     * </p>
+     * <p>
+     * Note that if there is currently an active session for a package a new one isn't created and
+     * the existing one isn't changed.
+     * </p>
+     * @param packageName The package to start a one-time permission session for
+     * @param timeoutMillis Number of milliseconds for an app to be in an inactive state
+     * @param importanceToResetTimer The least important level to uid must be to reset the timer
+     * @param importanceToKeepSessionAlive The least important level the uid must be to keep the
+     *                                    session alive
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(allOf = {Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
+            Manifest.permission.PACKAGE_USAGE_STATS})
+    public void startOneTimePermissionSession(@NonNull String packageName, long timeoutMillis,
+            @ActivityManager.RunningAppProcessInfo.Importance int importanceToResetTimer,
+            @ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) {
+        try {
+            mPermissionManager.startOneTimePermissionSession(packageName, mContext.getUserId(),
+                    timeoutMillis, importanceToResetTimer, importanceToKeepSessionAlive);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Stops the one-time permission session for the package. The callback to the end of session is
+     * not invoked. If there is no one-time session for the package then nothing happens.
+     *
+     * @param packageName Package to stop the one-time permission session for
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(allOf = {Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
+            Manifest.permission.PACKAGE_USAGE_STATS})
+    public void stopOneTimePermissionSession(@NonNull String packageName) {
+        try {
+            mPermissionManager.stopOneTimePermissionSession(packageName,
+                    mContext.getUserId());
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
 }
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/Column.java b/core/java/android/provider/Column.java
deleted file mode 100644
index 1364fb8..0000000
--- a/core/java/android/provider/Column.java
+++ /dev/null
@@ -1,50 +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.provider;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Denotes that a field is a {@link ContentProvider} column. It can be used as a
- * key for {@link ContentValues} when inserting or updating data, or as a
- * projection when querying.
- *
- * @hide
- */
-@Documented
-@Retention(RUNTIME)
-@Target({FIELD})
-public @interface Column {
-    /**
-     * The {@link Cursor#getType(int)} of the data stored in this column.
-     */
-    int value();
-
-    /**
-     * This column is read-only and cannot be defined during insert or updates.
-     */
-    boolean readOnly() default false;
-}
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/MediaStore.java b/core/java/android/provider/MediaStore.java
deleted file mode 100644
index 63204d3..0000000
--- a/core/java/android/provider/MediaStore.java
+++ /dev/null
@@ -1,3832 +0,0 @@
-/*
- * Copyright (C) 2007 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.provider;
-
-import android.annotation.BytesLong;
-import android.annotation.CurrentTimeMillisLong;
-import android.annotation.CurrentTimeSecondsLong;
-import android.annotation.DurationMillisLong;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.content.ClipData;
-import android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.UriPermission;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.ImageDecoder;
-import android.graphics.PostProcessor;
-import android.media.ExifInterface;
-import android.media.MediaFormat;
-import android.media.MediaMetadataRetriever;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.Environment;
-import android.os.OperationCanceledException;
-import android.os.RemoteException;
-import android.os.storage.StorageManager;
-import android.os.storage.StorageVolume;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.Size;
-
-import libcore.util.HexEncoding;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Objects;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-/**
- * The contract between the media provider and applications. Contains
- * definitions for the supported URIs and columns.
- * <p>
- * The media provider provides an indexed collection of common media types, such
- * as {@link Audio}, {@link Video}, and {@link Images}, from any attached
- * storage devices. Each collection is organized based on the primary MIME type
- * of the underlying content; for example, {@code image/*} content is indexed
- * under {@link Images}. The {@link Files} collection provides a broad view
- * across all collections, and does not filter by MIME type.
- */
-public final class MediaStore {
-    private final static String TAG = "MediaStore";
-
-    /** The authority for the media provider */
-    public static final String AUTHORITY = "media";
-    /** A content:// style uri to the authority for the media provider */
-    public static final @NonNull Uri AUTHORITY_URI =
-            Uri.parse("content://" + AUTHORITY);
-
-    /** @hide */
-    public static final String AUTHORITY_LEGACY = "media_legacy";
-    /** @hide */
-    public static final @NonNull Uri AUTHORITY_LEGACY_URI =
-            Uri.parse("content://" + AUTHORITY_LEGACY);
-
-    /**
-     * Synthetic volume name that provides a view of all content across the
-     * "internal" storage of the device.
-     * <p>
-     * This synthetic volume provides a merged view of all media distributed
-     * with the device, such as built-in ringtones and wallpapers.
-     * <p>
-     * Because this is a synthetic volume, you can't insert new content into
-     * this volume.
-     */
-    public static final String VOLUME_INTERNAL = "internal";
-
-    /**
-     * Synthetic volume name that provides a view of all content across the
-     * "external" storage of the device.
-     * <p>
-     * This synthetic volume provides a merged view of all media across all
-     * currently attached external storage devices.
-     * <p>
-     * Because this is a synthetic volume, you can't insert new content into
-     * this volume. Instead, you can insert content into a specific storage
-     * volume obtained from {@link #getExternalVolumeNames(Context)}.
-     */
-    public static final String VOLUME_EXTERNAL = "external";
-
-    /**
-     * Specific volume name that represents the primary external storage device
-     * at {@link Environment#getExternalStorageDirectory()}.
-     * <p>
-     * This volume may not always be available, such as when the user has
-     * ejected the device. You can find a list of all specific volume names
-     * using {@link #getExternalVolumeNames(Context)}.
-     */
-    public static final String VOLUME_EXTERNAL_PRIMARY = "external_primary";
-
-    /** {@hide} */
-    public static final String WAIT_FOR_IDLE_CALL = "wait_for_idle";
-    /** {@hide} */
-    public static final String SCAN_FILE_CALL = "scan_file";
-    /** {@hide} */
-    public static final String SCAN_VOLUME_CALL = "scan_volume";
-    /** {@hide} */
-    public static final String CREATE_WRITE_REQUEST_CALL = "create_write_request";
-    /** {@hide} */
-    public static final String CREATE_TRASH_REQUEST_CALL = "create_trash_request";
-    /** {@hide} */
-    public static final String CREATE_FAVORITE_REQUEST_CALL = "create_favorite_request";
-    /** {@hide} */
-    public static final String CREATE_DELETE_REQUEST_CALL = "create_delete_request";
-
-
-    /** {@hide} */
-    public static final String GET_VERSION_CALL = "get_version";
-
-    /** {@hide} */
-    public static final String GET_DOCUMENT_URI_CALL = "get_document_uri";
-    /** {@hide} */
-    public static final String GET_MEDIA_URI_CALL = "get_media_uri";
-
-    /** {@hide} */
-    public static final String EXTRA_URI = "uri";
-    /** {@hide} */
-    public static final String EXTRA_URI_PERMISSIONS = "uriPermissions";
-
-    /** {@hide} */
-    public static final String EXTRA_CLIP_DATA = "clip_data";
-    /** {@hide} */
-    public static final String EXTRA_CONTENT_VALUES = "content_values";
-    /** {@hide} */
-    public static final String EXTRA_RESULT = "result";
-
-    /**
-     * This is for internal use by the media scanner only.
-     * Name of the (optional) Uri parameter that determines whether to skip deleting
-     * the file pointed to by the _data column, when deleting the database entry.
-     * The only appropriate value for this parameter is "false", in which case the
-     * delete will be skipped. Note especially that setting this to true, or omitting
-     * the parameter altogether, will perform the default action, which is different
-     * for different types of media.
-     * @hide
-     */
-    public static final String PARAM_DELETE_DATA = "deletedata";
-
-    /** {@hide} */
-    @Deprecated
-    public static final String PARAM_INCLUDE_PENDING = "includePending";
-    /** {@hide} */
-    @Deprecated
-    public static final String PARAM_INCLUDE_TRASHED = "includeTrashed";
-    /** {@hide} */
-    public static final String PARAM_PROGRESS = "progress";
-    /** {@hide} */
-    public static final String PARAM_REQUIRE_ORIGINAL = "requireOriginal";
-    /** {@hide} */
-    public static final String PARAM_LIMIT = "limit";
-
-    /**
-     * Activity Action: Launch a music player.
-     * The activity should be able to play, browse, or manipulate music files stored on the device.
-     *
-     * @deprecated Use {@link android.content.Intent#CATEGORY_APP_MUSIC} instead.
-     */
-    @Deprecated
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
-
-    /**
-     * Activity Action: Perform a search for media.
-     * Contains at least the {@link android.app.SearchManager#QUERY} extra.
-     * May also contain any combination of the following extras:
-     * EXTRA_MEDIA_ARTIST, EXTRA_MEDIA_ALBUM, EXTRA_MEDIA_TITLE, EXTRA_MEDIA_FOCUS
-     *
-     * @see android.provider.MediaStore#EXTRA_MEDIA_ARTIST
-     * @see android.provider.MediaStore#EXTRA_MEDIA_ALBUM
-     * @see android.provider.MediaStore#EXTRA_MEDIA_TITLE
-     * @see android.provider.MediaStore#EXTRA_MEDIA_FOCUS
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String INTENT_ACTION_MEDIA_SEARCH = "android.intent.action.MEDIA_SEARCH";
-
-    /**
-     * An intent to perform a search for music media and automatically play content from the
-     * result when possible. This can be fired, for example, by the result of a voice recognition
-     * command to listen to music.
-     * <p>This intent always includes the {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS}
-     * and {@link android.app.SearchManager#QUERY} extras. The
-     * {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS} extra determines the search mode, and
-     * the value of the {@link android.app.SearchManager#QUERY} extra depends on the search mode.
-     * For more information about the search modes for this intent, see
-     * <a href="{@docRoot}guide/components/intents-common.html#PlaySearch">Play music based
-     * on a search query</a> in <a href="{@docRoot}guide/components/intents-common.html">Common
-     * Intents</a>.</p>
-     *
-     * <p>This intent makes the most sense for apps that can support large-scale search of music,
-     * such as services connected to an online database of music which can be streamed and played
-     * on the device.</p>
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH =
-            "android.media.action.MEDIA_PLAY_FROM_SEARCH";
-
-    /**
-     * An intent to perform a search for readable media and automatically play content from the
-     * result when possible. This can be fired, for example, by the result of a voice recognition
-     * command to read a book or magazine.
-     * <p>
-     * Contains the {@link android.app.SearchManager#QUERY} extra, which is a string that can
-     * contain any type of unstructured text search, like the name of a book or magazine, an author
-     * a genre, a publisher, or any combination of these.
-     * <p>
-     * Because this intent includes an open-ended unstructured search string, it makes the most
-     * sense for apps that can support large-scale search of text media, such as services connected
-     * to an online database of books and/or magazines which can be read on the device.
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String INTENT_ACTION_TEXT_OPEN_FROM_SEARCH =
-            "android.media.action.TEXT_OPEN_FROM_SEARCH";
-
-    /**
-     * An intent to perform a search for video media and automatically play content from the
-     * result when possible. This can be fired, for example, by the result of a voice recognition
-     * command to play movies.
-     * <p>
-     * Contains the {@link android.app.SearchManager#QUERY} extra, which is a string that can
-     * contain any type of unstructured video search, like the name of a movie, one or more actors,
-     * a genre, or any combination of these.
-     * <p>
-     * Because this intent includes an open-ended unstructured search string, it makes the most
-     * sense for apps that can support large-scale search of video, such as services connected to an
-     * online database of videos which can be streamed and played on the device.
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String INTENT_ACTION_VIDEO_PLAY_FROM_SEARCH =
-            "android.media.action.VIDEO_PLAY_FROM_SEARCH";
-
-    /**
-     * The name of the Intent-extra used to define the artist
-     */
-    public static final String EXTRA_MEDIA_ARTIST = "android.intent.extra.artist";
-    /**
-     * The name of the Intent-extra used to define the album
-     */
-    public static final String EXTRA_MEDIA_ALBUM = "android.intent.extra.album";
-    /**
-     * The name of the Intent-extra used to define the song title
-     */
-    public static final String EXTRA_MEDIA_TITLE = "android.intent.extra.title";
-    /**
-     * The name of the Intent-extra used to define the genre.
-     */
-    public static final String EXTRA_MEDIA_GENRE = "android.intent.extra.genre";
-    /**
-     * The name of the Intent-extra used to define the playlist.
-     */
-    public static final String EXTRA_MEDIA_PLAYLIST = "android.intent.extra.playlist";
-    /**
-     * The name of the Intent-extra used to define the radio channel.
-     */
-    public static final String EXTRA_MEDIA_RADIO_CHANNEL = "android.intent.extra.radio_channel";
-    /**
-     * The name of the Intent-extra used to define the search focus. The search focus
-     * indicates whether the search should be for things related to the artist, album
-     * or song that is identified by the other extras.
-     */
-    public static final String EXTRA_MEDIA_FOCUS = "android.intent.extra.focus";
-
-    /**
-     * The name of the Intent-extra used to control the orientation of a ViewImage or a MovieView.
-     * This is an int property that overrides the activity's requestedOrientation.
-     * @see android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED
-     */
-    public static final String EXTRA_SCREEN_ORIENTATION = "android.intent.extra.screenOrientation";
-
-    /**
-     * The name of an Intent-extra used to control the UI of a ViewImage.
-     * This is a boolean property that overrides the activity's default fullscreen state.
-     */
-    public static final String EXTRA_FULL_SCREEN = "android.intent.extra.fullScreen";
-
-    /**
-     * The name of an Intent-extra used to control the UI of a ViewImage.
-     * This is a boolean property that specifies whether or not to show action icons.
-     */
-    public static final String EXTRA_SHOW_ACTION_ICONS = "android.intent.extra.showActionIcons";
-
-    /**
-     * The name of the Intent-extra used to control the onCompletion behavior of a MovieView.
-     * This is a boolean property that specifies whether or not to finish the MovieView activity
-     * when the movie completes playing. The default value is true, which means to automatically
-     * exit the movie player activity when the movie completes playing.
-     */
-    public static final String EXTRA_FINISH_ON_COMPLETION = "android.intent.extra.finishOnCompletion";
-
-    /**
-     * The name of the Intent action used to launch a camera in still image mode.
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
-
-    /**
-     * Name under which an activity handling {@link #INTENT_ACTION_STILL_IMAGE_CAMERA} or
-     * {@link #INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE} publishes the service name for its prewarm
-     * service.
-     * <p>
-     * This meta-data should reference the fully qualified class name of the prewarm service
-     * extending {@code CameraPrewarmService}.
-     * <p>
-     * The prewarm service will get bound and receive a prewarm signal
-     * {@code CameraPrewarmService#onPrewarm()} when a camera launch intent fire might be imminent.
-     * An application implementing a prewarm service should do the absolute minimum amount of work
-     * to initialize the camera in order to reduce startup time in likely case that shortly after a
-     * camera launch intent would be sent.
-     */
-    public static final String META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE =
-            "android.media.still_image_camera_preview_service";
-
-    /**
-     * The name of the Intent action used to launch a camera in still image mode
-     * for use when the device is secured (e.g. with a pin, password, pattern,
-     * or face unlock). Applications responding to this intent must not expose
-     * any personal content like existing photos or videos on the device. The
-     * applications should be careful not to share any photo or video with other
-     * applications or internet. The activity should use {@link
-     * Activity#setShowWhenLocked} to display
-     * on top of the lock screen while secured. There is no activity stack when
-     * this flag is used, so launching more than one activity is strongly
-     * discouraged.
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE =
-            "android.media.action.STILL_IMAGE_CAMERA_SECURE";
-
-    /**
-     * The name of the Intent action used to launch a camera in video mode.
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
-
-    /**
-     * Standard Intent action that can be sent to have the camera application
-     * capture an image and return it.
-     * <p>
-     * The caller may pass an extra EXTRA_OUTPUT to control where this image will be written.
-     * If the EXTRA_OUTPUT is not present, then a small sized image is returned as a Bitmap
-     * object in the extra field. This is useful for applications that only need a small image.
-     * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri
-     * value of EXTRA_OUTPUT.
-     * As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this uri can also be supplied through
-     * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must
-     * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
-     * If you don't set a ClipData, it will be copied there for you when calling
-     * {@link Context#startActivity(Intent)}.
-     *
-     * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#M M} and above
-     * and declares as using the {@link android.Manifest.permission#CAMERA} permission which
-     * is not granted, then attempting to use this action will result in a {@link
-     * java.lang.SecurityException}.
-     *
-     *  @see #EXTRA_OUTPUT
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public final static String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
-
-    /**
-     * Intent action that can be sent to have the camera application capture an image and return
-     * it when the device is secured (e.g. with a pin, password, pattern, or face unlock).
-     * Applications responding to this intent must not expose any personal content like existing
-     * photos or videos on the device. The applications should be careful not to share any photo
-     * or video with other applications or Internet. The activity should use {@link
-     * Activity#setShowWhenLocked} to display on top of the
-     * lock screen while secured. There is no activity stack when this flag is used, so
-     * launching more than one activity is strongly discouraged.
-     * <p>
-     * The caller may pass an extra EXTRA_OUTPUT to control where this image will be written.
-     * If the EXTRA_OUTPUT is not present, then a small sized image is returned as a Bitmap
-     * object in the extra field. This is useful for applications that only need a small image.
-     * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri
-     * value of EXTRA_OUTPUT.
-     * As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this uri can also be supplied through
-     * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must
-     * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
-     * If you don't set a ClipData, it will be copied there for you when calling
-     * {@link Context#startActivity(Intent)}.
-     *
-     * @see #ACTION_IMAGE_CAPTURE
-     * @see #EXTRA_OUTPUT
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String ACTION_IMAGE_CAPTURE_SECURE =
-            "android.media.action.IMAGE_CAPTURE_SECURE";
-
-    /**
-     * Standard Intent action that can be sent to have the camera application
-     * capture a video and return it.
-     * <p>
-     * The caller may pass in an extra EXTRA_VIDEO_QUALITY to control the video quality.
-     * <p>
-     * The caller may pass in an extra EXTRA_OUTPUT to control
-     * where the video is written. If EXTRA_OUTPUT is not present the video will be
-     * written to the standard location for videos, and the Uri of that location will be
-     * returned in the data field of the Uri.
-     * As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this uri can also be supplied through
-     * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must
-     * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
-     * If you don't set a ClipData, it will be copied there for you when calling
-     * {@link Context#startActivity(Intent)}.
-     *
-     * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#M M} and above
-     * and declares as using the {@link android.Manifest.permission#CAMERA} permission which
-     * is not granted, then atempting to use this action will result in a {@link
-     * java.lang.SecurityException}.
-     *
-     * @see #EXTRA_OUTPUT
-     * @see #EXTRA_VIDEO_QUALITY
-     * @see #EXTRA_SIZE_LIMIT
-     * @see #EXTRA_DURATION_LIMIT
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public final static String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
-
-    /**
-     * Standard action that can be sent to review the given media file.
-     * <p>
-     * The launched application is expected to provide a large-scale view of the
-     * given media file, while allowing the user to quickly access other
-     * recently captured media files.
-     * <p>
-     * Input: {@link Intent#getData} is URI of the primary media item to
-     * initially display.
-     *
-     * @see #ACTION_REVIEW_SECURE
-     * @see #EXTRA_BRIGHTNESS
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public final static String ACTION_REVIEW = "android.provider.action.REVIEW";
-
-    /**
-     * Standard action that can be sent to review the given media file when the
-     * device is secured (e.g. with a pin, password, pattern, or face unlock).
-     * The applications should be careful not to share any media with other
-     * applications or Internet. The activity should use
-     * {@link Activity#setShowWhenLocked} to display on top of the lock screen
-     * while secured. There is no activity stack when this flag is used, so
-     * launching more than one activity is strongly discouraged.
-     * <p>
-     * The launched application is expected to provide a large-scale view of the
-     * given primary media file, while only allowing the user to quickly access
-     * other media from an explicit secondary list.
-     * <p>
-     * Input: {@link Intent#getData} is URI of the primary media item to
-     * initially display. {@link Intent#getClipData} is the limited list of
-     * secondary media items that the user is allowed to review. If
-     * {@link Intent#getClipData} is undefined, then no other media access
-     * should be allowed.
-     *
-     * @see #EXTRA_BRIGHTNESS
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public final static String ACTION_REVIEW_SECURE = "android.provider.action.REVIEW_SECURE";
-
-    /**
-     * When defined, the launched application is requested to set the given
-     * brightness value via
-     * {@link android.view.WindowManager.LayoutParams#screenBrightness} to help
-     * ensure a smooth transition when launching {@link #ACTION_REVIEW} or
-     * {@link #ACTION_REVIEW_SECURE} intents.
-     */
-    public final static String EXTRA_BRIGHTNESS = "android.provider.extra.BRIGHTNESS";
-
-    /**
-     * The name of the Intent-extra used to control the quality of a recorded video. This is an
-     * integer property. Currently value 0 means low quality, suitable for MMS messages, and
-     * value 1 means high quality. In the future other quality levels may be added.
-     */
-    public final static String EXTRA_VIDEO_QUALITY = "android.intent.extra.videoQuality";
-
-    /**
-     * Specify the maximum allowed size.
-     */
-    public final static String EXTRA_SIZE_LIMIT = "android.intent.extra.sizeLimit";
-
-    /**
-     * Specify the maximum allowed recording duration in seconds.
-     */
-    public final static String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit";
-
-    /**
-     * The name of the Intent-extra used to indicate a content resolver Uri to be used to
-     * store the requested image or video.
-     */
-    public final static String EXTRA_OUTPUT = "output";
-
-    /**
-      * The string that is used when a media attribute is not known. For example,
-      * if an audio file does not have any meta data, the artist and album columns
-      * will be set to this value.
-      */
-    public static final String UNKNOWN_STRING = "<unknown>";
-
-    /**
-     * Specify a {@link Uri} that is "related" to the current operation being
-     * performed.
-     * <p>
-     * This is typically used to allow an operation that may normally be
-     * rejected, such as making a copy of a pre-existing image located under a
-     * {@link MediaColumns#RELATIVE_PATH} where new images are not allowed.
-     * <p>
-     * It's strongly recommended that when making a copy of pre-existing content
-     * that you define the "original document ID" GUID as defined by the <em>XMP
-     * Media Management</em> standard.
-     * <p>
-     * This key can be placed in a {@link Bundle} of extras and passed to
-     * {@link ContentResolver#insert}.
-     */
-    public static final String QUERY_ARG_RELATED_URI = "android:query-arg-related-uri";
-
-    /**
-     * Specify how {@link MediaColumns#IS_PENDING} items should be filtered when
-     * performing a {@link MediaStore} operation.
-     * <p>
-     * This key can be placed in a {@link Bundle} of extras and passed to
-     * {@link ContentResolver#query}, {@link ContentResolver#update}, or
-     * {@link ContentResolver#delete}.
-     * <p>
-     * By default, pending items are filtered away from operations.
-     */
-    @Match
-    public static final String QUERY_ARG_MATCH_PENDING = "android:query-arg-match-pending";
-
-    /**
-     * Specify how {@link MediaColumns#IS_TRASHED} items should be filtered when
-     * performing a {@link MediaStore} operation.
-     * <p>
-     * This key can be placed in a {@link Bundle} of extras and passed to
-     * {@link ContentResolver#query}, {@link ContentResolver#update}, or
-     * {@link ContentResolver#delete}.
-     * <p>
-     * By default, trashed items are filtered away from operations.
-     *
-     * @see MediaColumns#IS_TRASHED
-     * @see MediaStore#QUERY_ARG_MATCH_TRASHED
-     * @see MediaStore#createTrashRequest
-     */
-    @Match
-    public static final String QUERY_ARG_MATCH_TRASHED = "android:query-arg-match-trashed";
-
-    /**
-     * Specify how {@link MediaColumns#IS_FAVORITE} items should be filtered
-     * when performing a {@link MediaStore} operation.
-     * <p>
-     * This key can be placed in a {@link Bundle} of extras and passed to
-     * {@link ContentResolver#query}, {@link ContentResolver#update}, or
-     * {@link ContentResolver#delete}.
-     * <p>
-     * By default, favorite items are <em>not</em> filtered away from
-     * operations.
-     *
-     * @see MediaColumns#IS_FAVORITE
-     * @see MediaStore#QUERY_ARG_MATCH_FAVORITE
-     * @see MediaStore#createFavoriteRequest
-     */
-    @Match
-    public static final String QUERY_ARG_MATCH_FAVORITE = "android:query-arg-match-favorite";
-
-    /** @hide */
-    @IntDef(flag = true, prefix = { "MATCH_" }, value = {
-            MATCH_DEFAULT,
-            MATCH_INCLUDE,
-            MATCH_EXCLUDE,
-            MATCH_ONLY,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Match {}
-
-    /**
-     * Value indicating that the default matching behavior should be used, as
-     * defined by the key documentation.
-     */
-    public static final int MATCH_DEFAULT = 0;
-
-    /**
-     * Value indicating that operations should include items matching the
-     * criteria defined by this key.
-     * <p>
-     * Note that items <em>not</em> matching the criteria <em>may</em> also be
-     * included depending on the default behavior documented by the key. If you
-     * want to operate exclusively on matching items, use {@link #MATCH_ONLY}.
-     */
-    public static final int MATCH_INCLUDE = 1;
-
-    /**
-     * Value indicating that operations should exclude items matching the
-     * criteria defined by this key.
-     */
-    public static final int MATCH_EXCLUDE = 2;
-
-    /**
-     * Value indicating that operations should only operate on items explicitly
-     * matching the criteria defined by this key.
-     */
-    public static final int MATCH_ONLY = 3;
-
-    /**
-     * Update the given {@link Uri} to also include any pending media items from
-     * calls such as
-     * {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}.
-     * By default no pending items are returned.
-     *
-     * @see MediaColumns#IS_PENDING
-     * @see MediaStore#getIncludePending(Uri)
-     * @deprecated consider migrating to {@link #QUERY_ARG_MATCH_PENDING} which
-     *             is more expressive.
-     */
-    @Deprecated
-    public static @NonNull Uri setIncludePending(@NonNull Uri uri) {
-        return setIncludePending(uri.buildUpon()).build();
-    }
-
-    /** @hide */
-    @Deprecated
-    public static @NonNull Uri.Builder setIncludePending(@NonNull Uri.Builder uriBuilder) {
-        return uriBuilder.appendQueryParameter(PARAM_INCLUDE_PENDING, "1");
-    }
-
-    /**
-     * Return if any pending media items should be included in calls such as
-     * {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}.
-     *
-     * @see MediaColumns#IS_PENDING
-     * @see MediaStore#setIncludePending(Uri)
-     * @deprecated consider migrating to {@link #QUERY_ARG_MATCH_PENDING} which
-     *             is more expressive.
-     * @removed
-     */
-    @Deprecated
-    public static boolean getIncludePending(@NonNull Uri uri) {
-        return parseBoolean(uri.getQueryParameter(MediaStore.PARAM_INCLUDE_PENDING));
-    }
-
-    /**
-     * Update the given {@link Uri} to also include any trashed media items from
-     * calls such as
-     * {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}.
-     * By default no trashed items are returned.
-     *
-     * @see MediaColumns#IS_TRASHED
-     * @see MediaStore#setIncludeTrashed(Uri)
-     * @see MediaStore#trash(Context, Uri)
-     * @see MediaStore#untrash(Context, Uri)
-     * @deprecated consider migrating to {@link #QUERY_ARG_MATCH_TRASHED} which
-     *             is more expressive.
-     * @removed
-     */
-    @Deprecated
-    public static @NonNull Uri setIncludeTrashed(@NonNull Uri uri) {
-        return uri.buildUpon().appendQueryParameter(PARAM_INCLUDE_TRASHED, "1").build();
-    }
-
-    /**
-     * Update the given {@link Uri} to indicate that the caller requires the
-     * original file contents when calling
-     * {@link ContentResolver#openFileDescriptor(Uri, String)}.
-     * <p>
-     * This can be useful when the caller wants to ensure they're backing up the
-     * exact bytes of the underlying media, without any Exif redaction being
-     * performed.
-     * <p>
-     * If the original file contents cannot be provided, a
-     * {@link UnsupportedOperationException} will be thrown when the returned
-     * {@link Uri} is used, such as when the caller doesn't hold
-     * {@link android.Manifest.permission#ACCESS_MEDIA_LOCATION}.
-     *
-     * @see MediaStore#getRequireOriginal(Uri)
-     */
-    public static @NonNull Uri setRequireOriginal(@NonNull Uri uri) {
-        return uri.buildUpon().appendQueryParameter(PARAM_REQUIRE_ORIGINAL, "1").build();
-    }
-
-    /**
-     * Return if the caller requires the original file contents when calling
-     * {@link ContentResolver#openFileDescriptor(Uri, String)}.
-     *
-     * @see MediaStore#setRequireOriginal(Uri)
-     */
-    public static boolean getRequireOriginal(@NonNull Uri uri) {
-        return parseBoolean(uri.getQueryParameter(MediaStore.PARAM_REQUIRE_ORIGINAL));
-    }
-
-    /**
-     * Mark the given item as being "trashed", meaning it should be deleted at
-     * some point in the future. This is a more gentle operation than simply
-     * calling {@link ContentResolver#delete(Uri, String, String[])}, which
-     * would take effect immediately.
-     * <p>
-     * This method preserves trashed items for at least 48 hours before erasing
-     * them, giving the user a chance to untrash the item.
-     *
-     * @see MediaColumns#IS_TRASHED
-     * @see MediaStore#setIncludeTrashed(Uri)
-     * @see MediaStore#trash(Context, Uri)
-     * @see MediaStore#untrash(Context, Uri)
-     * @removed
-     */
-    @Deprecated
-    public static void trash(@NonNull Context context, @NonNull Uri uri) {
-        trash(context, uri, 48 * DateUtils.HOUR_IN_MILLIS);
-    }
-
-    /**
-     * Mark the given item as being "trashed", meaning it should be deleted at
-     * some point in the future. This is a more gentle operation than simply
-     * calling {@link ContentResolver#delete(Uri, String, String[])}, which
-     * would take effect immediately.
-     * <p>
-     * This method preserves trashed items for at least the given timeout before
-     * erasing them, giving the user a chance to untrash the item.
-     *
-     * @see MediaColumns#IS_TRASHED
-     * @see MediaStore#setIncludeTrashed(Uri)
-     * @see MediaStore#trash(Context, Uri)
-     * @see MediaStore#untrash(Context, Uri)
-     * @removed
-     */
-    @Deprecated
-    public static void trash(@NonNull Context context, @NonNull Uri uri,
-            @DurationMillisLong long timeoutMillis) {
-        if (timeoutMillis < 0) {
-            throw new IllegalArgumentException();
-        }
-
-        final ContentValues values = new ContentValues();
-        values.put(MediaColumns.IS_TRASHED, 1);
-        values.put(MediaColumns.DATE_EXPIRES,
-                (System.currentTimeMillis() + timeoutMillis) / 1000);
-        context.getContentResolver().update(uri, values, null, null);
-    }
-
-    /**
-     * Mark the given item as being "untrashed", meaning it should no longer be
-     * deleted as previously requested through {@link #trash(Context, Uri)}.
-     *
-     * @see MediaColumns#IS_TRASHED
-     * @see MediaStore#setIncludeTrashed(Uri)
-     * @see MediaStore#trash(Context, Uri)
-     * @see MediaStore#untrash(Context, Uri)
-     * @removed
-     */
-    @Deprecated
-    public static void untrash(@NonNull Context context, @NonNull Uri uri) {
-        final ContentValues values = new ContentValues();
-        values.put(MediaColumns.IS_TRASHED, 0);
-        values.putNull(MediaColumns.DATE_EXPIRES);
-        context.getContentResolver().update(uri, values, null, null);
-    }
-
-    /**
-     * Rewrite the given {@link Uri} to point at
-     * {@link MediaStore#AUTHORITY_LEGACY}.
-     *
-     * @hide
-     */
-    public static @NonNull Uri rewriteToLegacy(@NonNull Uri uri) {
-        return uri.buildUpon().authority(MediaStore.AUTHORITY_LEGACY).build();
-    }
-
-    private static @NonNull PendingIntent createRequest(@NonNull ContentResolver resolver,
-            @NonNull String method, @NonNull Collection<Uri> uris, @Nullable ContentValues values) {
-        Objects.requireNonNull(resolver);
-        Objects.requireNonNull(uris);
-
-        final Iterator<Uri> it = uris.iterator();
-        final ClipData clipData = ClipData.newRawUri(null, it.next());
-        while (it.hasNext()) {
-            clipData.addItem(new ClipData.Item(it.next()));
-        }
-
-        final Bundle extras = new Bundle();
-        extras.putParcelable(EXTRA_CLIP_DATA, clipData);
-        extras.putParcelable(EXTRA_CONTENT_VALUES, values);
-        return resolver.call(AUTHORITY, method, null, extras).getParcelable(EXTRA_RESULT);
-    }
-
-    /**
-     * Create a {@link PendingIntent} that will prompt the user to grant your
-     * app write access for the requested media items.
-     * <p>
-     * This call only generates the request for a prompt; to display the prompt,
-     * call {@link Activity#startIntentSenderForResult} with
-     * {@link PendingIntent#getIntentSender()}. You can then determine if the
-     * user granted your request by testing for {@link Activity#RESULT_OK} in
-     * {@link Activity#onActivityResult}.
-     * <p>
-     * Permissions granted through this mechanism are tied to the lifecycle of
-     * the {@link Activity} that requests them. If you need to retain
-     * longer-term access for background actions, you can place items into a
-     * {@link ClipData} or {@link Intent} which can then be passed to
-     * {@link Context#startService} or
-     * {@link android.app.job.JobInfo.Builder#setClipData}. Be sure to include
-     * any relevant access modes you want to retain, such as
-     * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}.
-     * <p>
-     * The displayed prompt will reflect all the media items you're requesting,
-     * including those for which you already hold write access. If you want to
-     * determine if you already hold write access before requesting access, use
-     * {@code ContentResolver#checkUriPermission(Uri, int, int)} with
-     * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}.
-     * <p>
-     * For security and performance reasons this method does not support
-     * {@link Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION} or
-     * {@link Intent#FLAG_GRANT_PREFIX_URI_PERMISSION}.
-     *
-     * @param resolver Used to connect with {@link MediaStore#AUTHORITY}.
-     *            Typically this value is {@link Context#getContentResolver()},
-     *            but if you need more explicit lifecycle controls, you can
-     *            obtain a {@link ContentProviderClient} and wrap it using
-     *            {@link ContentResolver#wrap(ContentProviderClient)}.
-     * @param uris The set of media items to include in this request. Each item
-     *            must be hosted by {@link MediaStore#AUTHORITY} and must
-     *            reference a specific media item by {@link BaseColumns#_ID}.
-     */
-    public static @NonNull PendingIntent createWriteRequest(@NonNull ContentResolver resolver,
-            @NonNull Collection<Uri> uris) {
-        return createRequest(resolver, CREATE_WRITE_REQUEST_CALL, uris, null);
-    }
-
-    /**
-     * Create a {@link PendingIntent} that will prompt the user to trash the
-     * requested media items. When the user approves this request,
-     * {@link MediaColumns#IS_TRASHED} is set on these items.
-     * <p>
-     * This call only generates the request for a prompt; to display the prompt,
-     * call {@link Activity#startIntentSenderForResult} with
-     * {@link PendingIntent#getIntentSender()}. You can then determine if the
-     * user granted your request by testing for {@link Activity#RESULT_OK} in
-     * {@link Activity#onActivityResult}.
-     * <p>
-     * The displayed prompt will reflect all the media items you're requesting,
-     * including those for which you already hold write access. If you want to
-     * determine if you already hold write access before requesting access, use
-     * {@code ContentResolver#checkUriPermission(Uri, int, int)} with
-     * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}.
-     *
-     * @param resolver Used to connect with {@link MediaStore#AUTHORITY}.
-     *            Typically this value is {@link Context#getContentResolver()},
-     *            but if you need more explicit lifecycle controls, you can
-     *            obtain a {@link ContentProviderClient} and wrap it using
-     *            {@link ContentResolver#wrap(ContentProviderClient)}.
-     * @param uris The set of media items to include in this request. Each item
-     *            must be hosted by {@link MediaStore#AUTHORITY} and must
-     *            reference a specific media item by {@link BaseColumns#_ID}.
-     * @param value The {@link MediaColumns#IS_TRASHED} value to apply.
-     * @see MediaColumns#IS_TRASHED
-     * @see MediaStore#QUERY_ARG_MATCH_TRASHED
-     */
-    public static @NonNull PendingIntent createTrashRequest(@NonNull ContentResolver resolver,
-            @NonNull Collection<Uri> uris, boolean value) {
-        final ContentValues values = new ContentValues();
-        if (value) {
-            values.put(MediaColumns.IS_TRASHED, 1);
-            values.put(MediaColumns.DATE_EXPIRES,
-                    (System.currentTimeMillis() + DateUtils.WEEK_IN_MILLIS) / 1000);
-        } else {
-            values.put(MediaColumns.IS_TRASHED, 0);
-            values.putNull(MediaColumns.DATE_EXPIRES);
-        }
-        return createRequest(resolver, CREATE_TRASH_REQUEST_CALL, uris, values);
-    }
-
-    /**
-     * Create a {@link PendingIntent} that will prompt the user to favorite the
-     * requested media items. When the user approves this request,
-     * {@link MediaColumns#IS_FAVORITE} is set on these items.
-     * <p>
-     * This call only generates the request for a prompt; to display the prompt,
-     * call {@link Activity#startIntentSenderForResult} with
-     * {@link PendingIntent#getIntentSender()}. You can then determine if the
-     * user granted your request by testing for {@link Activity#RESULT_OK} in
-     * {@link Activity#onActivityResult}.
-     * <p>
-     * The displayed prompt will reflect all the media items you're requesting,
-     * including those for which you already hold write access. If you want to
-     * determine if you already hold write access before requesting access, use
-     * {@code ContentResolver#checkUriPermission(Uri, int, int)} with
-     * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}.
-     *
-     * @param resolver Used to connect with {@link MediaStore#AUTHORITY}.
-     *            Typically this value is {@link Context#getContentResolver()},
-     *            but if you need more explicit lifecycle controls, you can
-     *            obtain a {@link ContentProviderClient} and wrap it using
-     *            {@link ContentResolver#wrap(ContentProviderClient)}.
-     * @param uris The set of media items to include in this request. Each item
-     *            must be hosted by {@link MediaStore#AUTHORITY} and must
-     *            reference a specific media item by {@link BaseColumns#_ID}.
-     * @param value The {@link MediaColumns#IS_FAVORITE} value to apply.
-     * @see MediaColumns#IS_FAVORITE
-     * @see MediaStore#QUERY_ARG_MATCH_FAVORITE
-     */
-    public static @NonNull PendingIntent createFavoriteRequest(@NonNull ContentResolver resolver,
-            @NonNull Collection<Uri> uris, boolean value) {
-        final ContentValues values = new ContentValues();
-        if (value) {
-            values.put(MediaColumns.IS_FAVORITE, 1);
-        } else {
-            values.put(MediaColumns.IS_FAVORITE, 0);
-        }
-        return createRequest(resolver, CREATE_FAVORITE_REQUEST_CALL, uris, values);
-    }
-
-    /**
-     * Create a {@link PendingIntent} that will prompt the user to permanently
-     * delete the requested media items. When the user approves this request,
-     * {@link ContentResolver#delete} will be called on these items.
-     * <p>
-     * This call only generates the request for a prompt; to display the prompt,
-     * call {@link Activity#startIntentSenderForResult} with
-     * {@link PendingIntent#getIntentSender()}. You can then determine if the
-     * user granted your request by testing for {@link Activity#RESULT_OK} in
-     * {@link Activity#onActivityResult}.
-     * <p>
-     * The displayed prompt will reflect all the media items you're requesting,
-     * including those for which you already hold write access. If you want to
-     * determine if you already hold write access before requesting access, use
-     * {@code ContentResolver#checkUriPermission(Uri, int, int)} with
-     * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}.
-     *
-     * @param resolver Used to connect with {@link MediaStore#AUTHORITY}.
-     *            Typically this value is {@link Context#getContentResolver()},
-     *            but if you need more explicit lifecycle controls, you can
-     *            obtain a {@link ContentProviderClient} and wrap it using
-     *            {@link ContentResolver#wrap(ContentProviderClient)}.
-     * @param uris The set of media items to include in this request. Each item
-     *            must be hosted by {@link MediaStore#AUTHORITY} and must
-     *            reference a specific media item by {@link BaseColumns#_ID}.
-     */
-    public static @NonNull PendingIntent createDeleteRequest(@NonNull ContentResolver resolver,
-            @NonNull Collection<Uri> uris) {
-        return createRequest(resolver, CREATE_DELETE_REQUEST_CALL, uris, null);
-    }
-
-    /**
-     * Common media metadata columns.
-     */
-    public interface MediaColumns extends BaseColumns {
-        /**
-         * Absolute filesystem path to the media item on disk.
-         * <p>
-         * Note that apps may not have filesystem permissions to directly access
-         * this path. Instead of trying to open this path directly, apps should
-         * use {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
-         * access.
-         *
-         * @deprecated Apps may not have filesystem permissions to directly
-         *             access this path. Instead of trying to open this path
-         *             directly, apps should use
-         *             {@link ContentResolver#openFileDescriptor(Uri, String)}
-         *             to gain access.
-         */
-        @Deprecated
-        @Column(Cursor.FIELD_TYPE_STRING)
-        public static final String DATA = "_data";
-
-        /**
-         * Indexed value of {@link File#length()} extracted from this media
-         * item.
-         */
-        @BytesLong
-        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-        public static final String SIZE = "_size";
-
-        /**
-         * The display name of the media item.
-         * <p>
-         * For example, an item stored at
-         * {@code /storage/0000-0000/DCIM/Vacation/IMG1024.JPG} would have a
-         * display name of {@code IMG1024.JPG}.
-         */
-        @Column(Cursor.FIELD_TYPE_STRING)
-        public static final String DISPLAY_NAME = "_display_name";
-
-        /**
-         * The time the media item was first added.
-         */
-        @CurrentTimeSecondsLong
-        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-        public static final String DATE_ADDED = "date_added";
-
-        /**
-         * Indexed value of {@link File#lastModified()} extracted from this
-         * media item.
-         */
-        @CurrentTimeSecondsLong
-        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-        public static final String DATE_MODIFIED = "date_modified";
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_DATE} or
-         * {@link ExifInterface#TAG_DATETIME_ORIGINAL} extracted from this media
-         * item.
-         * <p>
-         * Note that images must define both
-         * {@link ExifInterface#TAG_DATETIME_ORIGINAL} and
-         * {@code ExifInterface#TAG_OFFSET_TIME_ORIGINAL} to reliably determine
-         * this value in relation to the epoch.
-         */
-        @CurrentTimeMillisLong
-        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-        public static final String DATE_TAKEN = "datetaken";
-
-        /**
-         * The MIME type of the media item.
-         * <p>
-         * This is typically defined based on the file extension of the media
-         * item. However, it may be the value of the {@code format} attribute
-         * defined by the <em>Dublin Core Media Initiative</em> standard,
-         * extracted from any XMP metadata contained within this media item.
-         * <p class="note">
-         * Note: the {@code format} attribute may be ignored if the top-level
-         * MIME type disagrees with the file extension. For example, it's
-         * reasonable for an {@code image/jpeg} file to declare a {@code format}
-         * of {@code image/vnd.google.panorama360+jpg}, but declaring a
-         * {@code format} of {@code audio/ogg} would be ignored.
-         * <p>
-         * This is a read-only column that is automatically computed.
-         */
-        @Column(Cursor.FIELD_TYPE_STRING)
-        public static final String MIME_TYPE = "mime_type";
-
-        /**
-         * Non-zero if the media file is drm-protected
-         * @hide
-         */
-        @UnsupportedAppUsage
-        @Deprecated
-        @Column(Cursor.FIELD_TYPE_INTEGER)
-        public static final String IS_DRM = "is_drm";
-
-        /**
-         * Flag indicating if a media item is pending, and still being inserted
-         * by its owner. While this flag is set, only the owner of the item can
-         * open the underlying file; requests from other apps will be rejected.
-         * <p>
-         * Pending items are retained either until they are published by setting
-         * the field to {@code 0}, or until they expire as defined by
-         * {@link #DATE_EXPIRES}.
-         *
-         * @see MediaStore#QUERY_ARG_MATCH_PENDING
-         */
-        @Column(Cursor.FIELD_TYPE_INTEGER)
-        public static final String IS_PENDING = "is_pending";
-
-        /**
-         * Flag indicating if a media item is trashed.
-         * <p>
-         * Trashed items are retained until they expire as defined by
-         * {@link #DATE_EXPIRES}.
-         *
-         * @see MediaColumns#IS_TRASHED
-         * @see MediaStore#QUERY_ARG_MATCH_TRASHED
-         * @see MediaStore#createTrashRequest
-         */
-        @Column(Cursor.FIELD_TYPE_INTEGER)
-        public static final String IS_TRASHED = "is_trashed";
-
-        /**
-         * The time the media item should be considered expired. Typically only
-         * meaningful in the context of {@link #IS_PENDING} or
-         * {@link #IS_TRASHED}.
-         */
-        @CurrentTimeSecondsLong
-        @Column(Cursor.FIELD_TYPE_INTEGER)
-        public static final String DATE_EXPIRES = "date_expires";
-
-        /**
-         * Indexed value of
-         * {@link MediaMetadataRetriever#METADATA_KEY_VIDEO_WIDTH},
-         * {@link MediaMetadataRetriever#METADATA_KEY_IMAGE_WIDTH} or
-         * {@link ExifInterface#TAG_IMAGE_WIDTH} extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-        public static final String WIDTH = "width";
-
-        /**
-         * Indexed value of
-         * {@link MediaMetadataRetriever#METADATA_KEY_VIDEO_HEIGHT},
-         * {@link MediaMetadataRetriever#METADATA_KEY_IMAGE_HEIGHT} or
-         * {@link ExifInterface#TAG_IMAGE_LENGTH} extracted from this media
-         * item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-        public static final String HEIGHT = "height";
-
-        /**
-         * Calculated value that combines {@link #WIDTH} and {@link #HEIGHT}
-         * into a user-presentable string.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String RESOLUTION = "resolution";
-
-        /**
-         * Package name that contributed this media. The value may be
-         * {@code NULL} if ownership cannot be reliably determined.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String OWNER_PACKAGE_NAME = "owner_package_name";
-
-        /**
-         * Volume name of the specific storage device where this media item is
-         * persisted. The value is typically one of the volume names returned
-         * from {@link MediaStore#getExternalVolumeNames(Context)}.
-         * <p>
-         * This is a read-only column that is automatically computed.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String VOLUME_NAME = "volume_name";
-
-        /**
-         * Relative path of this media item within the storage device where it
-         * is persisted. For example, an item stored at
-         * {@code /storage/0000-0000/DCIM/Vacation/IMG1024.JPG} would have a
-         * path of {@code DCIM/Vacation/}.
-         * <p>
-         * This value should only be used for organizational purposes, and you
-         * should not attempt to construct or access a raw filesystem path using
-         * this value. If you need to open a media item, use an API like
-         * {@link ContentResolver#openFileDescriptor(Uri, String)}.
-         * <p>
-         * When this value is set to {@code NULL} during an
-         * {@link ContentResolver#insert} operation, the newly created item will
-         * be placed in a relevant default location based on the type of media
-         * being inserted. For example, a {@code image/jpeg} item will be placed
-         * under {@link Environment#DIRECTORY_PICTURES}.
-         * <p>
-         * You can modify this column during an {@link ContentResolver#update}
-         * call, which will move the underlying file on disk.
-         * <p>
-         * In both cases above, content must be placed under a top-level
-         * directory that is relevant to the media type. For example, attempting
-         * to place a {@code audio/mpeg} file under
-         * {@link Environment#DIRECTORY_PICTURES} will be rejected.
-         */
-        @Column(Cursor.FIELD_TYPE_STRING)
-        public static final String RELATIVE_PATH = "relative_path";
-
-        /**
-         * The primary bucket ID of this media item. This can be useful to
-         * present the user a first-level clustering of related media items.
-         * This is a read-only column that is automatically computed.
-         */
-        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-        public static final String BUCKET_ID = "bucket_id";
-
-        /**
-         * The primary bucket display name of this media item. This can be
-         * useful to present the user a first-level clustering of related
-         * media items. This is a read-only column that is automatically
-         * computed.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
-
-        /**
-         * The group ID of this media item. This can be useful to present
-         * the user a grouping of related media items, such a burst of
-         * images, or a {@code JPG} and {@code DNG} version of the same
-         * image.
-         * <p>
-         * This is a read-only column that is automatically computed based
-         * on the first portion of the filename. For example,
-         * {@code IMG1024.BURST001.JPG} and {@code IMG1024.BURST002.JPG}
-         * will have the same {@link #GROUP_ID} because the first portion of
-         * their filenames is identical.
-         *
-         * @removed
-         */
-        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-        @Deprecated
-        public static final String GROUP_ID = "group_id";
-
-        /**
-         * The "document ID" GUID as defined by the <em>XMP Media
-         * Management</em> standard, extracted from any XMP metadata contained
-         * within this media item. The value is {@code null} when no metadata
-         * was found.
-         * <p>
-         * Each "document ID" is created once for each new resource. Different
-         * renditions of that resource are expected to have different IDs.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String DOCUMENT_ID = "document_id";
-
-        /**
-         * The "instance ID" GUID as defined by the <em>XMP Media
-         * Management</em> standard, extracted from any XMP metadata contained
-         * within this media item. The value is {@code null} when no metadata
-         * was found.
-         * <p>
-         * This "instance ID" changes with each save operation of a specific
-         * "document ID".
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String INSTANCE_ID = "instance_id";
-
-        /**
-         * The "original document ID" GUID as defined by the <em>XMP Media
-         * Management</em> standard, extracted from any XMP metadata contained
-         * within this media item.
-         * <p>
-         * This "original document ID" links a resource to its original source.
-         * For example, when you save a PSD document as a JPEG, then convert the
-         * JPEG to GIF format, the "original document ID" of both the JPEG and
-         * GIF files is the "document ID" of the original PSD file.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String ORIGINAL_DOCUMENT_ID = "original_document_id";
-
-        /**
-         * Indexed value of
-         * {@link MediaMetadataRetriever#METADATA_KEY_VIDEO_ROTATION},
-         * {@link MediaMetadataRetriever#METADATA_KEY_IMAGE_ROTATION}, or
-         * {@link ExifInterface#TAG_ORIENTATION} extracted from this media item.
-         * <p>
-         * For consistency the indexed value is expressed in degrees, such as 0,
-         * 90, 180, or 270.
-         */
-        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-        public static final String ORIENTATION = "orientation";
-
-        /**
-         * Flag indicating if the media item has been marked as being a
-         * "favorite" by the user.
-         *
-         * @see MediaColumns#IS_FAVORITE
-         * @see MediaStore#QUERY_ARG_MATCH_FAVORITE
-         * @see MediaStore#createFavoriteRequest
-         */
-        @Column(Cursor.FIELD_TYPE_INTEGER)
-        public static final String IS_FAVORITE = "is_favorite";
-
-        // =======================================
-        // ==== MediaMetadataRetriever values ====
-        // =======================================
-
-        /**
-         * Indexed value of
-         * {@link MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER} extracted
-         * from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String CD_TRACK_NUMBER = "cd_track_number";
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_ALBUM}
-         * extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String ALBUM = "album";
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_ARTIST}
-         * or {@link ExifInterface#TAG_ARTIST} extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String ARTIST = "artist";
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_AUTHOR}
-         * extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String AUTHOR = "author";
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_COMPOSER}
-         * extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String COMPOSER = "composer";
-
-        // METADATA_KEY_DATE is DATE_TAKEN
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_GENRE}
-         * extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String GENRE = "genre";
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_TITLE}
-         * extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String TITLE = "title";
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_YEAR}
-         * extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-        public static final String YEAR = "year";
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_DURATION}
-         * extracted from this media item.
-         */
-        @DurationMillisLong
-        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-        public static final String DURATION = "duration";
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_NUM_TRACKS}
-         * extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-        public static final String NUM_TRACKS = "num_tracks";
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_WRITER}
-         * extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String WRITER = "writer";
-
-        // METADATA_KEY_MIMETYPE is MIME_TYPE
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST}
-         * extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String ALBUM_ARTIST = "album_artist";
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER}
-         * extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String DISC_NUMBER = "disc_number";
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_COMPILATION}
-         * extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String COMPILATION = "compilation";
-
-        // HAS_AUDIO is ignored
-        // HAS_VIDEO is ignored
-        // VIDEO_WIDTH is WIDTH
-        // VIDEO_HEIGHT is HEIGHT
-
-        /**
-         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_BITRATE}
-         * extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-        public static final String BITRATE = "bitrate";
-
-        // TIMED_TEXT_LANGUAGES is ignored
-        // IS_DRM is ignored
-        // LOCATION is LATITUDE and LONGITUDE
-        // VIDEO_ROTATION is ORIENTATION
-
-        /**
-         * Indexed value of
-         * {@link MediaMetadataRetriever#METADATA_KEY_CAPTURE_FRAMERATE}
-         * extracted from this media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true)
-        public static final String CAPTURE_FRAMERATE = "capture_framerate";
-
-        // HAS_IMAGE is ignored
-        // IMAGE_COUNT is ignored
-        // IMAGE_PRIMARY is ignored
-        // IMAGE_WIDTH is WIDTH
-        // IMAGE_HEIGHT is HEIGHT
-        // IMAGE_ROTATION is ORIENTATION
-        // VIDEO_FRAME_COUNT is ignored
-        // EXIF_OFFSET is ignored
-        // EXIF_LENGTH is ignored
-        // COLOR_STANDARD is ignored
-        // COLOR_TRANSFER is ignored
-        // COLOR_RANGE is ignored
-        // SAMPLERATE is ignored
-        // BITS_PER_SAMPLE is ignored
-    }
-
-    /**
-     * Media provider table containing an index of all files in the media storage,
-     * including non-media files.  This should be used by applications that work with
-     * non-media file types (text, HTML, PDF, etc) as well as applications that need to
-     * work with multiple media file types in a single query.
-     */
-    public static final class Files {
-        /** @hide */
-        public static final String TABLE = "files";
-
-        /** @hide */
-        public static final Uri EXTERNAL_CONTENT_URI = getContentUri(VOLUME_EXTERNAL);
-
-        /**
-         * Get the content:// style URI for the files table on the
-         * given volume.
-         *
-         * @param volumeName the name of the volume to get the URI for
-         * @return the URI to the files table on the given volume
-         */
-        public static Uri getContentUri(String volumeName) {
-            return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("file").build();
-        }
-
-        /**
-         * Get the content:// style URI for a single row in the files table on the
-         * given volume.
-         *
-         * @param volumeName the name of the volume to get the URI for
-         * @param rowId the file to get the URI for
-         * @return the URI to the files table on the given volume
-         */
-        public static final Uri getContentUri(String volumeName,
-                long rowId) {
-            return ContentUris.withAppendedId(getContentUri(volumeName), rowId);
-        }
-
-        /** {@hide} */
-        @UnsupportedAppUsage
-        public static Uri getMtpObjectsUri(@NonNull String volumeName) {
-            return MediaStore.Files.getContentUri(volumeName);
-        }
-
-        /** {@hide} */
-        @UnsupportedAppUsage
-        public static final Uri getMtpObjectsUri(@NonNull String volumeName, long fileId) {
-            return MediaStore.Files.getContentUri(volumeName, fileId);
-        }
-
-        /** {@hide} */
-        @UnsupportedAppUsage
-        public static final Uri getMtpReferencesUri(@NonNull String volumeName, long fileId) {
-            return MediaStore.Files.getContentUri(volumeName, fileId);
-        }
-
-        /**
-         * Used to trigger special logic for directories.
-         * @hide
-         */
-        public static final Uri getDirectoryUri(String volumeName) {
-            return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("dir").build();
-        }
-
-        /** @hide */
-        public static final Uri getContentUriForPath(String path) {
-            return getContentUri(getVolumeName(new File(path)));
-        }
-
-        /**
-         * File metadata columns.
-         */
-        public interface FileColumns extends MediaColumns {
-            /**
-             * The MTP storage ID of the file
-             * @hide
-             */
-            @UnsupportedAppUsage
-            @Deprecated
-            // @Column(Cursor.FIELD_TYPE_INTEGER)
-            public static final String STORAGE_ID = "storage_id";
-
-            /**
-             * The MTP format code of the file
-             * @hide
-             */
-            @UnsupportedAppUsage
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String FORMAT = "format";
-
-            /**
-             * The index of the parent directory of the file
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String PARENT = "parent";
-
-            /**
-             * The MIME type of the media item.
-             * <p>
-             * This is typically defined based on the file extension of the media
-             * item. However, it may be the value of the {@code format} attribute
-             * defined by the <em>Dublin Core Media Initiative</em> standard,
-             * extracted from any XMP metadata contained within this media item.
-             * <p class="note">
-             * Note: the {@code format} attribute may be ignored if the top-level
-             * MIME type disagrees with the file extension. For example, it's
-             * reasonable for an {@code image/jpeg} file to declare a {@code format}
-             * of {@code image/vnd.google.panorama360+jpg}, but declaring a
-             * {@code format} of {@code audio/ogg} would be ignored.
-             * <p>
-             * This is a read-only column that is automatically computed.
-             */
-            @Column(Cursor.FIELD_TYPE_STRING)
-            public static final String MIME_TYPE = "mime_type";
-
-            /** @removed promoted to parent interface */
-            public static final String TITLE = "title";
-
-            /**
-             * The media type (audio, video, image or playlist)
-             * of the file, or 0 for not a media file
-             */
-            @Column(Cursor.FIELD_TYPE_INTEGER)
-            public static final String MEDIA_TYPE = "media_type";
-
-            /**
-             * Constant for the {@link #MEDIA_TYPE} column indicating that file
-             * is not an audio, image, video, playlist, or subtitles file.
-             */
-            public static final int MEDIA_TYPE_NONE = 0;
-
-            /**
-             * Constant for the {@link #MEDIA_TYPE} column indicating that file
-             * is an image file.
-             */
-            public static final int MEDIA_TYPE_IMAGE = 1;
-
-            /**
-             * Constant for the {@link #MEDIA_TYPE} column indicating that file
-             * is an audio file.
-             */
-            public static final int MEDIA_TYPE_AUDIO = 2;
-
-            /**
-             * Constant for the {@link #MEDIA_TYPE} column indicating that file
-             * is a video file.
-             */
-            public static final int MEDIA_TYPE_VIDEO = 3;
-
-            /**
-             * Constant for the {@link #MEDIA_TYPE} column indicating that file
-             * is a playlist file.
-             */
-            public static final int MEDIA_TYPE_PLAYLIST = 4;
-
-            /**
-             * Constant for the {@link #MEDIA_TYPE} column indicating that file
-             * is a subtitles or lyrics file.
-             */
-            public static final int MEDIA_TYPE_SUBTITLE = 5;
-
-            /**
-             * Column indicating if the file is part of Downloads collection.
-             * @hide
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String IS_DOWNLOAD = "is_download";
-        }
-    }
-
-    /** @hide */
-    public static class ThumbnailConstants {
-        public static final int MINI_KIND = 1;
-        public static final int FULL_SCREEN_KIND = 2;
-        public static final int MICRO_KIND = 3;
-
-        public static final Size MINI_SIZE = new Size(512, 384);
-        public static final Size FULL_SCREEN_SIZE = new Size(1024, 786);
-        public static final Size MICRO_SIZE = new Size(96, 96);
-
-        public static @NonNull Size getKindSize(int kind) {
-            if (kind == ThumbnailConstants.MICRO_KIND) {
-                return ThumbnailConstants.MICRO_SIZE;
-            } else if (kind == ThumbnailConstants.FULL_SCREEN_KIND) {
-                return ThumbnailConstants.FULL_SCREEN_SIZE;
-            } else if (kind == ThumbnailConstants.MINI_KIND) {
-                return ThumbnailConstants.MINI_SIZE;
-            } else {
-                throw new IllegalArgumentException("Unsupported kind: " + kind);
-            }
-        }
-    }
-
-    /**
-     * Download metadata columns.
-     */
-    public interface DownloadColumns extends MediaColumns {
-        /**
-         * Uri indicating where the item has been downloaded from.
-         */
-        @Column(Cursor.FIELD_TYPE_STRING)
-        String DOWNLOAD_URI = "download_uri";
-
-        /**
-         * Uri indicating HTTP referer of {@link #DOWNLOAD_URI}.
-         */
-        @Column(Cursor.FIELD_TYPE_STRING)
-        String REFERER_URI = "referer_uri";
-
-        /**
-         * The description of the download.
-         *
-         * @removed
-         */
-        @Deprecated
-        @Column(Cursor.FIELD_TYPE_STRING)
-        String DESCRIPTION = "description";
-    }
-
-    /**
-     * Collection of downloaded items.
-     */
-    public static final class Downloads implements DownloadColumns {
-        private Downloads() {}
-
-        /**
-         * The content:// style URI for the internal storage.
-         */
-        @NonNull
-        public static final Uri INTERNAL_CONTENT_URI =
-                getContentUri("internal");
-
-        /**
-         * The content:// style URI for the "primary" external storage
-         * volume.
-         */
-        @NonNull
-        public static final Uri EXTERNAL_CONTENT_URI =
-                getContentUri("external");
-
-        /**
-         * The MIME type for this table.
-         */
-        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/download";
-
-        /**
-         * Regex that matches paths that needs to be considered part of downloads collection.
-         * @hide
-         */
-        public static final Pattern PATTERN_DOWNLOADS_FILE = Pattern.compile(
-                "(?i)^/storage/[^/]+/(?:[0-9]+/)?(?:Android/sandbox/[^/]+/)?Download/.+");
-        private static final Pattern PATTERN_DOWNLOADS_DIRECTORY = Pattern.compile(
-                "(?i)^/storage/[^/]+/(?:[0-9]+/)?(?:Android/sandbox/[^/]+/)?Download/?");
-
-        /**
-         * Get the content:// style URI for the downloads table on the
-         * given volume.
-         *
-         * @param volumeName the name of the volume to get the URI for
-         * @return the URI to the image media table on the given volume
-         */
-        public static @NonNull Uri getContentUri(@NonNull String volumeName) {
-            return AUTHORITY_URI.buildUpon().appendPath(volumeName)
-                    .appendPath("downloads").build();
-        }
-
-        /**
-         * Get the content:// style URI for a single row in the downloads table
-         * on the given volume.
-         *
-         * @param volumeName the name of the volume to get the URI for
-         * @param id the download to get the URI for
-         * @return the URI to the downloads table on the given volume
-         */
-        public static @NonNull Uri getContentUri(@NonNull String volumeName, long id) {
-            return ContentUris.withAppendedId(getContentUri(volumeName), id);
-        }
-
-        /** @hide */
-        public static @NonNull Uri getContentUriForPath(@NonNull String path) {
-            return getContentUri(getVolumeName(new File(path)));
-        }
-
-        /** @hide */
-        public static boolean isDownload(@NonNull String path) {
-            return PATTERN_DOWNLOADS_FILE.matcher(path).matches();
-        }
-
-        /** @hide */
-        public static boolean isDownloadDir(@NonNull String path) {
-            return PATTERN_DOWNLOADS_DIRECTORY.matcher(path).matches();
-        }
-    }
-
-    /**
-     * @deprecated since this method doesn't have a {@link Context}, we can't
-     *             find the actual {@link StorageVolume} for the given path, so
-     *             only a vague guess is returned. Callers should use
-     *             {@link StorageManager#getStorageVolume(File)} instead.
-     * @hide
-     */
-    @Deprecated
-    public static @NonNull String getVolumeName(@NonNull File path) {
-        // Ideally we'd find the relevant StorageVolume, but we don't have a
-        // Context to obtain it from, so the best we can do is assume
-        if (path.getAbsolutePath()
-                .startsWith(Environment.getStorageDirectory().getAbsolutePath())) {
-            return MediaStore.VOLUME_EXTERNAL;
-        } else {
-            return MediaStore.VOLUME_INTERNAL;
-        }
-    }
-
-    /**
-     * This class is used internally by Images.Thumbnails and Video.Thumbnails, it's not intended
-     * to be accessed elsewhere.
-     */
-    @Deprecated
-    private static class InternalThumbnails implements BaseColumns {
-        /**
-         * Currently outstanding thumbnail requests that can be cancelled.
-         */
-        // @GuardedBy("sPending")
-        private static ArrayMap<Uri, CancellationSignal> sPending = new ArrayMap<>();
-
-        /**
-         * Make a blocking request to obtain the given thumbnail, generating it
-         * if needed.
-         *
-         * @see #cancelThumbnail(ContentResolver, Uri)
-         */
-        @Deprecated
-        static @Nullable Bitmap getThumbnail(@NonNull ContentResolver cr, @NonNull Uri uri,
-                int kind, @Nullable BitmapFactory.Options opts) {
-            final Size size = ThumbnailConstants.getKindSize(kind);
-
-            CancellationSignal signal = null;
-            synchronized (sPending) {
-                signal = sPending.get(uri);
-                if (signal == null) {
-                    signal = new CancellationSignal();
-                    sPending.put(uri, signal);
-                }
-            }
-
-            try {
-                return cr.loadThumbnail(uri, size, signal);
-            } catch (IOException e) {
-                Log.w(TAG, "Failed to obtain thumbnail for " + uri, e);
-                return null;
-            } finally {
-                synchronized (sPending) {
-                    sPending.remove(uri);
-                }
-            }
-        }
-
-        /**
-         * This method cancels the thumbnail request so clients waiting for
-         * {@link #getThumbnail} will be interrupted and return immediately.
-         * Only the original process which made the request can cancel their own
-         * requests.
-         */
-        @Deprecated
-        static void cancelThumbnail(@NonNull ContentResolver cr, @NonNull Uri uri) {
-            synchronized (sPending) {
-                final CancellationSignal signal = sPending.get(uri);
-                if (signal != null) {
-                    signal.cancel();
-                }
-            }
-        }
-    }
-
-    /**
-     * Collection of all media with MIME type of {@code image/*}.
-     */
-    public static final class Images {
-        /**
-         * Image metadata columns.
-         */
-        public interface ImageColumns extends MediaColumns {
-            /**
-             * The picasa id of the image
-             *
-             * @deprecated this value was only relevant for images hosted on
-             *             Picasa, which are no longer supported.
-             */
-            @Deprecated
-            @Column(Cursor.FIELD_TYPE_STRING)
-            public static final String PICASA_ID = "picasa_id";
-
-            /**
-             * Whether the video should be published as public or private
-             */
-            @Column(Cursor.FIELD_TYPE_INTEGER)
-            public static final String IS_PRIVATE = "isprivate";
-
-            /**
-             * The latitude where the image was captured.
-             *
-             * @deprecated location details are no longer indexed for privacy
-             *             reasons, and this value is now always {@code null}.
-             *             You can still manually obtain location metadata using
-             *             {@link ExifInterface#getLatLong(float[])}.
-             */
-            @Deprecated
-            @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true)
-            public static final String LATITUDE = "latitude";
-
-            /**
-             * The longitude where the image was captured.
-             *
-             * @deprecated location details are no longer indexed for privacy
-             *             reasons, and this value is now always {@code null}.
-             *             You can still manually obtain location metadata using
-             *             {@link ExifInterface#getLatLong(float[])}.
-             */
-            @Deprecated
-            @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true)
-            public static final String LONGITUDE = "longitude";
-
-            /** @removed promoted to parent interface */
-            public static final String DATE_TAKEN = "datetaken";
-            /** @removed promoted to parent interface */
-            public static final String ORIENTATION = "orientation";
-
-            /**
-             * The mini thumb id.
-             *
-             * @deprecated all thumbnails should be obtained via
-             *             {@link MediaStore.Images.Thumbnails#getThumbnail}, as this
-             *             value is no longer supported.
-             */
-            @Deprecated
-            @Column(Cursor.FIELD_TYPE_INTEGER)
-            public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
-
-            /** @removed promoted to parent interface */
-            public static final String BUCKET_ID = "bucket_id";
-            /** @removed promoted to parent interface */
-            public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
-            /** @removed promoted to parent interface */
-            public static final String GROUP_ID = "group_id";
-
-            /**
-             * Indexed value of {@link ExifInterface#TAG_IMAGE_DESCRIPTION}
-             * extracted from this media item.
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String DESCRIPTION = "description";
-
-            /**
-             * Indexed value of {@link ExifInterface#TAG_EXPOSURE_TIME}
-             * extracted from this media item.
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String EXPOSURE_TIME = "exposure_time";
-
-            /**
-             * Indexed value of {@link ExifInterface#TAG_F_NUMBER}
-             * extracted from this media item.
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String F_NUMBER = "f_number";
-
-            /**
-             * Indexed value of {@link ExifInterface#TAG_ISO_SPEED_RATINGS}
-             * extracted from this media item.
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String ISO = "iso";
-        }
-
-        public static final class Media implements ImageColumns {
-            /**
-             * @deprecated all queries should be performed through
-             *             {@link ContentResolver} directly, which offers modern
-             *             features like {@link CancellationSignal}.
-             */
-            @Deprecated
-            public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
-                return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
-            }
-
-            /**
-             * @deprecated all queries should be performed through
-             *             {@link ContentResolver} directly, which offers modern
-             *             features like {@link CancellationSignal}.
-             */
-            @Deprecated
-            public static final Cursor query(ContentResolver cr, Uri uri, String[] projection,
-                    String where, String orderBy) {
-                return cr.query(uri, projection, where,
-                                             null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
-            }
-
-            /**
-             * @deprecated all queries should be performed through
-             *             {@link ContentResolver} directly, which offers modern
-             *             features like {@link CancellationSignal}.
-             */
-            @Deprecated
-            public static final Cursor query(ContentResolver cr, Uri uri, String[] projection,
-                    String selection, String [] selectionArgs, String orderBy) {
-                return cr.query(uri, projection, selection,
-                        selectionArgs, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
-            }
-
-            /**
-             * Retrieves an image for the given url as a {@link Bitmap}.
-             *
-             * @param cr The content resolver to use
-             * @param url The url of the image
-             * @deprecated loading of images should be performed through
-             *             {@link ImageDecoder#createSource(ContentResolver, Uri)},
-             *             which offers modern features like
-             *             {@link PostProcessor}.
-             */
-            @Deprecated
-            public static final Bitmap getBitmap(ContentResolver cr, Uri url)
-                    throws FileNotFoundException, IOException {
-                InputStream input = cr.openInputStream(url);
-                Bitmap bitmap = BitmapFactory.decodeStream(input);
-                input.close();
-                return bitmap;
-            }
-
-            /**
-             * Insert an image and create a thumbnail for it.
-             *
-             * @param cr The content resolver to use
-             * @param imagePath The path to the image to insert
-             * @param name The name of the image
-             * @param description The description of the image
-             * @return The URL to the newly created image
-             * @deprecated inserting of images should be performed using
-             *             {@link MediaColumns#IS_PENDING}, which offers richer
-             *             control over lifecycle.
-             */
-            @Deprecated
-            public static final String insertImage(ContentResolver cr, String imagePath,
-                    String name, String description) throws FileNotFoundException {
-                final Bitmap source;
-                try {
-                    source = ImageDecoder
-                            .decodeBitmap(ImageDecoder.createSource(new File(imagePath)));
-                } catch (IOException e) {
-                    throw new FileNotFoundException(e.getMessage());
-                }
-                return insertImage(cr, source, name, description);
-            }
-
-            /**
-             * Insert an image and create a thumbnail for it.
-             *
-             * @param cr The content resolver to use
-             * @param source The stream to use for the image
-             * @param title The name of the image
-             * @param description The description of the image
-             * @return The URL to the newly created image, or <code>null</code> if the image failed to be stored
-             *              for any reason.
-             * @deprecated inserting of images should be performed using
-             *             {@link MediaColumns#IS_PENDING}, which offers richer
-             *             control over lifecycle.
-             */
-            @Deprecated
-            public static final String insertImage(ContentResolver cr, Bitmap source, String title,
-                    String description) {
-                if (TextUtils.isEmpty(title)) title = "Image";
-
-                final long now = System.currentTimeMillis();
-                final ContentValues values = new ContentValues();
-                values.put(MediaColumns.DISPLAY_NAME, title);
-                values.put(MediaColumns.MIME_TYPE, "image/jpeg");
-                values.put(MediaColumns.DATE_ADDED, now / 1000);
-                values.put(MediaColumns.DATE_MODIFIED, now / 1000);
-                values.put(MediaColumns.DATE_EXPIRES, (now + DateUtils.DAY_IN_MILLIS) / 1000);
-                values.put(MediaColumns.IS_PENDING, 1);
-
-                final Uri uri = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
-                try {
-                    try (OutputStream out = cr.openOutputStream(uri)) {
-                        source.compress(Bitmap.CompressFormat.JPEG, 90, out);
-                    }
-
-                    // Everything went well above, publish it!
-                    values.clear();
-                    values.put(MediaColumns.IS_PENDING, 0);
-                    values.putNull(MediaColumns.DATE_EXPIRES);
-                    cr.update(uri, values, null, null);
-                    return uri.toString();
-                } catch (Exception e) {
-                    Log.w(TAG, "Failed to insert image", e);
-                    cr.delete(uri, null, null);
-                    return null;
-                }
-            }
-
-            /**
-             * Get the content:// style URI for the image media table on the
-             * given volume.
-             *
-             * @param volumeName the name of the volume to get the URI for
-             * @return the URI to the image media table on the given volume
-             */
-            public static Uri getContentUri(String volumeName) {
-                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("images")
-                        .appendPath("media").build();
-            }
-
-            /**
-             * Get the content:// style URI for a single row in the images table
-             * on the given volume.
-             *
-             * @param volumeName the name of the volume to get the URI for
-             * @param id the image to get the URI for
-             * @return the URI to the images table on the given volume
-             */
-            public static @NonNull Uri getContentUri(@NonNull String volumeName, long id) {
-                return ContentUris.withAppendedId(getContentUri(volumeName), id);
-            }
-
-            /**
-             * The content:// style URI for the internal storage.
-             */
-            public static final Uri INTERNAL_CONTENT_URI =
-                    getContentUri("internal");
-
-            /**
-             * The content:// style URI for the "primary" external storage
-             * volume.
-             */
-            public static final Uri EXTERNAL_CONTENT_URI =
-                    getContentUri("external");
-
-            /**
-             * The MIME type of of this directory of
-             * images.  Note that each entry in this directory will have a standard
-             * image MIME type as appropriate -- for example, image/jpeg.
-             */
-            public static final String CONTENT_TYPE = "vnd.android.cursor.dir/image";
-
-            /**
-             * The default sort order for this table
-             */
-            public static final String DEFAULT_SORT_ORDER = ImageColumns.BUCKET_DISPLAY_NAME;
-        }
-
-        /**
-         * This class provides utility methods to obtain thumbnails for various
-         * {@link Images} items.
-         *
-         * @deprecated Callers should migrate to using
-         *             {@link ContentResolver#loadThumbnail}, since it offers
-         *             richer control over requested thumbnail sizes and
-         *             cancellation behavior.
-         */
-        @Deprecated
-        public static class Thumbnails implements BaseColumns {
-            /**
-             * @deprecated all queries should be performed through
-             *             {@link ContentResolver} directly, which offers modern
-             *             features like {@link CancellationSignal}.
-             */
-            @Deprecated
-            public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
-                return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
-            }
-
-            /**
-             * @deprecated all queries should be performed through
-             *             {@link ContentResolver} directly, which offers modern
-             *             features like {@link CancellationSignal}.
-             */
-            @Deprecated
-            public static final Cursor queryMiniThumbnails(ContentResolver cr, Uri uri, int kind,
-                    String[] projection) {
-                return cr.query(uri, projection, "kind = " + kind, null, DEFAULT_SORT_ORDER);
-            }
-
-            /**
-             * @deprecated all queries should be performed through
-             *             {@link ContentResolver} directly, which offers modern
-             *             features like {@link CancellationSignal}.
-             */
-            @Deprecated
-            public static final Cursor queryMiniThumbnail(ContentResolver cr, long origId, int kind,
-                    String[] projection) {
-                return cr.query(EXTERNAL_CONTENT_URI, projection,
-                        IMAGE_ID + " = " + origId + " AND " + KIND + " = " +
-                        kind, null, null);
-            }
-
-            /**
-             * Cancel any outstanding {@link #getThumbnail} requests, causing
-             * them to return by throwing a {@link OperationCanceledException}.
-             * <p>
-             * This method has no effect on
-             * {@link ContentResolver#loadThumbnail} calls, since they provide
-             * their own {@link CancellationSignal}.
-             *
-             * @deprecated Callers should migrate to using
-             *             {@link ContentResolver#loadThumbnail}, since it
-             *             offers richer control over requested thumbnail sizes
-             *             and cancellation behavior.
-             */
-            @Deprecated
-            public static void cancelThumbnailRequest(ContentResolver cr, long origId) {
-                final Uri uri = ContentUris.withAppendedId(
-                        Images.Media.EXTERNAL_CONTENT_URI, origId);
-                InternalThumbnails.cancelThumbnail(cr, uri);
-            }
-
-            /**
-             * Return thumbnail representing a specific image item. If a
-             * thumbnail doesn't exist, this method will block until it's
-             * generated. Callers are responsible for their own in-memory
-             * caching of returned values.
-             *
-             * As of {@link android.os.Build.VERSION_CODES#Q}, this output
-             * of the thumbnail has correct rotation, don't need to rotate
-             * it again.
-             *
-             * @param imageId the image item to obtain a thumbnail for.
-             * @param kind optimal thumbnail size desired.
-             * @return decoded thumbnail, or {@code null} if problem was
-             *         encountered.
-             * @deprecated Callers should migrate to using
-             *             {@link ContentResolver#loadThumbnail}, since it
-             *             offers richer control over requested thumbnail sizes
-             *             and cancellation behavior.
-             */
-            @Deprecated
-            public static Bitmap getThumbnail(ContentResolver cr, long imageId, int kind,
-                    BitmapFactory.Options options) {
-                final Uri uri = ContentUris.withAppendedId(
-                        Images.Media.EXTERNAL_CONTENT_URI, imageId);
-                return InternalThumbnails.getThumbnail(cr, uri, kind, options);
-            }
-
-            /**
-             * Cancel any outstanding {@link #getThumbnail} requests, causing
-             * them to return by throwing a {@link OperationCanceledException}.
-             * <p>
-             * This method has no effect on
-             * {@link ContentResolver#loadThumbnail} calls, since they provide
-             * their own {@link CancellationSignal}.
-             *
-             * @deprecated Callers should migrate to using
-             *             {@link ContentResolver#loadThumbnail}, since it
-             *             offers richer control over requested thumbnail sizes
-             *             and cancellation behavior.
-             */
-            @Deprecated
-            public static void cancelThumbnailRequest(ContentResolver cr, long origId,
-                    long groupId) {
-                cancelThumbnailRequest(cr, origId);
-            }
-
-            /**
-             * Return thumbnail representing a specific image item. If a
-             * thumbnail doesn't exist, this method will block until it's
-             * generated. Callers are responsible for their own in-memory
-             * caching of returned values.
-             *
-             * As of {@link android.os.Build.VERSION_CODES#Q}, this output
-             * of the thumbnail has correct rotation, don't need to rotate
-             * it again.
-             *
-             * @param imageId the image item to obtain a thumbnail for.
-             * @param kind optimal thumbnail size desired.
-             * @return decoded thumbnail, or {@code null} if problem was
-             *         encountered.
-             * @deprecated Callers should migrate to using
-             *             {@link ContentResolver#loadThumbnail}, since it
-             *             offers richer control over requested thumbnail sizes
-             *             and cancellation behavior.
-             */
-            @Deprecated
-            public static Bitmap getThumbnail(ContentResolver cr, long imageId, long groupId,
-                    int kind, BitmapFactory.Options options) {
-                return getThumbnail(cr, imageId, kind, options);
-            }
-
-            /**
-             * Get the content:// style URI for the image media table on the
-             * given volume.
-             *
-             * @param volumeName the name of the volume to get the URI for
-             * @return the URI to the image media table on the given volume
-             */
-            public static Uri getContentUri(String volumeName) {
-                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("images")
-                        .appendPath("thumbnails").build();
-            }
-
-            /**
-             * The content:// style URI for the internal storage.
-             */
-            public static final Uri INTERNAL_CONTENT_URI =
-                    getContentUri("internal");
-
-            /**
-             * The content:// style URI for the "primary" external storage
-             * volume.
-             */
-            public static final Uri EXTERNAL_CONTENT_URI =
-                    getContentUri("external");
-
-            /**
-             * The default sort order for this table
-             */
-            public static final String DEFAULT_SORT_ORDER = "image_id ASC";
-
-            /**
-             * Path to the thumbnail file on disk.
-             * <p>
-             * Note that apps may not have filesystem permissions to directly
-             * access this path. Instead of trying to open this path directly,
-             * apps should use
-             * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
-             * access.
-             *
-             * As of {@link android.os.Build.VERSION_CODES#Q}, this thumbnail
-             * has correct rotation, don't need to rotate it again.
-             *
-             * @deprecated Apps may not have filesystem permissions to directly
-             *             access this path. Instead of trying to open this path
-             *             directly, apps should use
-             *             {@link ContentResolver#loadThumbnail}
-             *             to gain access.
-             */
-            @Deprecated
-            @Column(Cursor.FIELD_TYPE_STRING)
-            public static final String DATA = "_data";
-
-            /**
-             * The original image for the thumbnal
-             */
-            @Column(Cursor.FIELD_TYPE_INTEGER)
-            public static final String IMAGE_ID = "image_id";
-
-            /**
-             * The kind of the thumbnail
-             */
-            @Column(Cursor.FIELD_TYPE_INTEGER)
-            public static final String KIND = "kind";
-
-            public static final int MINI_KIND = ThumbnailConstants.MINI_KIND;
-            public static final int FULL_SCREEN_KIND = ThumbnailConstants.FULL_SCREEN_KIND;
-            public static final int MICRO_KIND = ThumbnailConstants.MICRO_KIND;
-
-            /**
-             * Return the typical {@link Size} (in pixels) used internally when
-             * the given thumbnail kind is requested.
-             */
-            public static @NonNull Size getKindSize(int kind) {
-                return ThumbnailConstants.getKindSize(kind);
-            }
-
-            /**
-             * The blob raw data of thumbnail
-             *
-             * @deprecated this column never existed internally, and could never
-             *             have returned valid data.
-             */
-            @Deprecated
-            @Column(Cursor.FIELD_TYPE_BLOB)
-            public static final String THUMB_DATA = "thumb_data";
-
-            /**
-             * The width of the thumbnal
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String WIDTH = "width";
-
-            /**
-             * The height of the thumbnail
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String HEIGHT = "height";
-        }
-    }
-
-    /**
-     * Collection of all media with MIME type of {@code audio/*}.
-     */
-    public static final class Audio {
-        /**
-         * Audio metadata columns.
-         */
-        public interface AudioColumns extends MediaColumns {
-
-            /**
-             * A non human readable key calculated from the TITLE, used for
-             * searching, sorting and grouping
-             *
-             * @see Audio#keyFor(String)
-             * @deprecated These keys are generated using
-             *             {@link java.util.Locale#ROOT}, which means they don't
-             *             reflect locale-specific sorting preferences. To apply
-             *             locale-specific sorting preferences, use
-             *             {@link ContentResolver#QUERY_ARG_SQL_SORT_ORDER} with
-             *             {@code COLLATE LOCALIZED}, or
-             *             {@link ContentResolver#QUERY_ARG_SORT_LOCALE}.
-             */
-            @Deprecated
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String TITLE_KEY = "title_key";
-
-            /** @removed promoted to parent interface */
-            public static final String DURATION = "duration";
-
-            /**
-             * The position within the audio item at which playback should be
-             * resumed.
-             */
-            @DurationMillisLong
-            @Column(Cursor.FIELD_TYPE_INTEGER)
-            public static final String BOOKMARK = "bookmark";
-
-            /**
-             * The id of the artist who created the audio file, if any
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String ARTIST_ID = "artist_id";
-
-            /** @removed promoted to parent interface */
-            public static final String ARTIST = "artist";
-
-            /**
-             * The artist credited for the album that contains the audio file
-             * @hide
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String ALBUM_ARTIST = "album_artist";
-
-            /**
-             * A non human readable key calculated from the ARTIST, used for
-             * searching, sorting and grouping
-             *
-             * @see Audio#keyFor(String)
-             * @deprecated These keys are generated using
-             *             {@link java.util.Locale#ROOT}, which means they don't
-             *             reflect locale-specific sorting preferences. To apply
-             *             locale-specific sorting preferences, use
-             *             {@link ContentResolver#QUERY_ARG_SQL_SORT_ORDER} with
-             *             {@code COLLATE LOCALIZED}, or
-             *             {@link ContentResolver#QUERY_ARG_SORT_LOCALE}.
-             */
-            @Deprecated
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String ARTIST_KEY = "artist_key";
-
-            /** @removed promoted to parent interface */
-            public static final String COMPOSER = "composer";
-
-            /**
-             * The id of the album the audio file is from, if any
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String ALBUM_ID = "album_id";
-
-            /** @removed promoted to parent interface */
-            public static final String ALBUM = "album";
-
-            /**
-             * A non human readable key calculated from the ALBUM, used for
-             * searching, sorting and grouping
-             *
-             * @see Audio#keyFor(String)
-             * @deprecated These keys are generated using
-             *             {@link java.util.Locale#ROOT}, which means they don't
-             *             reflect locale-specific sorting preferences. To apply
-             *             locale-specific sorting preferences, use
-             *             {@link ContentResolver#QUERY_ARG_SQL_SORT_ORDER} with
-             *             {@code COLLATE LOCALIZED}, or
-             *             {@link ContentResolver#QUERY_ARG_SORT_LOCALE}.
-             */
-            @Deprecated
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String ALBUM_KEY = "album_key";
-
-            /**
-             * The track number of this song on the album, if any.
-             * This number encodes both the track number and the
-             * disc number. For multi-disc sets, this number will
-             * be 1xxx for tracks on the first disc, 2xxx for tracks
-             * on the second disc, etc.
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String TRACK = "track";
-
-            /**
-             * The year the audio file was recorded, if any
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String YEAR = "year";
-
-            /**
-             * Non-zero if the audio file is music
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String IS_MUSIC = "is_music";
-
-            /**
-             * Non-zero if the audio file is a podcast
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String IS_PODCAST = "is_podcast";
-
-            /**
-             * Non-zero if the audio file may be a ringtone
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String IS_RINGTONE = "is_ringtone";
-
-            /**
-             * Non-zero if the audio file may be an alarm
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String IS_ALARM = "is_alarm";
-
-            /**
-             * Non-zero if the audio file may be a notification sound
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String IS_NOTIFICATION = "is_notification";
-
-            /**
-             * Non-zero if the audio file is an audiobook
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String IS_AUDIOBOOK = "is_audiobook";
-
-            /**
-             * The id of the genre the audio file is from, if any
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String GENRE_ID = "genre_id";
-
-            /**
-             * The genre of the audio file, if any.
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String GENRE = "genre";
-
-            /**
-             * A non human readable key calculated from the GENRE, used for
-             * searching, sorting and grouping
-             *
-             * @see Audio#keyFor(String)
-             * @deprecated These keys are generated using
-             *             {@link java.util.Locale#ROOT}, which means they don't
-             *             reflect locale-specific sorting preferences. To apply
-             *             locale-specific sorting preferences, use
-             *             {@link ContentResolver#QUERY_ARG_SQL_SORT_ORDER} with
-             *             {@code COLLATE LOCALIZED}, or
-             *             {@link ContentResolver#QUERY_ARG_SORT_LOCALE}.
-             */
-            @Deprecated
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String GENRE_KEY = "genre_key";
-
-            /**
-             * The resource URI of a localized title, if any.
-             * <p>
-             * Conforms to this pattern:
-             * <ul>
-             * <li>Scheme: {@link ContentResolver#SCHEME_ANDROID_RESOURCE}
-             * <li>Authority: Package Name of ringtone title provider
-             * <li>First Path Segment: Type of resource (must be "string")
-             * <li>Second Path Segment: Resource ID of title
-             * </ul>
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String TITLE_RESOURCE_URI = "title_resource_uri";
-        }
-
-        private static final Pattern PATTERN_TRIM_BEFORE = Pattern.compile(
-                "(?i)(^(the|an|a) |,\\s*(the|an|a)$|[^\\w\\s]|^\\s+|\\s+$)");
-        private static final Pattern PATTERN_TRIM_AFTER = Pattern.compile(
-                "(^(00)+|(00)+$)");
-
-        /**
-         * Converts a user-visible string into a "key" that can be used for
-         * grouping, sorting, and searching.
-         *
-         * @return Opaque token that should not be parsed or displayed to users.
-         * @deprecated These keys are generated using
-         *             {@link java.util.Locale#ROOT}, which means they don't
-         *             reflect locale-specific sorting preferences. To apply
-         *             locale-specific sorting preferences, use
-         *             {@link ContentResolver#QUERY_ARG_SQL_SORT_ORDER} with
-         *             {@code COLLATE LOCALIZED}, or
-         *             {@link ContentResolver#QUERY_ARG_SORT_LOCALE}.
-         */
-        @Deprecated
-        public static @Nullable String keyFor(@Nullable String name) {
-            if (TextUtils.isEmpty(name)) return null;
-
-            if (UNKNOWN_STRING.equals(name)) {
-                return "01";
-            }
-
-            final boolean sortFirst = name.startsWith("\001");
-
-            name = PATTERN_TRIM_BEFORE.matcher(name).replaceAll("");
-            if (TextUtils.isEmpty(name)) return null;
-
-            final Collator c = Collator.getInstance(Locale.ROOT);
-            c.setStrength(Collator.PRIMARY);
-            name = HexEncoding.encodeToString(c.getCollationKey(name).toByteArray(), false);
-
-            name = PATTERN_TRIM_AFTER.matcher(name).replaceAll("");
-            if (sortFirst) {
-                name = "01" + name;
-            }
-            return name;
-        }
-
-        public static final class Media implements AudioColumns {
-            /**
-             * Get the content:// style URI for the audio media table on the
-             * given volume.
-             *
-             * @param volumeName the name of the volume to get the URI for
-             * @return the URI to the audio media table on the given volume
-             */
-            public static Uri getContentUri(String volumeName) {
-                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
-                        .appendPath("media").build();
-            }
-
-            /**
-             * Get the content:// style URI for a single row in the audio table
-             * on the given volume.
-             *
-             * @param volumeName the name of the volume to get the URI for
-             * @param id the audio to get the URI for
-             * @return the URI to the audio table on the given volume
-             */
-            public static @NonNull Uri getContentUri(@NonNull String volumeName, long id) {
-                return ContentUris.withAppendedId(getContentUri(volumeName), id);
-            }
-
-            /**
-             * Get the content:// style URI for the given audio media file.
-             *
-             * @deprecated Apps may not have filesystem permissions to directly
-             *             access this path.
-             */
-            @Deprecated
-            public static @Nullable Uri getContentUriForPath(@NonNull String path) {
-                return getContentUri(getVolumeName(new File(path)));
-            }
-
-            /**
-             * The content:// style URI for the internal storage.
-             */
-            public static final Uri INTERNAL_CONTENT_URI =
-                    getContentUri("internal");
-
-            /**
-             * The content:// style URI for the "primary" external storage
-             * volume.
-             */
-            public static final Uri EXTERNAL_CONTENT_URI =
-                    getContentUri("external");
-
-            /**
-             * The MIME type for this table.
-             */
-            public static final String CONTENT_TYPE = "vnd.android.cursor.dir/audio";
-
-            /**
-             * The MIME type for an audio track.
-             */
-            public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/audio";
-
-            /**
-             * The default sort order for this table
-             */
-            public static final String DEFAULT_SORT_ORDER = TITLE_KEY;
-
-            /**
-             * Activity Action: Start SoundRecorder application.
-             * <p>Input: nothing.
-             * <p>Output: An uri to the recorded sound stored in the Media Library
-             * if the recording was successful.
-             * May also contain the extra EXTRA_MAX_BYTES.
-             * @see #EXTRA_MAX_BYTES
-             */
-            @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-            public static final String RECORD_SOUND_ACTION =
-                    "android.provider.MediaStore.RECORD_SOUND";
-
-            /**
-             * The name of the Intent-extra used to define a maximum file size for
-             * a recording made by the SoundRecorder application.
-             *
-             * @see #RECORD_SOUND_ACTION
-             */
-             public static final String EXTRA_MAX_BYTES =
-                    "android.provider.MediaStore.extra.MAX_BYTES";
-        }
-
-        /**
-         * Audio genre metadata columns.
-         */
-        public interface GenresColumns {
-            /**
-             * The name of the genre
-             */
-            @Column(Cursor.FIELD_TYPE_STRING)
-            public static final String NAME = "name";
-        }
-
-        /**
-         * Contains all genres for audio files
-         */
-        public static final class Genres implements BaseColumns, GenresColumns {
-            /**
-             * Get the content:// style URI for the audio genres table on the
-             * given volume.
-             *
-             * @param volumeName the name of the volume to get the URI for
-             * @return the URI to the audio genres table on the given volume
-             */
-            public static Uri getContentUri(String volumeName) {
-                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
-                        .appendPath("genres").build();
-            }
-
-            /**
-             * Get the content:// style URI for querying the genres of an audio file.
-             *
-             * @param volumeName the name of the volume to get the URI for
-             * @param audioId the ID of the audio file for which to retrieve the genres
-             * @return the URI to for querying the genres for the audio file
-             * with the given the volume and audioID
-             */
-            public static Uri getContentUriForAudioId(String volumeName, int audioId) {
-                return ContentUris.withAppendedId(Audio.Media.getContentUri(volumeName), audioId)
-                        .buildUpon().appendPath("genres").build();
-            }
-
-            /**
-             * The content:// style URI for the internal storage.
-             */
-            public static final Uri INTERNAL_CONTENT_URI =
-                    getContentUri("internal");
-
-            /**
-             * The content:// style URI for the "primary" external storage
-             * volume.
-             */
-            public static final Uri EXTERNAL_CONTENT_URI =
-                    getContentUri("external");
-
-            /**
-             * The MIME type for this table.
-             */
-            public static final String CONTENT_TYPE = "vnd.android.cursor.dir/genre";
-
-            /**
-             * The MIME type for entries in this table.
-             */
-            public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/genre";
-
-            /**
-             * The default sort order for this table
-             */
-            public static final String DEFAULT_SORT_ORDER = NAME;
-
-            /**
-             * Sub-directory of each genre containing all members.
-             */
-            public static final class Members implements AudioColumns {
-
-                public static final Uri getContentUri(String volumeName, long genreId) {
-                    return ContentUris
-                            .withAppendedId(Audio.Genres.getContentUri(volumeName), genreId)
-                            .buildUpon().appendPath("members").build();
-                }
-
-                /**
-                 * A subdirectory of each genre containing all member audio files.
-                 */
-                public static final String CONTENT_DIRECTORY = "members";
-
-                /**
-                 * The default sort order for this table
-                 */
-                public static final String DEFAULT_SORT_ORDER = TITLE_KEY;
-
-                /**
-                 * The ID of the audio file
-                 */
-                @Column(Cursor.FIELD_TYPE_INTEGER)
-                public static final String AUDIO_ID = "audio_id";
-
-                /**
-                 * The ID of the genre
-                 */
-                @Column(Cursor.FIELD_TYPE_INTEGER)
-                public static final String GENRE_ID = "genre_id";
-            }
-        }
-
-        /**
-         * Audio playlist metadata columns.
-         */
-        public interface PlaylistsColumns {
-            /**
-             * The name of the playlist
-             */
-            @Column(Cursor.FIELD_TYPE_STRING)
-            public static final String NAME = "name";
-
-            /**
-             * Path to the playlist file on disk.
-             * <p>
-             * Note that apps may not have filesystem permissions to directly
-             * access this path. Instead of trying to open this path directly,
-             * apps should use
-             * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
-             * access.
-             *
-             * @deprecated Apps may not have filesystem permissions to directly
-             *             access this path. Instead of trying to open this path
-             *             directly, apps should use
-             *             {@link ContentResolver#openFileDescriptor(Uri, String)}
-             *             to gain access.
-             */
-            @Deprecated
-            @Column(Cursor.FIELD_TYPE_STRING)
-            public static final String DATA = "_data";
-
-            /**
-             * The time the media item was first added.
-             */
-            @CurrentTimeSecondsLong
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String DATE_ADDED = "date_added";
-
-            /**
-             * The time the media item was last modified.
-             */
-            @CurrentTimeSecondsLong
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String DATE_MODIFIED = "date_modified";
-        }
-
-        /**
-         * Contains playlists for audio files
-         */
-        public static final class Playlists implements BaseColumns,
-                PlaylistsColumns {
-            /**
-             * Get the content:// style URI for the audio playlists table on the
-             * given volume.
-             *
-             * @param volumeName the name of the volume to get the URI for
-             * @return the URI to the audio playlists table on the given volume
-             */
-            public static Uri getContentUri(String volumeName) {
-                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
-                        .appendPath("playlists").build();
-            }
-
-            /**
-             * The content:// style URI for the internal storage.
-             */
-            public static final Uri INTERNAL_CONTENT_URI =
-                    getContentUri("internal");
-
-            /**
-             * The content:// style URI for the "primary" external storage
-             * volume.
-             */
-            public static final Uri EXTERNAL_CONTENT_URI =
-                    getContentUri("external");
-
-            /**
-             * The MIME type for this table.
-             */
-            public static final String CONTENT_TYPE = "vnd.android.cursor.dir/playlist";
-
-            /**
-             * The MIME type for entries in this table.
-             */
-            public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/playlist";
-
-            /**
-             * The default sort order for this table
-             */
-            public static final String DEFAULT_SORT_ORDER = NAME;
-
-            /**
-             * Sub-directory of each playlist containing all members.
-             */
-            public static final class Members implements AudioColumns {
-                public static final Uri getContentUri(String volumeName, long playlistId) {
-                    return ContentUris
-                            .withAppendedId(Audio.Playlists.getContentUri(volumeName), playlistId)
-                            .buildUpon().appendPath("members").build();
-                }
-
-                /**
-                 * Convenience method to move a playlist item to a new location
-                 * @param res The content resolver to use
-                 * @param playlistId The numeric id of the playlist
-                 * @param from The position of the item to move
-                 * @param to The position to move the item to
-                 * @return true on success
-                 */
-                public static final boolean moveItem(ContentResolver res,
-                        long playlistId, int from, int to) {
-                    Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external",
-                            playlistId)
-                            .buildUpon()
-                            .appendEncodedPath(String.valueOf(from))
-                            .appendQueryParameter("move", "true")
-                            .build();
-                    ContentValues values = new ContentValues();
-                    values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, to);
-                    return res.update(uri, values, null, null) != 0;
-                }
-
-                /**
-                 * The ID within the playlist.
-                 */
-                @Column(Cursor.FIELD_TYPE_INTEGER)
-                public static final String _ID = "_id";
-
-                /**
-                 * A subdirectory of each playlist containing all member audio
-                 * files.
-                 */
-                public static final String CONTENT_DIRECTORY = "members";
-
-                /**
-                 * The ID of the audio file
-                 */
-                @Column(Cursor.FIELD_TYPE_INTEGER)
-                public static final String AUDIO_ID = "audio_id";
-
-                /**
-                 * The ID of the playlist
-                 */
-                @Column(Cursor.FIELD_TYPE_INTEGER)
-                public static final String PLAYLIST_ID = "playlist_id";
-
-                /**
-                 * The order of the songs in the playlist
-                 */
-                @Column(Cursor.FIELD_TYPE_INTEGER)
-                public static final String PLAY_ORDER = "play_order";
-
-                /**
-                 * The default sort order for this table
-                 */
-                public static final String DEFAULT_SORT_ORDER = PLAY_ORDER;
-            }
-        }
-
-        /**
-         * Audio artist metadata columns.
-         */
-        public interface ArtistColumns {
-            /**
-             * The artist who created the audio file, if any
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String ARTIST = "artist";
-
-            /**
-             * A non human readable key calculated from the ARTIST, used for
-             * searching, sorting and grouping
-             *
-             * @see Audio#keyFor(String)
-             * @deprecated These keys are generated using
-             *             {@link java.util.Locale#ROOT}, which means they don't
-             *             reflect locale-specific sorting preferences. To apply
-             *             locale-specific sorting preferences, use
-             *             {@link ContentResolver#QUERY_ARG_SQL_SORT_ORDER} with
-             *             {@code COLLATE LOCALIZED}, or
-             *             {@link ContentResolver#QUERY_ARG_SORT_LOCALE}.
-             */
-            @Deprecated
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String ARTIST_KEY = "artist_key";
-
-            /**
-             * The number of albums in the database for this artist
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String NUMBER_OF_ALBUMS = "number_of_albums";
-
-            /**
-             * The number of albums in the database for this artist
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String NUMBER_OF_TRACKS = "number_of_tracks";
-        }
-
-        /**
-         * Contains artists for audio files
-         */
-        public static final class Artists implements BaseColumns, ArtistColumns {
-            /**
-             * Get the content:// style URI for the artists table on the
-             * given volume.
-             *
-             * @param volumeName the name of the volume to get the URI for
-             * @return the URI to the audio artists table on the given volume
-             */
-            public static Uri getContentUri(String volumeName) {
-                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
-                        .appendPath("artists").build();
-            }
-
-            /**
-             * The content:// style URI for the internal storage.
-             */
-            public static final Uri INTERNAL_CONTENT_URI =
-                    getContentUri("internal");
-
-            /**
-             * The content:// style URI for the "primary" external storage
-             * volume.
-             */
-            public static final Uri EXTERNAL_CONTENT_URI =
-                    getContentUri("external");
-
-            /**
-             * The MIME type for this table.
-             */
-            public static final String CONTENT_TYPE = "vnd.android.cursor.dir/artists";
-
-            /**
-             * The MIME type for entries in this table.
-             */
-            public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/artist";
-
-            /**
-             * The default sort order for this table
-             */
-            public static final String DEFAULT_SORT_ORDER = ARTIST_KEY;
-
-            /**
-             * Sub-directory of each artist containing all albums on which
-             * a song by the artist appears.
-             */
-            public static final class Albums implements AlbumColumns {
-                public static final Uri getContentUri(String volumeName,long artistId) {
-                    return ContentUris
-                            .withAppendedId(Audio.Artists.getContentUri(volumeName), artistId)
-                            .buildUpon().appendPath("albums").build();
-                }
-            }
-        }
-
-        /**
-         * Audio album metadata columns.
-         */
-        public interface AlbumColumns {
-
-            /**
-             * The id for the album
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String ALBUM_ID = "album_id";
-
-            /**
-             * The album on which the audio file appears, if any
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String ALBUM = "album";
-
-            /**
-             * The ID of the artist whose songs appear on this album.
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String ARTIST_ID = "artist_id";
-
-            /**
-             * The name of the artist whose songs appear on this album.
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String ARTIST = "artist";
-
-            /**
-             * A non human readable key calculated from the ARTIST, used for
-             * searching, sorting and grouping
-             *
-             * @see Audio#keyFor(String)
-             * @deprecated These keys are generated using
-             *             {@link java.util.Locale#ROOT}, which means they don't
-             *             reflect locale-specific sorting preferences. To apply
-             *             locale-specific sorting preferences, use
-             *             {@link ContentResolver#QUERY_ARG_SQL_SORT_ORDER} with
-             *             {@code COLLATE LOCALIZED}, or
-             *             {@link ContentResolver#QUERY_ARG_SORT_LOCALE}.
-             */
-            @Deprecated
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String ARTIST_KEY = "artist_key";
-
-            /**
-             * The number of songs on this album
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String NUMBER_OF_SONGS = "numsongs";
-
-            /**
-             * This column is available when getting album info via artist,
-             * and indicates the number of songs on the album by the given
-             * artist.
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String NUMBER_OF_SONGS_FOR_ARTIST = "numsongs_by_artist";
-
-            /**
-             * The year in which the earliest songs
-             * on this album were released. This will often
-             * be the same as {@link #LAST_YEAR}, but for compilation albums
-             * they might differ.
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String FIRST_YEAR = "minyear";
-
-            /**
-             * The year in which the latest songs
-             * on this album were released. This will often
-             * be the same as {@link #FIRST_YEAR}, but for compilation albums
-             * they might differ.
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String LAST_YEAR = "maxyear";
-
-            /**
-             * A non human readable key calculated from the ALBUM, used for
-             * searching, sorting and grouping
-             *
-             * @see Audio#keyFor(String)
-             * @deprecated These keys are generated using
-             *             {@link java.util.Locale#ROOT}, which means they don't
-             *             reflect locale-specific sorting preferences. To apply
-             *             locale-specific sorting preferences, use
-             *             {@link ContentResolver#QUERY_ARG_SQL_SORT_ORDER} with
-             *             {@code COLLATE LOCALIZED}, or
-             *             {@link ContentResolver#QUERY_ARG_SORT_LOCALE}.
-             */
-            @Deprecated
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String ALBUM_KEY = "album_key";
-
-            /**
-             * Cached album art.
-             *
-             * @deprecated Apps may not have filesystem permissions to directly
-             *             access this path. Instead of trying to open this path
-             *             directly, apps should use
-             *             {@link ContentResolver#loadThumbnail}
-             *             to gain access.
-             */
-            @Deprecated
-            @Column(Cursor.FIELD_TYPE_STRING)
-            public static final String ALBUM_ART = "album_art";
-        }
-
-        /**
-         * Contains artists for audio files
-         */
-        public static final class Albums implements BaseColumns, AlbumColumns {
-            /**
-             * Get the content:// style URI for the albums table on the
-             * given volume.
-             *
-             * @param volumeName the name of the volume to get the URI for
-             * @return the URI to the audio albums table on the given volume
-             */
-            public static Uri getContentUri(String volumeName) {
-                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
-                        .appendPath("albums").build();
-            }
-
-            /**
-             * The content:// style URI for the internal storage.
-             */
-            public static final Uri INTERNAL_CONTENT_URI =
-                    getContentUri("internal");
-
-            /**
-             * The content:// style URI for the "primary" external storage
-             * volume.
-             */
-            public static final Uri EXTERNAL_CONTENT_URI =
-                    getContentUri("external");
-
-            /**
-             * The MIME type for this table.
-             */
-            public static final String CONTENT_TYPE = "vnd.android.cursor.dir/albums";
-
-            /**
-             * The MIME type for entries in this table.
-             */
-            public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/album";
-
-            /**
-             * The default sort order for this table
-             */
-            public static final String DEFAULT_SORT_ORDER = ALBUM_KEY;
-        }
-
-        public static final class Radio {
-            /**
-             * The MIME type for entries in this table.
-             */
-            public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/radio";
-
-            // Not instantiable.
-            private Radio() { }
-        }
-
-        /**
-         * This class provides utility methods to obtain thumbnails for various
-         * {@link Audio} items.
-         *
-         * @deprecated Callers should migrate to using
-         *             {@link ContentResolver#loadThumbnail}, since it offers
-         *             richer control over requested thumbnail sizes and
-         *             cancellation behavior.
-         * @hide
-         */
-        @Deprecated
-        public static class Thumbnails implements BaseColumns {
-            /**
-             * Path to the thumbnail file on disk.
-             * <p>
-             * Note that apps may not have filesystem permissions to directly
-             * access this path. Instead of trying to open this path directly,
-             * apps should use
-             * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
-             * access.
-             *
-             * @deprecated Apps may not have filesystem permissions to directly
-             *             access this path. Instead of trying to open this path
-             *             directly, apps should use
-             *             {@link ContentResolver#loadThumbnail}
-             *             to gain access.
-             */
-            @Deprecated
-            @Column(Cursor.FIELD_TYPE_STRING)
-            public static final String DATA = "_data";
-
-            @Column(Cursor.FIELD_TYPE_INTEGER)
-            public static final String ALBUM_ID = "album_id";
-        }
-    }
-
-    /**
-     * Collection of all media with MIME type of {@code video/*}.
-     */
-    public static final class Video {
-
-        /**
-         * The default sort order for this table.
-         */
-        public static final String DEFAULT_SORT_ORDER = MediaColumns.DISPLAY_NAME;
-
-        /**
-         * @deprecated all queries should be performed through
-         *             {@link ContentResolver} directly, which offers modern
-         *             features like {@link CancellationSignal}.
-         */
-        @Deprecated
-        public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
-            return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
-        }
-
-        /**
-         * Video metadata columns.
-         */
-        public interface VideoColumns extends MediaColumns {
-            /** @removed promoted to parent interface */
-            public static final String DURATION = "duration";
-            /** @removed promoted to parent interface */
-            public static final String ARTIST = "artist";
-            /** @removed promoted to parent interface */
-            public static final String ALBUM = "album";
-            /** @removed promoted to parent interface */
-            public static final String RESOLUTION = "resolution";
-
-            /**
-             * The description of the video recording
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String DESCRIPTION = "description";
-
-            /**
-             * Whether the video should be published as public or private
-             */
-            @Column(Cursor.FIELD_TYPE_INTEGER)
-            public static final String IS_PRIVATE = "isprivate";
-
-            /**
-             * The user-added tags associated with a video
-             */
-            @Column(Cursor.FIELD_TYPE_STRING)
-            public static final String TAGS = "tags";
-
-            /**
-             * The YouTube category of the video
-             */
-            @Column(Cursor.FIELD_TYPE_STRING)
-            public static final String CATEGORY = "category";
-
-            /**
-             * The language of the video
-             */
-            @Column(Cursor.FIELD_TYPE_STRING)
-            public static final String LANGUAGE = "language";
-
-            /**
-             * The latitude where the video was captured.
-             *
-             * @deprecated location details are no longer indexed for privacy
-             *             reasons, and this value is now always {@code null}.
-             *             You can still manually obtain location metadata using
-             *             {@link ExifInterface#getLatLong(float[])}.
-             */
-            @Deprecated
-            @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true)
-            public static final String LATITUDE = "latitude";
-
-            /**
-             * The longitude where the video was captured.
-             *
-             * @deprecated location details are no longer indexed for privacy
-             *             reasons, and this value is now always {@code null}.
-             *             You can still manually obtain location metadata using
-             *             {@link ExifInterface#getLatLong(float[])}.
-             */
-            @Deprecated
-            @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true)
-            public static final String LONGITUDE = "longitude";
-
-            /** @removed promoted to parent interface */
-            public static final String DATE_TAKEN = "datetaken";
-
-            /**
-             * The mini thumb id.
-             *
-             * @deprecated all thumbnails should be obtained via
-             *             {@link MediaStore.Images.Thumbnails#getThumbnail}, as this
-             *             value is no longer supported.
-             */
-            @Deprecated
-            @Column(Cursor.FIELD_TYPE_INTEGER)
-            public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
-
-            /** @removed promoted to parent interface */
-            public static final String BUCKET_ID = "bucket_id";
-            /** @removed promoted to parent interface */
-            public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
-            /** @removed promoted to parent interface */
-            public static final String GROUP_ID = "group_id";
-
-            /**
-             * The position within the video item at which playback should be
-             * resumed.
-             */
-            @DurationMillisLong
-            @Column(Cursor.FIELD_TYPE_INTEGER)
-            public static final String BOOKMARK = "bookmark";
-
-            /**
-             * The color standard of this media file, if available.
-             *
-             * @see MediaFormat#COLOR_STANDARD_BT709
-             * @see MediaFormat#COLOR_STANDARD_BT601_PAL
-             * @see MediaFormat#COLOR_STANDARD_BT601_NTSC
-             * @see MediaFormat#COLOR_STANDARD_BT2020
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String COLOR_STANDARD = "color_standard";
-
-            /**
-             * The color transfer of this media file, if available.
-             *
-             * @see MediaFormat#COLOR_TRANSFER_LINEAR
-             * @see MediaFormat#COLOR_TRANSFER_SDR_VIDEO
-             * @see MediaFormat#COLOR_TRANSFER_ST2084
-             * @see MediaFormat#COLOR_TRANSFER_HLG
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String COLOR_TRANSFER = "color_transfer";
-
-            /**
-             * The color range of this media file, if available.
-             *
-             * @see MediaFormat#COLOR_RANGE_LIMITED
-             * @see MediaFormat#COLOR_RANGE_FULL
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String COLOR_RANGE = "color_range";
-        }
-
-        public static final class Media implements VideoColumns {
-            /**
-             * Get the content:// style URI for the video media table on the
-             * given volume.
-             *
-             * @param volumeName the name of the volume to get the URI for
-             * @return the URI to the video media table on the given volume
-             */
-            public static Uri getContentUri(String volumeName) {
-                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("video")
-                        .appendPath("media").build();
-            }
-
-            /**
-             * Get the content:// style URI for a single row in the videos table
-             * on the given volume.
-             *
-             * @param volumeName the name of the volume to get the URI for
-             * @param id the video to get the URI for
-             * @return the URI to the videos table on the given volume
-             */
-            public static @NonNull Uri getContentUri(@NonNull String volumeName, long id) {
-                return ContentUris.withAppendedId(getContentUri(volumeName), id);
-            }
-
-            /**
-             * The content:// style URI for the internal storage.
-             */
-            public static final Uri INTERNAL_CONTENT_URI =
-                    getContentUri("internal");
-
-            /**
-             * The content:// style URI for the "primary" external storage
-             * volume.
-             */
-            public static final Uri EXTERNAL_CONTENT_URI =
-                    getContentUri("external");
-
-            /**
-             * The MIME type for this table.
-             */
-            public static final String CONTENT_TYPE = "vnd.android.cursor.dir/video";
-
-            /**
-             * The default sort order for this table
-             */
-            public static final String DEFAULT_SORT_ORDER = TITLE;
-        }
-
-        /**
-         * This class provides utility methods to obtain thumbnails for various
-         * {@link Video} items.
-         *
-         * @deprecated Callers should migrate to using
-         *             {@link ContentResolver#loadThumbnail}, since it offers
-         *             richer control over requested thumbnail sizes and
-         *             cancellation behavior.
-         */
-        @Deprecated
-        public static class Thumbnails implements BaseColumns {
-            /**
-             * Cancel any outstanding {@link #getThumbnail} requests, causing
-             * them to return by throwing a {@link OperationCanceledException}.
-             * <p>
-             * This method has no effect on
-             * {@link ContentResolver#loadThumbnail} calls, since they provide
-             * their own {@link CancellationSignal}.
-             *
-             * @deprecated Callers should migrate to using
-             *             {@link ContentResolver#loadThumbnail}, since it
-             *             offers richer control over requested thumbnail sizes
-             *             and cancellation behavior.
-             */
-            @Deprecated
-            public static void cancelThumbnailRequest(ContentResolver cr, long origId) {
-                final Uri uri = ContentUris.withAppendedId(
-                        Video.Media.EXTERNAL_CONTENT_URI, origId);
-                InternalThumbnails.cancelThumbnail(cr, uri);
-            }
-
-            /**
-             * Return thumbnail representing a specific video item. If a
-             * thumbnail doesn't exist, this method will block until it's
-             * generated. Callers are responsible for their own in-memory
-             * caching of returned values.
-             *
-             * @param videoId the video item to obtain a thumbnail for.
-             * @param kind optimal thumbnail size desired.
-             * @return decoded thumbnail, or {@code null} if problem was
-             *         encountered.
-             * @deprecated Callers should migrate to using
-             *             {@link ContentResolver#loadThumbnail}, since it
-             *             offers richer control over requested thumbnail sizes
-             *             and cancellation behavior.
-             */
-            @Deprecated
-            public static Bitmap getThumbnail(ContentResolver cr, long videoId, int kind,
-                    BitmapFactory.Options options) {
-                final Uri uri = ContentUris.withAppendedId(
-                        Video.Media.EXTERNAL_CONTENT_URI, videoId);
-                return InternalThumbnails.getThumbnail(cr, uri, kind, options);
-            }
-
-            /**
-             * Cancel any outstanding {@link #getThumbnail} requests, causing
-             * them to return by throwing a {@link OperationCanceledException}.
-             * <p>
-             * This method has no effect on
-             * {@link ContentResolver#loadThumbnail} calls, since they provide
-             * their own {@link CancellationSignal}.
-             *
-             * @deprecated Callers should migrate to using
-             *             {@link ContentResolver#loadThumbnail}, since it
-             *             offers richer control over requested thumbnail sizes
-             *             and cancellation behavior.
-             */
-            @Deprecated
-            public static void cancelThumbnailRequest(ContentResolver cr, long videoId,
-                    long groupId) {
-                cancelThumbnailRequest(cr, videoId);
-            }
-
-            /**
-             * Return thumbnail representing a specific video item. If a
-             * thumbnail doesn't exist, this method will block until it's
-             * generated. Callers are responsible for their own in-memory
-             * caching of returned values.
-             *
-             * @param videoId the video item to obtain a thumbnail for.
-             * @param kind optimal thumbnail size desired.
-             * @return decoded thumbnail, or {@code null} if problem was
-             *         encountered.
-             * @deprecated Callers should migrate to using
-             *             {@link ContentResolver#loadThumbnail}, since it
-             *             offers richer control over requested thumbnail sizes
-             *             and cancellation behavior.
-             */
-            @Deprecated
-            public static Bitmap getThumbnail(ContentResolver cr, long videoId, long groupId,
-                    int kind, BitmapFactory.Options options) {
-                return getThumbnail(cr, videoId, kind, options);
-            }
-
-            /**
-             * Get the content:// style URI for the image media table on the
-             * given volume.
-             *
-             * @param volumeName the name of the volume to get the URI for
-             * @return the URI to the image media table on the given volume
-             */
-            public static Uri getContentUri(String volumeName) {
-                return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("video")
-                        .appendPath("thumbnails").build();
-            }
-
-            /**
-             * The content:// style URI for the internal storage.
-             */
-            public static final Uri INTERNAL_CONTENT_URI =
-                    getContentUri("internal");
-
-            /**
-             * The content:// style URI for the "primary" external storage
-             * volume.
-             */
-            public static final Uri EXTERNAL_CONTENT_URI =
-                    getContentUri("external");
-
-            /**
-             * The default sort order for this table
-             */
-            public static final String DEFAULT_SORT_ORDER = "video_id ASC";
-
-            /**
-             * Path to the thumbnail file on disk.
-             *
-             * @deprecated Apps may not have filesystem permissions to directly
-             *             access this path. Instead of trying to open this path
-             *             directly, apps should use
-             *             {@link ContentResolver#openFileDescriptor(Uri, String)}
-             *             to gain access.
-             */
-            @Deprecated
-            @Column(Cursor.FIELD_TYPE_STRING)
-            public static final String DATA = "_data";
-
-            /**
-             * The original image for the thumbnal
-             */
-            @Column(Cursor.FIELD_TYPE_INTEGER)
-            public static final String VIDEO_ID = "video_id";
-
-            /**
-             * The kind of the thumbnail
-             */
-            @Column(Cursor.FIELD_TYPE_INTEGER)
-            public static final String KIND = "kind";
-
-            public static final int MINI_KIND = ThumbnailConstants.MINI_KIND;
-            public static final int FULL_SCREEN_KIND = ThumbnailConstants.FULL_SCREEN_KIND;
-            public static final int MICRO_KIND = ThumbnailConstants.MICRO_KIND;
-
-            /**
-             * Return the typical {@link Size} (in pixels) used internally when
-             * the given thumbnail kind is requested.
-             */
-            public static @NonNull Size getKindSize(int kind) {
-                return ThumbnailConstants.getKindSize(kind);
-            }
-
-            /**
-             * The width of the thumbnal
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String WIDTH = "width";
-
-            /**
-             * The height of the thumbnail
-             */
-            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-            public static final String HEIGHT = "height";
-        }
-    }
-
-    /** @removed */
-    @Deprecated
-    public static @NonNull Set<String> getAllVolumeNames(@NonNull Context context) {
-        return getExternalVolumeNames(context);
-    }
-
-    /**
-     * Return list of all specific volume names that make up
-     * {@link #VOLUME_EXTERNAL}. This includes a unique volume name for each
-     * shared storage device that is currently attached, which typically
-     * includes {@link MediaStore#VOLUME_EXTERNAL_PRIMARY}.
-     * <p>
-     * Each specific volume name can be passed to APIs like
-     * {@link MediaStore.Images.Media#getContentUri(String)} to interact with
-     * media on that storage device.
-     */
-    public static @NonNull Set<String> getExternalVolumeNames(@NonNull Context context) {
-        final StorageManager sm = context.getSystemService(StorageManager.class);
-        final Set<String> res = new ArraySet<>();
-        for (StorageVolume sv : sm.getStorageVolumes()) {
-            switch (sv.getState()) {
-                case Environment.MEDIA_MOUNTED:
-                case Environment.MEDIA_MOUNTED_READ_ONLY: {
-                    final String volumeName = sv.getMediaStoreVolumeName();
-                    if (volumeName != null) {
-                        res.add(volumeName);
-                    }
-                    break;
-                }
-            }
-        }
-        return res;
-    }
-
-    /**
-     * Return list of all recent volume names that have been part of
-     * {@link #VOLUME_EXTERNAL}.
-     * <p>
-     * These volume names are not currently mounted, but they're likely to
-     * reappear in the future, so apps are encouraged to preserve any indexed
-     * metadata related to these volumes to optimize user experiences.
-     * <p>
-     * Each specific volume name can be passed to APIs like
-     * {@link MediaStore.Images.Media#getContentUri(String)} to interact with
-     * media on that storage device.
-     */
-    public static @NonNull Set<String> getRecentExternalVolumeNames(@NonNull Context context) {
-        final StorageManager sm = context.getSystemService(StorageManager.class);
-        final Set<String> res = new ArraySet<>();
-        for (StorageVolume sv : sm.getRecentStorageVolumes()) {
-            final String volumeName = sv.getMediaStoreVolumeName();
-            if (volumeName != null) {
-                res.add(volumeName);
-            }
-        }
-        return res;
-    }
-
-    /**
-     * Return the volume name that the given {@link Uri} references.
-     */
-    public static @NonNull String getVolumeName(@NonNull Uri uri) {
-        final List<String> segments = uri.getPathSegments();
-        switch (uri.getAuthority()) {
-            case AUTHORITY:
-            case AUTHORITY_LEGACY: {
-                if (segments != null && segments.size() > 0) {
-                    return segments.get(0);
-                }
-            }
-        }
-        throw new IllegalArgumentException("Missing volume name: " + uri);
-    }
-
-    /** {@hide} */
-    public static @NonNull String checkArgumentVolumeName(@NonNull String volumeName) {
-        if (TextUtils.isEmpty(volumeName)) {
-            throw new IllegalArgumentException();
-        }
-
-        if (VOLUME_INTERNAL.equals(volumeName)) {
-            return volumeName;
-        } else if (VOLUME_EXTERNAL.equals(volumeName)) {
-            return volumeName;
-        } else if (VOLUME_EXTERNAL_PRIMARY.equals(volumeName)) {
-            return volumeName;
-        }
-
-        // When not one of the well-known values above, it must be a hex UUID
-        for (int i = 0; i < volumeName.length(); i++) {
-            final char c = volumeName.charAt(i);
-            if (('a' <= c && c <= 'f') || ('0' <= c && c <= '9') || (c == '-')) {
-                continue;
-            } else {
-                throw new IllegalArgumentException("Invalid volume name: " + volumeName);
-            }
-        }
-        return volumeName;
-    }
-
-    private static boolean parseBoolean(@Nullable String value) {
-        if (value == null) return false;
-        if ("1".equals(value)) return true;
-        if ("true".equalsIgnoreCase(value)) return true;
-        return false;
-    }
-
-    /**
-     * Uri for querying the state of the media scanner.
-     */
-    public static Uri getMediaScannerUri() {
-        return AUTHORITY_URI.buildUpon().appendPath("none").appendPath("media_scanner").build();
-    }
-
-    /**
-     * Name of current volume being scanned by the media scanner.
-     */
-    public static final String MEDIA_SCANNER_VOLUME = "volume";
-
-    /**
-     * Name of the file signaling the media scanner to ignore media in the containing directory
-     * and its subdirectories. Developers should use this to avoid application graphics showing
-     * up in the Gallery and likewise prevent application sounds and music from showing up in
-     * the Music app.
-     */
-    public static final String MEDIA_IGNORE_FILENAME = ".nomedia";
-
-    /**
-     * Return an opaque version string describing the {@link MediaStore} state.
-     * <p>
-     * Applications that import data from {@link MediaStore} into their own
-     * caches can use this to detect that {@link MediaStore} has undergone
-     * substantial changes, and that data should be rescanned.
-     * <p>
-     * No other assumptions should be made about the meaning of the version.
-     * <p>
-     * This method returns the version for
-     * {@link MediaStore#VOLUME_EXTERNAL_PRIMARY}; to obtain a version for a
-     * different volume, use {@link #getVersion(Context, String)}.
-     */
-    public static @NonNull String getVersion(@NonNull Context context) {
-        return getVersion(context, VOLUME_EXTERNAL_PRIMARY);
-    }
-
-    /**
-     * Return an opaque version string describing the {@link MediaStore} state.
-     * <p>
-     * Applications that import data from {@link MediaStore} into their own
-     * caches can use this to detect that {@link MediaStore} has undergone
-     * substantial changes, and that data should be rescanned.
-     * <p>
-     * No other assumptions should be made about the meaning of the version.
-     *
-     * @param volumeName specific volume to obtain an opaque version string for.
-     *            Must be one of the values returned from
-     *            {@link #getExternalVolumeNames(Context)}.
-     */
-    public static @NonNull String getVersion(@NonNull Context context, @NonNull String volumeName) {
-        final ContentResolver resolver = context.getContentResolver();
-        try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
-            final Bundle in = new Bundle();
-            in.putString(Intent.EXTRA_TEXT, volumeName);
-            final Bundle out = client.call(GET_VERSION_CALL, null, in);
-            return out.getString(Intent.EXTRA_TEXT);
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
-    }
-
-    /**
-     * Return a {@link DocumentsProvider} Uri that is an equivalent to the given
-     * {@link MediaStore} Uri.
-     * <p>
-     * This allows apps with Storage Access Framework permissions to convert
-     * between {@link MediaStore} and {@link DocumentsProvider} Uris that refer
-     * to the same underlying item. Note that this method doesn't grant any new
-     * permissions; callers must already hold permissions obtained with
-     * {@link Intent#ACTION_OPEN_DOCUMENT} or related APIs.
-     *
-     * @param mediaUri The {@link MediaStore} Uri to convert.
-     * @return An equivalent {@link DocumentsProvider} Uri. Returns {@code null}
-     *         if no equivalent was found.
-     * @see #getMediaUri(Context, Uri)
-     */
-    public static @Nullable Uri getDocumentUri(@NonNull Context context, @NonNull Uri mediaUri) {
-        final ContentResolver resolver = context.getContentResolver();
-        final List<UriPermission> uriPermissions = resolver.getPersistedUriPermissions();
-
-        try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
-            final Bundle in = new Bundle();
-            in.putParcelable(EXTRA_URI, mediaUri);
-            in.putParcelableArrayList(EXTRA_URI_PERMISSIONS, new ArrayList<>(uriPermissions));
-            final Bundle out = client.call(GET_DOCUMENT_URI_CALL, null, in);
-            return out.getParcelable(EXTRA_URI);
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
-    }
-
-    /**
-     * Return a {@link MediaStore} Uri that is an equivalent to the given
-     * {@link DocumentsProvider} Uri.
-     * <p>
-     * This allows apps with Storage Access Framework permissions to convert
-     * between {@link MediaStore} and {@link DocumentsProvider} Uris that refer
-     * to the same underlying item. Note that this method doesn't grant any new
-     * permissions; callers must already hold permissions obtained with
-     * {@link Intent#ACTION_OPEN_DOCUMENT} or related APIs.
-     *
-     * @param documentUri The {@link DocumentsProvider} Uri to convert.
-     * @return An equivalent {@link MediaStore} Uri. Returns {@code null} if no
-     *         equivalent was found.
-     * @see #getDocumentUri(Context, Uri)
-     */
-    public static @Nullable Uri getMediaUri(@NonNull Context context, @NonNull Uri documentUri) {
-        final ContentResolver resolver = context.getContentResolver();
-        final List<UriPermission> uriPermissions = resolver.getPersistedUriPermissions();
-
-        try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
-            final Bundle in = new Bundle();
-            in.putParcelable(EXTRA_URI, documentUri);
-            in.putParcelableArrayList(EXTRA_URI_PERMISSIONS, new ArrayList<>(uriPermissions));
-            final Bundle out = client.call(GET_MEDIA_URI_CALL, null, in);
-            return out.getParcelable(EXTRA_URI);
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
-    }
-
-    /** @hide */
-    @TestApi
-    public static void waitForIdle(@NonNull ContentResolver resolver) {
-        resolver.call(AUTHORITY, WAIT_FOR_IDLE_CALL, null, null);
-    }
-
-    /**
-     * Perform a blocking scan of the given {@link File}, returning the
-     * {@link Uri} of the scanned file.
-     *
-     * @hide
-     */
-    @SystemApi
-    @TestApi
-    @SuppressLint("StreamFiles")
-    public static @NonNull Uri scanFile(@NonNull ContentResolver resolver, @NonNull File file) {
-        final Bundle out = resolver.call(AUTHORITY, SCAN_FILE_CALL, file.getAbsolutePath(), null);
-        return out.getParcelable(Intent.EXTRA_STREAM);
-    }
-
-    /**
-     * Perform a blocking scan of the given storage volume.
-     *
-     * @hide
-     */
-    @SystemApi
-    @TestApi
-    public static void scanVolume(@NonNull ContentResolver resolver, @NonNull String volumeName) {
-        resolver.call(AUTHORITY, SCAN_VOLUME_CALL, volumeName, null);
-    }
-}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 503d6db..7629e1b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3900,6 +3900,12 @@
         public static final String VOLUME_ACCESSIBILITY = "volume_a11y";
 
         /**
+         * @hide
+         * Volume index for virtual assistant.
+         */
+        public static final String VOLUME_ASSISTANT = "volume_assistant";
+
+        /**
          * Master volume (float in the range 0.0f to 1.0f).
          *
          * @hide
@@ -3977,7 +3983,7 @@
                 "" /*STREAM_SYSTEM_ENFORCED, no setting for this stream*/,
                 "" /*STREAM_DTMF, no setting for this stream*/,
                 "" /*STREAM_TTS, no setting for this stream*/,
-                VOLUME_ACCESSIBILITY
+                VOLUME_ACCESSIBILITY, VOLUME_ASSISTANT
             };
 
         /**
@@ -4524,6 +4530,7 @@
             PUBLIC_SETTINGS.add(VOLUME_ALARM);
             PUBLIC_SETTINGS.add(VOLUME_NOTIFICATION);
             PUBLIC_SETTINGS.add(VOLUME_BLUETOOTH_SCO);
+            PUBLIC_SETTINGS.add(VOLUME_ASSISTANT);
             PUBLIC_SETTINGS.add(RINGTONE);
             PUBLIC_SETTINGS.add(NOTIFICATION_SOUND);
             PUBLIC_SETTINGS.add(ALARM_ALERT);
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index c287ae3..fed3d7ba 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1389,7 +1389,6 @@
                 for (int i = 0; i < pduCount; i++) {
                     byte[] pdu = (byte[]) messages[i];
                     msgs[i] = SmsMessage.createFromPdu(pdu, format);
-                    if (msgs[i] != null) msgs[i].setSubId(subId);
                 }
                 return msgs;
             }
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/security/keystore/recovery/KeyChainProtectionParams.java b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
index 8801217..2b70c71 100644
--- a/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
+++ b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
@@ -22,11 +22,10 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.util.Preconditions;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * A {@link KeyChainSnapshot} is protected with a key derived from the user's lock screen. This
@@ -220,8 +219,8 @@
             if (mInstance.mUserSecretType == null) {
                 mInstance.mUserSecretType = TYPE_LOCKSCREEN;
             }
-            Preconditions.checkNotNull(mInstance.mLockScreenUiFormat);
-            Preconditions.checkNotNull(mInstance.mKeyDerivationParams);
+            Objects.requireNonNull(mInstance.mLockScreenUiFormat);
+            Objects.requireNonNull(mInstance.mKeyDerivationParams);
             if (mInstance.mSecret == null) {
                 mInstance.mSecret = new byte[]{};
             }
diff --git a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
index 2f58471..fdc00f4 100644
--- a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
+++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
@@ -27,6 +27,7 @@
 import java.security.cert.CertPath;
 import java.security.cert.CertificateException;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * A snapshot of a version of the keystore. Two events can trigger the generation of a new snapshot:
@@ -272,9 +273,9 @@
                     "keyChainProtectionParams");
             Preconditions.checkCollectionElementsNotNull(mInstance.mEntryRecoveryData,
                     "entryRecoveryData");
-            Preconditions.checkNotNull(mInstance.mEncryptedRecoveryKeyBlob);
-            Preconditions.checkNotNull(mInstance.mServerParams);
-            Preconditions.checkNotNull(mInstance.mCertPath);
+            Objects.requireNonNull(mInstance.mEncryptedRecoveryKeyBlob);
+            Objects.requireNonNull(mInstance.mServerParams);
+            Objects.requireNonNull(mInstance.mCertPath);
             return mInstance;
         }
     }
diff --git a/core/java/android/security/keystore/recovery/KeyDerivationParams.java b/core/java/android/security/keystore/recovery/KeyDerivationParams.java
index d036d14..6c541da 100644
--- a/core/java/android/security/keystore/recovery/KeyDerivationParams.java
+++ b/core/java/android/security/keystore/recovery/KeyDerivationParams.java
@@ -22,10 +22,9 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.util.Preconditions;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 /**
  * Collection of parameters which define a key derivation function.
@@ -109,7 +108,7 @@
     private KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt,
             int memoryDifficulty) {
         mAlgorithm = algorithm;
-        mSalt = Preconditions.checkNotNull(salt);
+        mSalt = Objects.requireNonNull(salt);
         mMemoryDifficulty = memoryDifficulty;
     }
 
diff --git a/core/java/android/security/keystore/recovery/RecoveryCertPath.java b/core/java/android/security/keystore/recovery/RecoveryCertPath.java
index 51bd2ae..ff10b29 100644
--- a/core/java/android/security/keystore/recovery/RecoveryCertPath.java
+++ b/core/java/android/security/keystore/recovery/RecoveryCertPath.java
@@ -20,13 +20,12 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.util.Preconditions;
-
 import java.io.ByteArrayInputStream;
 import java.security.cert.CertPath;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
+import java.util.Objects;
 
 /**
  * The certificate path of the recovery service.
@@ -67,7 +66,7 @@
     }
 
     private RecoveryCertPath(@NonNull byte[] encodedCertPath) {
-        mEncodedCertPath = Preconditions.checkNotNull(encodedCertPath);
+        mEncodedCertPath = Objects.requireNonNull(encodedCertPath);
     }
 
     private RecoveryCertPath(Parcel in) {
@@ -98,13 +97,13 @@
     @NonNull
     private static byte[] encodeCertPath(@NonNull CertPath certPath)
             throws CertificateEncodingException {
-        Preconditions.checkNotNull(certPath);
+        Objects.requireNonNull(certPath);
         return certPath.getEncoded(CERT_PATH_ENCODING);
     }
 
     @NonNull
     private static CertPath decodeCertPath(@NonNull byte[] bytes) throws CertificateException {
-        Preconditions.checkNotNull(bytes);
+        Objects.requireNonNull(bytes);
         CertificateFactory certFactory;
         try {
             certFactory = CertificateFactory.getInstance("X.509");
diff --git a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
index 665c937..0cb69a4 100644
--- a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
+++ b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
@@ -22,7 +22,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
 
 /**
  * Helper class with data necessary recover a single application key, given a recovery key.
@@ -106,8 +106,8 @@
          * @throws NullPointerException if some required fields were not set.
          */
         public @NonNull WrappedApplicationKey build() {
-            Preconditions.checkNotNull(mInstance.mAlias);
-            Preconditions.checkNotNull(mInstance.mEncryptedKeyMaterial);
+            Objects.requireNonNull(mInstance.mAlias);
+            Objects.requireNonNull(mInstance.mEncryptedKeyMaterial);
             return mInstance;
         }
     }
@@ -120,8 +120,8 @@
      */
     @Deprecated
     public WrappedApplicationKey(@NonNull String alias, @NonNull byte[] encryptedKeyMaterial) {
-        mAlias = Preconditions.checkNotNull(alias);
-        mEncryptedKeyMaterial = Preconditions.checkNotNull(encryptedKeyMaterial);
+        mAlias = Objects.requireNonNull(alias);
+        mEncryptedKeyMaterial = Objects.requireNonNull(encryptedKeyMaterial);
     }
 
     /**
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
index 373e1e5..54a4fa6 100644
--- a/core/java/android/service/dataloader/DataLoaderService.java
+++ b/core/java/android/service/dataloader/DataLoaderService.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
 import android.content.pm.DataLoaderParams;
@@ -45,30 +46,41 @@
  * The base class for implementing data loader service to control data loaders. Expecting
  * Incremental Service to bind to a children class of this.
  *
- * @hide
+ * WARNING: This is a system API to aid internal development.
+ * Use at your own risk. It will change or be removed without warning.
  *
- * Hide for now, should be @SystemApi
  * TODO(b/136132412): update with latest API design
+ *
+ * @hide
  */
+@SystemApi
 public abstract class DataLoaderService extends Service {
     private static final String TAG = "IncrementalDataLoaderService";
     private final DataLoaderBinderService mBinder = new DataLoaderBinderService();
 
+    /** @hide */
     public static final int DATA_LOADER_READY =
             IDataLoaderStatusListener.DATA_LOADER_READY;
+    /** @hide */
     public static final int DATA_LOADER_NOT_READY =
             IDataLoaderStatusListener.DATA_LOADER_NOT_READY;
+    /** @hide */
     public static final int DATA_LOADER_RUNNING =
             IDataLoaderStatusListener.DATA_LOADER_RUNNING;
+    /** @hide */
     public static final int DATA_LOADER_STOPPED =
             IDataLoaderStatusListener.DATA_LOADER_STOPPED;
+    /** @hide */
     public static final int DATA_LOADER_SLOW_CONNECTION =
             IDataLoaderStatusListener.DATA_LOADER_SLOW_CONNECTION;
+    /** @hide */
     public static final int DATA_LOADER_NO_CONNECTION =
             IDataLoaderStatusListener.DATA_LOADER_NO_CONNECTION;
+    /** @hide */
     public static final int DATA_LOADER_CONNECTION_OK =
             IDataLoaderStatusListener.DATA_LOADER_CONNECTION_OK;
 
+    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"DATA_LOADER_"}, value = {
             DATA_LOADER_READY,
@@ -85,6 +97,7 @@
     /**
      * Managed DataLoader interface. Each instance corresponds to a single Incremental File System
      * instance.
+     * @hide
      */
     public abstract static class DataLoader {
         /**
@@ -130,6 +143,7 @@
      * DataLoader factory method.
      *
      * @return An instance of a DataLoader.
+     * @hide
      */
     public abstract @Nullable DataLoader onCreateDataLoader();
 
@@ -220,8 +234,6 @@
      * Used by the DataLoaderService implementations.
      *
      * @hide
-     *
-     * TODO(b/136132412) Should be @SystemApi
      */
     public static final class FileSystemConnector {
         /**
@@ -264,7 +276,6 @@
     /**
      * Wrapper for native reporting DataLoader statuses.
      * @hide
-     * TODO(b/136132412) Should be @SystemApi
      */
     public static final class StatusListener {
         /**
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/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
index 6efcfbf..7b24ba9 100644
--- a/core/java/android/util/proto/ProtoOutputStream.java
+++ b/core/java/android/util/proto/ProtoOutputStream.java
@@ -16,7 +16,8 @@
 
 package android.util.proto;
 
-import android.annotation.TestApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.util.Log;
 
 import java.io.FileDescriptor;
@@ -28,19 +29,23 @@
 /**
  * Class to write to a protobuf stream.
  *
- * Each write method takes an ID code from the protoc generated classes
- * and the value to write.  To make a nested object, call #start
- * and then #end when you are done.
+ * <p>
+ * This API is not as convenient or type safe as the standard protobuf
+ * classes. If possible, the best recommended library is to use protobuf lite.
+ * However, in environements (such as the Android platform itself), a
+ * more memory efficient version is necessary.
  *
- * The ID codes have type information embedded into them, so if you call
- * the incorrect function you will get an IllegalArgumentException.
+ * <p>Each write method takes an ID code from the protoc generated classes
+ * and the value to write.  To make a nested object, call {@link #start(long)}
+ * and then {@link #end(long)} when you are done.
  *
- * To retrieve the encoded protobuf stream, call getBytes().
+ * <p>The ID codes have type information embedded into them, so if you call
+ * the incorrect function you will get an {@link IllegalArgumentException}.
  *
- * TODO: Add a constructor that takes an OutputStream and write to that
+ * <p>To retrieve the encoded protobuf stream, call {@link #getBytes()}.
+ *
  * stream as the top-level objects are finished.
  *
- * @hide
  */
 
 /* IMPLEMENTATION NOTES
@@ -99,7 +104,6 @@
  * correctly matched pairs of #start and #end calls, and issue
  * errors if they are not matched.
  */
-@TestApi
 public final class ProtoOutputStream extends ProtoStream {
     /**
      * @hide
@@ -124,7 +128,9 @@
     /**
      * An ID given to objects and returned in the token from startObject
      * and stored in the buffer until endObject is called, where the two
-     * are checked.  Starts at -1 and becomes more negative, so the values
+     * are checked.
+     *
+     * <p>Starts at -1 and becomes more negative, so the values
      * aren't likely to alias with the size it will be overwritten with,
      * which tend to be small, and we will be more likely to catch when
      * the caller of endObject uses a stale token that they didn't intend
@@ -133,8 +139,9 @@
     private int mNextObjectId = -1;
 
     /**
-     * The object token we are expecting in endObject.  If another call to
-     * startObject happens, this is written to that location, which gives
+     * The object token we are expecting in endObject.
+     *
+     * <p>If another call to startObject happens, this is written to that location, which gives
      * us a stack, stored in the space for the as-yet unused size fields.
      */
     private long mExpectedObjectToken;
@@ -151,39 +158,45 @@
     private boolean mCompacted;
 
     /**
-     * Construct a ProtoOutputStream with the default chunk size.
+     * Construct a {@link ProtoOutputStream} with the default chunk size.
+     *
+     * <p>This is for an in-memory proto. The caller should use {@link #getBytes()} for the result.
      */
     public ProtoOutputStream() {
         this(0);
     }
 
     /**
-     * Construct a ProtoOutputStream with the given chunk size.
+     * Construct a {@link ProtoOutputStream with the given chunk size.
+     *
+     * <p>This is for an in-memory proto. The caller should use {@link #getBytes()} for the result.
      */
     public ProtoOutputStream(int chunkSize) {
         mBuffer = new EncodedBuffer(chunkSize);
     }
 
     /**
-     * Construct a ProtoOutputStream that sits on top of an OutputStream.
-     * @more
-     * The {@link #flush() flush()} method must be called when done writing
-     * to flush any remanining data, althought data *may* be written at intermediate
+     * Construct a {@link ProtoOutputStream} that sits on top of an {@link OutputStream}.
+     *
+     * <p>The {@link #flush()} method must be called when done writing
+     * to flush any remaining data, although data *may* be written at intermediate
      * points within the writing as well.
      */
-    public ProtoOutputStream(OutputStream stream) {
+    public ProtoOutputStream(@NonNull OutputStream stream) {
         this();
         mStream = stream;
     }
 
     /**
-     * Construct a ProtoOutputStream that sits on top of a FileDescriptor.
-     * @more
-     * The {@link #flush() flush()} method must be called when done writing
-     * to flush any remanining data, althought data *may* be written at intermediate
+     * Construct a {@link ProtoOutputStream} that sits on top of a {@link FileDescriptor}.
+     *
+     * <p>The {@link #flush()} method must be called when done writing
+     * to flush any remaining data, although data *may* be written at intermediate
      * points within the writing as well.
+     *
+     * @hide
      */
-    public ProtoOutputStream(FileDescriptor fd) {
+    public ProtoOutputStream(@NonNull FileDescriptor fd) {
         this(new FileOutputStream(fd));
     }
 
@@ -202,7 +215,7 @@
     /**
      * Write a value for the given fieldId.
      *
-     * Will automatically convert for the following field types, and
+     * <p>Will automatically convert for the following field types, and
      * throw an exception for others: double, float, int32, int64, uint32, uint64,
      * sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
      *
@@ -337,7 +350,7 @@
     /**
      * Write a value for the given fieldId.
      *
-     * Will automatically convert for the following field types, and
+     * <p>Will automatically convert for the following field types, and
      * throw an exception for others: double, float, int32, int64, uint32, uint64,
      * sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
      *
@@ -472,7 +485,7 @@
     /**
      * Write a value for the given fieldId.
      *
-     * Will automatically convert for the following field types, and
+     * <p>Will automatically convert for the following field types, and
      * throw an exception for others: double, float, int32, int64, uint32, uint64,
      * sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
      *
@@ -607,7 +620,7 @@
     /**
      * Write a value for the given fieldId.
      *
-     * Will automatically convert for the following field types, and
+     * <p>Will automatically convert for the following field types, and
      * throw an exception for others: double, float, int32, int64, uint32, uint64,
      * sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
      *
@@ -742,7 +755,7 @@
     /**
      * Write a boolean value for the given fieldId.
      *
-     * If the field is not a bool field, an exception will be thrown.
+     * <p>If the field is not a bool field, an {@link IllegalStateException} will be thrown.
      *
      * @param fieldId The field identifier constant from the generated class.
      * @param val The value.
@@ -771,12 +784,12 @@
     /**
      * Write a string value for the given fieldId.
      *
-     * If the field is not a string field, an exception will be thrown.
+     * <p>If the field is not a string field, an exception will be thrown.
      *
      * @param fieldId The field identifier constant from the generated class.
      * @param val The value.
      */
-    public void write(long fieldId, String val) {
+    public void write(long fieldId, @Nullable String val) {
         assertNotCompacted();
         final int id = (int)fieldId;
 
@@ -800,12 +813,12 @@
     /**
      * Write a byte[] value for the given fieldId.
      *
-     * If the field is not a bytes or object field, an exception will be thrown.
+     * <p>If the field is not a bytes or object field, an exception will be thrown.
      *
      * @param fieldId The field identifier constant from the generated class.
      * @param val The value.
      */
-    public void write(long fieldId, byte[] val) {
+    public void write(long fieldId, @Nullable byte[] val) {
         assertNotCompacted();
         final int id = (int)fieldId;
 
@@ -836,6 +849,9 @@
 
     /**
      * Start a sub object.
+     *
+     * @param fieldId The field identifier constant from the generated class.
+     * @return The token to call {@link #end(long)} with.
      */
     public long start(long fieldId) {
         assertNotCompacted();
@@ -855,6 +871,8 @@
 
     /**
      * End the object started by start() that returned token.
+     *
+     * @param token The token returned from {@link #start(long)}
      */
     public void end(long token) {
         endObjectImpl(token, getRepeatedFromToken(token));
@@ -870,7 +888,8 @@
     /**
      * Write a single proto "double" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, double)} instead.
+     * @hide
      */
     @Deprecated
     public void writeDouble(long fieldId, double val) {
@@ -890,7 +909,8 @@
     /**
      * Write a single repeated proto "double" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, double)} instead.
+     * @hide
      */
     @Deprecated
     public void writeRepeatedDouble(long fieldId, double val) {
@@ -908,10 +928,11 @@
     /**
      * Write a list of packed proto "double" type field values.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, double)} instead.
+     * @hide
      */
     @Deprecated
-    public void writePackedDouble(long fieldId, double[] val) {
+    public void writePackedDouble(long fieldId, @Nullable double[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_DOUBLE);
 
@@ -934,7 +955,8 @@
     /**
      * Write a single proto "float" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, float)} instead.
+     * @hide
      */
     @Deprecated
     public void writeFloat(long fieldId, float val) {
@@ -954,7 +976,8 @@
     /**
      * Write a single repeated proto "float" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, float)} instead.
+     * @hide
      */
     @Deprecated
     public void writeRepeatedFloat(long fieldId, float val) {
@@ -972,10 +995,11 @@
     /**
      * Write a list of packed proto "float" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, float)} instead.
+     * @hide
      */
     @Deprecated
-    public void writePackedFloat(long fieldId, float[] val) {
+    public void writePackedFloat(long fieldId, @Nullable float[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FLOAT);
 
@@ -999,7 +1023,7 @@
     /**
      * Writes a java int as an usigned varint.
      *
-     * The unadorned int32 type in protobuf is unfortunate because it
+     * <p>The unadorned int32 type in protobuf is unfortunate because it
      * is stored in memory as a signed value, but encodes as unsigned
      * varints, which are formally always longs.  So here, we encode
      * negative values as 64 bits, which will get the sign-extension,
@@ -1017,11 +1041,12 @@
     /**
      * Write a single proto "int32" type field value.
      *
-     * Note that these are stored in memory as signed values and written as unsigned
+     * <p>Note that these are stored in memory as signed values and written as unsigned
      * varints, which if negative, are 10 bytes long. If you know the data is likely
      * to be negative, use "sint32".
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
     public void writeInt32(long fieldId, int val) {
@@ -1041,11 +1066,12 @@
     /**
      * Write a single repeated proto "int32" type field value.
      *
-     * Note that these are stored in memory as signed values and written as unsigned
+     * <p>Note that these are stored in memory as signed values and written as unsigned
      * varints, which if negative, are 10 bytes long. If you know the data is likely
      * to be negative, use "sint32".
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
     public void writeRepeatedInt32(long fieldId, int val) {
@@ -1063,14 +1089,15 @@
     /**
      * Write a list of packed proto "int32" type field value.
      *
-     * Note that these are stored in memory as signed values and written as unsigned
+     * <p>Note that these are stored in memory as signed values and written as unsigned
      * varints, which if negative, are 10 bytes long. If you know the data is likely
      * to be negative, use "sint32".
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
-    public void writePackedInt32(long fieldId, int[] val) {
+    public void writePackedInt32(long fieldId, @Nullable int[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT32);
 
@@ -1099,7 +1126,8 @@
     /**
      * Write a single proto "int64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
     public void writeInt64(long fieldId, long val) {
@@ -1119,7 +1147,8 @@
     /**
      * Write a single repeated proto "int64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
     public void writeRepeatedInt64(long fieldId, long val) {
@@ -1137,10 +1166,11 @@
     /**
      * Write a list of packed proto "int64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
-    public void writePackedInt64(long fieldId, long[] val) {
+    public void writePackedInt64(long fieldId, @Nullable long[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT64);
 
@@ -1168,7 +1198,8 @@
     /**
      * Write a single proto "uint32" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
     public void writeUInt32(long fieldId, int val) {
@@ -1188,7 +1219,8 @@
     /**
      * Write a single repeated proto "uint32" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
     public void writeRepeatedUInt32(long fieldId, int val) {
@@ -1206,10 +1238,11 @@
     /**
      * Write a list of packed proto "uint32" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
-    public void writePackedUInt32(long fieldId, int[] val) {
+    public void writePackedUInt32(long fieldId, @Nullable int[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT32);
 
@@ -1237,7 +1270,8 @@
     /**
      * Write a single proto "uint64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
     public void writeUInt64(long fieldId, long val) {
@@ -1257,7 +1291,8 @@
     /**
      * Write a single proto "uint64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
     public void writeRepeatedUInt64(long fieldId, long val) {
@@ -1275,10 +1310,11 @@
     /**
      * Write a single proto "uint64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
-    public void writePackedUInt64(long fieldId, long[] val) {
+    public void writePackedUInt64(long fieldId, @Nullable long[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT64);
 
@@ -1306,7 +1342,8 @@
     /**
      * Write a single proto "sint32" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
     public void writeSInt32(long fieldId, int val) {
@@ -1326,7 +1363,8 @@
     /**
      * Write a single repeated proto "sint32" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
     public void writeRepeatedSInt32(long fieldId, int val) {
@@ -1344,10 +1382,11 @@
     /**
      * Write a list of packed proto "sint32" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
-    public void writePackedSInt32(long fieldId, int[] val) {
+    public void writePackedSInt32(long fieldId, @Nullable int[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT32);
 
@@ -1375,7 +1414,8 @@
     /**
      * Write a single proto "sint64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
     public void writeSInt64(long fieldId, long val) {
@@ -1395,7 +1435,8 @@
     /**
      * Write a single repeated proto "sint64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
     public void writeRepeatedSInt64(long fieldId, long val) {
@@ -1413,10 +1454,11 @@
     /**
      * Write a list of packed proto "sint64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
-    public void writePackedSInt64(long fieldId, long[] val) {
+    public void writePackedSInt64(long fieldId, @Nullable long[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT64);
 
@@ -1443,7 +1485,8 @@
     /**
      * Write a single proto "fixed32" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
     public void writeFixed32(long fieldId, int val) {
@@ -1463,7 +1506,8 @@
     /**
      * Write a single repeated proto "fixed32" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
     public void writeRepeatedFixed32(long fieldId, int val) {
@@ -1481,10 +1525,11 @@
     /**
      * Write a list of packed proto "fixed32" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
-    public void writePackedFixed32(long fieldId, int[] val) {
+    public void writePackedFixed32(long fieldId, @Nullable int[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED32);
 
@@ -1507,7 +1552,8 @@
     /**
      * Write a single proto "fixed64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
     public void writeFixed64(long fieldId, long val) {
@@ -1527,7 +1573,8 @@
     /**
      * Write a single repeated proto "fixed64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
     public void writeRepeatedFixed64(long fieldId, long val) {
@@ -1545,10 +1592,11 @@
     /**
      * Write a list of packed proto "fixed64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
-    public void writePackedFixed64(long fieldId, long[] val) {
+    public void writePackedFixed64(long fieldId, @Nullable long[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED64);
 
@@ -1570,7 +1618,8 @@
     /**
      * Write a single proto "sfixed32" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
     public void writeSFixed32(long fieldId, int val) {
@@ -1590,7 +1639,8 @@
     /**
      * Write a single repeated proto "sfixed32" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
     public void writeRepeatedSFixed32(long fieldId, int val) {
@@ -1608,10 +1658,11 @@
     /**
      * Write a list of packed proto "sfixed32" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
-    public void writePackedSFixed32(long fieldId, int[] val) {
+    public void writePackedSFixed32(long fieldId, @Nullable int[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED32);
 
@@ -1634,7 +1685,8 @@
     /**
      * Write a single proto "sfixed64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
     public void writeSFixed64(long fieldId, long val) {
@@ -1654,7 +1706,8 @@
     /**
      * Write a single repeated proto "sfixed64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
     public void writeRepeatedSFixed64(long fieldId, long val) {
@@ -1672,10 +1725,11 @@
     /**
      * Write a list of packed proto "sfixed64" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, long)} instead.
+     * @hide
      */
     @Deprecated
-    public void writePackedSFixed64(long fieldId, long[] val) {
+    public void writePackedSFixed64(long fieldId, @Nullable long[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED64);
 
@@ -1698,7 +1752,8 @@
     /**
      * Write a single proto "bool" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, boolean)} instead.
+     * @hide
      */
     @Deprecated
     public void writeBool(long fieldId, boolean val) {
@@ -1719,7 +1774,8 @@
     /**
      * Write a single repeated proto "bool" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, boolean)} instead.
+     * @hide
      */
     @Deprecated
     public void writeRepeatedBool(long fieldId, boolean val) {
@@ -1737,10 +1793,11 @@
     /**
      * Write a list of packed proto "bool" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, boolean)} instead.
+     * @hide
      */
     @Deprecated
-    public void writePackedBool(long fieldId, boolean[] val) {
+    public void writePackedBool(long fieldId, @Nullable boolean[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_BOOL);
 
@@ -1767,10 +1824,11 @@
     /**
      * Write a single proto "string" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, String)} instead.
+     * @hide
      */
     @Deprecated
-    public void writeString(long fieldId, String val) {
+    public void writeString(long fieldId, @Nullable String val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_STRING);
 
@@ -1786,10 +1844,11 @@
     /**
      * Write a single repeated proto "string" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, String)} instead.
+     * @hide
      */
     @Deprecated
-    public void writeRepeatedString(long fieldId, String val) {
+    public void writeRepeatedString(long fieldId, @Nullable String val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_STRING);
 
@@ -1828,10 +1887,11 @@
     /**
      * Write a single proto "bytes" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, byte[])} instead.
+     * @hide
      */
     @Deprecated
-    public void writeBytes(long fieldId, byte[] val) {
+    public void writeBytes(long fieldId, @Nullable byte[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_BYTES);
 
@@ -1848,10 +1908,11 @@
     /**
      * Write a single repeated proto "bytes" type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, byte[])} instead.
+     * @hide
      */
     @Deprecated
-    public void writeRepeatedBytes(long fieldId, byte[] val) {
+    public void writeRepeatedBytes(long fieldId, @Nullable byte[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_BYTES);
 
@@ -1874,7 +1935,8 @@
     /**
      * Write a single proto enum type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
     public void writeEnum(long fieldId, int val) {
@@ -1894,7 +1956,8 @@
     /**
      * Write a single repeated proto enum type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
     public void writeRepeatedEnum(long fieldId, int val) {
@@ -1912,10 +1975,11 @@
     /**
      * Write a list of packed proto enum type field value.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, int)} instead.
+     * @hide
      */
     @Deprecated
-    public void writePackedEnum(long fieldId, int[] val) {
+    public void writePackedEnum(long fieldId, @Nullable int[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_ENUM);
 
@@ -1940,7 +2004,8 @@
      * Returns a token which should be passed to endObject.  Calls to endObject must be
      * nested properly.
      *
-     * @deprecated Use #start() instead.
+     * @deprecated Use {@link #start(long)} instead.
+     * @hide
      */
     @Deprecated
     public long startObject(long fieldId) {
@@ -1953,7 +2018,8 @@
     /**
      * End a child object. Pass in the token from the correspoinding startObject call.
      *
-     * @deprecated Use #end() instead.
+     * @deprecated Use {@link #end(long)} instead.
+     * @hide
      */
     @Deprecated
     public void endObject(long token) {
@@ -1968,7 +2034,8 @@
      * Returns a token which should be passed to endObject.  Calls to endObject must be
      * nested properly.
      *
-     * @deprecated Use #start() instead.
+     * @deprecated Use {@link #start(long)} instead.
+     * @hide
      */
     @Deprecated
     public long startRepeatedObject(long fieldId) {
@@ -1981,7 +2048,8 @@
     /**
      * End a child object. Pass in the token from the correspoinding startRepeatedObject call.
      *
-     * @deprecated Use #end() instead.
+     * @deprecated Use {@link #end(long)} instead.
+     * @hide
      */
     @Deprecated
     public void endRepeatedObject(long token) {
@@ -2064,12 +2132,13 @@
     }
 
     /**
-     * Write an object that has already been flattend.
+     * Write an object that has already been flattened.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, byte[])} instead.
+     * @hide
      */
     @Deprecated
-    public void writeObject(long fieldId, byte[] value) {
+    public void writeObject(long fieldId, @Nullable byte[] value) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_MESSAGE);
 
@@ -2084,12 +2153,13 @@
     }
 
     /**
-     * Write an object that has already been flattend.
+     * Write an object that has already been flattened.
      *
-     * @deprecated Use #write instead.
+     * @deprecated Use {@link #write(long, byte[])} instead.
+     * @hide
      */
     @Deprecated
-    public void writeRepeatedObject(long fieldId, byte[] value) {
+    public void writeRepeatedObject(long fieldId, @Nullable byte[] value) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_MESSAGE);
 
@@ -2115,11 +2185,11 @@
     }
 
     /**
-     * Validates that the fieldId providied is of the type and count from expectedType.
+     * Validates that the fieldId provided is of the type and count from expectedType.
      *
-     * The type must match exactly to pass this check.
+     * <p>The type must match exactly to pass this check.
      *
-     * The count must match according to this truth table to pass the check:
+     * <p>The count must match according to this truth table to pass the check:
      *
      *                  expectedFlags
      *                  UNKNOWN     SINGLE      REPEATED    PACKED
@@ -2129,7 +2199,7 @@
      *    REPEATED      x           false       true        false
      *    PACKED        x           false       true        true
      *
-     * @throws IllegalArgumentException if it is not.
+     * @throws {@link IllegalArgumentException} if it is not.
      *
      * @return The raw ID of that field.
      */
@@ -2201,7 +2271,7 @@
     }
 
     /**
-     * Write a field tage to the stream.
+     * Write a field tag to the stream.
      */
     public void writeTag(int id, int wireType) {
         mBuffer.writeRawVarint32((id << FIELD_ID_SHIFT) | wireType);
@@ -2239,10 +2309,10 @@
      * Finish the encoding of the data, and return a byte[] with
      * the protobuf formatted data.
      *
-     * After this call, do not call any of the write* functions. The
+     * <p>After this call, do not call any of the write* functions. The
      * behavior is undefined.
      */
-    public byte[] getBytes() {
+    public @NonNull byte[] getBytes() {
         compactIfNecessary();
 
         return mBuffer.getBytes(mBuffer.getReadableSize());
@@ -2289,7 +2359,7 @@
     }
 
     /**
-     * First compaction pass.  Iterate through the data, and fill in the
+     * First compaction pass. Iterate through the data, and fill in the
      * nested object sizes so the next pass can compact them.
      */
     private int editEncodedSize(int rawSize) {
@@ -2416,10 +2486,10 @@
     /**
      * Write remaining data to the output stream.  If there is no output stream,
      * this function does nothing. Any currently open objects (i.e. ones that
-     * have not had endObject called for them will not be written).  Whether this
+     * have not had {@link #end(long)} called for them will not be written).  Whether this
      * writes objects that are closed if there are remaining open objects is
      * undefined (current implementation does not write it, future ones will).
-     * For now, can either call getBytes() or flush(), but not both.
+     * For now, can either call {@link #getBytes()} or {@link #flush()}, but not both.
      */
     public void flush() {
         if (mStream == null) {
@@ -2457,7 +2527,7 @@
     /**
      * Dump debugging data about the buffers with the given log tag.
      */
-    public void dump(String tag) {
+    public void dump(@NonNull String tag) {
         Log.d(tag, mBuffer.getDebugString());
         mBuffer.dumpBuffers(tag);
     }
diff --git a/core/java/android/util/proto/ProtoStream.java b/core/java/android/util/proto/ProtoStream.java
index 9e2e95a..4969d8a 100644
--- a/core/java/android/util/proto/ProtoStream.java
+++ b/core/java/android/util/proto/ProtoStream.java
@@ -16,28 +16,104 @@
 
 package android.util.proto;
 
-import android.annotation.TestApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 
 /**
- * Abstract base class for both protobuf streams.
+ * Base utility class for protobuf streams.
  *
- * Contains a set of useful constants and methods used by both
- * ProtoOutputStream and ProtoInputStream
+ * Contains a set of constants and methods used in generated code for
+ * {@link ProtoOutputStream}.
  *
  * @hide
  */
-@TestApi
-public abstract class ProtoStream {
+public class ProtoStream {
 
+    /**
+     * Number of bits to shift the field number to form a tag.
+     *
+     * <pre>
+     * // Reading a field number from a tag.
+     * int fieldNumber = tag &gt;&gt;&gt; FIELD_ID_SHIFT;
+     *
+     * // Building a tag from a field number and a wire type.
+     * int tag = (fieldNumber &lt;&lt; FIELD_ID_SHIFT) | wireType;
+     * </pre>
+     *
+     * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+     * Encoding</a>
+     */
     public static final int FIELD_ID_SHIFT = 3;
+
+    /**
+     * Mask to select the wire type from a tag.
+     *
+     * <pre>
+     * // Reading a wire type from a tag.
+     * int wireType = tag &amp; WIRE_TYPE_MASK;
+     *
+     * // Building a tag from a field number and a wire type.
+     * int tag = (fieldNumber &lt;&lt; FIELD_ID_SHIFT) | wireType;
+     * </pre>
+     *
+     * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+     * Encoding</a>
+     */
     public static final int WIRE_TYPE_MASK = (1 << FIELD_ID_SHIFT) - 1;
+
+    /**
+     * Mask to select the field id from a tag.
+     * @hide (not used by anything, and not actually useful, because you also want
+     * to shift when you mask the field id).
+     */
     public static final int FIELD_ID_MASK = ~WIRE_TYPE_MASK;
 
+    /**
+     * Varint wire type code.
+     *
+     * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+     * Encoding</a>
+     */
     public static final int WIRE_TYPE_VARINT = 0;
+
+    /**
+     * Fixed64 wire type code.
+     *
+     * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+     * Encoding</a>
+     */
     public static final int WIRE_TYPE_FIXED64 = 1;
+
+    /**
+     * Length delimited wire type code.
+     *
+     * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+     * Encoding</a>
+     */
     public static final int WIRE_TYPE_LENGTH_DELIMITED = 2;
+
+    /**
+     * Start group wire type code.
+     *
+     * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+     * Encoding</a>
+     */
     public static final int WIRE_TYPE_START_GROUP = 3;
+
+    /**
+     * End group wire type code.
+     *
+     * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+     * Encoding</a>
+     */
     public static final int WIRE_TYPE_END_GROUP = 4;
+
+    /**
+     * Fixed32 wire type code.
+     *
+     * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+     * Encoding</a>
+     */
     public static final int WIRE_TYPE_FIXED32 = 5;
 
     /**
@@ -51,32 +127,147 @@
      */
     public static final long FIELD_TYPE_MASK = 0x0ffL << FIELD_TYPE_SHIFT;
 
+    /**
+     * Not a real wire type.
+     * @hide
+     */
     public static final long FIELD_TYPE_UNKNOWN = 0;
 
+
+    /*
+     * The FIELD_TYPE_ constants are copied from
+     * external/protobuf/src/google/protobuf/descriptor.h directly, so no
+     * extra mapping needs to be maintained in this case.
+     */
+
     /**
-     * The types are copied from external/protobuf/src/google/protobuf/descriptor.h directly,
-     * so no extra mapping needs to be maintained in this case.
+     * Field type code for double fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, double)
+     * ProtoOutputStream.write(long, double)} method.
      */
     public static final long FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for float fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, float)
+     * ProtoOutputStream.write(long, float)} method.
+     */
     public static final long FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for int64 fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, long)
+     * ProtoOutputStream.write(long, long)} method.
+     */
     public static final long FIELD_TYPE_INT64 = 3L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for uint64 fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, long)
+     * ProtoOutputStream.write(long, long)} method.
+     */
     public static final long FIELD_TYPE_UINT64 = 4L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for int32 fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, int)
+     * ProtoOutputStream.write(long, int)} method.
+     */
     public static final long FIELD_TYPE_INT32 = 5L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for fixed64 fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, long)
+     * ProtoOutputStream.write(long, long)} method.
+     */
     public static final long FIELD_TYPE_FIXED64 = 6L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for fixed32 fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, int)
+     * ProtoOutputStream.write(long, int)} method.
+     */
+
+    /**
+     * Field type code for fixed32 fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, int)
+     * ProtoOutputStream.write(long, int)} method.
+     */
     public static final long FIELD_TYPE_FIXED32 = 7L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for bool fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, boolean)
+     * ProtoOutputStream.write(long, boolean)} method.
+     */
     public static final long FIELD_TYPE_BOOL = 8L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for string fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, String)
+     * ProtoOutputStream.write(long, String)} method.
+     */
     public static final long FIELD_TYPE_STRING = 9L << FIELD_TYPE_SHIFT;
+
     //  public static final long FIELD_TYPE_GROUP = 10L << FIELD_TYPE_SHIFT; // Deprecated.
+
+    /**
+     * Field type code for message fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#start(long)
+     * ProtoOutputStream.start(long)} method.
+     */
     public static final long FIELD_TYPE_MESSAGE = 11L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for bytes fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, byte[])
+     * ProtoOutputStream.write(long, byte[])} method.
+     */
     public static final long FIELD_TYPE_BYTES = 12L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for uint32 fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, int)
+     * ProtoOutputStream.write(long, int)} method.
+     */
     public static final long FIELD_TYPE_UINT32 = 13L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for enum fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, int)
+     * ProtoOutputStream.write(long, int)} method.
+     */
     public static final long FIELD_TYPE_ENUM = 14L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for sfixed32 fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, int)
+     * ProtoOutputStream.write(long, int)} method.
+     */
     public static final long FIELD_TYPE_SFIXED32 = 15L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for sfixed64 fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, long)
+     * ProtoOutputStream.write(long, long)} method.
+     */
     public static final long FIELD_TYPE_SFIXED64 = 16L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for sint32 fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, int)
+     * ProtoOutputStream.write(long, int)} method.
+     */
     public static final long FIELD_TYPE_SINT32 = 17L << FIELD_TYPE_SHIFT;
+
+    /**
+     * Field type code for sint64 fields. Used to build constants in generated
+     * code for use with the {@link ProtoOutputStream#write(long, long)
+     * ProtoOutputStream.write(long, long)} method.
+     */
     public static final long FIELD_TYPE_SINT64 = 18L << FIELD_TYPE_SHIFT;
 
-    protected static final String[] FIELD_TYPE_NAMES = new String[]{
+    private static final @NonNull String[] FIELD_TYPE_NAMES = new String[]{
             "Double",
             "Float",
             "Int64",
@@ -100,19 +291,94 @@
     //
     // FieldId flags for whether the field is single, repeated or packed.
     //
+    /**
+     * Bit offset for building a field id to be used with a
+     * <code>{@link ProtoOutputStream}.write(...)</code>.
+     *
+     * @see #FIELD_COUNT_MASK
+     * @see #FIELD_COUNT_UNKNOWN
+     * @see #FIELD_COUNT_SINGLE
+     * @see #FIELD_COUNT_REPEATED
+     * @see #FIELD_COUNT_PACKED
+     */
     public static final int FIELD_COUNT_SHIFT = 40;
+
+    /**
+     * Bit mask for selecting the field count when reading a field id that
+     * is used with a <code>{@link ProtoOutputStream}.write(...)</code> method.
+     *
+     * @see #FIELD_COUNT_SHIFT
+     * @see #FIELD_COUNT_MASK
+     * @see #FIELD_COUNT_UNKNOWN
+     * @see #FIELD_COUNT_SINGLE
+     * @see #FIELD_COUNT_REPEATED
+     * @see #FIELD_COUNT_PACKED
+     * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+     * Encoding</a>
+     */
     public static final long FIELD_COUNT_MASK = 0x0fL << FIELD_COUNT_SHIFT;
 
+    /**
+     * Unknown field count, encoded into a field id used with a
+     * <code>{@link ProtoOutputStream}.write(...)</code> method.
+     *
+     * @see #FIELD_COUNT_SHIFT
+     * @see #FIELD_COUNT_MASK
+     * @see #FIELD_COUNT_SINGLE
+     * @see #FIELD_COUNT_REPEATED
+     * @see #FIELD_COUNT_PACKED
+     * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+     * Encoding</a>
+     */
     public static final long FIELD_COUNT_UNKNOWN = 0;
+
+    /**
+     * Single field count, encoded into a field id used with a
+     * <code>{@link ProtoOutputStream}.write(...)</code> method.
+     *
+     * @see #FIELD_COUNT_SHIFT
+     * @see #FIELD_COUNT_MASK
+     * @see #FIELD_COUNT_UNKNOWN
+     * @see #FIELD_COUNT_REPEATED
+     * @see #FIELD_COUNT_PACKED
+     * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+     * Encoding</a>
+     */
     public static final long FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT;
+
+    /**
+     * Repeated field count, encoded into a field id used with a
+     * <code>{@link ProtoOutputStream}.write(...)</code> method.
+     *
+     * @see #FIELD_COUNT_SHIFT
+     * @see #FIELD_COUNT_MASK
+     * @see #FIELD_COUNT_UNKNOWN
+     * @see #FIELD_COUNT_SINGLE
+     * @see #FIELD_COUNT_PACKED
+     * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+     * Encoding</a>
+     */
     public static final long FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT;
+
+    /**
+     * Repeated packed field count, encoded into a field id used with a
+     * <code>{@link ProtoOutputStream}.write(...)</code> method.
+     *
+     * @see #FIELD_COUNT_SHIFT
+     * @see #FIELD_COUNT_MASK
+     * @see #FIELD_COUNT_UNKNOWN
+     * @see #FIELD_COUNT_SINGLE
+     * @see #FIELD_COUNT_REPEATED
+     * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+     * Encoding</a>
+     */
     public static final long FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT;
 
 
     /**
      * Get the developer-usable name of a field type.
      */
-    public static String getFieldTypeString(long fieldType) {
+    public static @Nullable String getFieldTypeString(long fieldType) {
         int index = ((int) ((fieldType & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) - 1;
         if (index >= 0 && index < FIELD_TYPE_NAMES.length) {
             return FIELD_TYPE_NAMES[index];
@@ -124,7 +390,7 @@
     /**
      * Get the developer-usable name of a field count.
      */
-    public static String getFieldCountString(long fieldCount) {
+    public static @Nullable String getFieldCountString(long fieldCount) {
         if (fieldCount == FIELD_COUNT_SINGLE) {
             return "";
         } else if (fieldCount == FIELD_COUNT_REPEATED) {
@@ -139,7 +405,7 @@
     /**
      * Get the developer-usable name of a wire type.
      */
-    public static String getWireTypeString(int wireType) {
+    public static @Nullable String getWireTypeString(int wireType) {
         switch (wireType) {
             case WIRE_TYPE_VARINT:
                 return "Varint";
@@ -161,7 +427,7 @@
     /**
      * Get a debug string for a fieldId.
      */
-    public static String getFieldIdString(long fieldId) {
+    public static @NonNull String getFieldIdString(long fieldId) {
         final long fieldCount = fieldId & FIELD_COUNT_MASK;
         String countString = getFieldCountString(fieldCount);
         if (countString == null) {
@@ -218,29 +484,39 @@
 
     /**
      * Get the encoded tag size from the token.
+     *
+     * @hide
      */
     public static int getTagSizeFromToken(long token) {
         return (int) (0x7 & (token >> 61));
     }
 
     /**
-     * Get whether this is a call to startObject (false) or startRepeatedObject (true).
+     * Get whether the token has the repeated bit set to true or false
+     *
+     * @hide
      */
     public static boolean getRepeatedFromToken(long token) {
         return (0x1 & (token >> 60)) != 0;
     }
 
     /**
-     * Get the nesting depth of startObject calls from the token.
+     * Get the nesting depth from the token.
+     *
+     * @hide
      */
     public static int getDepthFromToken(long token) {
         return (int) (0x01ff & (token >> 51));
     }
 
     /**
-     * Get the object ID from the token. The object ID is a serial number for the
+     * Get the object ID from the token.
+     *
+     * <p>The object ID is a serial number for the
      * startObject calls that have happened on this object.  The values are truncated
      * to 9 bits, but that is sufficient for error checking.
+     *
+     * @hide
      */
     public static int getObjectIdFromToken(long token) {
         return (int) (0x07ffff & (token >> 32));
@@ -248,6 +524,8 @@
 
     /**
      * Get the location of the offset recorded in the token.
+     *
+     * @hide
      */
     public static int getOffsetFromToken(long token) {
         return (int) token;
@@ -255,8 +533,11 @@
 
     /**
      * Convert the object ID to the ordinal value -- the n-th call to startObject.
-     * The object IDs start at -1 and count backwards, so that the value is unlikely
+     *
+     * <p>The object IDs start at -1 and count backwards, so that the value is unlikely
      * to alias with an actual size field that had been written.
+     *
+     * @hide
      */
     public static int convertObjectIdToOrdinal(int objectId) {
         return (-1 & 0x07ffff) - objectId;
@@ -265,7 +546,7 @@
     /**
      * Return a debugging string of a token.
      */
-    public static String token2String(long token) {
+    public static @NonNull String token2String(long token) {
         if (token == 0L) {
             return "Token(0)";
         } else {
@@ -277,4 +558,9 @@
                     + ')';
         }
     }
+
+    /**
+     * @hide
+     */
+    protected ProtoStream() {}
 }
diff --git a/core/java/android/util/proto/ProtoUtils.java b/core/java/android/util/proto/ProtoUtils.java
index 03bf590..a71561b 100644
--- a/core/java/android/util/proto/ProtoUtils.java
+++ b/core/java/android/util/proto/ProtoUtils.java
@@ -24,12 +24,12 @@
 /**
  * This class contains a list of helper functions to write common proto in
  * //frameworks/base/core/proto/android/base directory
+ * @hide
  */
 public class ProtoUtils {
 
     /**
      * Dump AggStats to ProtoOutputStream
-     * @hide
      */
     public static void toAggStatsProto(ProtoOutputStream proto, long fieldId,
             long min, long average, long max) {
@@ -42,7 +42,6 @@
 
     /**
      * Dump Duration to ProtoOutputStream
-     * @hide
      */
     public static void toDuration(ProtoOutputStream proto, long fieldId, long startMs, long endMs) {
         final long token = proto.start(fieldId);
@@ -53,7 +52,6 @@
 
     /**
      * Helper function to write bit-wise flags to proto as repeated enums
-     * @hide
      */
     public static void writeBitWiseFlagsToProtoEnum(ProtoOutputStream proto, long fieldId,
             int flags, int[] origEnums, int[] protoEnums) {
diff --git a/core/java/android/util/proto/TEST_MAPPING b/core/java/android/util/proto/TEST_MAPPING
index cf9f077..5b98741 100644
--- a/core/java/android/util/proto/TEST_MAPPING
+++ b/core/java/android/util/proto/TEST_MAPPING
@@ -2,6 +2,9 @@
   "presubmit": [
     {
       "name": "ProtoInputStreamTests"
+    },
+    {
+      "name": "CtsProtoTestCases"
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/core/java/android/util/proto/package.html b/core/java/android/util/proto/package.html
index a636bd4..ef1125b 100644
--- a/core/java/android/util/proto/package.html
+++ b/core/java/android/util/proto/package.html
@@ -1,5 +1,5 @@
+<html>
 <body>
 Provides utility classes to export protocol buffers from the system.
-
-{@hide}
 </body>
+</html>
\ No newline at end of file
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/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/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl
index f1d152b..00edb3a 100644
--- a/core/java/android/view/IPinnedStackController.aidl
+++ b/core/java/android/view/IPinnedStackController.aidl
@@ -45,4 +45,17 @@
      * {@param animationDuration} suggests the animation duration transitioning to PiP window.
      */
     void startAnimation(in Rect destinationBounds, in Rect sourceRectHint, int animationDuration);
+
+    /**
+     * Notifies the controller to reset on bounds animation, if there is any.
+     * This could happen when screen rotation is happening and we need to notify the WM to reset
+     * any running bounds animation on the pinned stack.
+     * {@param bounds} here is the final destination bounds.
+     */
+    void resetBoundsAnimation(in Rect bounds);
+
+    /**
+     * Reports the current default and movement bounds to controller.
+     */
+    void reportBounds(in Rect defaultBounds, in Rect movementBounds);
 }
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 1639dbe..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;
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/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index 978ac5b..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;
diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
index d510724..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;
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/Editor.java b/core/java/android/widget/Editor.java
index eb0d9bf..3b6a009 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -148,8 +148,11 @@
 public class Editor {
     private static final String TAG = "Editor";
     private static final boolean DEBUG_UNDO = false;
-    // Specifies whether to use or not the magnifier when pressing the insertion or selection
-    // handles.
+
+    // Specifies whether to allow starting a cursor drag by dragging anywhere over the text.
+    @VisibleForTesting
+    public static boolean FLAG_ENABLE_CURSOR_DRAG = false;
+    // Specifies whether to use the magnifier when pressing the insertion or selection handles.
     private static final boolean FLAG_USE_MAGNIFIER = true;
 
     private static final int DELAY_BEFORE_HANDLE_FADES_OUT = 4000;
@@ -204,7 +207,7 @@
     private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
     // Cursor Controllers.
-    private InsertionPointCursorController mInsertionPointCursorController;
+    InsertionPointCursorController mInsertionPointCursorController;
     SelectionModifierCursorController mSelectionModifierCursorController;
     // Action mode used when text is selected or when actions on an insertion cursor are triggered.
     private ActionMode mTextActionMode;
@@ -1471,6 +1474,9 @@
         mTouchState.update(event, viewConfiguration);
         updateFloatingToolbarVisibility(event);
 
+        if (hasInsertionController()) {
+            getInsertionController().onTouchEvent(event);
+        }
         if (hasSelectionController()) {
             getSelectionController().onTouchEvent(event);
         }
@@ -5179,15 +5185,11 @@
 
                 case MotionEvent.ACTION_UP:
                     if (!offsetHasBeenChanged()) {
-                        final float deltaX = mLastDownRawX - ev.getRawX();
-                        final float deltaY = mLastDownRawY - ev.getRawY();
-                        final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
-
-                        final ViewConfiguration viewConfiguration = ViewConfiguration.get(
-                                mTextView.getContext());
-                        final int touchSlop = viewConfiguration.getScaledTouchSlop();
-
-                        if (distanceSquared < touchSlop * touchSlop) {
+                        ViewConfiguration config = ViewConfiguration.get(mTextView.getContext());
+                        boolean isWithinTouchSlop = EditorTouchState.isDistanceWithin(
+                                mLastDownRawX, mLastDownRawY, ev.getRawX(), ev.getRawY(),
+                                config.getScaledTouchSlop());
+                        if (isWithinTouchSlop) {
                             // Tapping on the handle toggles the insertion action mode.
                             if (mTextActionMode != null) {
                                 stopTextActionMode();
@@ -5237,6 +5239,10 @@
             } else {
                 offset = -1;
             }
+            if (TextView.DEBUG_CURSOR) {
+                logCursor("InsertionHandleView: updatePosition", "x=%f, y=%f, offset=%d, line=%d",
+                        x, y, offset, mPreviousLineTouched);
+            }
             positionAtCursorOffset(offset, false, fromTouchScreen);
             if (mTextActionMode != null) {
                 invalidateActionMode();
@@ -5716,8 +5722,82 @@
         }
     }
 
-    private class InsertionPointCursorController implements CursorController {
+    class InsertionPointCursorController implements CursorController {
         private InsertionHandleView mHandle;
+        private boolean mIsDraggingCursor;
+
+        public void onTouchEvent(MotionEvent event) {
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                    mIsDraggingCursor = false;
+                    break;
+                case MotionEvent.ACTION_MOVE:
+                    if (mIsDraggingCursor) {
+                        performCursorDrag(event);
+                    } else if (FLAG_ENABLE_CURSOR_DRAG
+                                && mTextView.getLayout() != null
+                                && mTextView.isFocused()
+                                && mTouchState.isMovedEnoughForDrag()) {
+                        startCursorDrag(event);
+                    }
+                    break;
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_CANCEL:
+                    if (mIsDraggingCursor) {
+                        endCursorDrag(event);
+                    }
+                    break;
+            }
+        }
+
+        private void positionCursorDuringDrag(MotionEvent event) {
+            int line = mTextView.getLineAtCoordinate(event.getY());
+            int offset = mTextView.getOffsetAtCoordinate(line, event.getX());
+            int oldSelectionStart = mTextView.getSelectionStart();
+            int oldSelectionEnd = mTextView.getSelectionEnd();
+            if (offset == oldSelectionStart && offset == oldSelectionEnd) {
+                return;
+            }
+            Selection.setSelection((Spannable) mTextView.getText(), offset);
+            updateCursorPosition();
+            if (mHapticTextHandleEnabled) {
+                mTextView.performHapticFeedback(HapticFeedbackConstants.TEXT_HANDLE_MOVE);
+            }
+        }
+
+        private void startCursorDrag(MotionEvent event) {
+            if (TextView.DEBUG_CURSOR) {
+                logCursor("InsertionPointCursorController", "start cursor drag");
+            }
+            mIsDraggingCursor = true;
+            // We don't want the parent scroll/long-press handlers to take over while dragging.
+            mTextView.getParent().requestDisallowInterceptTouchEvent(true);
+            mTextView.cancelLongPress();
+            // Update the cursor position.
+            positionCursorDuringDrag(event);
+            // Show the cursor handle and magnifier.
+            show();
+            getHandle().removeHiderCallback();
+            getHandle().updateMagnifier(event);
+            // TODO(b/146555651): Figure out if suspendBlink() should be called here.
+        }
+
+        private void performCursorDrag(MotionEvent event) {
+            positionCursorDuringDrag(event);
+            getHandle().updateMagnifier(event);
+        }
+
+        private void endCursorDrag(MotionEvent event) {
+            if (TextView.DEBUG_CURSOR) {
+                logCursor("InsertionPointCursorController", "end cursor drag");
+            }
+            mIsDraggingCursor = false;
+            // Hide the magnifier and set the handle to be hidden after a delay.
+            getHandle().dismissMagnifier();
+            getHandle().hideAfterDelay();
+            // We're no longer dragging, so let the parent receive events.
+            mTextView.getParent().requestDisallowInterceptTouchEvent(false);
+        }
 
         public void show() {
             getHandle().show();
@@ -5725,15 +5805,19 @@
             final long durationSinceCutOrCopy =
                     SystemClock.uptimeMillis() - TextView.sLastCutCopyOrTextChangedTime;
 
-            // Cancel the single tap delayed runnable.
-            if (mInsertionActionModeRunnable != null
-                    && (mTouchState.isMultiTap() || isCursorInsideEasyCorrectionSpan())) {
-                mTextView.removeCallbacks(mInsertionActionModeRunnable);
+            if (mInsertionActionModeRunnable != null) {
+                if (mIsDraggingCursor
+                        || mTouchState.isMultiTap()
+                        || isCursorInsideEasyCorrectionSpan()) {
+                    // Cancel the runnable for showing the floating toolbar.
+                    mTextView.removeCallbacks(mInsertionActionModeRunnable);
+                }
             }
 
-            // Prepare and schedule the single tap runnable to run exactly after the double tap
-            // timeout has passed.
-            if (!mTouchState.isMultiTap()
+            // If the user recently performed a Cut or Copy action, we want to show the floating
+            // toolbar even for a single tap.
+            if (!mIsDraggingCursor
+                    && !mTouchState.isMultiTap()
                     && !isCursorInsideEasyCorrectionSpan()
                     && (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION_MS)) {
                 if (mTextActionMode == null) {
@@ -5751,7 +5835,9 @@
                 }
             }
 
-            getHandle().hideAfterDelay();
+            if (!mIsDraggingCursor) {
+                getHandle().hideAfterDelay();
+            }
 
             if (mSelectionModifierCursorController != null) {
                 mSelectionModifierCursorController.hide();
@@ -5797,7 +5883,7 @@
 
         @Override
         public boolean isCursorBeingModified() {
-            return mHandle != null && mHandle.isDragging();
+            return mIsDraggingCursor || (mHandle != null && mHandle.isDragging());
         }
 
         @Override
@@ -5959,7 +6045,6 @@
                 case MotionEvent.ACTION_MOVE:
                     final ViewConfiguration viewConfig = ViewConfiguration.get(
                             mTextView.getContext());
-                    final int touchSlop = viewConfig.getScaledTouchSlop();
 
                     if (mGestureStayedInTapRegion || mHaventMovedEnoughToStartDrag) {
                         final float deltaX = eventX - mTouchState.getLastDownX();
@@ -5973,6 +6058,7 @@
                         }
                         if (mHaventMovedEnoughToStartDrag) {
                             // We don't start dragging until the user has moved enough.
+                            int touchSlop = viewConfig.getScaledTouchSlop();
                             mHaventMovedEnoughToStartDrag =
                                     distanceSquared <= touchSlop * touchSlop;
                         }
diff --git a/core/java/android/widget/EditorTouchState.java b/core/java/android/widget/EditorTouchState.java
index f880939..3798d00 100644
--- a/core/java/android/widget/EditorTouchState.java
+++ b/core/java/android/widget/EditorTouchState.java
@@ -55,6 +55,8 @@
     private int mMultiTapStatus = MultiTapStatus.NONE;
     private boolean mMultiTapInSameArea;
 
+    private boolean mMovedEnoughForDrag;
+
     public float getLastDownX() {
         return mLastDownX;
     }
@@ -88,10 +90,14 @@
         return isMultiTap() && mMultiTapInSameArea;
     }
 
+    public boolean isMovedEnoughForDrag() {
+        return mMovedEnoughForDrag;
+    }
+
     /**
      * Updates the state based on the new event.
      */
-    public void update(MotionEvent event, ViewConfiguration viewConfiguration) {
+    public void update(MotionEvent event, ViewConfiguration config) {
         final int action = event.getActionMasked();
         if (action == MotionEvent.ACTION_DOWN) {
             final boolean isMouse = event.isFromSource(InputDevice.SOURCE_MOUSE);
@@ -105,11 +111,8 @@
                 } else {
                     mMultiTapStatus = MultiTapStatus.TRIPLE_CLICK;
                 }
-                final float deltaX = event.getX() - mLastDownX;
-                final float deltaY = event.getY() - mLastDownY;
-                final int distanceSquared = (int) ((deltaX * deltaX) + (deltaY * deltaY));
-                int doubleTapSlop = viewConfiguration.getScaledDoubleTapSlop();
-                mMultiTapInSameArea = distanceSquared < doubleTapSlop * doubleTapSlop;
+                mMultiTapInSameArea = isDistanceWithin(mLastDownX, mLastDownY,
+                        event.getX(), event.getY(), config.getScaledDoubleTapSlop());
                 if (TextView.DEBUG_CURSOR) {
                     String status = isDoubleTap() ? "double" : "triple";
                     String inSameArea = mMultiTapInSameArea ? "in same area" : "not in same area";
@@ -125,6 +128,7 @@
             }
             mLastDownX = event.getX();
             mLastDownY = event.getY();
+            mMovedEnoughForDrag = false;
         } else if (action == MotionEvent.ACTION_UP) {
             if (TextView.DEBUG_CURSOR) {
                 logCursor("EditorTouchState", "ACTION_UP");
@@ -132,6 +136,23 @@
             mLastUpX = event.getX();
             mLastUpY = event.getY();
             mLastUpMillis = event.getEventTime();
+            mMovedEnoughForDrag = false;
+        } else if (action == MotionEvent.ACTION_MOVE) {
+            mMovedEnoughForDrag = !isDistanceWithin(mLastDownX, mLastDownY,
+                    event.getX(), event.getY(), config.getScaledTouchSlop());
         }
     }
+
+    /**
+     * Returns true if the distance between the given coordinates is <= to the specified max.
+     * This is useful to be able to determine e.g. when the user's touch has moved enough in
+     * order to be considered a drag (no longer within touch slop).
+     */
+    public static boolean isDistanceWithin(float x1, float y1, float x2, float y2,
+            int maxDistance) {
+        float deltaX = x2 - x1;
+        float deltaY = y2 - y1;
+        float distanceSquared = (deltaX * deltaX) + (deltaY * deltaY);
+        return distanceSquared <= maxDistance * maxDistance;
+    }
 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index ee169f2..43d9895 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10870,6 +10870,10 @@
         if (mEditor != null) {
             mEditor.onTouchEvent(event);
 
+            if (mEditor.mInsertionPointCursorController != null
+                    && mEditor.mInsertionPointCursorController.isCursorBeingModified()) {
+                return true;
+            }
             if (mEditor.mSelectionModifierCursorController != null
                     && mEditor.mSelectionModifierCursorController.isDragAcceleratorActive()) {
                 return true;
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 99bf93e..46025aa 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -32,14 +32,13 @@
     // and not be reordered
     int checkOperation(int code, int uid, String packageName);
     int noteOperation(int code, int uid, String packageName, @nullable String featureId);
-    int startOperation(IBinder token, int code, int uid, String packageName,
+    int startOperation(IBinder clientId, int code, int uid, String packageName,
             @nullable String featureId, boolean startIfModeDefault);
     @UnsupportedAppUsage
-    void finishOperation(IBinder token, int code, int uid, String packageName,
+    void finishOperation(IBinder clientId, int code, int uid, String packageName,
             @nullable String featureId);
     void startWatchingMode(int op, String packageName, IAppOpsCallback callback);
     void stopWatchingMode(IAppOpsCallback callback);
-    IBinder getToken(IBinder clientToken);
     int permissionToOpCode(String permission);
     int checkAudioOperation(int code, int usage, int uid, String packageName);
     void noteAsyncOp(@nullable String callingPackageName, int uid, @nullable String packageName,
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index bc80197..c7ec2cd 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -136,6 +136,13 @@
     }
 
     /**
+     * Returns the same array or an empty one if it's null.
+     */
+    public static @NonNull <T> T[] emptyIfNull(@Nullable T[] items, Class<T> kind) {
+        return items != null ? items : emptyArray(kind);
+    }
+
+    /**
      * Checks if given array is null or has zero elements.
      */
     public static boolean isEmpty(@Nullable Collection<?> array) {
@@ -751,6 +758,42 @@
         return result;
     }
 
+    /**
+     * Returns an array containing elements from the given one that match the given predicate.
+     */
+    public static @Nullable <T> T[] filter(@Nullable T[] items,
+            @NonNull IntFunction<T[]> arrayConstructor,
+            @NonNull java.util.function.Predicate<T> predicate) {
+        if (isEmpty(items)) {
+            return items;
+        }
+
+        int matchesCount = 0;
+        int size = size(items);
+        for (int i = 0; i < size; i++) {
+            if (predicate.test(items[i])) {
+                matchesCount++;
+            }
+        }
+        if (matchesCount == 0) {
+            return items;
+        }
+        if (matchesCount == items.length) {
+            return items;
+        }
+        if (matchesCount == 0) {
+            return null;
+        }
+        T[] result = arrayConstructor.apply(matchesCount);
+        int outIdx = 0;
+        for (int i = 0; i < size; i++) {
+            if (predicate.test(items[i])) {
+                result[outIdx++] = items[i];
+            }
+        }
+        return result;
+    }
+
     public static boolean startsWith(byte[] cur, byte[] val) {
         if (cur == null || val == null) return false;
         if (cur.length < val.length) return false;
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index c1d129b..362bc92 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -91,7 +91,15 @@
      * that are mapped in to processes.
      */
     public long getCachedSizeKb() {
-        return mInfos[Debug.MEMINFO_BUFFERS] + mInfos[Debug.MEMINFO_SLAB_RECLAIMABLE]
+        long kReclaimable = mInfos[Debug.MEMINFO_KRECLAIMABLE];
+
+        // Note: MEMINFO_KRECLAIMABLE includes MEMINFO_SLAB_RECLAIMABLE and ION pools.
+        // Fall back to using MEMINFO_SLAB_RECLAIMABLE in case of older kernels that do
+        // not include KReclaimable meminfo field.
+        if (kReclaimable == 0) {
+            kReclaimable = mInfos[Debug.MEMINFO_SLAB_RECLAIMABLE];
+        }
+        return mInfos[Debug.MEMINFO_BUFFERS] + kReclaimable
                 + mInfos[Debug.MEMINFO_CACHED] - mInfos[Debug.MEMINFO_MAPPED];
     }
 
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 60c5bf1..98ce8b0 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -141,6 +141,7 @@
                 "android_os_UEventObserver.cpp",
                 "android_os_VintfObject.cpp",
                 "android_os_VintfRuntimeInfo.cpp",
+                "android_os_incremental_IncrementalManager.cpp",
                 "android_net_LocalSocketImpl.cpp",
                 "android_net_NetUtils.cpp",
                 "android_service_DataLoaderService.cpp",
@@ -207,6 +208,7 @@
 
             static_libs: [
                 "libasync_safe",
+                "libdmabufinfo",
                 "libgif",
                 "libseccomp_policy",
                 "libgrallocusage",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 3cde887..c41b19e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -152,6 +152,7 @@
 extern int register_android_os_MemoryFile(JNIEnv* env);
 extern int register_android_os_SharedMemory(JNIEnv* env);
 extern int register_android_service_DataLoaderService(JNIEnv* env);
+extern int register_android_os_incremental_IncrementalManager(JNIEnv* env);
 extern int register_android_net_LocalSocketImpl(JNIEnv* env);
 extern int register_android_net_NetworkUtils(JNIEnv* env);
 extern int register_android_text_AndroidCharacter(JNIEnv *env);
@@ -1496,6 +1497,7 @@
     REG_JNI(register_android_net_NetworkUtils),
     REG_JNI(register_android_os_MemoryFile),
     REG_JNI(register_android_os_SharedMemory),
+    REG_JNI(register_android_os_incremental_IncrementalManager),
     REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
     REG_JNI(register_com_android_internal_os_Zygote),
     REG_JNI(register_com_android_internal_os_ZygoteInit),
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_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index ee11b61..25ffbab 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -96,28 +96,9 @@
     return toJavaStringArray(env, cStrings);
 }
 
-static jint android_os_VintfObject_verify(JNIEnv* env, jclass, jobjectArray packageInfo) {
-    std::vector<std::string> cPackageInfo;
-    if (packageInfo) {
-        size_t count = env->GetArrayLength(packageInfo);
-        cPackageInfo.resize(count);
-        for (size_t i = 0; i < count; ++i) {
-            jstring element = (jstring)env->GetObjectArrayElement(packageInfo, i);
-            const char *cString = env->GetStringUTFChars(element, NULL /* isCopy */);
-            cPackageInfo[i] = cString;
-            env->ReleaseStringUTFChars(element, cString);
-        }
-    }
-    std::string error;
-    int32_t status = VintfObject::CheckCompatibility(cPackageInfo, &error);
-    if (status)
-        LOG(WARNING) << "VintfObject.verify() returns " << status << ": " << error;
-    return status;
-}
-
 static jint android_os_VintfObject_verifyWithoutAvb(JNIEnv* env, jclass) {
     std::string error;
-    int32_t status = VintfObject::CheckCompatibility({}, &error,
+    int32_t status = VintfObject::GetInstance()->checkCompatibility(&error,
             ::android::vintf::CheckFlags::DISABLE_AVB_CHECK);
     if (status)
         LOG(WARNING) << "VintfObject.verifyWithoutAvb() returns " << status << ": " << error;
@@ -170,7 +151,6 @@
 
 static const JNINativeMethod gVintfObjectMethods[] = {
     {"report", "()[Ljava/lang/String;", (void*)android_os_VintfObject_report},
-    {"verify", "([Ljava/lang/String;)I", (void*)android_os_VintfObject_verify},
     {"verifyWithoutAvb", "()I", (void*)android_os_VintfObject_verifyWithoutAvb},
     {"getHalNamesAndVersions", "()[Ljava/lang/String;", (void*)android_os_VintfObject_getHalNamesAndVersions},
     {"getSepolicyVersion", "()Ljava/lang/String;", (void*)android_os_VintfObject_getSepolicyVersion},
diff --git a/core/jni/android_os_incremental_IncrementalManager.cpp b/core/jni/android_os_incremental_IncrementalManager.cpp
new file mode 100644
index 0000000..698062a
--- /dev/null
+++ b/core/jni/android_os_incremental_IncrementalManager.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "incremental_manager-jni"
+
+#include "core_jni_helpers.h"
+#include "incfs_ndk.h"
+#include "jni.h"
+#include "nativehelper/JNIHelp.h"
+
+#include <iterator>
+#include <memory>
+
+namespace android {
+
+static jboolean nativeIsIncrementalPath(JNIEnv* env,
+                                    jobject clazz,
+                                    jstring javaPath) {
+    ScopedUtfChars path(env, javaPath);
+    return (jboolean)IncFs_IsIncFsPath(path.c_str());
+}
+
+static const JNINativeMethod method_table[] = {
+        {"nativeIsIncrementalPath", "(Ljava/lang/String;)Z",
+         (void*)nativeIsIncrementalPath},
+};
+
+int register_android_os_incremental_IncrementalManager(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, "android/os/incremental/IncrementalManager",
+                                    method_table, std::size(method_table));
+}
+
+} // namespace android
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 8c1ecae..738965e 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -37,11 +37,13 @@
   "/apex/com.android.conscrypt/javalib/conscrypt.jar",
   "/apex/com.android.ipsec/javalib/ike.jar",
   "/apex/com.android.media/javalib/updatable-media.jar",
+  "/apex/com.android.mediaprovider/javalib/framework-mediaprovider.jar",
   "/apex/com.android.os.statsd/javalib/framework-statsd.jar",
   "/apex/com.android.sdkext/javalib/framework-sdkext.jar",
   "/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..b2a19cf 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -251,6 +251,9 @@
     // ACTION: Create a Settings shortcut item.
     ACTION_SETTINGS_CREATE_SHORTCUT = 829;
 
+    // ACTION: A tile in Settings information architecture is clicked
+    ACTION_SETTINGS_TILE_CLICK = 830;
+
     // ACTION: Settings advanced button is expanded
     ACTION_SETTINGS_ADVANCED_BUTTON_EXPAND = 834;
 
@@ -2504,4 +2507,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 dd09427..1165d2d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -307,6 +307,7 @@
     <protected-broadcast android:name="android.net.nsd.STATE_CHANGED" />
 
     <protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" />
+    <protected-broadcast android:name="android.nfc.action.PREFERRED_PAYMENT_CHANGED" />
     <protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
     <protected-broadcast android:name="com.android.nfc.action.LLCP_UP" />
     <protected-broadcast android:name="com.android.nfc.action.LLCP_DOWN" />
@@ -1629,6 +1630,14 @@
     <permission android:name="android.permission.NETWORK_SETTINGS"
         android:protectionLevel="signature|telephony" />
 
+    <!-- Allows holder to request bluetooth/wifi scan bypassing global "use location" setting and
+         location permissions.
+         <p>Not for use by third-party or privileged applications.
+         @hide
+    -->
+    <permission android:name="android.permission.RADIO_SCAN_WITHOUT_LOCATION"
+                android:protectionLevel="signature|companion" />
+
     <!-- Allows SetupWizard to call methods in Networking services
          <p>Not for use by any other third-party or privileged applications.
          @SystemApi
@@ -1749,6 +1758,14 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.NFC_TRANSACTION_EVENT"
+      android:protectionLevel="normal" />
+
+    <!-- Allows applications to receive NFC preferred payment service information.
+         <p>Protection level: normal
+    -->
+    <permission android:name="android.permission.NFC_PREFERRED_PAYMENT_INFO"
+        android:description="@string/permdesc_preferredPaymentInfo"
+        android:label="@string/permlab_preferredPaymentInfo"
         android:protectionLevel="normal" />
 
     <!-- @deprecated This permission used to allow too broad access to sensitive methods and all its
@@ -2208,6 +2225,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 +2961,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.
@@ -4696,6 +4732,12 @@
     <permission android:name="android.permission.PEEK_DROPBOX_DATA"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows an application to access TV tuner HAL
+         <p>Not for use by third-party applications.
+         @hide -->
+    <permission android:name="android.permission.ACCESS_TV_TUNER"
+        android:protectionLevel="signature|privileged" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 166cde0..b17d473 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -298,6 +298,9 @@
         <!-- Additional flag from base permission type: this permission can be automatically
             granted to the system telephony apps -->
         <flag name="telephony" value="0x400000" />
+        <!-- Additional flag from base permission type: this permission can be automatically
+            granted to the system companion device manager service -->
+        <flag name="companion" value="0x800000" />
     </attr>
 
     <!-- Flags indicating more context for a permission group. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 85406c7..32ec95a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3572,6 +3572,13 @@
         <item>android.ext.services</item>
     </string-array>
 
+    <!-- The package name for the system companion device manager service.
+         This service must be trusted, as it can be activated without explicit consent of the user.
+         Example: "com.android.companiondevicemanager"
+         See android.companion.CompanionDeviceManager.
+    -->
+    <string name="config_companionDeviceManagerPackage" translatable="false"></string>
+
     <!-- The package name for the default wellbeing app.
          This package must be trusted, as it has the permissions to control other applications
          on the device.
@@ -4272,4 +4279,7 @@
          value is left empty.  When this is non-empty then config_rawContactsLocalAccountName
          should also be non-empty.-->
     <string name="config_rawContactsLocalAccountType" translatable="false"></string>
+
+    <!-- Whether or not to use assistant stream volume separately from music volume -->
+    <bool name="config_useAssistantVolume">false</bool>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ab10738..31becf7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1345,6 +1345,12 @@
       connections with paired devices.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_preferredPaymentInfo">Preferred NFC Payment Service Information</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_preferredPaymentInfo">Allows the app to get preferred nfc payment service information like
+      registered aids and route destination.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_nfc">control Near Field Communication</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_nfc">Allows the app to communicate
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1e59c37..d30c7bf 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -468,6 +468,7 @@
   <java-symbol type="string" name="config_deviceSpecificAudioService" />
   <java-symbol type="integer" name="config_num_physical_slots" />
   <java-symbol type="array" name="config_integrityRuleProviderPackages" />
+  <java-symbol type="bool" name="config_useAssistantVolume" />
 
   <java-symbol type="color" name="tab_indicator_text_v4" />
 
diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java
index 576ac73..5cb7852 100644
--- a/core/tests/coretests/src/android/os/PowerManagerTest.java
+++ b/core/tests/coretests/src/android/os/PowerManagerTest.java
@@ -239,4 +239,17 @@
         verify(mListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
                 .times(1)).onThermalStatusChanged(status);
     }
+
+    @Test
+    public void testUserspaceRebootNotSupported_throwsUnsupportedOperationException() {
+        // Can't use assumption framework with AndroidTestCase :(
+        if (mPm.isRebootingUserspaceSupported()) {
+            return;
+        }
+        try {
+            mPm.reboot(PowerManager.REBOOT_USERSPACE);
+            fail("UnsupportedOperationException not thrown");
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
new file mode 100644
index 0000000..b4f2c91
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.widget;
+
+import static android.widget.espresso.TextViewActions.dragOnText;
+import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.replaceText;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.coretests.R;
+
+import com.google.common.base.Strings;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class EditorCursorDragTest {
+    @Rule
+    public ActivityTestRule<TextViewActivity> mActivityRule = new ActivityTestRule<>(
+            TextViewActivity.class);
+
+    private boolean mOriginalFlagValue;
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    @Before
+    public void before() throws Throwable {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mOriginalFlagValue = Editor.FLAG_ENABLE_CURSOR_DRAG;
+        Editor.FLAG_ENABLE_CURSOR_DRAG = true;
+    }
+    @After
+    public void after() throws Throwable {
+        Editor.FLAG_ENABLE_CURSOR_DRAG = mOriginalFlagValue;
+    }
+
+    @Test
+    public void testCursorDrag_horizontal_whenTextViewContentsFitOnScreen() throws Throwable {
+        String text = "Hello world!";
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
+
+        // Drag left to right. The cursor should end up at the position where the finger is lifted.
+        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("llo"), text.indexOf("!")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(11));
+
+        // Drag right to left. The cursor should end up at the position where the finger is lifted.
+        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("!"), text.indexOf("llo")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2));
+    }
+
+    @Test
+    public void testCursorDrag_horizontal_whenTextViewContentsLargerThanScreen() throws Throwable {
+        String text = "Hello world!"
+                + Strings.repeat("\n", 500) + "012345middle"
+                + Strings.repeat("\n", 10) + "012345last";
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
+
+        // Drag left to right. The cursor should end up at the position where the finger is lifted.
+        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("llo"), text.indexOf("!")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(11));
+
+        // Drag right to left. The cursor should end up at the position where the finger is lifted.
+        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("!"), text.indexOf("llo")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2));
+    }
+
+    @Test
+    public void testCursorDrag_diagonal_whenTextViewContentsLargerThanScreen() throws Throwable {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 1; i <= 9; i++) {
+            sb.append("line").append(i).append("\n");
+        }
+        sb.append(Strings.repeat("0123456789\n\n", 500)).append("Last line");
+        String text = sb.toString();
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
+
+        // Drag along a diagonal path.
+        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("2")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("2")));
+
+        // Drag along a steeper diagonal path.
+        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("9")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("9")));
+
+        // Drag along an almost vertical path.
+        // TODO(b/145833335): Consider whether this should scroll instead of dragging the cursor.
+        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("ne1"), text.indexOf("9")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("9")));
+
+        // Drag along a vertical path from line 1 to line 9.
+        // TODO(b/145833335): Consider whether this should scroll instead of dragging the cursor.
+        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("e1"), text.indexOf("e9")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("e9")));
+
+        // Drag along a vertical path from line 9 to line 1.
+        // TODO(b/145833335): Consider whether this should scroll instead of dragging the cursor.
+        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("e9"), text.indexOf("e1")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("e1")));
+    }
+
+    @Test
+    public void testCursorDrag_vertical_whenTextViewContentsFitOnScreen() throws Throwable {
+        String text = "012first\n\n" + Strings.repeat("012345\n\n", 10) + "012last";
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
+
+        // Drag down. Since neither the TextView nor its container require scrolling, the cursor
+        // drag should execute and the cursor should end up at the position where the finger is
+        // lifted.
+        onView(withId(R.id.textview)).perform(
+                dragOnText(text.indexOf("first"), text.indexOf("last")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length() - 4));
+
+        // Drag up. Since neither the TextView nor its container require scrolling, the cursor
+        // drag should execute and the cursor should end up at the position where the finger is
+        // lifted.
+        onView(withId(R.id.textview)).perform(
+                dragOnText(text.indexOf("last"), text.indexOf("first")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(3));
+    }
+
+    @Test
+    public void testCursorDrag_vertical_whenTextViewContentsLargerThanScreen() throws Throwable {
+        String text = "012345first\n\n"
+                + Strings.repeat("0123456789\n\n", 10) + "012345middle"
+                + Strings.repeat("0123456789\n\n", 500) + "012345last";
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        int initialCursorPosition = 0;
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(initialCursorPosition));
+
+        // Drag up.
+        // TODO(b/145833335): Consider whether this should scroll instead of dragging the cursor.
+        onView(withId(R.id.textview)).perform(
+                dragOnText(text.indexOf("middle"), text.indexOf("first")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("first")));
+
+        // Drag down.
+        // TODO(b/145833335): Consider whether this should scroll instead of dragging the cursor.
+        onView(withId(R.id.textview)).perform(
+                dragOnText(text.indexOf("first"), text.indexOf("middle")));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("middle")));
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
index 6d50e3a..6adb1b8 100644
--- a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
+++ b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
@@ -16,6 +16,9 @@
 
 package android.widget;
 
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 
@@ -50,19 +53,19 @@
         long event1Time = 1000;
         MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
         mTouchState.update(event1, mConfig);
-        assertSingleTap(mTouchState, 20f, 30f, 0, 0);
+        assertSingleTap(mTouchState, 20f, 30f, 0, 0, false);
 
         // Simulate an ACTION_UP event.
         long event2Time = 1001;
         MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f);
         mTouchState.update(event2, mConfig);
-        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f);
+        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f, false);
 
         // Generate an ACTION_DOWN event whose time is after the double-tap timeout.
         long event3Time = event2Time + ViewConfiguration.getDoubleTapTimeout() + 1;
         MotionEvent event3 = downEvent(event3Time, event3Time, 22f, 33f);
         mTouchState.update(event3, mConfig);
-        assertSingleTap(mTouchState, 22f, 33f, 20f, 30f);
+        assertSingleTap(mTouchState, 22f, 33f, 20f, 30f, false);
     }
 
     @Test
@@ -71,19 +74,19 @@
         long event1Time = 1000;
         MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
         mTouchState.update(event1, mConfig);
-        assertSingleTap(mTouchState, 20f, 30f, 0, 0);
+        assertSingleTap(mTouchState, 20f, 30f, 0, 0, false);
 
         // Simulate an ACTION_UP event.
         long event2Time = 1001;
         MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f);
         mTouchState.update(event2, mConfig);
-        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f);
+        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f, false);
 
         // Generate an ACTION_DOWN event whose time is within the double-tap timeout.
         long event3Time = 1002;
         MotionEvent event3 = downEvent(event3Time, event3Time, 22f, 33f);
         mTouchState.update(event3, mConfig);
-        assertTap(mTouchState, 22f, 33f, 20f, 30f,
+        assertMultiTap(mTouchState, 22f, 33f, 20f, 30f,
                 MultiTapStatus.DOUBLE_TAP, true);
     }
 
@@ -93,26 +96,26 @@
         long event1Time = 1000;
         MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
         mTouchState.update(event1, mConfig);
-        assertSingleTap(mTouchState, 20f, 30f, 0, 0);
+        assertSingleTap(mTouchState, 20f, 30f, 0, 0, false);
 
         // Simulate an ACTION_UP event.
         long event2Time = 1001;
         MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f);
         mTouchState.update(event2, mConfig);
-        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f);
+        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f, false);
 
         // Generate an ACTION_DOWN event whose time is within the double-tap timeout.
         long event3Time = 1002;
         MotionEvent event3 = downEvent(event3Time, event3Time, 200f, 300f);
         mTouchState.update(event3, mConfig);
-        assertTap(mTouchState, 200f, 300f, 20f, 30f,
+        assertMultiTap(mTouchState, 200f, 300f, 20f, 30f,
                 MultiTapStatus.DOUBLE_TAP, false);
 
         // Simulate an ACTION_UP event.
         long event4Time = 1003;
         MotionEvent event4 = upEvent(event3Time, event4Time, 200f, 300f);
         mTouchState.update(event4, mConfig);
-        assertTap(mTouchState, 200f, 300f, 200f, 300f,
+        assertMultiTap(mTouchState, 200f, 300f, 200f, 300f,
                 MultiTapStatus.DOUBLE_TAP, false);
     }
 
@@ -123,21 +126,21 @@
         MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
         event1.setSource(InputDevice.SOURCE_MOUSE);
         mTouchState.update(event1, mConfig);
-        assertSingleTap(mTouchState, 20f, 30f, 0, 0);
+        assertSingleTap(mTouchState, 20f, 30f, 0, 0, false);
 
         // Simulate an ACTION_UP event.
         long event2Time = 1001;
         MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f);
         event2.setSource(InputDevice.SOURCE_MOUSE);
         mTouchState.update(event2, mConfig);
-        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f);
+        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f, false);
 
         // Generate a second ACTION_DOWN event whose time is within the double-tap timeout.
         long event3Time = 1002;
         MotionEvent event3 = downEvent(event3Time, event3Time, 21f, 31f);
         event3.setSource(InputDevice.SOURCE_MOUSE);
         mTouchState.update(event3, mConfig);
-        assertTap(mTouchState, 21f, 31f, 20f, 30f,
+        assertMultiTap(mTouchState, 21f, 31f, 20f, 30f,
                 MultiTapStatus.DOUBLE_TAP, true);
 
         // Simulate an ACTION_UP event.
@@ -145,7 +148,7 @@
         MotionEvent event4 = upEvent(event3Time, event4Time, 21f, 31f);
         event4.setSource(InputDevice.SOURCE_MOUSE);
         mTouchState.update(event4, mConfig);
-        assertTap(mTouchState, 21f, 31f, 21f, 31f,
+        assertMultiTap(mTouchState, 21f, 31f, 21f, 31f,
                 MultiTapStatus.DOUBLE_TAP, true);
 
         // Generate a third ACTION_DOWN event whose time is within the double-tap timeout.
@@ -153,7 +156,7 @@
         MotionEvent event5 = downEvent(event5Time, event5Time, 22f, 32f);
         event5.setSource(InputDevice.SOURCE_MOUSE);
         mTouchState.update(event5, mConfig);
-        assertTap(mTouchState, 22f, 32f, 21f, 31f,
+        assertMultiTap(mTouchState, 22f, 32f, 21f, 31f,
                 MultiTapStatus.TRIPLE_CLICK, true);
     }
 
@@ -163,34 +166,71 @@
         long event1Time = 1000;
         MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
         mTouchState.update(event1, mConfig);
-        assertSingleTap(mTouchState, 20f, 30f, 0, 0);
+        assertSingleTap(mTouchState, 20f, 30f, 0, 0, false);
 
         // Simulate an ACTION_UP event.
         long event2Time = 1001;
         MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f);
         mTouchState.update(event2, mConfig);
-        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f);
+        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f, false);
 
         // Generate a second ACTION_DOWN event whose time is within the double-tap timeout.
         long event3Time = 1002;
         MotionEvent event3 = downEvent(event3Time, event3Time, 21f, 31f);
         mTouchState.update(event3, mConfig);
-        assertTap(mTouchState, 21f, 31f, 20f, 30f,
+        assertMultiTap(mTouchState, 21f, 31f, 20f, 30f,
                 MultiTapStatus.DOUBLE_TAP, true);
 
         // Simulate an ACTION_UP event.
         long event4Time = 1003;
         MotionEvent event4 = upEvent(event3Time, event4Time, 21f, 31f);
         mTouchState.update(event4, mConfig);
-        assertTap(mTouchState, 21f, 31f, 21f, 31f,
+        assertMultiTap(mTouchState, 21f, 31f, 21f, 31f,
                 MultiTapStatus.DOUBLE_TAP, true);
 
         // Generate a third ACTION_DOWN event whose time is within the double-tap timeout.
         long event5Time = 1004;
         MotionEvent event5 = downEvent(event5Time, event5Time, 22f, 32f);
         mTouchState.update(event5, mConfig);
-        assertTap(mTouchState, 22f, 32f, 21f, 31f,
-                MultiTapStatus.FIRST_TAP, false);
+        assertSingleTap(mTouchState, 22f, 32f, 21f, 31f, false);
+    }
+
+    @Test
+    public void testUpdate_drag() throws Exception {
+        // Simulate an ACTION_DOWN event.
+        long event1Time = 1000;
+        MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+        mTouchState.update(event1, mConfig);
+        assertSingleTap(mTouchState, 20f, 30f, 0, 0, false);
+
+        // Simulate an ACTION_MOVE event whose location is not far enough to start a drag.
+        long event2Time = 1001;
+        MotionEvent event2 = moveEvent(event1Time, event2Time, 21f, 30f);
+        mTouchState.update(event2, mConfig);
+        assertSingleTap(mTouchState, 20f, 30f, 0, 0, false);
+
+        // Simulate another ACTION_MOVE event whose location is far enough to start a drag.
+        int touchSlop = mConfig.getScaledTouchSlop();
+        float newX = event1.getX() + touchSlop + 1;
+        float newY = event1.getY();
+        long event3Time = 1002;
+        MotionEvent event3 = moveEvent(event3Time, event3Time, newX, newY);
+        mTouchState.update(event3, mConfig);
+        assertSingleTap(mTouchState, 20f, 30f, 0, 0, true);
+
+        // Simulate an ACTION_UP event.
+        long event4Time = 1003;
+        MotionEvent event4 = upEvent(event3Time, event4Time, 200f, 300f);
+        mTouchState.update(event4, mConfig);
+        assertSingleTap(mTouchState, 20f, 30f, 200f, 300f, false);
+    }
+
+    @Test
+    public void testIsDistanceWithin() throws Exception {
+        assertTrue(EditorTouchState.isDistanceWithin(0, 0, 0, 0, 8));
+        assertTrue(EditorTouchState.isDistanceWithin(3, 9, 5, 11, 8));
+        assertTrue(EditorTouchState.isDistanceWithin(5, 11, 3, 9, 8));
+        assertFalse(EditorTouchState.isDistanceWithin(5, 10, 5, 20, 8));
     }
 
     private static MotionEvent downEvent(long downTime, long eventTime, float x, float y) {
@@ -201,8 +241,12 @@
         return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
     }
 
+    private static MotionEvent moveEvent(long downTime, long eventTime, float x, float y) {
+        return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
+    }
+
     private static void assertSingleTap(EditorTouchState touchState, float lastDownX,
-            float lastDownY, float lastUpX, float lastUpY) {
+            float lastDownY, float lastUpX, float lastUpY, boolean isMovedEnoughForDrag) {
         assertThat(touchState.getLastDownX(), is(lastDownX));
         assertThat(touchState.getLastDownY(), is(lastDownY));
         assertThat(touchState.getLastUpX(), is(lastUpX));
@@ -211,9 +255,10 @@
         assertThat(touchState.isTripleClick(), is(false));
         assertThat(touchState.isMultiTap(), is(false));
         assertThat(touchState.isMultiTapInSameArea(), is(false));
+        assertThat(touchState.isMovedEnoughForDrag(), is(isMovedEnoughForDrag));
     }
 
-    private static void assertTap(EditorTouchState touchState,
+    private static void assertMultiTap(EditorTouchState touchState,
             float lastDownX, float lastDownY, float lastUpX, float lastUpY,
             @MultiTapStatus int multiTapStatus, boolean isMultiTapInSameArea) {
         assertThat(touchState.getLastDownX(), is(lastDownX));
@@ -225,5 +270,6 @@
         assertThat(touchState.isMultiTap(), is(multiTapStatus == MultiTapStatus.DOUBLE_TAP
                 || multiTapStatus == MultiTapStatus.TRIPLE_CLICK));
         assertThat(touchState.isMultiTapInSameArea(), is(isMultiTapInSameArea));
+        assertThat(touchState.isMovedEnoughForDrag(), is(false));
     }
 }
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 83ce67b..4808a0b 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -358,6 +358,27 @@
     }
 
     /**
+     * Returns an action that drags on text from startIndex to endIndex on the TextView.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a TextView displayed on screen
+     * <ul>
+     *
+     * @param startIndex The index of the TextView's text to start a drag from
+     * @param endIndex The index of the TextView's text to end the drag at
+     */
+    public static ViewAction dragOnText(int startIndex, int endIndex) {
+        return actionWithAssertions(
+                new DragAction(
+                        DragAction.Drag.TAP,
+                        new TextCoordinates(startIndex),
+                        new TextCoordinates(endIndex),
+                        Press.FINGER,
+                        TextView.class));
+    }
+
+    /**
      * A provider of the x, y coordinates of the handle dragging point.
      */
     private static final class CurrentHandleCoordinates implements CoordinatesProvider {
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..f1941fc 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"/>
@@ -266,6 +266,8 @@
     </privapp-permissions>
 
     <privapp-permissions package="com.android.shell">
+        <!-- Needed for test only -->
+        <permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
         <permission name="android.permission.ACCESS_LOWPAN_STATE"/>
         <permission name="android.permission.BACKUP"/>
         <permission name="android.permission.BATTERY_STATS"/>
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/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/libs/androidfw/OWNERS b/libs/androidfw/OWNERS
index 87b1467..8cffd6a 100644
--- a/libs/androidfw/OWNERS
+++ b/libs/androidfw/OWNERS
@@ -3,3 +3,4 @@
 rtmitchell@google.com
 
 per-file CursorWindow.cpp=omakoto@google.com
+per-file LocaleDataTables.cpp=vichang@google.com,tobiast@google.com,nikitai@google.com
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/LocationListener.java b/location/java/android/location/LocationListener.java
index aa9dddc..8df0834 100644
--- a/location/java/android/location/LocationListener.java
+++ b/location/java/android/location/LocationListener.java
@@ -16,6 +16,7 @@
 
 package android.location;
 
+import android.annotation.NonNull;
 import android.os.Bundle;
 
 /**
@@ -37,36 +38,32 @@
     /**
      * Called when the location has changed.
      *
-     * <p> There are no restrictions on the use of the supplied Location object.
-     *
-     * @param location The new location, as a Location object.
+     * @param location the updated location
      */
-    void onLocationChanged(Location location);
+    void onLocationChanged(@NonNull Location location);
 
     /**
-     * This callback will never be invoked and providers can be considers as always in the
-     * {@link LocationProvider#AVAILABLE} state.
+     * This callback will never be invoked on Android Q and above, and providers can be considered
+     * as always in the {@link LocationProvider#AVAILABLE} state.
      *
-     * @deprecated This callback will never be invoked.
+     * @deprecated This callback will never be invoked on Android Q and above.
      */
     @Deprecated
-    void onStatusChanged(String provider, int status, Bundle extras);
+    default void onStatusChanged(String provider, int status, Bundle extras) {}
 
     /**
      * Called when the provider is enabled by the user.
      *
-     * @param provider the name of the location provider associated with this
-     * update.
+     * @param provider the name of the location provider that has become enabled
      */
-    void onProviderEnabled(String provider);
+    default void onProviderEnabled(@NonNull String provider) {}
 
     /**
      * Called when the provider is disabled by the user. If requestLocationUpdates
      * is called on an already disabled provider, this method is called
      * immediately.
      *
-     * @param provider the name of the location provider associated with this
-     * update.
+     * @param provider the name of the location provider that has become disabled
      */
-    void onProviderDisabled(String provider);
+    default void onProviderDisabled(@NonNull String provider) {}
 }
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..34ed5b3 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;
@@ -374,6 +374,10 @@
     public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
     /** Used to identify the volume of audio streams for accessibility prompts */
     public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY;
+    /** @hide Used to identify the volume of audio streams for virtual assistant */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT;
 
     /** Number of audio streams */
     /**
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..e584add 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;
@@ -80,6 +80,8 @@
     public static final int STREAM_TTS = 9;
     /** Used to identify the volume of audio streams for accessibility prompts */
     public static final int STREAM_ACCESSIBILITY = 10;
+    /** Used to identify the volume of audio streams for virtual assistant */
+    public static final int STREAM_ASSISTANT = 11;
     /**
      * @deprecated Use {@link #numStreamTypes() instead}
      */
@@ -92,7 +94,7 @@
     private static native int native_get_FCC_8();
 
     // Expose only the getter method publicly so we can change it in the future
-    private static final int NUM_STREAM_TYPES = 11;
+    private static final int NUM_STREAM_TYPES = 12;
     @UnsupportedAppUsage
     public static final int getNumStreamTypes() { return NUM_STREAM_TYPES; }
 
@@ -107,7 +109,8 @@
         "STREAM_SYSTEM_ENFORCED",
         "STREAM_DTMF",
         "STREAM_TTS",
-        "STREAM_ACCESSIBILITY"
+        "STREAM_ACCESSIBILITY",
+        "STREAM_ASSISTANT"
     };
 
     /*
@@ -1277,6 +1280,7 @@
         5, // STREAM_DTMF
         5, // STREAM_TTS
         5, // STREAM_ACCESSIBILITY
+        5, // STREAM_ASSISTANT
     };
 
     public static String streamToString(int stream) {
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/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/media/java/android/media/RouteSessionInfo.aidl b/media/java/android/media/RouteSessionInfo.aidl
new file mode 100644
index 0000000..fb5d836
--- /dev/null
+++ b/media/java/android/media/RouteSessionInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+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/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
index 77596a5..56e5566 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
@@ -22,7 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
 import android.hardware.soundtrigger.SoundTrigger;
 import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index 1c38301..61b3e76 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -23,7 +23,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.hardware.soundtrigger.ModelParams;
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 377b2bc..1b9cac0 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -20,7 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.StringRes;
 import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 7fbb337..5c11ed9b 100755
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -22,9 +22,9 @@
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
+import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.Service;
-import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.PixelFormat;
diff --git a/media/java/android/media/tv/tuner/FrontendSettings.java b/media/java/android/media/tv/tuner/FrontendSettings.java
index 3782cc6..531e210 100644
--- a/media/java/android/media/tv/tuner/FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/FrontendSettings.java
@@ -16,15 +16,22 @@
 
 package android.media.tv.tuner;
 
+import android.annotation.SystemApi;
 import android.media.tv.tuner.TunerConstants.FrontendSettingsType;
 
 import java.util.List;
 
 /**
+ * Frontend settings for tune and scan operations.
  * @hide
  */
+@SystemApi
 public abstract class FrontendSettings {
-    protected int mFrequency;
+    private final int mFrequency;
+
+    FrontendSettings(int frequency) {
+        mFrequency = frequency;
+    }
 
     /**
      * Returns the frontend type.
@@ -32,7 +39,12 @@
     @FrontendSettingsType
     public abstract int getType();
 
-    public int getFrequency() {
+    /**
+     * Gets the frequency setting.
+     *
+     * @return the frequency in Hz.
+     */
+    public final int getFrequency() {
         return mFrequency;
     }
 
@@ -42,6 +54,7 @@
 
     /**
      * Frontend settings for analog.
+     * @hide
      */
     public static class FrontendAnalogSettings extends FrontendSettings {
         private int mAnalogType;
@@ -68,7 +81,7 @@
         }
 
         private FrontendAnalogSettings(int frequency, int analogType, int sifStandard) {
-            mFrequency = frequency;
+            super(frequency);
             mAnalogType = analogType;
             mSifStandard = sifStandard;
         }
@@ -118,10 +131,15 @@
 
     /**
      * Frontend settings for ATSC.
+     * @hide
      */
     public static class FrontendAtscSettings extends FrontendSettings {
         public int modulation;
 
+        FrontendAtscSettings(int frequency) {
+            super(frequency);
+        }
+
         @Override
         public int getType() {
             return TunerConstants.FRONTEND_TYPE_ATSC;
@@ -130,12 +148,17 @@
 
     /**
      * Frontend settings for ATSC-3.
+     * @hide
      */
     public static class FrontendAtsc3Settings extends FrontendSettings {
         public int bandwidth;
         public byte demodOutputFormat;
         public List<FrontendAtsc3PlpSettings> plpSettings;
 
+        FrontendAtsc3Settings(int frequency) {
+            super(frequency);
+        }
+
         @Override
         public int getType() {
             return TunerConstants.FRONTEND_TYPE_ATSC3;
@@ -144,6 +167,7 @@
 
     /**
      * Frontend settings for DVBS.
+     * @hide
      */
     public static class FrontendDvbsSettings extends FrontendSettings {
         public int modulation;
@@ -154,6 +178,10 @@
         public int inputStreamId;
         public byte standard;
 
+        FrontendDvbsSettings(int frequency) {
+            super(frequency);
+        }
+
         @Override
         public int getType() {
             return TunerConstants.FRONTEND_TYPE_DVBS;
@@ -162,6 +190,7 @@
 
     /**
      * Frontend settings for DVBC.
+     * @hide
      */
     public static class FrontendDvbcSettings extends FrontendSettings {
         public int modulation;
@@ -171,6 +200,10 @@
         public byte annex;
         public int spectralInversion;
 
+        FrontendDvbcSettings(int frequency) {
+            super(frequency);
+        }
+
         @Override
         public int getType() {
             return TunerConstants.FRONTEND_TYPE_DVBC;
@@ -179,6 +212,7 @@
 
     /**
      * Frontend settings for DVBT.
+     * @hide
      */
     public static class FrontendDvbtSettings extends FrontendSettings {
         public int transmissionMode;
@@ -195,6 +229,10 @@
         public byte plpId;
         public byte plpGroupId;
 
+        FrontendDvbtSettings(int frequency) {
+            super(frequency);
+        }
+
         @Override
         public int getType() {
             return TunerConstants.FRONTEND_TYPE_DVBT;
@@ -203,6 +241,7 @@
 
     /**
      * Frontend settings for ISDBS.
+     * @hide
      */
     public static class FrontendIsdbsSettings extends FrontendSettings {
         public int streamId;
@@ -212,6 +251,10 @@
         public int symbolRate;
         public int rolloff;
 
+        FrontendIsdbsSettings(int frequency) {
+            super(frequency);
+        }
+
         @Override
         public int getType() {
             return TunerConstants.FRONTEND_TYPE_ISDBS;
@@ -220,6 +263,7 @@
 
     /**
      * Frontend settings for ISDBS-3.
+     * @hide
      */
     public static class FrontendIsdbs3Settings extends FrontendSettings {
         public int streamId;
@@ -229,6 +273,10 @@
         public int symbolRate;
         public int rolloff;
 
+        FrontendIsdbs3Settings(int frequency) {
+            super(frequency);
+        }
+
         @Override
         public int getType() {
             return TunerConstants.FRONTEND_TYPE_ISDBS3;
@@ -237,6 +285,7 @@
 
     /**
      * Frontend settings for ISDBT.
+     * @hide
      */
     public static class FrontendIsdbtSettings extends FrontendSettings {
         public int modulation;
@@ -245,6 +294,10 @@
         public int guardInterval;
         public int serviceAreaId;
 
+        FrontendIsdbtSettings(int frequency) {
+            super(frequency);
+        }
+
         @Override
         public int getType() {
             return TunerConstants.FRONTEND_TYPE_ISDBT;
@@ -253,6 +306,7 @@
 
     /**
      * PLP settings for ATSC-3.
+     * @hide
      */
     public static class FrontendAtsc3PlpSettings {
         public byte plpId;
@@ -264,6 +318,7 @@
 
     /**
      * Code rate for DVBS.
+     * @hide
      */
     public static class FrontendDvbsCodeRate {
         public long fec;
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 4c93101..a4197441 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -18,6 +18,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.media.tv.tuner.TunerConstants.DemuxPidType;
 import android.os.Handler;
 import android.os.Looper;
@@ -26,14 +30,20 @@
 import java.util.List;
 
 /**
- * Tuner is used to interact with tuner devices.
+ * This class is used to interact with hardware tuners devices.
+ *
+ * <p> Each TvInputService Session should create one instance of this class.
+ *
+ * <p> This class controls the TIS interaction with Tuner HAL.
  *
  * @hide
  */
+@SystemApi
 public final class Tuner implements AutoCloseable  {
     private static final String TAG = "MediaTvTuner";
     private static final boolean DEBUG = false;
 
+    private static final String PERMISSION = android.Manifest.permission.ACCESS_TV_TUNER;
     private static final int MSG_ON_FRONTEND_EVENT = 1;
     private static final int MSG_ON_FILTER_EVENT = 2;
     private static final int MSG_ON_FILTER_STATUS = 3;
@@ -44,6 +54,8 @@
         nativeInit();
     }
 
+    private final Context mContext;
+
     private List<Integer> mFrontendIds;
     private Frontend mFrontend;
     private EventHandler mHandler;
@@ -51,12 +63,26 @@
     private List<Integer> mLnbIds;
     private Lnb mLnb;
 
-    public Tuner() {
+    /**
+     * Constructs a Tuner instance.
+     *
+     * @param context context of the caller.
+     */
+    public Tuner(@NonNull Context context) {
+        mContext = context;
         nativeSetup();
     }
 
+    private void checkPermission() {
+        if (mContext.checkCallingOrSelfPermission(PERMISSION)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Caller must have " + PERMISSION + " permission.");
+        }
+    }
+
     private long mNativeContext; // used by native jMediaTuner
 
+    /** @hide */
     @Override
     public void close() {}
 
@@ -92,6 +118,8 @@
 
     /**
      * Frontend Callback.
+     *
+     * @hide
      */
     public interface FrontendCallback {
 
@@ -103,6 +131,8 @@
 
     /**
      * LNB Callback.
+     *
+     * @hide
      */
     public interface LnbCallback {
         /**
@@ -113,6 +143,8 @@
 
     /**
      * Frontend Callback.
+     *
+     * @hide
      */
     public interface FilterCallback {
         /**
@@ -123,6 +155,8 @@
 
     /**
      * DVR Callback.
+     *
+     * @hide
      */
     public interface DvrCallback {
         /**
@@ -177,7 +211,7 @@
         }
     }
 
-    protected class Frontend {
+    private class Frontend {
         private int mId;
         private FrontendCallback mCallback;
 
@@ -210,9 +244,15 @@
     }
 
     /**
-     * Tunes the frontend to using the settings given.
+     * Tunes the frontend to the settings given.
+     *
+     * @return result status of tune operation.
+     * @throws SecurityException if the caller does not have appropriate permissions.
+     * TODO: add result constants or throw exceptions.
      */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     public int tune(@NonNull FrontendSettings settings) {
+        checkPermission();
         return nativeTune(settings.getType(), settings);
     }
 
@@ -238,7 +278,8 @@
         }
     }
 
-    protected class Filter {
+    /** @hide */
+    public class Filter {
         private long mNativeContext;
         private FilterCallback mCallback;
         int mId;
@@ -297,7 +338,8 @@
         return filter;
     }
 
-    protected class Lnb {
+    /** @hide */
+    public class Lnb {
         private int mId;
         private LnbCallback mCallback;
 
@@ -338,7 +380,8 @@
         }
     }
 
-    protected class Descrambler {
+    /** @hide */
+    public class Descrambler {
         private long mNativeContext;
 
         private native boolean nativeAddPid(int pidType, int pid, Filter filter);
@@ -362,7 +405,8 @@
     }
 
     // TODO: consider splitting Dvr to Playback and Recording
-    protected class Dvr {
+    /** @hide */
+    public class Dvr {
         private long mNativeContext;
         private DvrCallback mCallback;
 
diff --git a/media/java/android/mtp/MtpPropertyList.java b/media/java/android/mtp/MtpPropertyList.java
index 53d838d..557f099 100644
--- a/media/java/android/mtp/MtpPropertyList.java
+++ b/media/java/android/mtp/MtpPropertyList.java
@@ -16,8 +16,7 @@
 
 package android.mtp;
 
-import android.compat.annotation.UnsupportedAppUsage;
-
+import android.annotation.UnsupportedAppUsage;
 import java.util.ArrayList;
 import java.util.List;
 
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index 9fd0a28..c7dbca6 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -16,7 +16,7 @@
 
 package android.mtp;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.os.storage.StorageVolume;
 import android.provider.MediaStore;
 
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 06adf30..86a1076 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -21,8 +21,8 @@
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.UnsupportedAppUsage;
 import android.app.Service;
-import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index baa779c..f5ba92e 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -19,7 +19,7 @@
 
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AudioPresentationInfo.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
 #include <media/DataSource.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
diff --git a/media/mca/effect/java/android/media/effect/SingleFilterEffect.java b/media/mca/effect/java/android/media/effect/SingleFilterEffect.java
index 121443f..dfbf5d2 100644
--- a/media/mca/effect/java/android/media/effect/SingleFilterEffect.java
+++ b/media/mca/effect/java/android/media/effect/SingleFilterEffect.java
@@ -17,11 +17,12 @@
 
 package android.media.effect;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.filterfw.core.Filter;
 import android.filterfw.core.FilterFactory;
 import android.filterfw.core.FilterFunction;
 import android.filterfw.core.Frame;
+import android.media.effect.EffectContext;
 
 /**
  * Effect subclass for effects based on a single Filter. Subclasses need only invoke the
diff --git a/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java b/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java
index 3a7f1ed..52615bf 100644
--- a/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java
+++ b/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java
@@ -17,11 +17,11 @@
 
 package android.filterfw;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.filterfw.core.AsyncRunner;
-import android.filterfw.core.FilterContext;
 import android.filterfw.core.FilterGraph;
+import android.filterfw.core.FilterContext;
 import android.filterfw.core.FrameManager;
 import android.filterfw.core.GraphRunner;
 import android.filterfw.core.RoundRobinScheduler;
diff --git a/media/mca/filterfw/java/android/filterfw/core/Filter.java b/media/mca/filterfw/java/android/filterfw/core/Filter.java
index a608ef5..4f56b92 100644
--- a/media/mca/filterfw/java/android/filterfw/core/Filter.java
+++ b/media/mca/filterfw/java/android/filterfw/core/Filter.java
@@ -17,15 +17,19 @@
 
 package android.filterfw.core;
 
-import android.compat.annotation.UnsupportedAppUsage;
-import android.filterfw.format.ObjectFormat;
-import android.filterfw.io.GraphIOException;
+import android.annotation.UnsupportedAppUsage;
+import android.filterfw.core.FilterContext;
+import android.filterfw.core.FilterPort;
+import android.filterfw.core.KeyValueMap;
 import android.filterfw.io.TextGraphReader;
+import android.filterfw.io.GraphIOException;
+import android.filterfw.format.ObjectFormat;
 import android.util.Log;
 
 import java.io.Serializable;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
+import java.lang.Thread;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterContext.java b/media/mca/filterfw/java/android/filterfw/core/FilterContext.java
index 6b0a219..a19220e 100644
--- a/media/mca/filterfw/java/android/filterfw/core/FilterContext.java
+++ b/media/mca/filterfw/java/android/filterfw/core/FilterContext.java
@@ -17,7 +17,11 @@
 
 package android.filterfw.core;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
+import android.filterfw.core.Filter;
+import android.filterfw.core.Frame;
+import android.filterfw.core.FrameManager;
+import android.filterfw.core.GLEnvironment;
 
 import java.util.HashMap;
 import java.util.HashSet;
diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java b/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java
index 35a298f..e6ca11f 100644
--- a/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java
+++ b/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java
@@ -17,11 +17,6 @@
 
 package android.filterfw.core;
 
-import android.compat.annotation.UnsupportedAppUsage;
-import android.filterpacks.base.FrameBranch;
-import android.filterpacks.base.NullFilter;
-import android.util.Log;
-
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -30,6 +25,14 @@
 import java.util.Set;
 import java.util.Stack;
 
+import android.filterfw.core.FilterContext;
+import android.filterfw.core.KeyValueMap;
+import android.filterpacks.base.FrameBranch;
+import android.filterpacks.base.NullFilter;
+
+import android.annotation.UnsupportedAppUsage;
+import android.util.Log;
+
 /**
  * @hide
  */
diff --git a/media/mca/filterfw/java/android/filterfw/core/Frame.java b/media/mca/filterfw/java/android/filterfw/core/Frame.java
index c4d935a..e880783 100644
--- a/media/mca/filterfw/java/android/filterfw/core/Frame.java
+++ b/media/mca/filterfw/java/android/filterfw/core/Frame.java
@@ -17,7 +17,9 @@
 
 package android.filterfw.core;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
+import android.filterfw.core.FrameFormat;
+import android.filterfw.core.FrameManager;
 import android.graphics.Bitmap;
 
 import java.nio.ByteBuffer;
diff --git a/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java b/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java
index a87e9b9..eb0ff0a 100644
--- a/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java
+++ b/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java
@@ -17,7 +17,9 @@
 
 package android.filterfw.core;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
+import android.filterfw.core.KeyValueMap;
+import android.filterfw.core.MutableFrameFormat;
 
 import java.util.Arrays;
 import java.util.Map.Entry;
diff --git a/media/mca/filterfw/java/android/filterfw/core/FrameManager.java b/media/mca/filterfw/java/android/filterfw/core/FrameManager.java
index e49aaf1..85c8fcd 100644
--- a/media/mca/filterfw/java/android/filterfw/core/FrameManager.java
+++ b/media/mca/filterfw/java/android/filterfw/core/FrameManager.java
@@ -17,7 +17,10 @@
 
 package android.filterfw.core;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
+import android.filterfw.core.Frame;
+import android.filterfw.core.FrameFormat;
+import android.filterfw.core.MutableFrameFormat;
 
 /**
  * @hide
diff --git a/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java b/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java
index 7e4e8a6..e25d6a7 100644
--- a/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java
+++ b/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java
@@ -17,12 +17,13 @@
 
 package android.filterfw.core;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
+import android.filterfw.core.NativeAllocatorTag;
 import android.graphics.SurfaceTexture;
-import android.media.MediaRecorder;
 import android.os.Looper;
 import android.util.Log;
 import android.view.Surface;
+import android.media.MediaRecorder;
 
 /**
  * @hide
diff --git a/media/mca/filterfw/java/android/filterfw/core/GLFrame.java b/media/mca/filterfw/java/android/filterfw/core/GLFrame.java
index 1ccd7fe..9e3025f 100644
--- a/media/mca/filterfw/java/android/filterfw/core/GLFrame.java
+++ b/media/mca/filterfw/java/android/filterfw/core/GLFrame.java
@@ -17,10 +17,15 @@
 
 package android.filterfw.core;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
+import android.filterfw.core.Frame;
+import android.filterfw.core.FrameFormat;
+import android.filterfw.core.FrameManager;
+import android.filterfw.core.NativeFrame;
+import android.filterfw.core.StopWatchMap;
 import android.graphics.Bitmap;
-import android.graphics.Rect;
 import android.opengl.GLES20;
+import android.graphics.Rect;
 
 import java.nio.ByteBuffer;
 
diff --git a/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java b/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java
index b57e8bb..250cfaa 100644
--- a/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java
+++ b/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java
@@ -17,7 +17,7 @@
 
 package android.filterfw.core;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 
 /**
  * @hide
diff --git a/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java b/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java
index da00b1f..ae2ad99 100644
--- a/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java
+++ b/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java
@@ -17,7 +17,9 @@
 
 package android.filterfw.core;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
+import android.filterfw.core.FrameFormat;
+import android.filterfw.core.KeyValueMap;
 
 import java.util.Arrays;
 
diff --git a/media/mca/filterfw/java/android/filterfw/core/Program.java b/media/mca/filterfw/java/android/filterfw/core/Program.java
index 145388e..376c085 100644
--- a/media/mca/filterfw/java/android/filterfw/core/Program.java
+++ b/media/mca/filterfw/java/android/filterfw/core/Program.java
@@ -17,7 +17,8 @@
 
 package android.filterfw.core;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
+import android.filterfw.core.Frame;
 
 /**
  * @hide
diff --git a/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java b/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java
index e043be0..f41636e 100644
--- a/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java
+++ b/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java
@@ -17,7 +17,12 @@
 
 package android.filterfw.core;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
+import android.filterfw.core.Frame;
+import android.filterfw.core.NativeAllocatorTag;
+import android.filterfw.core.Program;
+import android.filterfw.core.StopWatchMap;
+import android.filterfw.core.VertexFrame;
 import android.filterfw.geometry.Quad;
 import android.opengl.GLES20;
 
diff --git a/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java b/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java
index 0e05092..ac08730 100644
--- a/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java
+++ b/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java
@@ -17,7 +17,7 @@
 
 package android.filterfw.format;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.filterfw.core.FrameFormat;
 import android.filterfw.core.MutableFrameFormat;
 import android.graphics.Bitmap;
diff --git a/media/mca/filterfw/java/android/filterfw/geometry/Point.java b/media/mca/filterfw/java/android/filterfw/geometry/Point.java
index 96d2d7b..d7acf12 100644
--- a/media/mca/filterfw/java/android/filterfw/geometry/Point.java
+++ b/media/mca/filterfw/java/android/filterfw/geometry/Point.java
@@ -17,7 +17,8 @@
 
 package android.filterfw.geometry;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
+import java.lang.Math;
 
 /**
  * @hide
diff --git a/media/mca/filterfw/java/android/filterfw/geometry/Quad.java b/media/mca/filterfw/java/android/filterfw/geometry/Quad.java
index 2b308a9..610e5b8 100644
--- a/media/mca/filterfw/java/android/filterfw/geometry/Quad.java
+++ b/media/mca/filterfw/java/android/filterfw/geometry/Quad.java
@@ -17,8 +17,10 @@
 
 package android.filterfw.geometry;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
+import android.filterfw.geometry.Point;
 
+import java.lang.Float;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
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/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 177f2b8..203adfc 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -40,6 +40,7 @@
     AConfiguration_getOrientation;
     AConfiguration_getScreenHeightDp; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
     AConfiguration_getScreenLong;
+    AConfiguration_getScreenRound; # introduced=30
     AConfiguration_getScreenSize;
     AConfiguration_getScreenWidthDp; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
     AConfiguration_getSdkVersion;
diff --git a/opengl/java/android/opengl/EGL14.java b/opengl/java/android/opengl/EGL14.java
index 90b46fd..728e6e1 100644
--- a/opengl/java/android/opengl/EGL14.java
+++ b/opengl/java/android/opengl/EGL14.java
@@ -18,11 +18,11 @@
 
 package android.opengl;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.graphics.SurfaceTexture;
 import android.view.Surface;
-import android.view.SurfaceHolder;
 import android.view.SurfaceView;
+import android.view.SurfaceHolder;
 
 /**
  * EGL 1.4
diff --git a/opengl/java/android/opengl/GLES20.java b/opengl/java/android/opengl/GLES20.java
index e853e44..d66e7ac 100644
--- a/opengl/java/android/opengl/GLES20.java
+++ b/opengl/java/android/opengl/GLES20.java
@@ -19,7 +19,7 @@
 
 package android.opengl;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 
 /** OpenGL ES 2.0
  */
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 75131b0..8a3e6a0 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -16,7 +16,7 @@
 
 package android.opengl;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Trace;
 import android.util.AttributeSet;
diff --git a/opengl/java/com/google/android/gles_jni/EGLImpl.java b/opengl/java/com/google/android/gles_jni/EGLImpl.java
index b4ea0a6..f94f69f 100644
--- a/opengl/java/com/google/android/gles_jni/EGLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLImpl.java
@@ -16,12 +16,13 @@
 
 package com.google.android.gles_jni;
 
-import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.SurfaceTexture;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import javax.microedition.khronos.egl.EGL10;
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.egl.EGLContext;
diff --git a/opengl/java/com/google/android/gles_jni/GLImpl.java b/opengl/java/com/google/android/gles_jni/GLImpl.java
index 3c808a6..2a8d07f 100644
--- a/opengl/java/com/google/android/gles_jni/GLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/GLImpl.java
@@ -20,13 +20,14 @@
 package com.google.android.gles_jni;
 
 import android.app.AppGlobals;
-import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.os.Build;
 import android.os.UserHandle;
 import android.util.Log;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import java.nio.Buffer;
 
 import javax.microedition.khronos.opengles.GL10;
diff --git a/opengl/java/javax/microedition/khronos/egl/EGL10.java b/opengl/java/javax/microedition/khronos/egl/EGL10.java
index ea571c7..8a25170 100644
--- a/opengl/java/javax/microedition/khronos/egl/EGL10.java
+++ b/opengl/java/javax/microedition/khronos/egl/EGL10.java
@@ -16,7 +16,8 @@
 
 package javax.microedition.khronos.egl;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
+import java.lang.String;
 
 public interface EGL10 extends EGL {
     int EGL_SUCCESS                     = 0x3000;
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 96bcda31..2a8a39a 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -137,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/CompanionDeviceManager/Android.bp b/packages/CompanionDeviceManager/Android.bp
index a379bfc..1453ec3 100644
--- a/packages/CompanionDeviceManager/Android.bp
+++ b/packages/CompanionDeviceManager/Android.bp
@@ -15,5 +15,6 @@
 android_app {
     name: "CompanionDeviceManager",
     srcs: ["src/**/*.java"],
+
     platform_apis: true,
 }
diff --git a/packages/CompanionDeviceManager/AndroidManifest.xml b/packages/CompanionDeviceManager/AndroidManifest.xml
index 42885e8..a9c6685 100644
--- a/packages/CompanionDeviceManager/AndroidManifest.xml
+++ b/packages/CompanionDeviceManager/AndroidManifest.xml
@@ -29,6 +29,7 @@
     <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
+    <uses-permission android:name="android.permission.RADIO_SCAN_WITHOUT_LOCATION"/>
 
     <application
         android:allowClearUserData="true"
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 7b2922ba..1e19786 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -102,6 +102,9 @@
             DocumentsContract.EXTERNAL_STORAGE_PRIMARY_EMULATED_ROOT_ID;
     private static final String ROOT_ID_HOME = "home";
 
+    private static final String GET_DOCUMENT_URI_CALL = "get_document_uri";
+    private static final String GET_MEDIA_URI_CALL = "get_media_uri";
+
     private StorageManager mStorageManager;
     private UserManager mUserManager;
 
@@ -665,7 +668,7 @@
                     }
                     break;
                 }
-                case MediaStore.GET_DOCUMENT_URI_CALL: {
+                case GET_DOCUMENT_URI_CALL: {
                     // All callers must go through MediaProvider
                     getContext().enforceCallingPermission(
                             android.Manifest.permission.WRITE_MEDIA_STORAGE, TAG);
@@ -684,7 +687,7 @@
                         throw new IllegalStateException("File in " + path + " is not found.", e);
                     }
                 }
-                case MediaStore.GET_MEDIA_URI_CALL: {
+                case GET_MEDIA_URI_CALL: {
                     // All callers must go through MediaProvider
                     getContext().enforceCallingPermission(
                             android.Manifest.permission.WRITE_MEDIA_STORAGE, TAG);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
index e936c35..68a3729 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
@@ -17,8 +17,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.util.LongSparseLongArray;
-import android.util.Pair;
+import android.util.LongSparseArray;
 
 import org.junit.Before;
 import org.junit.Ignore;
@@ -159,14 +158,11 @@
 
     private OpEntry createOpEntryWithTime(int op, long time) {
         // Slot for background access timestamp.
-        final LongSparseLongArray accessTimes = new LongSparseLongArray();
-        accessTimes.put(AppOpsManager.makeKey(AppOpsManager.UID_STATE_BACKGROUND,
-            AppOpsManager.OP_FLAG_SELF), time);
+        final LongSparseArray<AppOpsManager.NoteOpEvent> accessEvents = new LongSparseArray<>();
+        accessEvents.put(AppOpsManager.makeKey(AppOpsManager.UID_STATE_BACKGROUND,
+            AppOpsManager.OP_FLAG_SELF), new AppOpsManager.NoteOpEvent(time, -1, null));
 
-        OpFeatureEntry.Builder featureEntry = new OpFeatureEntry.Builder(false, accessTimes,
-                null /*rejectTimes*/, null /*durations*/, null /* proxyUids */,
-                null /* proxyPackages */, null /* proxyFeatureIds */);
-        return new OpEntry(op, AppOpsManager.MODE_ALLOWED,
-                new Pair[]{new Pair(null, featureEntry)});
+        return new OpEntry(op, AppOpsManager.MODE_ALLOWED, Collections.singletonMap(null,
+                new OpFeatureEntry(op, false, accessEvents, null)));
     }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
index 3fde48b..3f8d758 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
@@ -17,6 +17,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.LongSparseArray;
 import android.util.LongSparseLongArray;
 import android.util.Pair;
 
@@ -158,17 +159,11 @@
     }
 
     private OpEntry createOpEntryWithTime(int op, long time, int duration) {
-        final LongSparseLongArray accessTimes = new LongSparseLongArray();
-        accessTimes.put(AppOpsManager.makeKey(AppOpsManager.UID_STATE_TOP,
-                AppOpsManager.OP_FLAG_SELF), time);
-        final LongSparseLongArray durations = new LongSparseLongArray();
-        durations.put(AppOpsManager.makeKey(AppOpsManager.UID_STATE_TOP,
-                AppOpsManager.OP_FLAG_SELF), duration);
+        final LongSparseArray<AppOpsManager.NoteOpEvent> accessEvents = new LongSparseArray<>();
+        accessEvents.put(AppOpsManager.makeKey(AppOpsManager.UID_STATE_TOP,
+                AppOpsManager.OP_FLAG_SELF), new AppOpsManager.NoteOpEvent(time, duration, null));
 
-        OpFeatureEntry.Builder featureEntry = new OpFeatureEntry.Builder(false, accessTimes,
-                null /*rejectTimes*/, durations, null /* proxyUids */,
-                null /* proxyPackages */, null /* proxyFeatureIds */);
-        return new OpEntry(op, AppOpsManager.MODE_ALLOWED,
-                new Pair[]{new Pair(null, featureEntry)});
+        return new OpEntry(op, AppOpsManager.MODE_ALLOWED, Collections.singletonMap(null,
+                new OpFeatureEntry(op, false, accessEvents, null)));
     }
 }
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 19ff244..443811f 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -87,6 +87,7 @@
                     Settings.System.VOLUME_ACCESSIBILITY, // used internally, changing value will
                                                           // not change volume
                     Settings.System.VOLUME_ALARM, // deprecated since API 2?
+                    Settings.System.VOLUME_ASSISTANT, // candidate for backup?
                     Settings.System.VOLUME_BLUETOOTH_SCO, // deprecated since API 2?
                     Settings.System.VOLUME_MASTER, // candidate for backup?
                     Settings.System.VOLUME_MUSIC, // deprecated since API 2?
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 0d5ede4..4fb3be2 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -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/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/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index e3694ac..bfac4fc 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.accessibility;
 
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
@@ -196,6 +198,7 @@
         params.token = mOverlayView.getWindowToken();
         params.x = mMagnificationFrame.left;
         params.y = mMagnificationFrame.top;
+        params.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
         params.setTitle(mContext.getString(R.string.magnification_window_title));
 
         mMirrorView = LayoutInflater.from(mContext).inflate(R.layout.window_magnifier_view, null);
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/BasePipManager.java b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
index 75e260e..d1d9b3d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
@@ -20,11 +20,13 @@
 import android.content.res.Configuration;
 
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.wm.DisplayWindowController;
 
 import java.io.PrintWriter;
 
 public interface BasePipManager {
-    void initialize(Context context, BroadcastDispatcher broadcastDispatcher);
+    void initialize(Context context, BroadcastDispatcher broadcastDispatcher,
+            DisplayWindowController displayWindowController);
     void showPictureInPictureMenu();
     default void expandPip() {}
     default void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index f10274a..8e34a90 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -16,8 +16,14 @@
 
 package com.android.systemui.pip;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.util.TypedValue.COMPLEX_UNIT_DIP;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
 
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
@@ -32,10 +38,9 @@
 import android.view.Gravity;
 import android.view.IPinnedStackController;
 import android.view.IWindowManager;
+import android.view.WindowContainerTransaction;
 import android.view.WindowManagerGlobal;
 
-import com.android.internal.policy.PipSnapAlgorithm;
-
 import java.io.PrintWriter;
 
 /**
@@ -154,6 +159,7 @@
      */
     public void onMinimizedStateChanged(boolean minimized) {
         mIsMinimized = minimized;
+        mSnapAlgorithm.setMinimized(minimized);
     }
 
     /**
@@ -199,6 +205,7 @@
         mReentrySnapFraction = INVALID_SNAP_FRACTION;
         mReentrySize = null;
         mLastPipComponentName = null;
+        mLastDestinationBounds.setEmpty();
     }
 
     public Rect getLastDestinationBounds() {
@@ -235,8 +242,9 @@
      */
     public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) {
         final Rect destinationBounds;
+        final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
         if (bounds == null) {
-            destinationBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
+            destinationBounds = new Rect(defaultBounds);
         } else {
             destinationBounds = new Rect(bounds);
         }
@@ -253,12 +261,85 @@
             mPinnedStackController.startAnimation(destinationBounds, sourceRectHint,
                     -1 /* animationDuration */);
             mLastDestinationBounds.set(destinationBounds);
+            mPinnedStackController.reportBounds(defaultBounds,
+                    getMovementBounds(defaultBounds));
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to start PiP animation from SysUI", e);
         }
     }
 
     /**
+     * Updates the display info, calculating and returning the new stack and movement bounds in the
+     * new orientation of the device if necessary.
+     *
+     * @return {@code true} if internal {@link DisplayInfo} is rotated, {@code false} otherwise.
+     */
+    public boolean onDisplayRotationChanged(Rect outBounds, int displayId, int fromRotation,
+            int toRotation, WindowContainerTransaction t) {
+        // Bail early if the event is not sent to current {@link #mDisplayInfo}
+        if ((displayId != mDisplayInfo.displayId) || (fromRotation == toRotation)) {
+            return false;
+        }
+
+        // Bail early if the pinned stack is staled.
+        final ActivityManager.StackInfo pinnedStackInfo;
+        try {
+            pinnedStackInfo = ActivityTaskManager.getService()
+                    .getStackInfo(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+            if (pinnedStackInfo == null) return false;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get StackInfo for pinned stack", e);
+            return false;
+        }
+
+        // Calculate the snap fraction of the current stack along the old movement bounds
+        final Rect postChangeStackBounds = new Rect(mLastDestinationBounds);
+        final float snapFraction = getSnapFraction(postChangeStackBounds);
+
+        // Populate the new {@link #mDisplayInfo}.
+        // The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
+        // therefore, the width/height may require a swap first.
+        // Moving forward, we should get the new dimensions after rotation from DisplayLayout.
+        mDisplayInfo.rotation = toRotation;
+        updateDisplayInfoIfNeeded();
+
+        // Calculate the stack bounds in the new orientation based on same fraction along the
+        // rotated movement bounds.
+        final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
+                false /* adjustForIme */);
+        mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
+                snapFraction);
+        if (mIsMinimized) {
+            applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds);
+        }
+
+        try {
+            outBounds.set(postChangeStackBounds);
+            mLastDestinationBounds.set(outBounds);
+            mPinnedStackController.resetBoundsAnimation(outBounds);
+            mPinnedStackController.reportBounds(outBounds, getMovementBounds(outBounds));
+            t.setBounds(pinnedStackInfo.stackToken, outBounds);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to resize PiP on display rotation", e);
+        }
+        return true;
+    }
+
+    private void updateDisplayInfoIfNeeded() {
+        final boolean updateNeeded;
+        if ((mDisplayInfo.rotation == ROTATION_0) || (mDisplayInfo.rotation == ROTATION_180)) {
+            updateNeeded = (mDisplayInfo.logicalWidth > mDisplayInfo.logicalHeight);
+        } else {
+            updateNeeded = (mDisplayInfo.logicalWidth < mDisplayInfo.logicalHeight);
+        }
+        if (updateNeeded) {
+            final int newLogicalHeight = mDisplayInfo.logicalWidth;
+            mDisplayInfo.logicalWidth = mDisplayInfo.logicalHeight;
+            mDisplayInfo.logicalHeight = newLogicalHeight;
+        }
+    }
+
+    /**
      * @return whether the given {@param aspectRatio} is valid.
      */
     private boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
similarity index 99%
rename from core/java/com/android/internal/policy/PipSnapAlgorithm.java
rename to packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
index e3623c5..f3e707c 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy;
+package com.android.systemui.pip;
 
 import android.content.Context;
 import android.content.res.Configuration;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
index 583ce67..29de90b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
@@ -28,6 +28,7 @@
 import com.android.systemui.SystemUI;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.wm.DisplayWindowController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -44,15 +45,17 @@
     private final CommandQueue mCommandQueue;
     private BasePipManager mPipManager;
     private final BroadcastDispatcher mBroadcastDispatcher;
-
+    private final DisplayWindowController mDisplayWindowController;
     private boolean mSupportsPip;
 
     @Inject
     public PipUI(Context context, CommandQueue commandQueue,
-            BroadcastDispatcher broadcastDispatcher) {
+            BroadcastDispatcher broadcastDispatcher,
+            DisplayWindowController displayWindowController) {
         super(context);
         mBroadcastDispatcher = broadcastDispatcher;
         mCommandQueue = commandQueue;
+        mDisplayWindowController = displayWindowController;
     }
 
     @Override
@@ -72,7 +75,7 @@
         mPipManager = pm.hasSystemFeature(FEATURE_LEANBACK_ONLY)
                 ? com.android.systemui.pip.tv.PipManager.getInstance()
                 : com.android.systemui.pip.phone.PipManager.getInstance();
-        mPipManager.initialize(mContext, mBroadcastDispatcher);
+        mPipManager.initialize(mContext, mBroadcastDispatcher, mDisplayWindowController);
 
         mCommandQueue.addCallback(this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index a4707cf..0a89017 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -34,6 +34,7 @@
 import android.util.Pair;
 import android.view.DisplayInfo;
 import android.view.IPinnedStackController;
+import android.view.WindowContainerTransaction;
 
 import com.android.systemui.Dependency;
 import com.android.systemui.UiOffloadThread;
@@ -45,6 +46,7 @@
 import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.wm.DisplayWindowController;
 
 import java.io.PrintWriter;
 
@@ -75,9 +77,22 @@
     private PipAppOpsListener mAppOpsListener;
 
     /**
+     * Handler for display rotation changes.
+     */
+    private final DisplayWindowController.OnDisplayWindowRotationController mRotationController = (
+            int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
+        final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mTmpNormalBounds,
+                displayId, fromRotation, toRotation, t);
+        if (changed) {
+            updateMovementBounds(mTmpNormalBounds, false /* fromImeAdjustment */,
+                    false /* fromShelfAdjustment */);
+        }
+    };
+
+    /**
      * Handler for system task stack changes.
      */
-    TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
+    private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
         @Override
         public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
             mTouchHandler.onActivityPinned();
@@ -214,7 +229,8 @@
     /**
      * Initializes {@link PipManager}.
      */
-    public void initialize(Context context, BroadcastDispatcher broadcastDispatcher) {
+    public void initialize(Context context, BroadcastDispatcher broadcastDispatcher,
+            DisplayWindowController displayWindowController) {
         mContext = context;
         mActivityManager = ActivityManager.getService();
         mActivityTaskManager = ActivityTaskManager.getService();
@@ -235,6 +251,7 @@
                 mMenuController, mInputConsumerController, mPipBoundsHandler);
         mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
                 mTouchHandler.getMotionHelper());
+        displayWindowController.addRotationController(mRotationController);
 
         // If SystemUI restart, and it already existed a pinned stack,
         // register the pip input consumer to ensure touch can send to it.
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index fa60477..6afa0bf 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -46,7 +46,7 @@
 
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.internal.os.SomeArgs;
-import com.android.internal.policy.PipSnapAlgorithm;
+import com.android.systemui.pip.PipSnapAlgorithm;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
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..95e3444 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -46,9 +46,9 @@
 import android.view.accessibility.AccessibilityWindowInfo;
 
 import com.android.internal.os.logging.MetricsLoggerWrapper;
-import com.android.internal.policy.PipSnapAlgorithm;
 import com.android.systemui.R;
 import com.android.systemui.pip.PipBoundsHandler;
+import com.android.systemui.pip.PipSnapAlgorithm;
 import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
@@ -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/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 195fca8..696db68 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -55,6 +55,7 @@
 import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.wm.DisplayWindowController;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -228,7 +229,8 @@
     /**
      * Initializes {@link PipManager}.
      */
-    public void initialize(Context context, BroadcastDispatcher broadcastDispatcher) {
+    public void initialize(Context context, BroadcastDispatcher broadcastDispatcher,
+            DisplayWindowController displayWindowController) {
         if (mInitialized) {
             return;
         }
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/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/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 4f50f5d..2f39c13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -384,8 +384,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/src/com/android/systemui/util/animation/PhysicsAnimator.kt b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
index 62ae7b9..cca76bd 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
@@ -679,6 +679,7 @@
         internal var instanceConstructor: (Any) -> PhysicsAnimator<*> = ::PhysicsAnimator
 
         @JvmStatic
+        @Suppress("UNCHECKED_CAST")
         fun <T : Any> getInstance(target: T): PhysicsAnimator<T> {
             if (!animators.containsKey(target)) {
                 animators[target] = instanceConstructor(target)
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt
index a1f74eb..e86970c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt
@@ -142,6 +142,7 @@
      */
     @JvmStatic
     @Throws(InterruptedException::class)
+    @Suppress("UNCHECKED_CAST")
     fun <T : Any> blockUntilAnimationsEnd(
         properties: FloatPropertyCompat<in T>
     ) {
@@ -236,6 +237,14 @@
         vararg additionalUpdateMatchers: UpdateMatcher
     ) {
         val updateFrames: UpdateFramesPerProperty<T> = getAnimationUpdateFrames(animator)
+
+        if (!updateFrames.containsKey(property)) {
+            error("No frames for given target object and property.")
+        }
+
+        // Copy the frames to avoid a ConcurrentModificationException if the animation update
+        // listeners attempt to add a new frame while we're verifying these.
+        val framesForProperty = ArrayList(updateFrames[property]!!)
         val matchers = ArrayDeque<UpdateMatcher>(
                 additionalUpdateMatchers.toList())
         val frameTraceMessage = StringBuilder()
@@ -243,8 +252,7 @@
         var curMatcher = firstUpdateMatcher
 
         // Loop through the updates from the testable animator.
-        for (update in updateFrames[property]
-                ?: error("No frames for given target object and property.")) {
+        for (update in framesForProperty) {
 
             // Check whether this frame satisfies the current matcher.
             if (curMatcher(update)) {
@@ -320,6 +328,7 @@
     /**
      * Returns all of the values that have ever been reported to update listeners, per property.
      */
+    @Suppress("UNCHECKED_CAST")
     fun <T : Any> getAnimationUpdateFrames(animator: PhysicsAnimator<T>):
             UpdateFramesPerProperty<T> {
         return animatorTestHelpers[animator]?.getUpdates() as UpdateFramesPerProperty<T>
@@ -333,6 +342,7 @@
         animatorTestHelpers[animator]?.clearUpdates()
     }
 
+    @Suppress("UNCHECKED_CAST")
     private fun <T> getAnimationTestHelper(animator: PhysicsAnimator<T>): AnimatorTestHelper<T> {
         return animatorTestHelpers[animator] as AnimatorTestHelper<T>
     }
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
index ae82115..aa56ffb 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
@@ -101,10 +101,11 @@
                             }
                             DisplayRecord record = new DisplayRecord();
                             record.mDisplayId = displayId;
-                            Display display = getDisplay(displayId);
-                            record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
-                                    : mContext.createDisplayContext(display);
-                            record.mDisplayLayout = new DisplayLayout(record.mContext, display);
+                            // TODO(b/146566787): disabled for MultiDisplayActivityLaunchTests
+                            // Display display = getDisplay(displayId);
+                            // record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
+                            //         : mContext.createDisplayContext(display);
+                            // record.mDisplayLayout = new DisplayLayout(record.mContext, display);
                             mDisplays.put(displayId, record);
                             for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
                                 mDisplayChangedListeners.get(i).onDisplayAdded(displayId);
@@ -123,13 +124,14 @@
                                         + " display.");
                                 return;
                             }
-                            Display display = getDisplay(displayId);
-                            Context perDisplayContext = mContext;
-                            if (displayId != Display.DEFAULT_DISPLAY) {
-                                perDisplayContext = mContext.createDisplayContext(display);
-                            }
-                            dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
-                            dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
+                            // TODO(b/146566787): disabled for MultiDisplaySystemDecorationTests
+                            // Display display = getDisplay(displayId);
+                            // Context perDisplayContext = mContext;
+                            // if (displayId != Display.DEFAULT_DISPLAY) {
+                            //     perDisplayContext = mContext.createDisplayContext(display);
+                            // }
+                            // dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
+                            // dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
                             for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
                                 mDisplayChangedListeners.get(i).onDisplayConfigurationChanged(
                                         displayId, newConfig);
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/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/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/rs/java/android/renderscript/BaseObj.java b/rs/java/android/renderscript/BaseObj.java
index 7b5514b..b7e05d9 100644
--- a/rs/java/android/renderscript/BaseObj.java
+++ b/rs/java/android/renderscript/BaseObj.java
@@ -16,10 +16,8 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
-
+import android.annotation.UnsupportedAppUsage;
 import dalvik.system.CloseGuard;
-
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java
index 0941907..b8eb3a1 100644
--- a/rs/java/android/renderscript/Element.java
+++ b/rs/java/android/renderscript/Element.java
@@ -16,7 +16,7 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 
 /**
  * <p>An Element represents one item within an {@link
diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java
index 7cc2825..9a6b0bc 100644
--- a/rs/java/android/renderscript/FileA3D.java
+++ b/rs/java/android/renderscript/FileA3D.java
@@ -16,13 +16,13 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.res.AssetManager;
-import android.content.res.Resources;
-
 import java.io.File;
 import java.io.InputStream;
 
+import android.annotation.UnsupportedAppUsage;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+
 /**
  * @hide
  * @deprecated in API 16
diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java
index df9d801..583350e 100644
--- a/rs/java/android/renderscript/Font.java
+++ b/rs/java/android/renderscript/Font.java
@@ -16,16 +16,17 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.res.AssetManager;
-import android.content.res.Resources;
-import android.os.Environment;
-
 import java.io.File;
 import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Map;
 
+import android.os.Environment;
+
+import android.annotation.UnsupportedAppUsage;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+
 /**
  * @hide
  * @deprecated in API 16
diff --git a/rs/java/android/renderscript/Matrix4f.java b/rs/java/android/renderscript/Matrix4f.java
index a9469c9..026c9fb 100644
--- a/rs/java/android/renderscript/Matrix4f.java
+++ b/rs/java/android/renderscript/Matrix4f.java
@@ -16,7 +16,8 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
+import java.lang.Math;
 
 
 /**
diff --git a/rs/java/android/renderscript/Mesh.java b/rs/java/android/renderscript/Mesh.java
index 826225a..5321dcb 100644
--- a/rs/java/android/renderscript/Mesh.java
+++ b/rs/java/android/renderscript/Mesh.java
@@ -16,8 +16,7 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
-
+import android.annotation.UnsupportedAppUsage;
 import java.util.Vector;
 
 /**
diff --git a/rs/java/android/renderscript/Program.java b/rs/java/android/renderscript/Program.java
index ff07218..e28d646 100644
--- a/rs/java/android/renderscript/Program.java
+++ b/rs/java/android/renderscript/Program.java
@@ -17,14 +17,14 @@
 package android.renderscript;
 
 
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.res.Resources;
-import android.util.Log;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 
+import android.annotation.UnsupportedAppUsage;
+import android.content.res.Resources;
+import android.util.Log;
+
 
 /**
  * @hide
diff --git a/rs/java/android/renderscript/ProgramFragment.java b/rs/java/android/renderscript/ProgramFragment.java
index 8805312..3dde9b6 100644
--- a/rs/java/android/renderscript/ProgramFragment.java
+++ b/rs/java/android/renderscript/ProgramFragment.java
@@ -16,7 +16,7 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 
 
 /**
diff --git a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java
index c741ce6..d05d41d 100644
--- a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java
+++ b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java
@@ -16,7 +16,7 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 
 
 /**
diff --git a/rs/java/android/renderscript/ProgramRaster.java b/rs/java/android/renderscript/ProgramRaster.java
index a21696c..33000ac 100644
--- a/rs/java/android/renderscript/ProgramRaster.java
+++ b/rs/java/android/renderscript/ProgramRaster.java
@@ -16,7 +16,7 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 
 
 /**
diff --git a/rs/java/android/renderscript/ProgramStore.java b/rs/java/android/renderscript/ProgramStore.java
index 7e61347..622fe21 100644
--- a/rs/java/android/renderscript/ProgramStore.java
+++ b/rs/java/android/renderscript/ProgramStore.java
@@ -16,7 +16,7 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 
 
 /**
diff --git a/rs/java/android/renderscript/ProgramVertex.java b/rs/java/android/renderscript/ProgramVertex.java
index 9257234..83d9ea7 100644
--- a/rs/java/android/renderscript/ProgramVertex.java
+++ b/rs/java/android/renderscript/ProgramVertex.java
@@ -38,7 +38,7 @@
  **/
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 
 
 /**
diff --git a/rs/java/android/renderscript/ProgramVertexFixedFunction.java b/rs/java/android/renderscript/ProgramVertexFixedFunction.java
index 03c2eaf..579d3bb 100644
--- a/rs/java/android/renderscript/ProgramVertexFixedFunction.java
+++ b/rs/java/android/renderscript/ProgramVertexFixedFunction.java
@@ -16,7 +16,7 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 
 
 /**
diff --git a/rs/java/android/renderscript/RSSurfaceView.java b/rs/java/android/renderscript/RSSurfaceView.java
index 6bdde38..561373c 100644
--- a/rs/java/android/renderscript/RSSurfaceView.java
+++ b/rs/java/android/renderscript/RSSurfaceView.java
@@ -16,7 +16,7 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.SurfaceHolder;
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 46c49e5..f4c2777 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -16,7 +16,7 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.AssetManager;
 import android.graphics.Bitmap;
diff --git a/rs/java/android/renderscript/RenderScriptCacheDir.java b/rs/java/android/renderscript/RenderScriptCacheDir.java
index 862d032..1797bef 100644
--- a/rs/java/android/renderscript/RenderScriptCacheDir.java
+++ b/rs/java/android/renderscript/RenderScriptCacheDir.java
@@ -16,8 +16,7 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
-
+import android.annotation.UnsupportedAppUsage;
 import java.io.File;
 
 /**
diff --git a/rs/java/android/renderscript/RenderScriptGL.java b/rs/java/android/renderscript/RenderScriptGL.java
index dafaf36..6fac83e 100644
--- a/rs/java/android/renderscript/RenderScriptGL.java
+++ b/rs/java/android/renderscript/RenderScriptGL.java
@@ -16,7 +16,7 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.graphics.SurfaceTexture;
 import android.view.Surface;
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index d1d3a76..9ad9aea 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -16,7 +16,7 @@
 
 package android.renderscript;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.util.SparseArray;
 
 /**
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/accessibility/java/com/android/server/accessibility/gestures/Swipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java
index b246c67..a285c10 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java
@@ -26,6 +26,7 @@
 import android.util.Slog;
 import android.util.TypedValue;
 import android.view.MotionEvent;
+import android.view.ViewConfiguration;
 
 import java.util.ArrayList;
 
@@ -85,6 +86,10 @@
     private static final float MIN_CM_BETWEEN_SAMPLES = 0.25f;
     private final float mMinPixelsBetweenSamplesX;
     private final float mMinPixelsBetweenSamplesY;
+    // The minmimum distance the finger must travel before we evaluate the initial direction of the
+    // swipe.
+    // Anything less is still considered a touch.
+    private int mTouchSlop;
 
     // Constants for separating gesture segments
     private static final float ANGLE_THRESHOLD = 0.0f;
@@ -122,6 +127,7 @@
         final float pixelsPerCmY = displayMetrics.ydpi / 2.54f;
         mMinPixelsBetweenSamplesX = MIN_CM_BETWEEN_SAMPLES * pixelsPerCmX;
         mMinPixelsBetweenSamplesY = MIN_CM_BETWEEN_SAMPLES * pixelsPerCmY;
+        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         clear();
     }
 
@@ -165,7 +171,10 @@
                             + Float.toString(mGestureDetectionThreshold));
         }
         if (getState() == STATE_CLEAR) {
-            if (mStrokeBuffer.size() == 0) {
+            if (moveDelta < mTouchSlop) {
+                // This still counts as a touch not a swipe.
+                return;
+            } else if (mStrokeBuffer.size() == 0) {
                 // First, make sure the pointer is going in the right direction.
                 cancelAfterDelay(event, rawEvent, policyFlags);
                 int direction = toDirection(x - mBaseX, y - mBaseY);
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index d2f1113..78f278e 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -63,6 +63,9 @@
     public static final int PACKAGE_INCIDENT_REPORT_APPROVER = 10;
     public static final int PACKAGE_APP_PREDICTOR = 11;
     public static final int PACKAGE_TELEPHONY = 12;
+    public static final int PACKAGE_WIFI = 13;
+    public static final int PACKAGE_COMPANION = 14;
+
     @IntDef(value = {
         PACKAGE_SYSTEM,
         PACKAGE_SETUP_WIZARD,
@@ -77,6 +80,8 @@
         PACKAGE_INCIDENT_REPORT_APPROVER,
         PACKAGE_APP_PREDICTOR,
         PACKAGE_TELEPHONY,
+        PACKAGE_WIFI,
+        PACKAGE_COMPANION,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface KnownPackage {}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 5bec7a3..2091c2a 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -551,16 +551,13 @@
                         if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
                             unregisterScreenOffEvent();
                         }
-                        // Only persist setting if not in car mode
-                        if (!mCarModeEnabled) {
-                            Secure.putIntForUser(getContext().getContentResolver(),
-                                    Secure.UI_NIGHT_MODE, mode, user);
-                            Secure.putIntForUser(getContext().getContentResolver(),
-                                    OVERRIDE_NIGHT_MODE, mNightModeOverride, user);
-                        }
 
                         mNightMode = mode;
                         mNightModeOverride = mode;
+                        // Only persist setting if not in car mode
+                        if (!mCarModeEnabled) {
+                            persistNightMode(user);
+                        }
                         // on screen off will update configuration instead
                         if (mNightMode != UiModeManager.MODE_NIGHT_AUTO || mCar) {
                             updateLocked(0, 0);
@@ -610,6 +607,7 @@
         @Override
         public boolean setNightModeActivated(boolean active) {
             synchronized (mLock) {
+                final int user = UserHandle.getCallingUserId();
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
@@ -625,6 +623,7 @@
                     }
                     updateConfigurationLocked();
                     applyConfigurationExternallyLocked();
+                    persistNightMode(user);
                     return true;
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -834,6 +833,13 @@
         }
     }
 
+    private void persistNightMode(int user) {
+        Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.UI_NIGHT_MODE, mNightMode, user);
+        Secure.putIntForUser(getContext().getContentResolver(),
+                OVERRIDE_NIGHT_MODE, mNightModeOverride, user);
+    }
+
     private void updateConfigurationLocked() {
         int uiMode = mDefaultUiModeType;
         if (mUiModeLocked) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1609606..6dc49b7 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;
@@ -1621,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;
             }
         }
     }
@@ -9381,9 +9370,9 @@
         }
     }
 
-    void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) {
+    void killAppAtUsersRequest(ProcessRecord app) {
         synchronized (this) {
-            mAppErrors.killAppAtUserRequestLocked(app, fromDialog);
+            mAppErrors.killAppAtUserRequestLocked(app);
         }
     }
 
@@ -13062,14 +13051,31 @@
                     pw.println(totalPss - cachedPss);
                 }
             }
-            long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
+            long kernelUsed = memInfo.getKernelUsedSizeKb();
+            final long ionHeap = Debug.getIonHeapsSizeKb();
+            if (ionHeap > 0) {
+                final long ionMapped = Debug.getIonMappedSizeKb();
+                final long ionUnmapped = ionHeap - ionMapped;
+                final long ionPool = Debug.getIonPoolsSizeKb();
+                pw.print("      ION: ");
+                        pw.print(stringifyKBSize(ionHeap + ionPool));
+                        pw.print(" (");
+                        pw.print(stringifyKBSize(ionMapped));
+                        pw.print(" mapped + ");
+                        pw.print(stringifyKBSize(ionUnmapped));
+                        pw.print(" unmapped + ");
+                        pw.print(stringifyKBSize(ionPool));
+                        pw.println(" pools)");
+                kernelUsed += ionUnmapped;
+            }
+            final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
                     - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
-                    - memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb();
+                    - kernelUsed - memInfo.getZramTotalSizeKb();
             if (!opts.isCompact) {
                 pw.print(" Used RAM: "); pw.print(stringifyKBSize(totalPss - cachedPss
-                        + memInfo.getKernelUsedSizeKb())); pw.print(" (");
+                        + kernelUsed)); pw.print(" (");
                 pw.print(stringifyKBSize(totalPss - cachedPss)); pw.print(" used pss + ");
-                pw.print(stringifyKBSize(memInfo.getKernelUsedSizeKb())); pw.print(" kernel)\n");
+                pw.print(stringifyKBSize(kernelUsed)); pw.print(" kernel)\n");
                 pw.print(" Lost RAM: "); pw.println(stringifyKBSize(lostRAM));
             } else {
                 pw.print("lostram,"); pw.println(lostRAM);
@@ -13835,14 +13841,25 @@
         memInfoBuilder.append(stringifyKBSize(cachedPss + memInfo.getCachedSizeKb()
                 + memInfo.getFreeSizeKb()));
         memInfoBuilder.append("\n");
+        long kernelUsed = memInfo.getKernelUsedSizeKb();
+        final long ionHeap = Debug.getIonHeapsSizeKb();
+        if (ionHeap > 0) {
+            final long ionMapped = Debug.getIonMappedSizeKb();
+            final long ionUnmapped = ionHeap - ionMapped;
+            final long ionPool = Debug.getIonPoolsSizeKb();
+            memInfoBuilder.append("       ION: ");
+            memInfoBuilder.append(stringifyKBSize(ionHeap + ionPool));
+            memInfoBuilder.append("\n");
+            kernelUsed += ionUnmapped;
+        }
         memInfoBuilder.append("  Used RAM: ");
         memInfoBuilder.append(stringifyKBSize(
-                                  totalPss - cachedPss + memInfo.getKernelUsedSizeKb()));
+                                  totalPss - cachedPss + kernelUsed));
         memInfoBuilder.append("\n");
         memInfoBuilder.append("  Lost RAM: ");
         memInfoBuilder.append(stringifyKBSize(memInfo.getTotalSizeKb()
                 - (totalPss - totalSwapPss) - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
-                - memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb()));
+                - kernelUsed - memInfo.getZramTotalSizeKb()));
         memInfoBuilder.append("\n");
         Slog.i(TAG, "Low on memory:");
         Slog.i(TAG, shortNativeBuilder.toString());
@@ -14008,18 +14025,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/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/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 728291d..f9730a9 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -407,6 +407,7 @@
      */
     private boolean finishUserUnlocking(final UserState uss) {
         final int userId = uss.mHandle.getIdentifier();
+        Slog.d(TAG, "UserController event: finishUserUnlocking(" + userId + ")");
         // Only keep marching forward if user is actually unlocked
         if (!StorageManager.isUserKeyUnlocked(userId)) return false;
         synchronized (mLock) {
@@ -451,6 +452,7 @@
      */
     void finishUserUnlocked(final UserState uss) {
         final int userId = uss.mHandle.getIdentifier();
+        Slog.d(TAG, "UserController event: finishUserUnlocked(" + userId + ")");
         // Only keep marching forward if user is actually unlocked
         if (!StorageManager.isUserKeyUnlocked(userId)) return;
         synchronized (mLock) {
@@ -521,6 +523,7 @@
 
     private void finishUserUnlockedCompleted(UserState uss) {
         final int userId = uss.mHandle.getIdentifier();
+        Slog.d(TAG, "UserController event: finishUserUnlockedCompleted(" + userId + ")");
         synchronized (mLock) {
             // Bail if we ended up with a stale user
             if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
@@ -730,6 +733,7 @@
     }
 
     void finishUserStopping(final int userId, final UserState uss) {
+        Slog.d(TAG, "UserController event: finishUserStopping(" + userId + ")");
         // On to the next.
         final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
         // This is the result receiver for the final shutdown broadcast.
@@ -769,6 +773,7 @@
 
     void finishUserStopped(UserState uss) {
         final int userId = uss.mHandle.getIdentifier();
+        Slog.d(TAG, "UserController event: finishUserStopped(" + userId + ")");
         final boolean stopped;
         boolean lockUser = true;
         final ArrayList<IStopUserCallback> stopCallbacks;
@@ -1280,6 +1285,7 @@
     boolean unlockUser(final @UserIdInt int userId, byte[] token, byte[] secret,
             IProgressListener listener) {
         checkCallingPermission(INTERACT_ACROSS_USERS_FULL, "unlockUser");
+        Slog.i(TAG, "unlocking user " + userId);
         final long binderToken = Binder.clearCallingIdentity();
         try {
             return unlockUserCleared(userId, token, secret, listener);
@@ -1364,6 +1370,7 @@
 
     boolean switchUser(final int targetUserId) {
         enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, targetUserId);
+        Slog.i(TAG, "switching to user " + targetUserId);
         int currentUserId = getCurrentUserId();
         UserInfo targetUserInfo = getUserInfo(targetUserId);
         if (targetUserId == currentUserId) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 14f9654..0b74840 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -17,11 +17,12 @@
 package com.android.server.appop;
 
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
-import static android.app.AppOpsManager.MAX_PRIORITY_UID_STATE;
-import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
+import static android.app.AppOpsManager.NoteOpEvent;
+import static android.app.AppOpsManager.OpEventProxyInfo;
 import static android.app.AppOpsManager.OP_CAMERA;
 import static android.app.AppOpsManager.OP_COARSE_LOCATION;
 import static android.app.AppOpsManager.OP_FLAGS_ALL;
+import static android.app.AppOpsManager.OP_FLAG_SELF;
 import static android.app.AppOpsManager.OP_NONE;
 import static android.app.AppOpsManager.OP_PLAY_AUDIO;
 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
@@ -33,6 +34,9 @@
 import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
 import static android.app.AppOpsManager.UID_STATE_TOP;
 import static android.app.AppOpsManager._NUM_OP;
+import static android.app.AppOpsManager.extractFlagsFromKey;
+import static android.app.AppOpsManager.extractUidStateFromKey;
+import static android.app.AppOpsManager.makeKey;
 import static android.app.AppOpsManager.modeToName;
 import static android.app.AppOpsManager.opToName;
 import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState;
@@ -93,7 +97,6 @@
 import android.util.AtomicFile;
 import android.util.KeyValueListParser;
 import android.util.LongSparseArray;
-import android.util.LongSparseLongArray;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -365,8 +368,6 @@
         public long pendingStateCommitTime;
         public int capability;
         public int pendingCapability;
-        // For all features combined
-        public int startNesting;
 
         public ArrayMap<String, Ops> pkgOps;
         public SparseIntArray opModes;
@@ -474,126 +475,318 @@
         }
     }
 
-    private static final class FeatureOp {
+    /** A in progress startOp->finishOp event */
+    private static final class InProgressStartOpEvent implements IBinder.DeathRecipient {
+        /** Time of startOp event */
+        final long startTime;
+
+        /** Id of the client that started the event */
+        final @NonNull IBinder clientId;
+
+        /** To call when client dies */
+        final @NonNull Runnable onDeath;
+
+        /** uidstate used when calling startOp */
+        final @AppOpsManager.UidState int uidState;
+
+        /** How many times the op was started but not finished yet */
+        int numUnfinishedStarts;
+
+        private InProgressStartOpEvent(long startTime, @NonNull IBinder clientId,
+                @NonNull Runnable onDeath, int uidState) throws RemoteException {
+            this.startTime = startTime;
+            this.clientId = clientId;
+            this.onDeath = onDeath;
+            this.uidState = uidState;
+
+            clientId.linkToDeath(this, 0);
+        }
+
+        /** Clean up event */
+        public void finish() {
+            clientId.unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            onDeath.run();
+        }
+    }
+
+    private final class FeatureOp {
         public final @NonNull Op parent;
 
-        public boolean running;
+        /**
+         * Last successful accesses (noteOp + finished startOp) for each uidState/opFlag combination
+         *
+         * <p>Key is {@link AppOpsManager#makeKey}
+         */
+        @GuardedBy("AppOpsService.this")
+        private @Nullable LongSparseArray<AppOpsManager.NoteOpEvent> mAccessEvents;
 
-        private @Nullable LongSparseLongArray mAccessTimes;
-        private @Nullable LongSparseLongArray mRejectTimes;
-        private @Nullable LongSparseLongArray mDurations;
-        private @Nullable LongSparseLongArray mProxyUids;
-        private @Nullable LongSparseArray<String> mProxyFeatureIds;
-        private @Nullable LongSparseArray<String> mProxyPackageNames;
+        /**
+         * Last rejected accesses for each uidState/opFlag combination
+         *
+         * <p>Key is {@link AppOpsManager#makeKey}
+         */
+        @GuardedBy("AppOpsService.this")
+        private @Nullable LongSparseArray<AppOpsManager.NoteOpEvent> mRejectEvents;
 
-        public int startNesting;
-        public long startRealtime;
+        /**
+         * Currently in progress startOp events
+         *
+         * <p>Key is clientId
+         */
+        @GuardedBy("AppOpsService.this")
+        private @Nullable ArrayMap<IBinder, InProgressStartOpEvent> mInProgressEvents;
 
         FeatureOp(@NonNull Op parent) {
             this.parent = parent;
         }
 
-        public void accessed(long time, int proxyUid, @Nullable String proxyPackageName,
+        /**
+         * Update state when noteOp was rejected or startOp->finishOp event finished
+         *
+         * @param proxyUid The uid of the proxy
+         * @param proxyPackageName The package name of the proxy
+         * @param proxyFeatureId the featureId in the proxies package
+         * @param uidState UID state of the app noteOp/startOp was called for
+         * @param flags OpFlags of the call
+         */
+        public void accessed(int proxyUid, @Nullable String proxyPackageName,
                 @Nullable String proxyFeatureId, @AppOpsManager.UidState int uidState,
                 @OpFlags int flags) {
-            final long key = AppOpsManager.makeKey(uidState, flags);
-            if (mAccessTimes == null) {
-                mAccessTimes = new LongSparseLongArray();
-            }
-            mAccessTimes.put(key, time);
-            updateProxyState(key, proxyUid, proxyPackageName, proxyFeatureId);
-            if (mDurations != null) {
-                mDurations.delete(key);
-            }
+            accessed(System.currentTimeMillis(), -1, proxyUid, proxyPackageName,
+                    proxyFeatureId, uidState, flags);
         }
 
-        public void rejected(long time, int proxyUid, @Nullable String proxyPackageName,
-                @Nullable String proxyFeatureId, @AppOpsManager.UidState int uidState,
-                @OpFlags int flags) {
-            final long key = AppOpsManager.makeKey(uidState, flags);
-            if (mRejectTimes == null) {
-                mRejectTimes = new LongSparseLongArray();
-            }
-            mRejectTimes.put(key, time);
-            updateProxyState(key, proxyUid, proxyPackageName, proxyFeatureId);
-            if (mDurations != null) {
-                mDurations.delete(key);
-            }
-        }
-
-        public void started(long time, @AppOpsManager.UidState int uidState, @OpFlags int flags) {
-            updateAccessTimeAndDuration(time, -1 /*duration*/, uidState, flags);
-            running = true;
-        }
-
-        public void finished(long time, long duration, @AppOpsManager.UidState int uidState,
-                @OpFlags int flags) {
-            updateAccessTimeAndDuration(time, duration, uidState, flags);
-            running = false;
-        }
-
-        public void running(long time, long duration, @AppOpsManager.UidState int uidState,
-                @OpFlags int flags) {
-            updateAccessTimeAndDuration(time, duration, uidState, flags);
-        }
-
-        public void continuing(long duration, @AppOpsManager.UidState int uidState,
-                @OpFlags int flags) {
-            final long key = AppOpsManager.makeKey(uidState, flags);
-            if (mDurations == null) {
-                mDurations = new LongSparseLongArray();
-            }
-            mDurations.put(key, duration);
-        }
-
-        private void updateAccessTimeAndDuration(long time, long duration,
+        /**
+         * Add an access that was previously collected.
+         *
+         * @param noteTime The time of the event
+         * @param duration The duration of the event
+         * @param proxyUid The uid of the proxy
+         * @param proxyPackageName The package name of the proxy
+         * @param proxyFeatureId the featureId in the proxies package
+         * @param uidState UID state of the app noteOp/startOp was called for
+         * @param flags OpFlags of the call
+         */
+        public void accessed(long noteTime, long duration, int proxyUid,
+                @Nullable String proxyPackageName, @Nullable String proxyFeatureId,
                 @AppOpsManager.UidState int uidState, @OpFlags int flags) {
-            final long key = AppOpsManager.makeKey(uidState, flags);
-            if (mAccessTimes == null) {
-                mAccessTimes = new LongSparseLongArray();
+            long key = makeKey(uidState, flags);
+
+            if (mAccessEvents == null) {
+                mAccessEvents = new LongSparseArray<>(1);
             }
-            mAccessTimes.put(key, time);
-            if (mDurations == null) {
-                mDurations = new LongSparseLongArray();
+
+            OpEventProxyInfo proxyInfo = null;
+            if (proxyUid != Process.INVALID_UID) {
+                proxyInfo = new OpEventProxyInfo(proxyUid, proxyPackageName, proxyFeatureId);
             }
-            mDurations.put(key, duration);
+            mAccessEvents.put(key, new NoteOpEvent(noteTime, duration, proxyInfo));
         }
 
-        private void updateProxyState(long key, int proxyUid,
-                @Nullable String proxyPackageName, @Nullable String featureId) {
-            if (proxyUid == Process.INVALID_UID) {
+        /**
+         * Update state when noteOp/startOp was rejected.
+         *
+         * @param uidState UID state of the app noteOp is called for
+         * @param flags OpFlags of the call
+         */
+        public void rejected(@AppOpsManager.UidState int uidState, @OpFlags int flags) {
+            rejected(System.currentTimeMillis(), uidState, flags);
+        }
+
+        /**
+         * Add an rejection that was previously collected
+         *
+         * @param noteTime The time of the event
+         * @param uidState UID state of the app noteOp/startOp was called for
+         * @param flags OpFlags of the call
+         */
+        public void rejected(long noteTime, @AppOpsManager.UidState int uidState,
+                @OpFlags int flags) {
+            long key = makeKey(uidState, flags);
+
+            if (mRejectEvents == null) {
+                mRejectEvents = new LongSparseArray<>(1);
+            }
+
+            // We do not collect proxy information for rejections yet
+            mRejectEvents.put(key, new NoteOpEvent(noteTime, -1, null));
+        }
+
+        /**
+         * Update state when start was called
+         *
+         * @param clientId Id of the startOp caller
+         * @param uidState UID state of the app startOp is called for
+         */
+        public void started(@NonNull IBinder clientId, @AppOpsManager.UidState int uidState)
+                throws RemoteException {
+            if (!parent.isRunning()) {
+                scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
+                        parent.packageName, true);
+            }
+
+            if (mInProgressEvents == null) {
+                mInProgressEvents = new ArrayMap<>(1);
+            }
+
+
+            InProgressStartOpEvent event = mInProgressEvents.get(clientId);
+            if (event == null) {
+                event = new InProgressStartOpEvent(System.currentTimeMillis(), clientId, () -> {
+                    // In the case the client dies without calling finish first
+                    synchronized (AppOpsService.this) {
+                        if (mInProgressEvents == null) {
+                            return;
+                        }
+
+                        InProgressStartOpEvent deadEvent = mInProgressEvents.get(clientId);
+                        if (deadEvent != null) {
+                            deadEvent.numUnfinishedStarts = 1;
+                        }
+
+                        finished(clientId);
+                    }
+                }, uidState);
+                mInProgressEvents.put(clientId, event);
+            } else {
+                if (uidState != event.uidState) {
+                    onUidStateChanged(uidState);
+                }
+            }
+
+            event.numUnfinishedStarts++;
+
+            // startOp events don't support proxy, hence use flags==SELF
+            mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
+                    uidState, OP_FLAG_SELF);
+        }
+
+        /**
+         * Update state when finishOp was called
+         *
+         * @param clientId Id of the finishOp caller
+         */
+        public void finished(@NonNull IBinder clientId) {
+            finished(clientId, true);
+        }
+
+        private void finished(@NonNull IBinder clientId, boolean triggerCallbackIfNeeded) {
+            if (mInProgressEvents == null) {
+                Slog.wtf(TAG, "No ops running");
                 return;
             }
 
-            if (mProxyUids == null) {
-                mProxyUids = new LongSparseLongArray();
+            int indexOfToken = mInProgressEvents.indexOfKey(clientId);
+            if (indexOfToken < 0) {
+                Slog.wtf(TAG, "No op running for the client");
+                return;
             }
-            mProxyUids.put(key, proxyUid);
 
-            if (mProxyPackageNames == null) {
-                mProxyPackageNames = new LongSparseArray<>();
-            }
-            mProxyPackageNames.put(key, proxyPackageName);
+            InProgressStartOpEvent event = mInProgressEvents.valueAt(indexOfToken);
+            event.numUnfinishedStarts--;
+            if (event.numUnfinishedStarts == 0) {
+                event.finish();
+                mInProgressEvents.removeAt(indexOfToken);
 
-            if (mProxyFeatureIds == null) {
-                mProxyFeatureIds = new LongSparseArray<>();
+                if (mAccessEvents == null) {
+                    mAccessEvents = new LongSparseArray<>(1);
+                }
+
+                // startOp events don't support proxy, hence use flags==SELF
+                NoteOpEvent finishedEvent = new NoteOpEvent(event.startTime,
+                        System.currentTimeMillis() - event.startTime, null);
+                mAccessEvents.put(makeKey(event.uidState, OP_FLAG_SELF), finishedEvent);
+
+                mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
+                        parent.packageName, event.uidState, AppOpsManager.OP_FLAG_SELF,
+                        finishedEvent.duration);
+
+                if (mInProgressEvents.isEmpty()) {
+                    mInProgressEvents = null;
+
+                    // TODO moltmann: Also callback for single feature activity changes
+                    if (triggerCallbackIfNeeded && !parent.isRunning()) {
+                        scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
+                                parent.packageName, false);
+                    }
+                }
             }
-            mProxyFeatureIds.put(key, featureId);
+        }
+
+        /**
+         * Notify that the state of the uid changed
+         *
+         * @param newState The new state
+         */
+        public void onUidStateChanged(@AppOpsManager.UidState int newState) {
+            if (mInProgressEvents == null) {
+                return;
+            }
+
+            int numInProgressEvents = mInProgressEvents.size();
+            for (int i = 0; i < numInProgressEvents; i++) {
+                InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
+
+                if (event.uidState != newState) {
+                    try {
+                        finished(event.clientId, false);
+                        started(event.clientId, newState);
+                    } catch (RemoteException e) {
+                        if (DEBUG) Slog.e(TAG, "Cannot switch to new uidState " + newState);
+                    }
+                }
+            }
+        }
+
+        public boolean isRunning() {
+            return mInProgressEvents != null;
         }
 
         boolean hasAnyTime() {
-            return (mAccessTimes != null && mAccessTimes.size() > 0)
-                    || (mRejectTimes != null && mRejectTimes.size() > 0);
+            return (mAccessEvents != null && mAccessEvents.size() > 0)
+                    || (mRejectEvents != null && mRejectEvents.size() > 0);
         }
 
-        @NonNull OpFeatureEntry.Builder createFeatureEntryBuilderLocked() {
-            return new OpFeatureEntry.Builder(running, mAccessTimes, mRejectTimes, mDurations,
-                    mProxyUids, mProxyPackageNames, mProxyFeatureIds);
+        @NonNull OpFeatureEntry createFeatureEntryLocked() {
+            LongSparseArray<NoteOpEvent> accessEvents = null;
+            if (mAccessEvents != null) {
+                accessEvents = mAccessEvents.clone();
+            }
+
+            // Add in progress events as access events
+            if (mInProgressEvents != null) {
+                long now = System.currentTimeMillis();
+                int numInProgressEvents = mInProgressEvents.size();
+
+                if (accessEvents == null) {
+                    accessEvents = new LongSparseArray<>(numInProgressEvents);
+                }
+
+                for (int i = 0; i < numInProgressEvents; i++) {
+                    InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
+
+                    // startOp events don't support proxy
+                    accessEvents.append(makeKey(event.uidState, OP_FLAG_SELF),
+                            new NoteOpEvent(event.startTime, now - event.startTime, null));
+                }
+            }
+
+            LongSparseArray<NoteOpEvent> rejectEvents = null;
+            if (mRejectEvents != null) {
+                rejectEvents = mRejectEvents.clone();
+            }
+
+            return new OpFeatureEntry(parent.op, isRunning(), accessEvents, rejectEvents);
         }
     }
 
-    final static class Op {
+    final class Op {
         int op;
+        int uid;
         final UidState uidState;
         final @NonNull String packageName;
 
@@ -602,8 +795,9 @@
         /** featureId -> FeatureOp */
         final ArrayMap<String, FeatureOp> mFeatures = new ArrayMap<>(1);
 
-        Op(UidState uidState, String packageName, int op) {
+        Op(UidState uidState, String packageName, int op, int uid) {
             this.op = op;
+            this.uid = uid;
             this.uidState = uidState;
             this.packageName = packageName;
             this.mode = AppOpsManager.opToDefaultMode(op);
@@ -641,11 +835,10 @@
         @NonNull OpEntry createEntryLocked() {
             final int numFeatures = mFeatures.size();
 
-            final Pair<String, OpFeatureEntry.Builder>[] featureEntries =
-                    new Pair[numFeatures];
+            final ArrayMap<String, OpFeatureEntry> featureEntries = new ArrayMap<>(numFeatures);
             for (int i = 0; i < numFeatures; i++) {
-                featureEntries[i] = new Pair<>(mFeatures.keyAt(i),
-                        mFeatures.valueAt(i).createFeatureEntryBuilderLocked());
+                featureEntries.put(mFeatures.keyAt(i),
+                        mFeatures.valueAt(i).createFeatureEntryLocked());
             }
 
             return new OpEntry(op, mode, featureEntries);
@@ -654,18 +847,28 @@
         @NonNull OpEntry createSingleFeatureEntryLocked(@Nullable String featureId) {
             final int numFeatures = mFeatures.size();
 
-            final Pair<String, AppOpsManager.OpFeatureEntry.Builder>[] featureEntries =
-                    new Pair[1];
+            final ArrayMap<String, OpFeatureEntry> featureEntries = new ArrayMap<>(1);
             for (int i = 0; i < numFeatures; i++) {
                 if (Objects.equals(mFeatures.keyAt(i), featureId)) {
-                    featureEntries[0] = new Pair<>(mFeatures.keyAt(i),
-                            mFeatures.valueAt(i).createFeatureEntryBuilderLocked());
+                    featureEntries.put(mFeatures.keyAt(i),
+                            mFeatures.valueAt(i).createFeatureEntryLocked());
                     break;
                 }
             }
 
             return new OpEntry(op, mode, featureEntries);
         }
+
+        boolean isRunning() {
+            final int numFeatures = mFeatures.size();
+            for (int i = 0; i < numFeatures; i++) {
+                if (mFeatures.valueAt(i).isRunning()) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
     }
 
     final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
@@ -815,53 +1018,6 @@
         }
     }
 
-    final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
-
-    final class ClientState extends Binder implements DeathRecipient {
-        final ArrayList<Pair<Op, String>> mStartedOps = new ArrayList<>();
-        final IBinder mAppToken;
-        final int mPid;
-
-        ClientState(IBinder appToken) {
-            mAppToken = appToken;
-            mPid = Binder.getCallingPid();
-            // Watch only for remote processes dying
-            if (!(appToken instanceof Binder)) {
-                try {
-                    mAppToken.linkToDeath(this, 0);
-                } catch (RemoteException e) {
-                    /* do nothing */
-                }
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "ClientState{" +
-                    "mAppToken=" + mAppToken +
-                    ", " + "pid=" + mPid +
-                    '}';
-        }
-
-        @Override
-        public void binderDied() {
-            synchronized (AppOpsService.this) {
-                for (int i=mStartedOps.size()-1; i>=0; i--) {
-                    final Pair<Op, String> startedOp = mStartedOps.get(i);
-                    final Op op = startedOp.first;
-                    final String featureId = startedOp.second;
-
-                    finishOperationLocked(op, featureId, /*finishNested*/ true);
-                    if (op.mFeatures.get(featureId).startNesting <= 0) {
-                        scheduleOpActiveChangedIfNeededLocked(op.op, op.uidState.uid,
-                                op.packageName, false);
-                    }
-                }
-                mClients.remove(mAppToken);
-            }
-        }
-    }
-
     public AppOpsService(File storagePath, Handler handler) {
         LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
         mFile = new AtomicFile(storagePath, "appops");
@@ -1024,43 +1180,19 @@
                 mUidStates.remove(uid);
             }
 
-            // Finish ops other packages started on behalf of the package.
-            final int clientCount = mClients.size();
-            for (int i = 0; i < clientCount; i++) {
-                final ClientState client = mClients.valueAt(i);
-                if (client.mStartedOps == null) {
-                    continue;
-                }
-                final int startedOpCount = client.mStartedOps.size();
-                for (int j = startedOpCount - 1; j >= 0; j--) {
-                    final Pair<Op, String> startedOp = client.mStartedOps.get(j);
-                    final Op op = startedOp.first;
-                    final String featureId = startedOp.second;
-
-                    if (uid == op.uidState.uid && packageName.equals(op.packageName)) {
-                        finishOperationLocked(op, featureId, /*finishNested*/ true);
-                        client.mStartedOps.remove(j);
-                        if (op.mFeatures.get(featureId).startNesting <= 0) {
-                            scheduleOpActiveChangedIfNeededLocked(op.op,
-                                    uid, packageName, false);
-                        }
-                    }
-                }
-            }
-
             if (ops != null) {
                 scheduleFastWriteLocked();
 
-                final int opCount = ops.size();
-                for (int opNum = 0; opNum < opCount; opNum++) {
+                final int numOps = ops.size();
+                for (int opNum = 0; opNum < numOps; opNum++) {
                     final Op op = ops.valueAt(opNum);
 
                     final int numFeatures = op.mFeatures.size();
                     for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
-                        if (op.mFeatures.valueAt(featureNum).running) {
-                            scheduleOpActiveChangedIfNeededLocked(
-                                    op.op, op.uidState.uid, op.packageName, false);
-                            break;
+                        FeatureOp featureOp = op.mFeatures.valueAt(featureNum);
+
+                        while (featureOp.mInProgressEvents != null) {
+                            featureOp.mInProgressEvents.valueAt(0).onDeath.run();
                         }
                     }
                 }
@@ -1112,35 +1244,21 @@
                     }
                     uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime;
                 }
-                if (uidState.startNesting != 0) {
-                    // There is some actively running operation...  need to find it
-                    // and appropriately update its state.
-                    final long now = System.currentTimeMillis();
-                    final long nowElapsed = SystemClock.elapsedRealtime();
-                    for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
-                        final Ops ops = uidState.pkgOps.valueAt(i);
-                        for (int j = ops.size() - 1; j >= 0; j--) {
-                            final Op op = ops.valueAt(j);
+
+                if (uidState.pkgOps != null) {
+                    int numPkgs = uidState.pkgOps.size();
+                    for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
+                        Ops ops = uidState.pkgOps.valueAt(pkgNum);
+
+                        int numOps = ops.size();
+                        for (int opNum = 0; opNum < numOps; opNum++) {
+                            Op op = ops.valueAt(opNum);
 
                             int numFeatures = op.mFeatures.size();
-                            for (int featureNum = 0; featureNum < numFeatures;
-                                    featureNum++) {
-                                final FeatureOp featureOp = op.mFeatures.valueAt(
-                                        featureNum);
-                                if (featureOp.startNesting > 0) {
-                                    final long duration = SystemClock.elapsedRealtime()
-                                            - featureOp.startRealtime;
-                                    // We don't support proxy long running ops (start/stop)
-                                    mHistoricalRegistry.increaseOpAccessDuration(op.op,
-                                            op.uidState.uid, op.packageName, oldPendingState,
-                                            AppOpsManager.OP_FLAG_SELF, duration);
-                                    // Finish the op in the old state
-                                    featureOp.finished(now, duration, oldPendingState,
-                                            AppOpsManager.OP_FLAG_SELF);
-                                    // Start the op in the new state
-                                    featureOp.startRealtime = nowElapsed;
-                                    featureOp.started(now, newState, AppOpsManager.OP_FLAG_SELF);
-                                }
+                            for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
+                                FeatureOp featureOp = op.mFeatures.valueAt(featureNum);
+
+                                featureOp.onUidStateChanged(newState);
                             }
                         }
                     }
@@ -1202,7 +1320,7 @@
             resOps = new ArrayList<>();
             for (int i = 0; i < opModeCount; i++) {
                 int code = uidState.opModes.keyAt(i);
-                resOps.add(new OpEntry(code, uidState.opModes.get(code), new Pair[0]));
+                resOps.add(new OpEntry(code, uidState.opModes.get(code), Collections.emptyMap()));
             }
         } else {
             for (int j=0; j<ops.length; j++) {
@@ -1211,7 +1329,8 @@
                     if (resOps == null) {
                         resOps = new ArrayList<>();
                     }
-                    resOps.add(new OpEntry(code, uidState.opModes.get(code), new Pair[0]));
+                    resOps.add(new OpEntry(code, uidState.opModes.get(code),
+                            Collections.emptyMap()));
                 }
             }
         }
@@ -1219,16 +1338,6 @@
     }
 
     private static @NonNull OpEntry getOpEntryForResult(@NonNull Op op, long elapsedNow) {
-        final int numFeatures = op.mFeatures.size();
-
-        for (int i = 0; i < numFeatures; i++) {
-            final FeatureOp featureOp = op.mFeatures.valueAt(i);
-            if (featureOp.running) {
-                featureOp.continuing(elapsedNow - featureOp.startRealtime,
-                        op.uidState.state, AppOpsManager.OP_FLAG_SELF);
-            }
-        }
-
         return op.createEntryLocked();
     }
 
@@ -1962,18 +2071,6 @@
         }
     }
 
-    @Override
-    public IBinder getToken(IBinder clientToken) {
-        synchronized (this) {
-            ClientState cs = mClients.get(clientToken);
-            if (cs == null) {
-                cs = new ClientState(clientToken);
-                mClients.put(clientToken, cs);
-            }
-            return cs;
-        }
-    }
-
     public CheckOpsDelegate getAppOpsServiceDelegate() {
         synchronized (this) {
             return mCheckOpsDelegate;
@@ -2214,15 +2311,10 @@
                 return AppOpsManager.MODE_IGNORED;
             }
             final UidState uidState = ops.uidState;
-            if (featureOp.running) {
-                final OpFeatureEntry entry = getOpLocked(ops, code,
-                        false).createSingleFeatureEntryLocked(featureId).getFeatures().get(
-                        featureId);
-
-                Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
-                        + " code " + code + " time=" + entry.getLastAccessTime(uidState.state,
-                        uidState.state, flags) + " duration=" + entry.getLastDuration(
-                                uidState.state, uidState.state, flags));
+            if (featureOp.isRunning()) {
+                Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code "
+                        + code + " startTime of in progress event="
+                        + featureOp.mInProgressEvents.valueAt(0).startTime);
             }
 
             final int switchCode = AppOpsManager.opToSwitch(code);
@@ -2234,8 +2326,7 @@
                     if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
                             + packageName);
-                    featureOp.rejected(System.currentTimeMillis(), proxyUid, proxyPackageName,
-                            proxyFeatureId, uidState.state, flags);
+                    featureOp.rejected(uidState.state, flags);
                     mHistoricalRegistry.incrementOpRejected(code, uid, packageName,
                             uidState.state, flags);
                     scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
@@ -2248,8 +2339,7 @@
                     if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
                             + packageName);
-                    featureOp.rejected(System.currentTimeMillis(), proxyUid, proxyPackageName,
-                            proxyFeatureId, uidState.state, flags);
+                    featureOp.rejected(uidState.state, flags);
                     mHistoricalRegistry.incrementOpRejected(code, uid, packageName,
                             uidState.state, flags);
                     scheduleOpNotedIfNeededLocked(code, uid, packageName, mode);
@@ -2258,8 +2348,7 @@
             }
             if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
                     + " package " + packageName + (featureId == null ? "" : "." + featureId));
-            featureOp.accessed(System.currentTimeMillis(), proxyUid, proxyPackageName,
-                    proxyFeatureId, uidState.state, flags);
+            featureOp.accessed(proxyUid, proxyPackageName, proxyFeatureId, uidState.state, flags);
             // TODO moltmann: Add features to historical app-ops
             mHistoricalRegistry.incrementOpAccessedCount(op.op, uid, packageName,
                     uidState.state, flags);
@@ -2496,7 +2585,7 @@
     }
 
     @Override
-    public int startOperation(IBinder token, int code, int uid, String packageName,
+    public int startOperation(IBinder clientId, int code, int uid, String packageName,
             String featureId, boolean startIfModeDefault) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
@@ -2504,7 +2593,6 @@
         if (resolvedPackageName == null) {
             return  AppOpsManager.MODE_IGNORED;
         }
-        ClientState client = (ClientState)token;
 
         boolean isPrivileged;
         try {
@@ -2539,10 +2627,7 @@
                     if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
                             + resolvedPackageName);
-                    // We don't support proxy long running ops (start/stop)
-                    featureOp.rejected(System.currentTimeMillis(), -1 /*proxyUid*/,
-                            null /*proxyPackage*/, null, uidState.state,
-                            AppOpsManager.OP_FLAG_SELF);
+                    featureOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
                     mHistoricalRegistry.incrementOpRejected(opCode, uid, packageName,
                             uidState.state, AppOpsManager.OP_FLAG_SELF);
                     return uidMode;
@@ -2555,10 +2640,7 @@
                     if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
                             + resolvedPackageName);
-                    // We don't support proxy long running ops (start/stop)
-                    featureOp.rejected(System.currentTimeMillis(), -1 /*proxyUid*/,
-                            null /*proxyPackage*/, null, uidState.state,
-                            AppOpsManager.OP_FLAG_SELF);
+                    featureOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
                     mHistoricalRegistry.incrementOpRejected(opCode, uid, packageName,
                             uidState.state, AppOpsManager.OP_FLAG_SELF);
                     return mode;
@@ -2566,29 +2648,19 @@
             }
             if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
                     + " package " + resolvedPackageName);
-            if (featureOp.startNesting == 0) {
-                featureOp.startRealtime = SystemClock.elapsedRealtime();
-                // We don't support proxy long running ops (start/stop)
-                featureOp.started(System.currentTimeMillis(), uidState.state,
-                        AppOpsManager.OP_FLAG_SELF);
-                mHistoricalRegistry.incrementOpAccessedCount(opCode, uid, packageName,
-                        uidState.state, AppOpsManager.OP_FLAG_SELF);
 
-                // TODO moltmann: call back when a feature became inactive
-                if (uidState.startNesting == 0) {
-                    scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
-                }
+            try {
+                featureOp.started(clientId, uidState.state);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
             }
-            featureOp.startNesting++;
-            uidState.startNesting++;
-            client.mStartedOps.add(new Pair<>(op, featureId));
         }
 
         return AppOpsManager.MODE_ALLOWED;
     }
 
     @Override
-    public void finishOperation(IBinder token, int code, int uid, String packageName,
+    public void finishOperation(IBinder clientId, int code, int uid, String packageName,
             String featureId) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
@@ -2596,10 +2668,6 @@
         if (resolvedPackageName == null) {
             return;
         }
-        if (!(token instanceof ClientState)) {
-            return;
-        }
-        ClientState client = (ClientState) token;
 
         boolean isPrivileged;
         try {
@@ -2619,36 +2687,13 @@
                 return;
             }
 
-            if (client.mStartedOps.remove(new Pair<>(op, featureId))) {
-                finishOperationLocked(op, featureId, /*finishNested*/ false);
-
-                // TODO moltmann: call back when a feature became inactive
-                if (op.uidState.startNesting <= 0) {
-                    scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
-                }
-
-                return;
+            try {
+                featureOp.finished(clientId);
+            } catch (IllegalStateException e) {
+                Slog.e(TAG, "Operation not started: uid=" + uid + " pkg="
+                        + packageName + " op=" + AppOpsManager.opToName(code), e);
             }
         }
-
-        // We finish ops when packages get removed to guarantee no dangling
-        // started ops. However, some part of the system may asynchronously
-        // finish ops for an already gone package. Hence, finishing an op
-        // for a non existing package is fine and we don't log as a wtf.
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
-                    resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
-                Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
-                        + " for non-existing package=" + resolvedPackageName
-                        + " in uid=" + uid);
-                return;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-        Slog.wtf(TAG, "Operation not started: uid=" + uid + " pkg="
-                + packageName + " op=" + AppOpsManager.opToName(code));
     }
 
     private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
@@ -2769,38 +2814,6 @@
         return permInfo.getProtection() == PROTECTION_DANGEROUS;
     }
 
-    void finishOperationLocked(@NonNull Op op, @Nullable String featureId, boolean finishNested) {
-        final FeatureOp featureOp = op.mFeatures.get(featureId);
-        final int opCode = featureOp.parent.op;
-        final int uid = featureOp.parent.uidState.uid;
-        if (featureOp.startNesting <= 1 || finishNested) {
-            if (featureOp.startNesting == 1 || finishNested) {
-                // We don't support proxy long running ops (start/stop)
-                final long duration = SystemClock.elapsedRealtime() - featureOp.startRealtime;
-                featureOp.finished(System.currentTimeMillis(), duration, op.uidState.state,
-                        AppOpsManager.OP_FLAG_SELF);
-                mHistoricalRegistry.increaseOpAccessDuration(opCode, uid, op.packageName,
-                        op.uidState.state, AppOpsManager.OP_FLAG_SELF, duration);
-            } else {
-                final OpFeatureEntry entry = op.createSingleFeatureEntryLocked(
-                        featureId).getFeatures().get(featureId);
-                Slog.w(TAG, "Finishing op nesting under-run: uid " + uid + " pkg "
-                        + op.packageName + " code " + opCode + " time="
-                        + entry.getLastAccessTime(OP_FLAGS_ALL)
-                        + " duration=" + entry.getLastDuration(MAX_PRIORITY_UID_STATE,
-                        MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL) + " nesting="
-                        + featureOp.startNesting);
-            }
-            if (featureOp.startNesting >= 1) {
-                op.uidState.startNesting -= featureOp.startNesting;
-            }
-            featureOp.startNesting = 0;
-        } else {
-            featureOp.startNesting--;
-            op.uidState.startNesting--;
-        }
-    }
-
     private void verifyIncomingUid(int uid) {
         if (uid == Binder.getCallingUid()) {
             return;
@@ -3064,7 +3077,7 @@
             if (!edit) {
                 return null;
             }
-            op = new Op(ops.uidState, ops.packageName, code);
+            op = new Op(ops.uidState, ops.packageName, code, ops.uidState.uid);
             ops.put(code, op);
         }
         if (edit) {
@@ -3208,7 +3221,7 @@
                     final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
                     if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
                         final Op copy = new Op(op.uidState, op.packageName,
-                            AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
+                                AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uidState.uid);
                         copy.mode = op.mode;
                         ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
                         changed = true;
@@ -3336,25 +3349,22 @@
         final FeatureOp featureOp = parent.getOrCreateFeature(parent, feature);
 
         final long key = XmlUtils.readLongAttribute(parser, "n");
-
-        final int flags = AppOpsManager.extractFlagsFromKey(key);
-        final int state = AppOpsManager.extractUidStateFromKey(key);
+        final int uidState = extractUidStateFromKey(key);
+        final int opFlags = extractFlagsFromKey(key);
 
         final long accessTime = XmlUtils.readLongAttribute(parser, "t", 0);
         final long rejectTime = XmlUtils.readLongAttribute(parser, "r", 0);
-        final long accessDuration = XmlUtils.readLongAttribute(parser, "d", 0);
+        final long accessDuration = XmlUtils.readLongAttribute(parser, "d", -1);
         final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp");
-        final int proxyUid = XmlUtils.readIntAttribute(parser, "pu", 0);
+        final int proxyUid = XmlUtils.readIntAttribute(parser, "pu", Process.INVALID_UID);
         final String proxyFeatureId = XmlUtils.readStringAttribute(parser, "pc");
 
         if (accessTime > 0) {
-            featureOp.accessed(accessTime, proxyUid, proxyPkg, proxyFeatureId, state, flags);
+            featureOp.accessed(accessTime, accessDuration, proxyUid, proxyPkg, proxyFeatureId,
+                    uidState, opFlags);
         }
         if (rejectTime > 0) {
-            featureOp.rejected(rejectTime, proxyUid, proxyPkg, proxyFeatureId, state, flags);
-        }
-        if (accessDuration > 0) {
-            featureOp.running(accessTime, accessDuration, state, flags);
+            featureOp.rejected(rejectTime, uidState, opFlags);
         }
     }
 
@@ -3362,7 +3372,8 @@
         @NonNull String pkgName, boolean isPrivileged) throws NumberFormatException,
         XmlPullParserException, IOException {
         Op op = new Op(uidState, pkgName,
-                Integer.parseInt(parser.getAttributeValue(null, "n")));
+                Integer.parseInt(parser.getAttributeValue(null, "n")),
+                uidState.uid);
 
         final int mode = XmlUtils.readIntAttribute(parser, "m",
                 AppOpsManager.opToDefaultMode(op.op));
@@ -3496,35 +3507,39 @@
                                 final OpFeatureEntry feature = op.getFeatures().get(
                                         featureId);
 
-                                final LongSparseArray keys = feature.collectKeys();
-                                if (keys == null || keys.size() <= 0) {
-                                    continue;
-                                }
-                                final int keyCount = keys.size();
+                                final ArraySet<Long> keys = feature.collectKeys();
 
+                                final int keyCount = keys.size();
                                 for (int k = 0; k < keyCount; k++) {
-                                    final long key = keys.keyAt(k);
+                                    final long key = keys.valueAt(k);
 
                                     final int uidState = AppOpsManager.extractUidStateFromKey(key);
                                     final int flags = AppOpsManager.extractFlagsFromKey(key);
 
-                                    final long accessTime = feature.getLastAccessTime(
-                                            uidState, uidState, flags);
-                                    final long rejectTime = feature.getLastRejectTime(
-                                            uidState, uidState, flags);
-                                    final long accessDuration = feature.getLastDuration(
-                                            uidState, uidState, flags);
-                                    final String proxyPkg = feature.getProxyPackageName(uidState,
-                                            flags);
-                                    final String proxyFeatureId = feature.getProxyFeatureId(
+                                    final long accessTime = feature.getLastAccessTime(uidState,
                                             uidState, flags);
-                                    final int proxyUid = feature.getProxyUid(uidState, flags);
+                                    final long rejectTime = feature.getLastRejectTime(uidState,
+                                            uidState, flags);
+                                    final long accessDuration = feature.getLastDuration(uidState,
+                                            uidState, flags);
+                                    // Proxy information for rejections is not backed up
+                                    final OpEventProxyInfo proxy = feature.getLastProxyInfo(
+                                            uidState, uidState, flags);
 
                                     if (accessTime <= 0 && rejectTime <= 0 && accessDuration <= 0
-                                            && proxyPkg == null && proxyUid < 0) {
+                                            && proxy == null) {
                                         continue;
                                     }
 
+                                    String proxyPkg = null;
+                                    String proxyFeatureId = null;
+                                    int proxyUid = Process.INVALID_UID;
+                                    if (proxy != null) {
+                                        proxyPkg = proxy.getPackageName();
+                                        proxyFeatureId = proxy.getFeatureId();
+                                        proxyUid = proxy.getUid();
+                                    }
+
                                     out.startTag(null, "st");
                                     if (featureId != null) {
                                         out.attribute(null, "id", featureId);
@@ -3591,10 +3606,7 @@
         Shell(IAppOpsService iface, AppOpsService internal) {
             mInterface = iface;
             mInternal = internal;
-            try {
-                mToken = mInterface.getToken(sBinder);
-            } catch (RemoteException e) {
-            }
+            mToken = AppOpsManager.getClientId();
         }
 
         @Override
@@ -3889,42 +3901,48 @@
                             pw.print(": ");
                             pw.print(AppOpsManager.modeToName(ent.getMode()));
                             if (shell.featureId == null) {
-                                if (ent.getTime() != 0) {
+                                if (ent.getLastAccessTime(OP_FLAGS_ALL) != -1) {
                                     pw.print("; time=");
-                                    TimeUtils.formatDuration(now - ent.getTime(), pw);
+                                    TimeUtils.formatDuration(
+                                            now - ent.getLastAccessTime(OP_FLAGS_ALL), pw);
                                     pw.print(" ago");
                                 }
-                                if (ent.getRejectTime() != 0) {
+                                if (ent.getLastRejectTime(OP_FLAGS_ALL) != -1) {
                                     pw.print("; rejectTime=");
-                                    TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
+                                    TimeUtils.formatDuration(
+                                            now - ent.getLastRejectTime(OP_FLAGS_ALL), pw);
                                     pw.print(" ago");
                                 }
-                                if (ent.getDuration() == -1) {
+                                if (ent.isRunning()) {
                                     pw.print(" (running)");
-                                } else if (ent.getDuration() != 0) {
+                                } else if (ent.getLastDuration(OP_FLAGS_ALL) != -1) {
                                     pw.print("; duration=");
-                                    TimeUtils.formatDuration(ent.getDuration(), pw);
+                                    TimeUtils.formatDuration(ent.getLastDuration(OP_FLAGS_ALL), pw);
                                 }
                             } else {
                                 final OpFeatureEntry featureEnt = ent.getFeatures().get(
                                         shell.featureId);
                                 if (featureEnt != null) {
-                                    if (featureEnt.getTime() != 0) {
+                                    if (featureEnt.getLastAccessTime(OP_FLAGS_ALL) != -1) {
                                         pw.print("; time=");
-                                        TimeUtils.formatDuration(now - featureEnt.getTime(), pw);
+                                        TimeUtils.formatDuration(now - featureEnt.getLastAccessTime(
+                                                OP_FLAGS_ALL), pw);
                                         pw.print(" ago");
                                     }
-                                    if (featureEnt.getRejectTime() != 0) {
+                                    if (featureEnt.getLastRejectTime(OP_FLAGS_ALL) != -1) {
                                         pw.print("; rejectTime=");
-                                        TimeUtils.formatDuration(now - featureEnt.getRejectTime(),
+                                        TimeUtils.formatDuration(
+                                                now - featureEnt.getLastRejectTime(OP_FLAGS_ALL),
                                                 pw);
                                         pw.print(" ago");
                                     }
-                                    if (featureEnt.getDuration() == -1) {
+                                    if (featureEnt.isRunning()) {
                                         pw.print(" (running)");
-                                    } else if (featureEnt.getDuration() != 0) {
+                                    } else if (featureEnt.getLastDuration(OP_FLAGS_ALL)
+                                            != -1) {
                                         pw.print("; duration=");
-                                        TimeUtils.formatDuration(featureEnt.getDuration(), pw);
+                                        TimeUtils.formatDuration(
+                                                featureEnt.getLastDuration(OP_FLAGS_ALL), pw);
                                     }
                                 }
                             }
@@ -4095,27 +4113,28 @@
         final OpFeatureEntry entry = op.createSingleFeatureEntryLocked(
                 featureId).getFeatures().get(featureId);
 
-        final LongSparseArray keys = entry.collectKeys();
-        if (keys == null || keys.size() <= 0) {
-            return;
-        }
+        final ArraySet<Long> keys = entry.collectKeys();
 
         final int keyCount = keys.size();
         for (int k = 0; k < keyCount; k++) {
-            final long key = keys.keyAt(k);
+            final long key = keys.valueAt(k);
 
             final int uidState = AppOpsManager.extractUidStateFromKey(key);
             final int flags = AppOpsManager.extractFlagsFromKey(key);
 
-            final long accessTime = entry.getLastAccessTime(
-                    uidState, uidState, flags);
-            final long rejectTime = entry.getLastRejectTime(
-                    uidState, uidState, flags);
-            final long accessDuration = entry.getLastDuration(
-                    uidState, uidState, flags);
-            final String proxyPkg = entry.getProxyPackageName(uidState, flags);
-            final String proxyFeatureId = entry.getProxyFeatureId(uidState, flags);
-            final int proxyUid = entry.getProxyUid(uidState, flags);
+            final long accessTime = entry.getLastAccessTime(uidState, uidState, flags);
+            final long rejectTime = entry.getLastRejectTime(uidState, uidState, flags);
+            final long accessDuration = entry.getLastDuration(uidState, uidState, flags);
+            final OpEventProxyInfo proxy = entry.getLastProxyInfo(uidState, uidState, flags);
+
+            String proxyPkg = null;
+            String proxyFeatureId = null;
+            int proxyUid = Process.INVALID_UID;
+            if (proxy != null) {
+                proxyPkg = proxy.getPackageName();
+                proxyFeatureId = proxy.getFeatureId();
+                proxyUid = proxy.getUid();
+            }
 
             if (accessTime > 0) {
                 pw.print(prefix);
@@ -4168,14 +4187,25 @@
         }
 
         final FeatureOp featureOp = op.mFeatures.get(featureId);
-        if (featureOp.running) {
+        if (featureOp.isRunning()) {
+            long earliestStartTime = Long.MAX_VALUE;
+            long maxNumStarts = 0;
+            int numInProgressEvents = featureOp.mInProgressEvents.size();
+            for (int i = 0; i < numInProgressEvents; i++) {
+                InProgressStartOpEvent event = featureOp.mInProgressEvents.valueAt(i);
+
+                earliestStartTime = Math.min(earliestStartTime, event.startTime);
+                maxNumStarts = Math.max(maxNumStarts, event.numUnfinishedStarts);
+            }
+
             pw.print(prefix + "Running start at: ");
-            TimeUtils.formatDuration(nowElapsed - featureOp.startRealtime, pw);
+            TimeUtils.formatDuration(nowElapsed - earliestStartTime, pw);
             pw.println();
-        }
-        if (featureOp.startNesting != 0) {
-            pw.print(prefix + "startNesting=");
-            pw.println(featureOp.startNesting);
+
+            if (maxNumStarts > 1) {
+                pw.print(prefix + "startNesting=");
+                pw.println(maxNumStarts);
+            }
         }
     }
 
@@ -4423,44 +4453,6 @@
                     pw.println(cb);
                 }
             }
-            if (mClients.size() > 0 && dumpMode < 0 && !dumpWatchers && !dumpHistory) {
-                needSep = true;
-                boolean printedHeader = false;
-                for (int i=0; i<mClients.size(); i++) {
-                    boolean printedClient = false;
-                    ClientState cs = mClients.valueAt(i);
-                    if (cs.mStartedOps.size() > 0) {
-                        boolean printedStarted = false;
-                        for (int j=0; j<cs.mStartedOps.size(); j++) {
-                            final Pair<Op, String> startedOp = cs.mStartedOps.get(j);
-                            final Op op = startedOp.first;
-                            if (dumpOp >= 0 && op.op != dumpOp) {
-                                continue;
-                            }
-                            if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
-                                continue;
-                            }
-                            if (!printedHeader) {
-                                pw.println("  Clients:");
-                                printedHeader = true;
-                            }
-                            if (!printedClient) {
-                                pw.print("    "); pw.print(mClients.keyAt(i)); pw.println(":");
-                                pw.print("      "); pw.println(cs);
-                                printedClient = true;
-                            }
-                            if (!printedStarted) {
-                                pw.println("      Started ops:");
-                                printedStarted = true;
-                            }
-                            pw.print("        "); pw.print("uid="); pw.print(op.uidState.uid);
-                            pw.print(" pkg="); pw.print(op.packageName);
-                            pw.print(" featureId="); pw.print(startedOp.second);
-                            pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
-                        }
-                    }
-                }
-            }
             if (mAudioRestrictionManager.hasActiveRestrictions() && dumpOp < 0
                     && dumpPackage != null && dumpMode < 0 && !dumpWatchers && !dumpWatchers) {
                 needSep = mAudioRestrictionManager.dump(pw) | needSep ;
@@ -4536,10 +4528,6 @@
                     TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
                     pw.println();
                 }
-                if (uidState.startNesting != 0) {
-                    pw.print("    startNesting=");
-                    pw.println(uidState.startNesting);
-                }
                 if (uidState.foregroundOps != null && (dumpMode < 0
                         || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
                     pw.println("    foregroundOps:");
@@ -4813,17 +4801,18 @@
         }
         // TODO moltmann: Allow to check for feature op activeness
         synchronized (AppOpsService.this) {
-            for (int i = mClients.size() - 1; i >= 0; i--) {
-                final ClientState client = mClients.valueAt(i);
-                for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
-                    final Pair<Op, String> startedOp = client.mStartedOps.get(j);
-                    if (startedOp.first.op == code && startedOp.first.uidState.uid == uid) {
-                        return true;
-                    }
-                }
+            Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false, false);
+            if (pkgOps == null) {
+                return false;
             }
+
+            Op op = pkgOps.get(code);
+            if (op == null) {
+                return false;
+            }
+
+            return op.isRunning();
         }
-        return false;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 352d0d5..21c4784 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -241,15 +241,17 @@
                 } else {
                     makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
                 }
+            } else if (state == BluetoothProfile.STATE_CONNECTED) {
+                // device is not already connected
+                if (a2dpVolume != -1) {
+                    mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
+                            // convert index to internal representation in VolumeStreamState
+                            a2dpVolume * 10,
+                            AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState");
+                }
+                makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice),
+                        "onSetA2dpSinkConnectionState", a2dpCodec);
             }
-            if (a2dpVolume != -1) {
-                mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
-                        // convert index to internal representation in VolumeStreamState
-                        a2dpVolume * 10,
-                        AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState");
-            }
-            makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice),
-                    "onSetA2dpSinkConnectionState", a2dpCodec);
         }
     }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 335cac8..21cecc2 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -310,7 +310,8 @@
         7,  // STREAM_SYSTEM_ENFORCED
         15, // STREAM_DTMF
         15, // STREAM_TTS
-        15  // STREAM_ACCESSIBILITY
+        15, // STREAM_ACCESSIBILITY
+        15  // STREAM_ASSISTANT
     };
 
     /** Minimum volume index values for audio streams */
@@ -325,7 +326,8 @@
         0,  // STREAM_SYSTEM_ENFORCED
         0,  // STREAM_DTMF
         0,  // STREAM_TTS
-        1   // STREAM_ACCESSIBILITY
+        1,  // STREAM_ACCESSIBILITY
+        0   // STREAM_ASSISTANT
     };
 
     /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
@@ -348,7 +350,8 @@
         AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
         AudioSystem.STREAM_RING,            // STREAM_DTMF
         AudioSystem.STREAM_MUSIC,           // STREAM_TTS
-        AudioSystem.STREAM_MUSIC            // STREAM_ACCESSIBILITY
+        AudioSystem.STREAM_MUSIC,           // STREAM_ACCESSIBILITY
+        AudioSystem.STREAM_MUSIC            // STREAM_ASSISTANT
     };
     private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
         AudioSystem.STREAM_MUSIC,       // STREAM_VOICE_CALL
@@ -361,7 +364,8 @@
         AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM_ENFORCED
         AudioSystem.STREAM_MUSIC,       // STREAM_DTMF
         AudioSystem.STREAM_MUSIC,       // STREAM_TTS
-        AudioSystem.STREAM_MUSIC        // STREAM_ACCESSIBILITY
+        AudioSystem.STREAM_MUSIC,       // STREAM_ACCESSIBILITY
+        AudioSystem.STREAM_MUSIC        // STREAM_ASSISTANT
     };
     private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
         AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
@@ -374,7 +378,8 @@
         AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
         AudioSystem.STREAM_RING,            // STREAM_DTMF
         AudioSystem.STREAM_MUSIC,           // STREAM_TTS
-        AudioSystem.STREAM_MUSIC            // STREAM_ACCESSIBILITY
+        AudioSystem.STREAM_MUSIC,           // STREAM_ACCESSIBILITY
+        AudioSystem.STREAM_MUSIC            // STREAM_ASSISTANT
     };
     protected static int[] mStreamVolumeAlias;
 
@@ -394,6 +399,7 @@
         AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_DTMF
         AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_TTS
         AppOpsManager.OP_AUDIO_ACCESSIBILITY_VOLUME,    // STREAM_ACCESSIBILITY
+        AppOpsManager.OP_AUDIO_MEDIA_VOLUME             // STREAM_ASSISTANT
     };
 
     private final boolean mUseFixedVolume;
@@ -1253,6 +1259,9 @@
         int dtmfStreamAlias;
         final int a11yStreamAlias = sIndependentA11yVolume ?
                 AudioSystem.STREAM_ACCESSIBILITY : AudioSystem.STREAM_MUSIC;
+        final int assistantStreamAlias = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_useAssistantVolume) ?
+                AudioSystem.STREAM_ASSISTANT : AudioSystem.STREAM_MUSIC;
 
         if (mIsSingleVolume) {
             mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
@@ -1282,6 +1291,7 @@
 
         mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
         mStreamVolumeAlias[AudioSystem.STREAM_ACCESSIBILITY] = a11yStreamAlias;
+        mStreamVolumeAlias[AudioSystem.STREAM_ASSISTANT] = assistantStreamAlias;
 
         if (updateVolumes && mStreamStates != null) {
             updateDefaultVolumes();
@@ -1808,6 +1818,17 @@
             return;
         }
 
+        // If the stream is STREAM_ASSISTANT,
+        // make sure that the calling app have the MODIFY_AUDIO_ROUTING permission.
+        if (streamType == AudioSystem.STREAM_ASSISTANT &&
+            mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+                    != PackageManager.PERMISSION_GRANTED) {
+            Log.w(TAG, "MODIFY_AUDIO_ROUTING Permission Denial: adjustStreamVolume from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
+            return;
+        }
+
         // use stream type alias here so that streams with same alias have the same behavior,
         // including with regard to silent mode control (e.g the use of STREAM_RING below and in
         // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
@@ -2244,6 +2265,14 @@
                     + " MODIFY_PHONE_STATE  callingPackage=" + callingPackage);
             return;
         }
+        if ((streamType == AudioManager.STREAM_ASSISTANT)
+            && (mContext.checkCallingOrSelfPermission(
+                    android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+                    != PackageManager.PERMISSION_GRANTED)) {
+            Log.w(TAG, "Trying to call setStreamVolume() for STREAM_ASSISTANT without"
+                    + " MODIFY_AUDIO_ROUTING  callingPackage=" + callingPackage);
+            return;
+        }
         sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType,
                 index/*val1*/, flags/*val2*/, callingPackage));
         setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
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 789551b..3049522 100644
--- a/services/core/java/com/android/server/incremental/IncrementalManagerService.java
+++ b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
@@ -67,13 +67,14 @@
         mDataLoaderManager = mContext.getSystemService(DataLoaderManager.class);
         ServiceManager.addService(BINDER_SERVICE_NAME, this);
         // Starts and register IIncrementalManagerNative service
-        // TODO(b/136132412): add jni implementation
+        mNativeInstance = nativeStartService();
     }
+
     /**
      * Notifies native IIncrementalManager service that system is ready.
      */
     public void systemReady() {
-        // TODO(b/136132412): add jni implementation
+        nativeSystemReady(mNativeInstance);
     }
 
     /**
@@ -152,4 +153,8 @@
         (new IncrementalManagerShellCommand(mContext)).exec(
                 this, in, out, err, args, callback, resultReceiver);
     }
+
+    private static native long nativeStartService();
+
+    private static native void nativeSystemReady(long nativeInstance);
 }
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/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 252ee1d..5865dc4 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3449,7 +3449,7 @@
     }
 
     /**
-     * This is kept due to {@link android.compat.annotation.UnsupportedAppUsage} in
+     * This is kept due to {@link android.annotation.UnsupportedAppUsage} in
      * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in
      * {@link InputMethodService#onCreate()}.
      *
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java
index 61dddf0..7d5e836 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java
@@ -30,6 +30,7 @@
 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 {
@@ -37,23 +38,29 @@
     private static final String DEFAULT_RULE_KEY = "N/A";
 
     /**
-     * Splits a given rule list into three indexing categories.
+     * Splits a given rule list into three indexing categories and returns a sorted list of rules
+     * per each index.
      *
-     * TODO(b/145488708): Instead of this structure, sort the values in the map and just return a
-     * sorted list.
+     * 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, Map<String, List<Rule>>> splitRulesIntoIndexBuckets(
-            List<Rule> rules) {
+    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 HashMap());
-        typeOrganizedRuleMap.put(PACKAGE_NAME_INDEXED, new HashMap());
-        typeOrganizedRuleMap.put(APP_CERTIFICATE_INDEXED, 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 =
@@ -73,7 +80,19 @@
                     .add(rule);
         }
 
-        return typeOrganizedRuleMap;
+        // 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) {
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/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 eb4b593..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;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index cb362b0..0e9199f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -96,6 +96,8 @@
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
+import static com.android.internal.util.ArrayUtils.emptyIfNull;
+import static com.android.internal.util.ArrayUtils.filter;
 import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
@@ -249,7 +251,6 @@
 import android.os.storage.VolumeRecord;
 import android.permission.IPermissionManager;
 import android.provider.DeviceConfig;
-import android.provider.MediaStore;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
 import android.security.KeyStore;
@@ -385,6 +386,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 /**
@@ -16629,37 +16631,48 @@
                 + " Activities needs verification ...");
 
         int count = 0;
-
+        boolean handlesWebUris = false;
+        final boolean alreadyVerified;
         synchronized (mLock) {
             // If this is a new install and we see that we've already run verification for this
             // package, we have nothing to do: it means the state was restored from backup.
-            if (!replacing) {
-                IntentFilterVerificationInfo ivi =
-                        mSettings.getIntentFilterVerificationLPr(packageName);
-                if (ivi != null) {
-                    if (DEBUG_DOMAIN_VERIFICATION) {
-                        Slog.i(TAG, "Package " + packageName+ " already verified: status="
-                                + ivi.getStatusString());
-                    }
-                    return;
+            final IntentFilterVerificationInfo ivi =
+                    mSettings.getIntentFilterVerificationLPr(packageName);
+            alreadyVerified = (ivi != null);
+            if (!replacing && alreadyVerified) {
+                if (DEBUG_DOMAIN_VERIFICATION) {
+                    Slog.i(TAG, "Package " + packageName + " already verified: status="
+                            + ivi.getStatusString());
                 }
+                return;
             }
 
-            // If any filters need to be verified, then all need to be.
+            // If any filters need to be verified, then all need to be.  In addition, we need to
+            // know whether an updating app has any web navigation intent filters, to re-
+            // examine handling policy even if not re-verifying.
             boolean needToVerify = false;
             for (ParsedActivity a : activities) {
                 for (ParsedActivityIntentInfo filter : a.intents) {
+                    if (filter.handlesWebUris(true)) {
+                        handlesWebUris = true;
+                    }
                     if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) {
                         if (DEBUG_DOMAIN_VERIFICATION) {
                             Slog.d(TAG,
                                     "Intent filter needs verification, so processing all filters");
                         }
                         needToVerify = true;
+                        // It's safe to break out here because filter.needsVerification()
+                        // can only be true if filter.handlesWebUris(true) returns true, so
+                        // we've already noted that.
                         break;
                     }
                 }
             }
 
+            // Note whether this app publishes any web navigation handling support at all,
+            // and whether there are any web-nav filters that fit the profile for running
+            // a verification pass now.
             if (needToVerify) {
                 final int verificationId = mIntentFilterVerificationToken++;
                 for (ParsedActivity a : activities) {
@@ -16677,13 +16690,23 @@
         }
 
         if (count > 0) {
+            // count > 0 means that we're running a full verification pass
             if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Starting " + count
                     + " IntentFilter verification" + (count > 1 ? "s" : "")
                     +  " for userId:" + userId);
             mIntentFilterVerifier.startVerifications(userId);
+        } else if (alreadyVerified && handlesWebUris) {
+            // App used autoVerify in the past, no longer does, but still handles web
+            // navigation starts.
+            if (DEBUG_DOMAIN_VERIFICATION) {
+                Slog.d(TAG, "App changed web filters but no longer verifying - resetting policy");
+            }
+            synchronized (mLock) {
+                clearIntentFilterVerificationsLPw(packageName, userId);
+            }
         } else {
             if (DEBUG_DOMAIN_VERIFICATION) {
-                Slog.d(TAG, "No filters or not all autoVerify for " + packageName);
+                Slog.d(TAG, "No web filters or no prior verify policy for " + packageName);
             }
         }
     }
@@ -19261,6 +19284,18 @@
         return ensureSystemPackageName(appPredictionServiceComponentName.getPackageName());
     }
 
+    private @NonNull String[] dropNonSystemPackages(@NonNull String[] pkgNames) {
+        return emptyIfNull(filter(pkgNames, String[]::new, mIsSystemPackage), String.class);
+    }
+
+    private Predicate<String> mIsSystemPackage = (pkgName) -> {
+        if ("android".equals(pkgName)) {
+            return true;
+        }
+        AndroidPackage pkg = mPackages.get(pkgName);
+        return pkg != null && pkg.isSystem();
+    };
+
     @Override
     public String getSystemCaptionsServicePackageName() {
         String flattenedSystemCaptionsServiceComponentName =
@@ -22539,7 +22574,11 @@
 
         @Override
         public @NonNull String[] getKnownPackageNames(int knownPackage, int userId) {
-            switch (knownPackage) {
+            return dropNonSystemPackages(getKnownPackageNamesInternal(knownPackage, userId));
+        }
+
+        private String[] getKnownPackageNamesInternal(int knownPackage, int userId) {
+            switch(knownPackage) {
                 case PackageManagerInternal.PACKAGE_BROWSER:
                     return new String[]{mPermissionManager.getDefaultBrowser(userId)};
                 case PackageManagerInternal.PACKAGE_INSTALLER:
@@ -22566,6 +22605,8 @@
                     return filterOnlySystemPackages(mAppPredictionServicePackage);
                 case PackageManagerInternal.PACKAGE_TELEPHONY:
                     return filterOnlySystemPackages(mTelephonyPackages);
+                case PackageManagerInternal.PACKAGE_COMPANION:
+                    return filterOnlySystemPackages("com.android.companiondevicemanager");
                 default:
                     return ArrayUtils.emptyArray(String.class);
             }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6653011..9642a1a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1249,6 +1249,7 @@
             return false;
         }
         ps.clearDomainVerificationStatusForUser(userId);
+        ps.setIntentFilterVerificationInfo(null);
         return true;
     }
 
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 3515cb7..5854e32 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3977,6 +3977,10 @@
 
     @Override
     public boolean isUserNameSet(@UserIdInt int userId) {
+        if (!hasManageUsersOrPermission(android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED)) {
+            throw new SecurityException("You need MANAGE_USERS or GET_ACCOUNTS_PRIVILEGED "
+                    + "permissions to: get whether user name is set");
+        }
         synchronized (mUsersLock) {
             final UserInfo userInfo = getUserInfoLU(userId);
             return userInfo != null && userInfo.name != null;
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/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 05545cd..565a85f 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -280,6 +280,9 @@
     public boolean isTelephony() {
         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_TELEPHONY) != 0;
     }
+    public boolean isCompanion() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_COMPANION) != 0;
+    }
 
     public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
         if (!origPackageName.equals(sourcePackageName)) {
diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
new file mode 100644
index 0000000..b809951
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
@@ -0,0 +1,281 @@
+/*
+ * 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.pm.permission;
+
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED;
+
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.permission.PermissionControllerManager;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * Class that handles one-time permissions for a user
+ */
+public class OneTimePermissionUserManager {
+
+    private static final String LOG_TAG = OneTimePermissionUserManager.class.getSimpleName();
+
+    private final @NonNull Context mContext;
+    private final @NonNull ActivityManager mActivityManager;
+    private final @NonNull AlarmManager mAlarmManager;
+    private final @NonNull PermissionControllerManager mPermissionControllerManager;
+
+    private final Object mLock = new Object();
+
+    /** Maps the uid to the PackageInactivityListener */
+    @GuardedBy("mLock")
+    private final SparseArray<PackageInactivityListener> mListeners = new SparseArray<>();
+
+    OneTimePermissionUserManager(@NonNull Context context) {
+        mContext = context;
+        mActivityManager = context.getSystemService(ActivityManager.class);
+        mAlarmManager = context.getSystemService(AlarmManager.class);
+        mPermissionControllerManager = context.getSystemService(PermissionControllerManager.class);
+    }
+
+    /**
+     * Starts a one-time permission session for a given package. A one-time permission session is
+     * ended if app becomes inactive. Inactivity is defined as the package's uid importance level
+     * staying > importanceToResetTimer for timeoutMillis milliseconds. If the package's uid
+     * importance level goes <= importanceToResetTimer then the timer is reset and doesn't start
+     * until going > importanceToResetTimer.
+     * <p>
+     * When this timeoutMillis is reached if the importance level is <= importanceToKeepSessionAlive
+     * then the session is extended until either the importance goes above
+     * importanceToKeepSessionAlive which will end the session or <= importanceToResetTimer which
+     * will continue the session and reset the timer.
+     * </p>
+     * <p>
+     * Importance levels are defined in {@link android.app.ActivityManager.RunningAppProcessInfo}.
+     * </p>
+     * <p>
+     * Once the session ends PermissionControllerService#onNotifyOneTimePermissionSessionTimeout
+     * is invoked.
+     * </p>
+     * <p>
+     * Note that if there is currently an active session for a package a new one isn't created and
+     * the existing one isn't changed.
+     * </p>
+     * @param packageName The package to start a one-time permission session for
+     * @param timeoutMillis Number of milliseconds for an app to be in an inactive state
+     * @param importanceToResetTimer The least important level to uid must be to reset the timer
+     * @param importanceToKeepSessionAlive The least important level the uid must be to keep the
+     *                                    session alive
+     *
+     * @hide
+     */
+    void startPackageOneTimeSession(@NonNull String packageName, long timeoutMillis,
+            int importanceToResetTimer, int importanceToKeepSessionAlive) {
+        int uid;
+        try {
+            uid = mContext.getPackageManager().getPackageUid(packageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(LOG_TAG, "Unknown package name " + packageName, e);
+            return;
+        }
+
+        synchronized (mLock) {
+            PackageInactivityListener listener = mListeners.get(uid);
+            if (listener == null) {
+                listener = new PackageInactivityListener(uid, packageName, timeoutMillis,
+                        importanceToResetTimer, importanceToKeepSessionAlive);
+                mListeners.put(uid, listener);
+            }
+        }
+    }
+
+    /**
+     * Stops the one-time permission session for the package. The callback to the end of session is
+     * not invoked. If there is no one-time session for the package then nothing happens.
+     *
+     * @param packageName Package to stop the one-time permission session for
+     */
+    void stopPackageOneTimeSession(@NonNull String packageName) {
+        int uid;
+        try {
+            uid = mContext.getPackageManager().getPackageUid(packageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(LOG_TAG, "Unknown package name " + packageName, e);
+            return;
+        }
+
+        synchronized (mLock) {
+            PackageInactivityListener listener = mListeners.get(uid);
+            if (listener != null) {
+                mListeners.remove(uid);
+                listener.cancel();
+            }
+        }
+    }
+
+    /**
+     * A class which watches a package for inactivity and notifies the permission controller when
+     * the package becomes inactive
+     */
+    private class PackageInactivityListener implements AlarmManager.OnAlarmListener {
+
+        private static final long TIMER_INACTIVE = -1;
+
+        private final int mUid;
+        private final @NonNull String mPackageName;
+        private final long mTimeout;
+        private final int mImportanceToResetTimer;
+        private final int mImportanceToKeepSessionAlive;
+
+        private boolean mIsAlarmSet;
+        private boolean mIsFinished;
+
+        private long mTimerStart = TIMER_INACTIVE;
+
+        private final ActivityManager.OnUidImportanceListener mStartTimerListener;
+        private final ActivityManager.OnUidImportanceListener mSessionKillableListener;
+        private final ActivityManager.OnUidImportanceListener mGoneListener;
+
+        private final Object mInnerLock = new Object();
+
+        private PackageInactivityListener(int uid, @NonNull String packageName, long timeout,
+                int importanceToResetTimer, int importanceToKeepSessionAlive) {
+            mUid = uid;
+            mPackageName = packageName;
+            mTimeout = timeout;
+            mImportanceToResetTimer = importanceToResetTimer;
+            mImportanceToKeepSessionAlive = importanceToKeepSessionAlive;
+
+            mStartTimerListener =
+                    (changingUid, importance) -> onImportanceChanged(changingUid, importance);
+            mSessionKillableListener =
+                    (changingUid, importance) -> onImportanceChanged(changingUid, importance);
+            mGoneListener =
+                    (changingUid, importance) -> onImportanceChanged(changingUid, importance);
+
+            mActivityManager.addOnUidImportanceListener(mStartTimerListener,
+                    importanceToResetTimer);
+            mActivityManager.addOnUidImportanceListener(mSessionKillableListener,
+                    importanceToKeepSessionAlive);
+            mActivityManager.addOnUidImportanceListener(mGoneListener, IMPORTANCE_CACHED);
+
+            onImportanceChanged(mUid, mActivityManager.getPackageImportance(packageName));
+        }
+
+        private void onImportanceChanged(int uid, int importance) {
+            if (uid != mUid) {
+                return;
+            }
+            synchronized (mInnerLock) {
+                if (importance > IMPORTANCE_CACHED) {
+                    onPackageInactiveLocked();
+                    return;
+                }
+                if (importance > mImportanceToResetTimer) {
+                    if (mTimerStart == TIMER_INACTIVE) {
+                        mTimerStart = System.currentTimeMillis();
+                    }
+                } else {
+                    mTimerStart = TIMER_INACTIVE;
+                }
+                if (importance > mImportanceToKeepSessionAlive) {
+                    setAlarmLocked();
+                } else {
+                    cancelAlarmLocked();
+                }
+            }
+        }
+
+        /**
+         * Stop watching the package for inactivity
+         */
+        private void cancel() {
+            synchronized (mInnerLock) {
+                mIsFinished = true;
+                cancelAlarmLocked();
+                mActivityManager.removeOnUidImportanceListener(mStartTimerListener);
+                mActivityManager.removeOnUidImportanceListener(mSessionKillableListener);
+                mActivityManager.removeOnUidImportanceListener(mGoneListener);
+            }
+        }
+
+        /**
+         * Set the alarm which will callback when the package is inactive
+         */
+        @GuardedBy("mInnerLock")
+        private void setAlarmLocked() {
+            if (mIsAlarmSet) {
+                return;
+            }
+
+            long revokeTime = mTimerStart + mTimeout;
+            if (revokeTime > System.currentTimeMillis()) {
+                mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, revokeTime, LOG_TAG, this,
+                        mContext.getMainThreadHandler());
+                mIsAlarmSet = true;
+            } else {
+                mIsAlarmSet = true;
+                onAlarm();
+            }
+        }
+
+        /**
+         * Cancel the alarm
+         */
+        @GuardedBy("mInnerLock")
+        private void cancelAlarmLocked() {
+            if (mIsAlarmSet) {
+                mAlarmManager.cancel(this);
+                mIsAlarmSet = false;
+            }
+        }
+
+        /**
+         * Called when the package is considered inactive. This is the end of the session
+         */
+        @GuardedBy("mInnerLock")
+        private void onPackageInactiveLocked() {
+            if (mIsFinished) {
+                return;
+            }
+            mIsFinished = true;
+            cancelAlarmLocked();
+            mContext.getMainThreadHandler().post(
+                    () -> mPermissionControllerManager.notifyOneTimePermissionSessionTimeout(
+                            mPackageName));
+            mActivityManager.removeOnUidImportanceListener(mStartTimerListener);
+            mActivityManager.removeOnUidImportanceListener(mSessionKillableListener);
+            mActivityManager.removeOnUidImportanceListener(mGoneListener);
+            synchronized (mLock) {
+                mListeners.remove(mUid);
+            }
+        }
+
+        @Override
+        public void onAlarm() {
+            synchronized (mInnerLock) {
+                if (!mIsAlarmSet) {
+                    return;
+                }
+                mIsAlarmSet = false;
+                onPackageInactiveLocked();
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 8ce1a52..a6ba77c 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -204,6 +204,10 @@
     /** Permission controller: User space permission management */
     private PermissionControllerManager mPermissionControllerManager;
 
+    /** Map of OneTimePermissionUserManagers keyed by userId */
+    private final SparseArray<OneTimePermissionUserManager> mOneTimePermissionUserManagers =
+            new SparseArray<>();
+
     /** Default permission policy to provide proper behaviour out-of-the-box */
     private final DefaultPermissionGrantPolicy mDefaultPermissionGrantPolicy;
 
@@ -3009,6 +3013,53 @@
                 SystemConfig.getInstance().getSplitPermissions());
     }
 
+    private OneTimePermissionUserManager getOneTimePermissionUserManager(@UserIdInt int userId) {
+        synchronized (mLock) {
+            OneTimePermissionUserManager oneTimePermissionUserManager =
+                    mOneTimePermissionUserManagers.get(userId);
+            if (oneTimePermissionUserManager == null) {
+                oneTimePermissionUserManager = new OneTimePermissionUserManager(
+                        mContext.createContextAsUser(UserHandle.of(userId), /*flags*/ 0));
+                mOneTimePermissionUserManagers.put(userId, oneTimePermissionUserManager);
+            }
+            return oneTimePermissionUserManager;
+        }
+    }
+
+    @Override
+    public void startOneTimePermissionSession(String packageName, @UserIdInt int userId,
+            long timeoutMillis, int importanceToResetTimer, int importanceToKeepSessionAlive) {
+        mContext.enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
+                "Must be able to revoke runtime permissions to register permissions as one time.");
+        mContext.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS,
+                "Must be able to access usage stats to register permissions as one time.");
+        packageName = Preconditions.checkNotNull(packageName);
+
+        long token = Binder.clearCallingIdentity();
+        try {
+            getOneTimePermissionUserManager(userId).startPackageOneTimeSession(packageName,
+                    timeoutMillis, importanceToResetTimer, importanceToKeepSessionAlive);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    @Override
+    public void stopOneTimePermissionSession(String packageName, @UserIdInt int userId) {
+        mContext.enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
+                "Must be able to revoke runtime permissions to remove permissions as one time.");
+        mContext.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS,
+                "Must be able to access usage stats to remove permissions as one time.");
+        Preconditions.checkNotNull(packageName);
+
+        long token = Binder.clearCallingIdentity();
+        try {
+            getOneTimePermissionUserManager(userId).stopPackageOneTimeSession(packageName);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     private boolean isNewPlatformPermissionForPackage(String perm, AndroidPackage pkg) {
         boolean allowed = false;
         final int NP = PackageParser.NEW_PERMISSIONS.length;
@@ -3279,6 +3330,13 @@
                 // Special permissions for the system telephony apps.
                 allowed = true;
             }
+            if (!allowed && bp.isCompanion()
+                    && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
+                        PackageManagerInternal.PACKAGE_COMPANION, UserHandle.USER_SYSTEM),
+                    pkg.getPackageName())) {
+                // Special permissions for the system companion device manager.
+                allowed = true;
+            }
         }
         return allowed;
     }
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 d99e03b..c50248d 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -24,7 +24,6 @@
 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;
 import android.util.TimestampedValue;
@@ -32,12 +31,11 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.timezonedetector.ArrayMapWithHistory;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.LinkedList;
-import java.util.Map;
 
 /**
  * An implementation of TimeDetectorStrategy that passes phone and manual suggestions to
@@ -99,14 +97,12 @@
     private TimestampedValue<Long> mLastAutoSystemClockTimeSet;
 
     /**
-     * A mapping from phoneId to a linked list of time suggestions (the "first" being the latest).
-     * We typically expect one or two entries in this Map: devices will have a small number
-     * of telephony devices and phoneIds are assumed to be stable. The LinkedList associated with
-     * the ID will not exceed {@link #KEEP_SUGGESTION_HISTORY_SIZE} in size.
+     * A mapping from phoneId to a time suggestion. We typically expect one or two mappings: devices
+     * will have a small number of telephony devices and phoneIds are assumed to be stable.
      */
     @GuardedBy("this")
-    private ArrayMap<Integer, LinkedList<PhoneTimeSuggestion>> mSuggestionByPhoneId =
-            new ArrayMap<>();
+    private ArrayMapWithHistory<Integer, PhoneTimeSuggestion> mSuggestionByPhoneId =
+            new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
 
     @Override
     public void initialize(@NonNull Callback callback) {
@@ -179,16 +175,7 @@
 
         ipw.println("Phone suggestion history:");
         ipw.increaseIndent(); // level 2
-        for (Map.Entry<Integer, LinkedList<PhoneTimeSuggestion>> entry
-                : mSuggestionByPhoneId.entrySet()) {
-            ipw.println("Phone " + entry.getKey());
-
-            ipw.increaseIndent(); // level 3
-            for (PhoneTimeSuggestion suggestion : entry.getValue()) {
-                ipw.println(suggestion);
-            }
-            ipw.decreaseIndent(); // level 3
-        }
+        mSuggestionByPhoneId.dump(ipw);
         ipw.decreaseIndent(); // level 2
 
         ipw.decreaseIndent(); // level 1
@@ -205,20 +192,10 @@
         }
 
         int phoneId = suggestion.getPhoneId();
-        LinkedList<PhoneTimeSuggestion> phoneSuggestions = mSuggestionByPhoneId.get(phoneId);
-        if (phoneSuggestions == null) {
-            // The first time we've seen this phoneId.
-            phoneSuggestions = new LinkedList<>();
-            mSuggestionByPhoneId.put(phoneId, phoneSuggestions);
-        } else if (phoneSuggestions.isEmpty()) {
-            Slog.w(LOG_TAG, "Suggestions unexpectedly empty when adding suggestion=" + suggestion);
-        }
-
-        if (!phoneSuggestions.isEmpty()) {
+        PhoneTimeSuggestion previousSuggestion = mSuggestionByPhoneId.get(phoneId);
+        if (previousSuggestion != null) {
             // We can log / discard suggestions with obvious issues with the reference time clock.
-            PhoneTimeSuggestion previousSuggestion = phoneSuggestions.getFirst();
-            if (previousSuggestion == null
-                    || previousSuggestion.getUtcTime() == null
+            if (previousSuggestion.getUtcTime() == null
                     || previousSuggestion.getUtcTime().getValue() == null) {
                 // This should be impossible given we only store validated suggestions.
                 Slog.w(LOG_TAG, "Previous suggestion is null or has a null time."
@@ -240,10 +217,7 @@
         }
 
         // Store the latest suggestion.
-        phoneSuggestions.addFirst(suggestion);
-        if (phoneSuggestions.size() > KEEP_SUGGESTION_HISTORY_SIZE) {
-            phoneSuggestions.removeLast();
-        }
+        mSuggestionByPhoneId.put(phoneId, suggestion);
         return true;
     }
 
@@ -331,15 +305,7 @@
         int bestScore = PHONE_INVALID_SCORE;
         for (int i = 0; i < mSuggestionByPhoneId.size(); i++) {
             Integer phoneId = mSuggestionByPhoneId.keyAt(i);
-            LinkedList<PhoneTimeSuggestion> phoneSuggestions = mSuggestionByPhoneId.valueAt(i);
-            if (phoneSuggestions == null) {
-                // Unexpected - map is missing a value.
-                Slog.w(LOG_TAG, "Suggestions unexpectedly missing for phoneId."
-                        + " phoneId=" + phoneId);
-                continue;
-            }
-
-            PhoneTimeSuggestion candidateSuggestion = phoneSuggestions.getFirst();
+            PhoneTimeSuggestion candidateSuggestion = mSuggestionByPhoneId.valueAt(i);
             if (candidateSuggestion == null) {
                 // Unexpected - null suggestions should never be stored.
                 Slog.w(LOG_TAG, "Latest suggestion unexpectedly null for phoneId."
@@ -540,10 +506,6 @@
     @VisibleForTesting
     @Nullable
     public synchronized PhoneTimeSuggestion getLatestPhoneSuggestion(int phoneId) {
-        LinkedList<PhoneTimeSuggestion> suggestions = mSuggestionByPhoneId.get(phoneId);
-        if (suggestions == null) {
-            return null;
-        }
-        return suggestions.getFirst();
+        return mSuggestionByPhoneId.get(phoneId);
     }
 }
diff --git a/services/core/java/com/android/server/timezonedetector/ArrayMapWithHistory.java b/services/core/java/com/android/server/timezonedetector/ArrayMapWithHistory.java
new file mode 100644
index 0000000..3274f0e
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/ArrayMapWithHistory.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+
+/**
+ * A partial decorator for {@link ArrayMap} that records historic values for each mapping for
+ * debugging later with {@link #dump(IndentingPrintWriter)}.
+ *
+ * <p>This class is only intended for use in {@link TimeZoneDetectorStrategy} and
+ * {@link com.android.server.timedetector.TimeDetectorStrategy} so only provides the parts of the
+ * {@link ArrayMap} API needed. If it is ever extended to include deletion methods like
+ * {@link ArrayMap#remove(Object)} some thought would need to be given to the correct
+ * {@link ArrayMap#containsKey(Object)} behavior for the history. Like {@link ArrayMap}, it is not
+ * thread-safe.
+ *
+ * @param <K> the type of the key
+ * @param <V> the type of the value
+ */
+public final class ArrayMapWithHistory<K, V> {
+    private static final String TAG = "ArrayMapWithHistory";
+
+    /** The size the linked list against each value is allowed to grow to. */
+    private final int mMaxHistorySize;
+
+    @Nullable
+    private ArrayMap<K, ReferenceWithHistory<V>> mMap;
+
+    /**
+     * Creates an instance that records, at most, the specified number of values against each key.
+     */
+    public ArrayMapWithHistory(@IntRange(from = 1) int maxHistorySize) {
+        if (maxHistorySize < 1) {
+            throw new IllegalArgumentException("maxHistorySize < 1: " + maxHistorySize);
+        }
+        mMaxHistorySize = maxHistorySize;
+    }
+
+    /**
+     * See {@link ArrayMap#put(K, V)}.
+     */
+    @Nullable
+    public V put(@Nullable K key, @Nullable V value) {
+        if (mMap == null) {
+            mMap = new ArrayMap<>();
+        }
+
+        ReferenceWithHistory<V> valueHolder = mMap.get(key);
+        if (valueHolder == null) {
+            valueHolder = new ReferenceWithHistory<>(mMaxHistorySize);
+            mMap.put(key, valueHolder);
+        } else if (valueHolder.getHistoryCount() == 0) {
+            Log.w(TAG, "History for \"" + key + "\" was unexpectedly empty");
+        }
+
+        return valueHolder.set(value);
+    }
+
+    /**
+     * See {@link ArrayMap#get(Object)}.
+     */
+    @Nullable
+    public V get(@Nullable Object key) {
+        if (mMap == null) {
+            return null;
+        }
+
+        ReferenceWithHistory<V> valueHolder = mMap.get(key);
+        if (valueHolder == null) {
+            return null;
+        } else if (valueHolder.getHistoryCount() == 0) {
+            Log.w(TAG, "History for \"" + key + "\" was unexpectedly empty");
+        }
+        return valueHolder.get();
+    }
+
+    /**
+     * See {@link ArrayMap#size()}.
+     */
+    public int size() {
+        return mMap == null ? 0 : mMap.size();
+    }
+
+    /**
+     * See {@link ArrayMap#keyAt(int)}.
+     */
+    @Nullable
+    public K keyAt(int index) {
+        if (mMap == null) {
+            throw new ArrayIndexOutOfBoundsException(index);
+        }
+        return mMap.keyAt(index);
+    }
+
+    /**
+     * See {@link ArrayMap#valueAt(int)}.
+     */
+    @Nullable
+    public V valueAt(int index) {
+        if (mMap == null) {
+            throw new ArrayIndexOutOfBoundsException(index);
+        }
+
+        ReferenceWithHistory<V> valueHolder = mMap.valueAt(index);
+        if (valueHolder == null || valueHolder.getHistoryCount() == 0) {
+            Log.w(TAG, "valueAt(" + index + ") was unexpectedly null or empty");
+            return null;
+        }
+        return valueHolder.get();
+    }
+
+    /**
+     * Dumps the content of the map, including historic values, using the supplied writer.
+     */
+    public void dump(@NonNull IndentingPrintWriter ipw) {
+        if (mMap == null) {
+            ipw.println("{Empty}");
+        } else {
+            for (int i = 0; i < mMap.size(); i++) {
+                ipw.println("key idx: " + i + "=" + mMap.keyAt(i));
+                ReferenceWithHistory<V> value = mMap.valueAt(i);
+                ipw.println("val idx: " + i + "=" +  value);
+                ipw.increaseIndent();
+
+                ipw.println("Historic values=[");
+                ipw.increaseIndent();
+                value.dump(ipw);
+                ipw.decreaseIndent();
+                ipw.println("]");
+
+                ipw.decreaseIndent();
+            }
+        }
+        ipw.flush();
+    }
+
+    /**
+     * Internal method intended for tests that returns the number of historic values associated with
+     * the supplied key currently. If there is no mapping for the key then {@code 0} is returned.
+     */
+    @VisibleForTesting
+    public int getHistoryCountForKeyForTests(@Nullable K key) {
+        if (mMap == null) {
+            return 0;
+        }
+
+        ReferenceWithHistory<V> valueHolder = mMap.get(key);
+        if (valueHolder == null) {
+            return 0;
+        } else if (valueHolder.getHistoryCount() == 0) {
+            Log.w(TAG, "getValuesSizeForKeyForTests(\"" + key + "\") was unexpectedly empty");
+            return 0;
+        } else {
+            return valueHolder.getHistoryCount();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "ArrayMapWithHistory{"
+                + "mHistorySize=" + mMaxHistorySize
+                + ", mMap=" + mMap
+                + '}';
+    }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java b/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java
new file mode 100644
index 0000000..8bd1035
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java
@@ -0,0 +1,118 @@
+/*
+ * 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.timezonedetector;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.util.LinkedList;
+
+/**
+ * A class that behaves like the following definition, except it stores the history of values set
+ * that can be dumped for debugging with {@link #dump(IndentingPrintWriter)}.
+ *
+ * <pre>{@code
+ *     private static class Ref<V> {
+ *         private V mValue;
+ *
+ *         public V get() {
+ *             return mValue;
+ *         }
+ *
+ *         public V set(V value) {
+ *             V previous = mValue;
+ *             mValue = value;
+ *             return previous;
+ *         }
+ *     }
+ * }</pre>
+ *
+ * <p>This class is not thread-safe.
+ *
+ * @param <V> the type of the value
+ */
+public final class ReferenceWithHistory<V> {
+
+    /** The size the history linked list is allowed to grow to. */
+    private final int mMaxHistorySize;
+
+    @Nullable
+    private LinkedList<V> mValues;
+
+    /**
+     * Creates an instance that records, at most, the specified number of values.
+     */
+    public ReferenceWithHistory(@IntRange(from = 1) int maxHistorySize) {
+        if (maxHistorySize < 1) {
+            throw new IllegalArgumentException("maxHistorySize < 1: " + maxHistorySize);
+        }
+        this.mMaxHistorySize = maxHistorySize;
+    }
+
+    /** Returns the current value, or {@code null} if it has never been set. */
+    @Nullable
+    public V get() {
+        return (mValues == null || mValues.isEmpty()) ? null : mValues.getFirst();
+    }
+
+    /** Sets the current value. Returns the previous value, or {@code null}. */
+    @Nullable
+    public V set(@Nullable V newValue) {
+        if (mValues == null) {
+            mValues = new LinkedList<>();
+        }
+
+        V previous = get();
+
+        mValues.addFirst(newValue);
+        if (mValues.size() > mMaxHistorySize) {
+            mValues.removeLast();
+        }
+        return previous;
+    }
+
+    /**
+     * Dumps the content of the reference, including historic values, using the supplied writer.
+     */
+    public void dump(@NonNull IndentingPrintWriter ipw) {
+        if (mValues == null) {
+            ipw.println("{Empty}");
+        } else {
+            int i = 0;
+            for (V value : mValues) {
+                ipw.println(i + ": " + value);
+                i++;
+            }
+        }
+        ipw.flush();
+    }
+
+    /**
+     * Returns the number of historic entries stored currently.
+     */
+    public int getHistoryCount() {
+        return mValues == null ? 0 : mValues.size();
+    }
+
+    @Override
+    public String toString() {
+        return String.valueOf(get());
+    }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index b3013c7..b4a4399 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -27,7 +27,6 @@
 import android.app.timezonedetector.ManualTimeZoneSuggestion;
 import android.app.timezonedetector.PhoneTimeZoneSuggestion;
 import android.content.Context;
-import android.util.ArrayMap;
 import android.util.LocalLog;
 import android.util.Slog;
 
@@ -38,8 +37,6 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.LinkedList;
-import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -175,14 +172,13 @@
     private final LocalLog mTimeZoneChangesLog = new LocalLog(30, false /* useLocalTimestamps */);
 
     /**
-     * A mapping from phoneId to a linked list of phone time zone suggestions (the head being the
-     * latest). We typically expect one or two entries in this Map: devices will have a small number
-     * of telephony devices and phoneIds are assumed to be stable. The LinkedList associated with
-     * the ID will not exceed {@link #KEEP_PHONE_SUGGESTION_HISTORY_SIZE} in size.
+     * A mapping from phoneId to a phone time zone suggestion. We typically expect one or two
+     * mappings: devices will have a small number of telephony devices and phoneIds are assumed to
+     * be stable.
      */
     @GuardedBy("this")
-    private ArrayMap<Integer, LinkedList<QualifiedPhoneTimeZoneSuggestion>> mSuggestionByPhoneId =
-            new ArrayMap<>();
+    private ArrayMapWithHistory<Integer, QualifiedPhoneTimeZoneSuggestion> mSuggestionByPhoneId =
+            new ArrayMapWithHistory<>(KEEP_PHONE_SUGGESTION_HISTORY_SIZE);
 
     /**
      * Creates a new instance of {@link TimeZoneDetectorStrategy}.
@@ -226,16 +222,7 @@
                 new QualifiedPhoneTimeZoneSuggestion(suggestion, score);
 
         // Store the suggestion against the correct phoneId.
-        LinkedList<QualifiedPhoneTimeZoneSuggestion> suggestions =
-                mSuggestionByPhoneId.get(suggestion.getPhoneId());
-        if (suggestions == null) {
-            suggestions = new LinkedList<>();
-            mSuggestionByPhoneId.put(suggestion.getPhoneId(), suggestions);
-        }
-        suggestions.addFirst(scoredSuggestion);
-        if (suggestions.size() > KEEP_PHONE_SUGGESTION_HISTORY_SIZE) {
-            suggestions.removeLast();
-        }
+        mSuggestionByPhoneId.put(suggestion.getPhoneId(), scoredSuggestion);
 
         // Now perform auto time zone detection. The new suggestion may be used to modify the time
         // zone setting.
@@ -398,13 +385,7 @@
         // rate-limit so age is not a strong indicator of confidence. Instead, the callers are
         // expected to withdraw suggestions they no longer have confidence in.
         for (int i = 0; i < mSuggestionByPhoneId.size(); i++) {
-            LinkedList<QualifiedPhoneTimeZoneSuggestion> phoneSuggestions =
-                    mSuggestionByPhoneId.valueAt(i);
-            if (phoneSuggestions == null) {
-                // Unexpected
-                continue;
-            }
-            QualifiedPhoneTimeZoneSuggestion candidateSuggestion = phoneSuggestions.getFirst();
+            QualifiedPhoneTimeZoneSuggestion candidateSuggestion = mSuggestionByPhoneId.valueAt(i);
             if (candidateSuggestion == null) {
                 // Unexpected
                 continue;
@@ -474,16 +455,7 @@
 
         ipw.println("Phone suggestion history:");
         ipw.increaseIndent(); // level 2
-        for (Map.Entry<Integer, LinkedList<QualifiedPhoneTimeZoneSuggestion>> entry
-                : mSuggestionByPhoneId.entrySet()) {
-            ipw.println("Phone " + entry.getKey());
-
-            ipw.increaseIndent(); // level 3
-            for (QualifiedPhoneTimeZoneSuggestion suggestion : entry.getValue()) {
-                ipw.println(suggestion);
-            }
-            ipw.decreaseIndent(); // level 3
-        }
+        mSuggestionByPhoneId.dump(ipw);
         ipw.decreaseIndent(); // level 2
         ipw.decreaseIndent(); // level 1
         ipw.flush();
@@ -494,12 +466,7 @@
      */
     @VisibleForTesting
     public synchronized QualifiedPhoneTimeZoneSuggestion getLatestPhoneSuggestion(int phoneId) {
-        LinkedList<QualifiedPhoneTimeZoneSuggestion> suggestions =
-                mSuggestionByPhoneId.get(phoneId);
-        if (suggestions == null) {
-            return null;
-        }
-        return suggestions.getFirst();
+        return mSuggestionByPhoneId.get(phoneId);
     }
 
     /**
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 0d6e928..62dd7bb 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -821,10 +821,7 @@
         // Update bounds if applicable
         boolean hasNewOverrideBounds = false;
         // Use override windowing mode to prevent extra bounds changes if inheriting the mode.
-        if (overrideWindowingMode == WINDOWING_MODE_PINNED) {
-            // Pinned calculation already includes rotation
-            hasNewOverrideBounds = calculatePinnedBoundsForConfigChange(newBounds);
-        } else if (!matchParentBounds()) {
+        if ((overrideWindowingMode != WINDOWING_MODE_PINNED) && !matchParentBounds()) {
             // If the parent (display) has rotated, rotate our bounds to best-fit where their
             // bounds were on the pre-rotated display.
             final int newRotation = getWindowConfiguration().getRotation();
@@ -882,9 +879,6 @@
                         null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
                         null /* tempOtherTaskBounds */, null /* tempOtherTaskInsetBounds */,
                         PRESERVE_WINDOWS, true /* deferResume */);
-            } else {
-                resize(new Rect(newBounds), null /* tempTaskBounds */,
-                        null /* tempTaskInsetBounds */, PRESERVE_WINDOWS, true /* deferResume */);
             }
         }
         if (prevIsAlwaysOnTop != isAlwaysOnTop()) {
@@ -3664,8 +3658,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 +3676,6 @@
             // Stack is now empty...
           removeIfPossible();
         }
-
-        moveHomeStackToFrontIfNeeded(topFocused, display, reason);
     }
 
     @Override
@@ -3690,18 +3683,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) {
@@ -4102,45 +4083,27 @@
     }
 
     /**
-     * Updates the passed-in {@code inOutBounds} based on the current state of the
-     * pinned controller. This gets run *after* the override configuration is updated, so it's
-     * safe to rely on the controller's state in here (though eventually this dependence should
-     * be removed).
+     * Reset the current animation running on {@link #mBoundsAnimationTarget}.
      *
-     * This does NOT modify this TaskStack's configuration. However, it does, for the time-being,
-     * update pinned controller state.
-     *
-     * @param inOutBounds the bounds to update (both input and output).
-     * @return true if bounds were updated to some non-empty value.
+     * @param destinationBounds the final destination bounds
      */
-    boolean calculatePinnedBoundsForConfigChange(Rect inOutBounds) {
-        boolean animating = false;
-        if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) {
-            animating = true;
-            getFinalAnimationBounds(mTmpRect2);
-        } else {
-            mTmpRect2.set(inOutBounds);
-        }
-        boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(
-                mTmpRect2, mTmpRect3);
-        if (updated) {
-            inOutBounds.set(mTmpRect3);
+    void resetCurrentBoundsAnimation(Rect destinationBounds) {
+        boolean animating = (mBoundsAnimatingRequested || mBoundsAnimating)
+                && !mBoundsAnimationTarget.isEmpty();
 
-            // The final boundary is updated while there is an existing boundary animation. Let's
-            // cancel this animation to prevent the obsolete animation overwritten updated bounds.
-            if (animating && !inOutBounds.equals(mBoundsAnimationTarget)) {
-                final DisplayContent displayContent = getDisplayContent();
-                displayContent.mBoundsAnimationController.getHandler().post(() ->
-                        displayContent.mBoundsAnimationController.cancel(this));
-            }
-            // Once we've set the bounds based on the rotation of the old bounds in the new
-            // orientation, clear the animation target bounds since they are obsolete, and
-            // cancel any currently running animations
-            mBoundsAnimationTarget.setEmpty();
-            mBoundsAnimationSourceHintBounds.setEmpty();
-            mCancelCurrentBoundsAnimation = true;
+        // The final boundary is updated while there is an existing boundary animation. Let's
+        // cancel this animation to prevent the obsolete animation overwritten updated bounds.
+        if (animating && !destinationBounds.equals(mBoundsAnimationTarget)) {
+            final BoundsAnimationController controller =
+                    getDisplayContent().mBoundsAnimationController;
+            controller.getHandler().post(() -> controller.cancel(this));
         }
-        return updated;
+        // Once we've set the bounds based on the rotation of the old bounds in the new
+        // orientation, clear the animation target bounds since they are obsolete, and
+        // cancel any currently running animations
+        mBoundsAnimationTarget.setEmpty();
+        mBoundsAnimationSourceHintBounds.setEmpty();
+        mCancelCurrentBoundsAnimation = true;
     }
 
     /**
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/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 674955e..6ad439e 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -51,7 +51,6 @@
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
-import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
@@ -1688,19 +1687,9 @@
             return START_SUCCESS;
         }
 
-        // True if we are clearing top and resetting of a standard (default) launch mode
-        // ({@code LAUNCH_MULTIPLE}) activity. The existing activity will be finished.
-        final boolean clearTopAndResetStandardLaunchMode =
-                (mLaunchFlags & (FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED))
-                        == (FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
-                        && mLaunchMode == LAUNCH_MULTIPLE;
-
         boolean clearTaskForReuse = false;
         if (reusedTask != null) {
-            // If mStartActivity does not have a task associated with it, associate it with the
-            // reused activity's task. Do not do so if we're clearing top and resetting for a
-            // standard launchMode activity.
-            if (mStartActivity.getTask() == null && !clearTopAndResetStandardLaunchMode) {
+            if (mStartActivity.getTask() == null) {
                 mStartActivity.setTaskForReuse(reusedTask);
                 clearTaskForReuse = true;
             }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f0bc412..45b4818 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3302,6 +3302,23 @@
         Configuration c = new Configuration(container.getRequestedOverrideConfiguration());
         c.setTo(change.getConfiguration(), configMask, windowMask);
         container.onRequestedOverrideConfigurationChanged(c);
+        // TODO(b/145675353): remove the following once we could apply new bounds to the
+        // pinned stack together with its children.
+        resizePinnedStackIfNeeded(container, configMask, windowMask, c);
+    }
+
+    private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask,
+            int windowMask, Configuration config) {
+        if ((container instanceof ActivityStack)
+                && ((configMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0)
+                && ((windowMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)) {
+            final ActivityStack stack = (ActivityStack) container;
+            if (stack.inPinnedWindowingMode()) {
+                stack.resize(config.windowConfiguration.getBounds(),
+                        null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+                        PRESERVE_WINDOWS, true /* deferResume */);
+            }
+        }
     }
 
     @Override
@@ -4176,6 +4193,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/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 5dc88b3..9b464c2 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -185,6 +185,10 @@
             resume();
         };
 
+        // If this animator is explicitly cancelled when it's in paused state, we should not
+        // attempt to resume the animation. Use this flag to avoid such behavior.
+        private boolean mIsCancelled;
+
         BoundsAnimator(BoundsAnimationTarget target, @AnimationType int animationType, Rect from,
                 Rect to, @SchedulePipModeChangedState int schedulePipModeChangedState,
                 @SchedulePipModeChangedState int prevShedulePipModeChangedState,
@@ -221,6 +225,7 @@
             if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
                     + " mPrevSchedulePipModeChangedState=" + mPrevSchedulePipModeChangedState
                     + " mSchedulePipModeChangedState=" + mSchedulePipModeChangedState);
+            mIsCancelled = false;
             mFinishAnimationAfterTransition = false;
             mTmpRect.set(mFrom.left, mFrom.top, mFrom.left + mFrozenTaskWidth,
                     mFrom.top + mFrozenTaskHeight);
@@ -293,7 +298,7 @@
         public void resume() {
             if (DEBUG) Slog.d(TAG, "resume:");
             mHandler.removeCallbacks(mResumeRunnable);
-            super.resume();
+            if (!mIsCancelled) super.resume();
         }
 
         @Override
@@ -376,6 +381,7 @@
 
         @Override
         public void onAnimationCancel(Animator animation) {
+            mIsCancelled = true;
             // Always skip the final resize when the animation is canceled
             mSkipFinalResize = true;
             mMoveToFullscreen = false;
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/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index a8e7aea..b4f75e5 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -16,38 +16,29 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.util.TypedValue.COMPLEX_UNIT_DIP;
 
 import static com.android.server.wm.PinnedStackControllerProto.DEFAULT_BOUNDS;
 import static com.android.server.wm.PinnedStackControllerProto.MOVEMENT_BOUNDS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
-import android.annotation.NonNull;
 import android.app.RemoteAction;
 import android.content.ComponentName;
 import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.util.Size;
 import android.util.Slog;
-import android.util.TypedValue;
 import android.util.proto.ProtoOutputStream;
 import android.view.DisplayInfo;
-import android.view.Gravity;
 import android.view.IPinnedStackController;
 import android.view.IPinnedStackListener;
 
-import com.android.internal.policy.PipSnapAlgorithm;
-import com.android.internal.util.Preconditions;
 import com.android.server.UiThread;
 
 import java.io.PrintWriter;
@@ -74,7 +65,6 @@
 
     private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedStackController" : TAG_WM;
 
-    private static final float INVALID_SNAP_FRACTION = -1f;
     private final WindowManagerService mService;
     private final DisplayContent mDisplayContent;
     private final Handler mHandler = UiThread.getHandler();
@@ -84,7 +74,6 @@
             new PinnedStackListenerDeathHandler();
 
     private final PinnedStackControllerCallback mCallbacks = new PinnedStackControllerCallback();
-    private final PipSnapAlgorithm mSnapAlgorithm;
 
     // States that affect how the PIP can be manipulated
     private boolean mIsMinimized;
@@ -97,13 +86,9 @@
 
     // Used to calculate stack bounds across rotations
     private final DisplayInfo mDisplayInfo = new DisplayInfo();
-    private final Rect mStableInsets = new Rect();
 
     // The size and position information that describes where the pinned stack will go by default.
-    private int mDefaultMinSize;
-    private int mDefaultStackGravity;
     private float mDefaultAspectRatio;
-    private Point mScreenEdgeInsets;
 
     // The aspect ratio bounds of the PIP.
     private float mMinAspectRatio;
@@ -111,10 +96,11 @@
 
     // Temp vars for calculation
     private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
-    private final Rect mTmpInsets = new Rect();
-    private final Rect mTmpRect = new Rect();
-    private final Point mTmpDisplaySize = new Point();
 
+    // TODO(b/141200935): remove this when we have default/movement bounds tests in SysUI.
+    // Keep record of the default and movement bounds
+    private final Rect mLastReportedDefaultBounds = new Rect();
+    private final Rect mLastReportedMovementBounds = new Rect();
 
     /**
      * The callback object passed to listeners for them to notify the controller of state changes.
@@ -125,7 +111,6 @@
         public void setIsMinimized(final boolean isMinimized) {
             mHandler.post(() -> {
                 mIsMinimized = isMinimized;
-                mSnapAlgorithm.setMinimized(isMinimized);
             });
         }
 
@@ -145,6 +130,27 @@
                         sourceRectHint, animationDuration, true /* fromFullscreen */);
             }
         }
+
+        @Override
+        public void resetBoundsAnimation(Rect bounds) {
+            synchronized (mService.mGlobalLock) {
+                if (mDisplayContent.hasPinnedStack()) {
+                    final ActivityStack pinnedStack = mDisplayContent.getTopStackInWindowingMode(
+                            WINDOWING_MODE_PINNED);
+                    if (pinnedStack != null) {
+                        pinnedStack.resetCurrentBoundsAnimation(bounds);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void reportBounds(Rect defaultBounds, Rect movementBounds) {
+            synchronized (mService.mGlobalLock) {
+                mLastReportedDefaultBounds.set(defaultBounds);
+                mLastReportedMovementBounds.set(movementBounds);
+            }
+        }
     }
 
     /**
@@ -165,7 +171,6 @@
     PinnedStackController(WindowManagerService service, DisplayContent displayContent) {
         mService = service;
         mDisplayContent = displayContent;
-        mSnapAlgorithm = new PipSnapAlgorithm(service.mContext);
         mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
         reloadResources();
         // Initialize the aspect ratio to the default aspect ratio.  Don't do this in reload
@@ -183,21 +188,9 @@
      */
     private void reloadResources() {
         final Resources res = mService.mContext.getResources();
-        mDefaultMinSize = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
         mDefaultAspectRatio = res.getFloat(
                 com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
-        final String screenEdgeInsetsDpString = res.getString(
-                com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
-        final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
-                ? Size.parseSize(screenEdgeInsetsDpString)
-                : null;
-        mDefaultStackGravity = res.getInteger(
-                com.android.internal.R.integer.config_defaultPictureInPictureGravity);
         mDisplayContent.getDisplay().getRealMetrics(mTmpMetrics);
-        mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
-                : new Point(dpToPx(screenEdgeInsetsDp.getWidth(), mTmpMetrics),
-                        dpToPx(screenEdgeInsetsDp.getHeight(), mTmpMetrics));
         mMinAspectRatio = res.getFloat(
                 com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
         mMaxAspectRatio = res.getFloat(
@@ -215,7 +208,7 @@
             notifyDisplayInfoChanged(mDisplayInfo);
             notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
             // The movement bounds notification needs to be sent before the minimized state, since
-            // SystemUI may use the bounds to retore the minimized position
+            // SystemUI may use the bounds to restore the minimized position
             notifyMovementBoundsChanged(false /* fromImeAdjustment */,
                     false /* fromShelfAdjustment */);
             notifyActionsChanged(mActions);
@@ -257,30 +250,6 @@
         }
     }
 
-    /**
-     * @return the default bounds to show the PIP, if a {@param snapFraction} is provided, then it
-     * will apply the default bounds to the provided snap fraction.
-     */
-    private Rect getDefaultBounds(float snapFraction) {
-        synchronized (mService.mGlobalLock) {
-            final Rect insetBounds = new Rect();
-            getInsetBounds(insetBounds);
-
-            final Rect defaultBounds = new Rect();
-            final Size size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
-                    mDefaultMinSize, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
-            if (snapFraction != INVALID_SNAP_FRACTION) {
-                defaultBounds.set(0, 0, size.getWidth(), size.getHeight());
-                final Rect movementBounds = getMovementBounds(defaultBounds);
-                mSnapAlgorithm.applySnapFraction(defaultBounds, movementBounds, snapFraction);
-            } else {
-                Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
-                        0, mIsImeShowing ? mImeHeight : 0, defaultBounds);
-            }
-            return defaultBounds;
-        }
-    }
-
     private void setDisplayInfo(DisplayInfo displayInfo) {
         mDisplayInfo.copyFrom(displayInfo);
         notifyDisplayInfoChanged(mDisplayInfo);
@@ -300,51 +269,6 @@
     }
 
     /**
-     * Updates the display info, calculating and returning the new stack and movement bounds in the
-     * new orientation of the device if necessary.
-     */
-    boolean onTaskStackBoundsChanged(Rect targetBounds, Rect outBounds) {
-        synchronized (mService.mGlobalLock) {
-            final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
-            if (isSameDimensionAndRotation(mDisplayInfo, displayInfo)) {
-                // No dimension/rotation change, ignore
-                outBounds.setEmpty();
-                return false;
-            } else if (targetBounds.isEmpty()) {
-                // The stack is null, we are just initializing the stack, so just store the display
-                // info and ignore
-                setDisplayInfo(displayInfo);
-                outBounds.setEmpty();
-                return false;
-            }
-
-            mTmpRect.set(targetBounds);
-            final Rect postChangeStackBounds = mTmpRect;
-
-            // Calculate the snap fraction of the current stack along the old movement bounds
-            final float snapFraction = getSnapFraction(postChangeStackBounds);
-
-            setDisplayInfo(displayInfo);
-
-            // Calculate the stack bounds in the new orientation to the same same fraction along the
-            // rotated movement bounds.
-            final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
-                    false /* adjustForIme */);
-            mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
-                    snapFraction);
-            if (mIsMinimized) {
-                applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds);
-            }
-
-            notifyMovementBoundsChanged(false /* fromImeAdjustment */,
-                    false /* fromShelfAdjustment */);
-
-            outBounds.set(postChangeStackBounds);
-            return true;
-        }
-    }
-
-    /**
      * Sets the Ime state and height.
      */
     void setAdjustedForIme(boolean adjustedForIme, int imeHeight) {
@@ -400,15 +324,6 @@
         notifyPrepareAnimation(sourceRectHint, aspectRatio, stackBounds);
     }
 
-    private boolean isSameDimensionAndRotation(@NonNull DisplayInfo display1,
-            @NonNull DisplayInfo display2) {
-        Preconditions.checkNotNull(display1);
-        Preconditions.checkNotNull(display2);
-        return ((display1.rotation == display2.rotation)
-                && (display1.logicalWidth == display2.logicalWidth)
-                && (display1.logicalHeight == display2.logicalHeight));
-    }
-
     /**
      * Notifies listeners that the PIP needs to be adjusted for the IME.
      */
@@ -504,86 +419,11 @@
         }
     }
 
-    /**
-     * @return the bounds on the screen that the PIP can be visible in.
-     */
-    private void getInsetBounds(Rect outRect) {
-        synchronized (mService.mGlobalLock) {
-            mDisplayContent.getDisplayPolicy().getStableInsetsLw(mDisplayInfo.rotation,
-                    mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight,
-                    mDisplayInfo.displayCutout, mTmpInsets);
-            outRect.set(mTmpInsets.left + mScreenEdgeInsets.x, mTmpInsets.top + mScreenEdgeInsets.y,
-                    mDisplayInfo.logicalWidth - mTmpInsets.right - mScreenEdgeInsets.x,
-                    mDisplayInfo.logicalHeight - mTmpInsets.bottom - mScreenEdgeInsets.y);
-        }
-    }
-
-    /**
-     * @return the movement bounds for the given {@param stackBounds} and the current state of the
-     *         controller.
-     */
-    private Rect getMovementBounds(Rect stackBounds) {
-        synchronized (mService.mGlobalLock) {
-            return getMovementBounds(stackBounds, true /* adjustForIme */);
-        }
-    }
-
-    /**
-     * @return the movement bounds for the given {@param stackBounds} and the current state of the
-     *         controller.
-     */
-    private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) {
-        synchronized (mService.mGlobalLock) {
-            final Rect movementBounds = new Rect();
-            getInsetBounds(movementBounds);
-
-            // Apply the movement bounds adjustments based on the current state.
-            // Note that shelf offset does not affect the movement bounds here
-            // since it's been taken care of in system UI.
-            mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
-                    (adjustForIme && mIsImeShowing) ? mImeHeight : 0);
-            return movementBounds;
-        }
-    }
-
-    /**
-     * Applies the minimized offsets to the given stack bounds.
-     */
-    private void applyMinimizedOffset(Rect stackBounds, Rect movementBounds) {
-        synchronized (mService.mGlobalLock) {
-            mTmpDisplaySize.set(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
-            mService.getStableInsetsLocked(mDisplayContent.getDisplayId(), mStableInsets);
-            mSnapAlgorithm.applyMinimizedOffset(stackBounds, movementBounds, mTmpDisplaySize,
-                    mStableInsets);
-        }
-    }
-
-    /**
-     * @return the default snap fraction to apply instead of the default gravity when calculating
-     *         the default stack bounds when first entering PiP.
-     */
-    private float getSnapFraction(Rect stackBounds) {
-        return mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds));
-    }
-
-    /**
-     * @return the pixels for a given dp value.
-     */
-    private int dpToPx(float dpValue, DisplayMetrics dm) {
-        return (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, dpValue, dm);
-    }
-
     void dump(String prefix, PrintWriter pw) {
         pw.println(prefix + "PinnedStackController");
-        pw.print(prefix + "  defaultBounds=");
-        getDefaultBounds(INVALID_SNAP_FRACTION).printShortString(pw);
-        pw.println();
-        pw.println(prefix + "  mDefaultMinSize=" + mDefaultMinSize);
-        pw.println(prefix + "  mDefaultStackGravity=" + mDefaultStackGravity);
+        pw.println(prefix + "  mLastReportedDefaultBounds=" + mLastReportedDefaultBounds);
+        pw.println(prefix + "  mLastReportedMovementBounds=" + mLastReportedMovementBounds);
         pw.println(prefix + "  mDefaultAspectRatio=" + mDefaultAspectRatio);
-        mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
-        pw.print(prefix + "  movementBounds="); getMovementBounds(mTmpRect).printShortString(pw);
-        pw.println();
         pw.println(prefix + "  mIsImeShowing=" + mIsImeShowing);
         pw.println(prefix + "  mImeHeight=" + mImeHeight);
         pw.println(prefix + "  mIsMinimized=" + mIsMinimized);
@@ -606,9 +446,8 @@
 
     void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
-        getDefaultBounds(INVALID_SNAP_FRACTION).dumpDebug(proto, DEFAULT_BOUNDS);
-        mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
-        getMovementBounds(mTmpRect).dumpDebug(proto, MOVEMENT_BOUNDS);
+        mLastReportedDefaultBounds.dumpDebug(proto, DEFAULT_BOUNDS);
+        mLastReportedMovementBounds.dumpDebug(proto, MOVEMENT_BOUNDS);
         proto.end(token);
     }
 }
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 4de36b8b..456068c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -565,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 f23659e..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;
@@ -206,7 +206,7 @@
             }
             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 c95111f..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;
@@ -130,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 =
@@ -984,6 +986,7 @@
         }
     }
 
+    @ActivityInfo.ScreenOrientation
     int getOrientation() {
         return getOrientation(mOrientation);
     }
@@ -1036,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;
             }
         }
@@ -1728,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);
             }
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 68de4cd..ba9e9ce 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7371,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 2a8de3f..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) {
@@ -5480,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/Android.bp b/services/core/jni/Android.bp
index a34b7fd..fee29db 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -52,6 +52,7 @@
         "com_android_server_GraphicsStatsService.cpp",
         "com_android_server_am_AppCompactor.cpp",
         "com_android_server_am_LowMemDetector.cpp",
+        "com_android_server_incremental_IncrementalManagerService.cpp",
         "onload.cpp",
         ":lib_networkStatsFactory_native",
     ],
@@ -145,6 +146,7 @@
         "android.frameworks.schedulerservice@1.0",
         "android.frameworks.sensorservice@1.0",
         "android.system.suspend@1.0",
+        "service.incremental",
         "suspend_control_aidl_interface-cpp",
         "vintf-vibrator-cpp",
     ],
diff --git a/services/core/jni/com_android_server_incremental_IncrementalManagerService.cpp b/services/core/jni/com_android_server_incremental_IncrementalManagerService.cpp
new file mode 100644
index 0000000..5e255f4
--- /dev/null
+++ b/services/core/jni/com_android_server_incremental_IncrementalManagerService.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "incremental_manager_service-jni"
+
+#include "incremental_service.h"
+#include "jni.h"
+
+#include <memory>
+#include <nativehelper/JNIHelp.h>
+
+
+namespace android {
+
+static jlong nativeStartService(JNIEnv* env, jclass klass, jobject self) {
+    return Incremental_IncrementalService_Start();
+}
+
+static void nativeSystemReady(JNIEnv* env, jclass klass, jlong self) {
+    Incremental_IncrementalService_OnSystemReady(self);
+}
+
+static const JNINativeMethod method_table[] = {
+        {"nativeStartService", "()J", (void*)nativeStartService},
+        {"nativeSystemReady", "(J)V", (void*)nativeSystemReady},
+};
+
+int register_android_server_incremental_IncrementalManagerService(JNIEnv* env) {
+    return jniRegisterNativeMethods(env,
+        "com/android/server/incremental/IncrementalManagerService",
+        method_table, std::size(method_table));
+}
+
+} // namespace android
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/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 165edf1..c0a6e4e 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -58,6 +58,7 @@
 int register_android_server_am_LowMemDetector(JNIEnv* env);
 int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(
         JNIEnv* env);
+int register_android_server_incremental_IncrementalManagerService(JNIEnv* env);
 };
 
 using namespace android;
@@ -109,5 +110,6 @@
     register_android_server_am_LowMemDetector(env);
     register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(
             env);
+    register_android_server_incremental_IncrementalManagerService(env);
     return JNI_VERSION_1_4;
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d91ec42..eda69a9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -254,6 +254,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
+import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.JournaledFile;
 import com.android.internal.util.Preconditions;
@@ -430,6 +431,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 +474,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);
     }
 
     /**
@@ -2099,6 +2106,10 @@
              Binder.withCleanCallingIdentity(action);
         }
 
+        final <T> T binderWithCleanCallingIdentity(@NonNull ThrowingSupplier<T> action) {
+            return Binder.withCleanCallingIdentity(action);
+        }
+
         final int userHandleGetCallingUserId() {
             return UserHandle.getUserId(binderGetCallingUid());
         }
@@ -2363,12 +2374,7 @@
      * @return
      */
     DevicePolicyData getUserDataUnchecked(int userHandle) {
-        long ident = mInjector.binderClearCallingIdentity();
-        try {
-            return getUserData(userHandle);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        return mInjector.binderWithCleanCallingIdentity(() -> getUserData(userHandle));
     }
 
     void removeUserData(int userHandle) {
@@ -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()) {
@@ -2695,8 +2691,7 @@
             alarmTime = now + alarmInterval;
         }
 
-        long token = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             int affectedUserHandle = parent ? getProfileParentId(userHandle) : userHandle;
             AlarmManager am = mInjector.getAlarmManager();
             PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
@@ -2707,9 +2702,7 @@
             if (alarmTime != 0) {
                 am.set(AlarmManager.RTC, alarmTime, pi);
             }
-        } finally {
-            mInjector.binderRestoreCallingIdentity(token);
-        }
+        });
     }
 
     ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
@@ -3273,12 +3266,8 @@
     private void sendChangedNotification(int userHandle) {
         Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        long ident = mInjector.binderClearCallingIdentity();
-        try {
-            mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        mInjector.binderWithCleanCallingIdentity(() ->
+                mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle)));
     }
 
     private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
@@ -3846,8 +3835,7 @@
                 /* throwForMissingPermission= */ true);
         synchronized (getLockObject()) {
             checkActiveAdminPrecondition(adminReceiver, info, policy);
-            long ident = mInjector.binderClearCallingIdentity();
-            try {
+            mInjector.binderWithCleanCallingIdentity(() -> {
                 final ActiveAdmin existingAdmin
                         = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
                 if (!refreshing && existingAdmin != null) {
@@ -3878,9 +3866,7 @@
                 saveSettingsLocked(userHandle);
                 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
                         onEnableData, null);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
-            }
+            });
         }
     }
 
@@ -4062,8 +4048,7 @@
         }
         Preconditions.checkNotNull(adminReceiver, "ComponentName is null");
         enforceShell("forceRemoveActiveAdmin");
-        long ident = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             synchronized (getLockObject()) {
                 if (!isAdminTestOnlyLocked(adminReceiver, userHandle)) {
                     throw new SecurityException("Attempt to remove non-test admin "
@@ -4083,9 +4068,7 @@
             // Remove the admin skipping sending the broadcast.
             removeAdminArtifacts(adminReceiver, userHandle);
             Slog.i(LOG_TAG, "Admin " + adminReceiver + " removed from user " + userHandle);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        });
     }
 
     private void clearDeviceOwnerUserRestrictionLocked(UserHandle userHandle) {
@@ -4160,12 +4143,8 @@
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
             }
-            long ident = mInjector.binderClearCallingIdentity();
-            try {
-                removeActiveAdminLocked(adminReceiver, userHandle);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
-            }
+            mInjector.binderWithCleanCallingIdentity(() ->
+                    removeActiveAdminLocked(adminReceiver, userHandle));
         }
     }
 
@@ -4191,8 +4170,7 @@
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(
                     who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
-            final long ident = mInjector.binderClearCallingIdentity();
-            try {
+            mInjector.binderWithCleanCallingIdentity(() -> {
                 final PasswordPolicy passwordPolicy = ap.mPasswordPolicy;
                 if (passwordPolicy.quality != quality) {
                     passwordPolicy.quality = quality;
@@ -4202,9 +4180,7 @@
                     saveSettingsLocked(userId);
                 }
                 maybeLogPasswordComplexitySet(who, userId, parent, passwordPolicy);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
-            }
+            });
         }
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_PASSWORD_QUALITY)
@@ -4391,12 +4367,8 @@
     }
 
     private boolean isSeparateProfileChallengeEnabled(int userHandle) {
-        long ident = mInjector.binderClearCallingIdentity();
-        try {
-            return mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        return mInjector.binderWithCleanCallingIdentity(() ->
+                mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle));
     }
 
     @Override
@@ -5133,12 +5105,7 @@
     }
 
     private UserInfo getUserInfo(@UserIdInt int userId) {
-        final long token = mInjector.binderClearCallingIdentity();
-        try {
-            return mUserManager.getUserInfo(userId);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(token);
-        }
+        return mInjector.binderWithCleanCallingIdentity(() -> mUserManager.getUserInfo(userId));
     }
 
     private boolean setPasswordPrivileged(@NonNull String password, int flags, int callingUid) {
@@ -5263,12 +5230,7 @@
     }
 
     private boolean isLockScreenSecureUnchecked(int userId) {
-        long ident = mInjector.binderClearCallingIdentity();
-        try {
-            return mLockPatternUtils.isSecure(userId);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        return mInjector.binderWithCleanCallingIdentity(() -> mLockPatternUtils.isSecure(userId));
     }
 
     private void setDoNotAskCredentialsOnBoot() {
@@ -5320,12 +5282,10 @@
             updateProfileLockTimeoutLocked(userId);
         }
 
-        final long timeMs;
-        final long ident = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             // Update the device timeout
             final int parentId = getProfileParentId(userId);
-            timeMs = getMaximumTimeToLockPolicyFromAdmins(
+            final long timeMs = getMaximumTimeToLockPolicyFromAdmins(
                     getActiveAdminsForLockscreenPoliciesLocked(parentId, false));
 
             final DevicePolicyData policy = getUserDataUnchecked(parentId);
@@ -5341,9 +5301,7 @@
             }
             getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(
                     UserHandle.USER_SYSTEM, timeMs);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        });
     }
 
     private void updateProfileLockTimeoutLocked(@UserIdInt int userId) {
@@ -5361,13 +5319,9 @@
         }
         policy.mLastMaximumTimeToLock = timeMs;
 
-        final long ident = mInjector.binderClearCallingIdentity();
-        try {
-            getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(
-                    userId, policy.mLastMaximumTimeToLock);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        mInjector.binderWithCleanCallingIdentity(() ->
+                getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(
+                        userId, policy.mLastMaximumTimeToLock));
     }
 
     @Override
@@ -5635,24 +5589,21 @@
         }
         enforceCanManageCaCerts(admin, callerPackage);
 
-        final String alias;
-
         final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
-            alias = mCertificateMonitor.installCaCert(userHandle, certBuffer);
+        final String alias = mInjector.binderWithCleanCallingIdentity(() -> {
+            String installedAlias = mCertificateMonitor.installCaCert(userHandle, certBuffer);
             final boolean isDelegate = (admin == null);
             DevicePolicyEventLogger
                     .createEvent(DevicePolicyEnums.INSTALL_CA_CERT)
                     .setAdmin(callerPackage)
                     .setBoolean(isDelegate)
                     .write();
-            if (alias == null) {
-                Log.w(LOG_TAG, "Problem installing cert");
-                return false;
-            }
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
+            return installedAlias;
+        });
+
+        if (alias == null) {
+            Log.w(LOG_TAG, "Problem installing cert");
+            return false;
         }
 
         synchronized (getLockObject()) {
@@ -5670,8 +5621,7 @@
         enforceCanManageCaCerts(admin, callerPackage);
 
         final int userId = mInjector.userHandleGetCallingUserId();
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             mCertificateMonitor.uninstallCaCerts(UserHandle.of(userId), aliases);
             final boolean isDelegate = (admin == null);
             DevicePolicyEventLogger
@@ -5679,9 +5629,7 @@
                     .setAdmin(callerPackage)
                     .setBoolean(isDelegate)
                     .write();
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        });
 
         synchronized (getLockObject()) {
             if (getUserData(userId).mOwnerInstalledCaCerts.removeAll(Arrays.asList(aliases))) {
@@ -6085,8 +6033,7 @@
             isDelegate = false;
         }
 
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             mContext.sendOrderedBroadcastAsUser(intent, caller, null, new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
@@ -6099,9 +6046,7 @@
                     .setAdmin(intent.getComponent())
                     .setBoolean(isDelegate)
                     .write();
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        });
     }
 
     private void sendPrivateKeyAliasResponse(final String alias, final IBinder responseBinder) {
@@ -6517,8 +6462,7 @@
         enforceProfileOrDeviceOwner(admin);
 
         final int userId = mInjector.userHandleGetCallingUserId();
-        final long token = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             if (vpnPackage != null && !isPackageInstalledForUser(vpnPackage, userId)) {
                 Slog.w(LOG_TAG, "Non-existent VPN package specified: " + vpnPackage);
                 throw new ServiceSpecificException(
@@ -6546,9 +6490,7 @@
                     .setBoolean(lockdown)
                     .setInt(lockdownWhitelist != null ? lockdownWhitelist.size() : 0)
                     .write();
-        } finally {
-            mInjector.binderRestoreCallingIdentity(token);
-        }
+        });
         return true;
     }
 
@@ -6557,12 +6499,8 @@
         enforceProfileOrDeviceOwner(admin);
 
         final int userId = mInjector.userHandleGetCallingUserId();
-        final long token = mInjector.binderClearCallingIdentity();
-        try {
-            return mInjector.getConnectivityManager().getAlwaysOnVpnPackageForUser(userId);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(token);
-        }
+        return mInjector.binderWithCleanCallingIdentity(
+                () -> mInjector.getConnectivityManager().getAlwaysOnVpnPackageForUser(userId));
     }
 
     @Override
@@ -6570,12 +6508,8 @@
         enforceProfileOrDeviceOwner(admin);
 
         final int userId = mInjector.userHandleGetCallingUserId();
-        final long token = mInjector.binderClearCallingIdentity();
-        try {
-            return mInjector.getConnectivityManager().isVpnLockdownEnabled(userId);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(token);
-        }
+        return mInjector.binderWithCleanCallingIdentity(
+                () -> mInjector.getConnectivityManager().isVpnLockdownEnabled(userId));
     }
 
     @Override
@@ -6584,12 +6518,8 @@
         enforceProfileOrDeviceOwner(admin);
 
         final int userId = mInjector.userHandleGetCallingUserId();
-        final long token = mInjector.binderClearCallingIdentity();
-        try {
-            return mInjector.getConnectivityManager().getVpnLockdownWhitelist(userId);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(token);
-        }
+        return mInjector.binderWithCleanCallingIdentity(
+                () -> mInjector.getConnectivityManager().getVpnLockdownWhitelist(userId));
     }
 
     private void forceWipeDeviceNoLock(boolean wipeExtRequested, String reason, boolean wipeEuicc) {
@@ -6686,8 +6616,7 @@
                 // control over the device, wiping only the work profile. So the user restriction
                 // on profile removal needs to be removed first.
 
-                final long ident = mInjector.binderClearCallingIdentity();
-                try {
+                mInjector.binderWithCleanCallingIdentity(() -> {
                     // Clear restriction as user.
                     mUserManager.setUserRestriction(
                             UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false,
@@ -6695,9 +6624,7 @@
 
                     // Device-wide policies set by the profile owner need to be cleaned up here.
                     mLockPatternUtils.setDeviceOwnerInfo(null);
-                } finally {
-                    mInjector.binderRestoreCallingIdentity(ident);
-                }
+                });
             }
         }
 
@@ -6719,8 +6646,7 @@
                                 String wipeReasonForUser, int userId) {
         wtfIfInLock();
 
-        long ident = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             // First check whether the admin is allowed to wipe the device/user/profile.
             final String restriction;
             if (userId == UserHandle.USER_SYSTEM) {
@@ -6754,9 +6680,7 @@
             } else {
                 forceWipeUser(userId, wipeReasonForUser, (flags & WIPE_SILENTLY) != 0);
             }
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        });
     }
 
     private void sendWipeProfileNotification(String wipeReasonForUser) {
@@ -6931,8 +6855,7 @@
         synchronized (getLockObject()) {
             DevicePolicyData policy = getUserData(userHandle);
             if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
-                long ident = mInjector.binderClearCallingIdentity();
-                try {
+                mInjector.binderWithCleanCallingIdentity(() -> {
                     policy.mFailedPasswordAttempts = 0;
                     policy.mPasswordOwner = -1;
                     saveSettingsLocked(userHandle);
@@ -6941,9 +6864,7 @@
                                 DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
                                 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
                     }
-                } finally {
-                    mInjector.binderRestoreCallingIdentity(ident);
-                }
+                });
             }
         }
 
@@ -7042,12 +6963,7 @@
 
             // Reset the global proxy accordingly
             // Do this using system permissions, as apps cannot write to secure settings
-            long origId = mInjector.binderClearCallingIdentity();
-            try {
-                resetGlobalProxyLocked(policy);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(origId);
-            }
+            mInjector.binderWithCleanCallingIdentity(() -> resetGlobalProxyLocked(policy));
             return null;
         }
     }
@@ -7079,12 +6995,8 @@
     @Override
     public void setRecommendedGlobalProxy(ComponentName who, ProxyInfo proxyInfo) {
         enforceDeviceOwner(who);
-        long token = mInjector.binderClearCallingIdentity();
-        try {
-            mInjector.getConnectivityManager().setGlobalProxy(proxyInfo);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(token);
-        }
+        mInjector.binderWithCleanCallingIdentity(
+                () -> mInjector.getConnectivityManager().setGlobalProxy(proxyInfo));
     }
 
     private void resetGlobalProxyLocked(DevicePolicyData policy) {
@@ -7376,12 +7288,9 @@
         // TODO: (b/145604635) Add upgrade case
         // Turn AUTO_TIME on in settings if it is required
         if (required) {
-            long ident = mInjector.binderClearCallingIdentity();
-            try {
-                mInjector.settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1 /* AUTO_TIME on */);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
-            }
+            mInjector.binderWithCleanCallingIdentity(
+                    () -> mInjector.settingsGlobalPutInt(Settings.Global.AUTO_TIME,
+                            1 /* AUTO_TIME on */));
         }
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_AUTO_TIME_REQUIRED)
@@ -7512,12 +7421,7 @@
             }
         }
         if (removeAllUsers) {
-            long identitity = mInjector.binderClearCallingIdentity();
-            try {
-                mUserManagerInternal.removeAllUsers();
-            } finally {
-                mInjector.binderRestoreCallingIdentity(identitity);
-            }
+            mInjector.binderWithCleanCallingIdentity(() -> mUserManagerInternal.removeAllUsers());
         }
     }
 
@@ -8030,25 +7934,10 @@
             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?
-                sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, userId);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
-            }
+            // TODO Send to system too?
+            mInjector.binderWithCleanCallingIdentity(
+                    () -> sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED,
+                            userId));
             mDeviceAdminServiceController.startServiceForOwner(
                     admin.getPackageName(), userId, "set-device-owner");
 
@@ -8229,15 +8118,12 @@
             }
 
             final ActiveAdmin admin = getDeviceOwnerAdminLocked();
-            long ident = mInjector.binderClearCallingIdentity();
-            try {
+            mInjector.binderWithCleanCallingIdentity(() -> {
                 clearDeviceOwnerLocked(admin, deviceOwnerUserId);
                 removeActiveAdminLocked(deviceOwnerComponent, deviceOwnerUserId);
                 sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED,
                         deviceOwnerUserId);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
-            }
+            });
             Slog.i(LOG_TAG, "Device owner removed: " + deviceOwnerComponent);
         }
     }
@@ -8323,8 +8209,7 @@
             mOwners.writeProfileOwner(userHandle);
             Slog.i(LOG_TAG, "Profile owner set: " + who + " on user " + userHandle);
 
-            final long id = mInjector.binderClearCallingIdentity();
-            try {
+            mInjector.binderWithCleanCallingIdentity(() -> {
                 if (mUserManager.isManagedProfile(userHandle)) {
                     maybeSetDefaultRestrictionsForAdminLocked(userHandle, admin,
                             UserRestrictionsUtils.getDefaultEnabledForManagedProfiles());
@@ -8333,9 +8218,7 @@
                 }
                 sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED,
                         userHandle);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(id);
-            }
+            });
             mDeviceAdminServiceController.startServiceForOwner(
                     who.getPackageName(), userHandle, "set-profile-owner");
             return true;
@@ -8373,15 +8256,12 @@
             final ActiveAdmin admin =
                     getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            final long ident = mInjector.binderClearCallingIdentity();
-            try {
+            mInjector.binderWithCleanCallingIdentity(() -> {
                 clearProfileOwnerLocked(admin, userId);
                 removeActiveAdminLocked(who, userId);
                 sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED,
                         userId);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
-            }
+            });
             Slog.i(LOG_TAG, "Profile owner " + who + " removed from user " + userId);
         }
     }
@@ -8590,8 +8470,7 @@
                         "setProfileEnabled is called when the profile is already enabled");
                 return;
             }
-            long id = mInjector.binderClearCallingIdentity();
-            try {
+            mInjector.binderWithCleanCallingIdentity(() -> {
                 mUserManager.setUserEnabled(userId);
                 UserInfo parent = mUserManager.getProfileParent(userId);
                 Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED);
@@ -8599,9 +8478,7 @@
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY |
                         Intent.FLAG_RECEIVER_FOREGROUND);
                 mContext.sendBroadcastAsUser(intent, new UserHandle(parent.id));
-            } finally {
-                mInjector.binderRestoreCallingIdentity(id);
-            }
+            });
         }
     }
 
@@ -8611,16 +8488,13 @@
         enforceProfileOrDeviceOwner(who);
 
         final int userId = UserHandle.getCallingUserId();
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             mUserManager.setUserName(userId, profileName);
             DevicePolicyEventLogger
                     .createEvent(DevicePolicyEnums.SET_PROFILE_NAME)
                     .setAdmin(who)
                     .write();
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        });
     }
 
     @Override
@@ -8662,8 +8536,7 @@
 
     @GuardedBy("getLockObject()")
     ActiveAdmin getProfileOwnerOfOrganizationOwnedDeviceLocked(int userHandle) {
-        final long ident = mInjector.binderClearCallingIdentity();
-        try {
+        return mInjector.binderWithCleanCallingIdentity(() -> {
             for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) {
                 if (userInfo.isManagedProfile()) {
                     if (getProfileOwner(userInfo.id) != null
@@ -8673,10 +8546,8 @@
                     }
                 }
             }
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
-        return null;
+            return null;
+        });
     }
 
     @Override
@@ -8717,9 +8588,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;
         }
 
@@ -8773,8 +8650,7 @@
      * Canonical name for a given package.
      */
     private String getApplicationLabel(String packageName, int userHandle) {
-        long token = mInjector.binderClearCallingIdentity();
-        try {
+        return mInjector.binderWithCleanCallingIdentity(() -> {
             final Context userContext;
             try {
                 UserHandle handle = new UserHandle(userHandle);
@@ -8789,9 +8665,7 @@
                 result = appInfo.loadUnsafeLabel(userContext.getPackageManager());
             }
             return result != null ? result.toString() : null;
-        } finally {
-            mInjector.binderRestoreCallingIdentity(token);
-        }
+        });
     }
 
     /**
@@ -9082,28 +8956,23 @@
     }
 
     protected int getProfileParentId(int userHandle) {
-        final long ident = mInjector.binderClearCallingIdentity();
-        try {
+        return mInjector.binderWithCleanCallingIdentity(() -> {
             UserInfo parentUser = mUserManager.getProfileParent(userHandle);
             return parentUser != null ? parentUser.id : userHandle;
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        });
     }
 
-    private int getCredentialOwner(int userHandle, boolean parent) {
-        final long ident = mInjector.binderClearCallingIdentity();
-        try {
+    private int getCredentialOwner(final int userHandle, final boolean parent) {
+        return mInjector.binderWithCleanCallingIdentity(() -> {
+            int effectiveUserHandle = userHandle;
             if (parent) {
                 UserInfo parentProfile = mUserManager.getProfileParent(userHandle);
                 if (parentProfile != null) {
-                    userHandle = parentProfile.id;
+                    effectiveUserHandle = parentProfile.id;
                 }
             }
-            return mUserManager.getCredentialOwnerProfile(userHandle);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+            return mUserManager.getCredentialOwnerProfile(effectiveUserHandle);
+        });
     }
 
     private boolean isManagedProfile(int userHandle) {
@@ -9290,8 +9159,7 @@
                 DELEGATION_APP_RESTRICTIONS);
 
         final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             mUserManager.setApplicationRestrictions(packageName, settings, userHandle);
             final boolean isDelegate = (who == null);
             DevicePolicyEventLogger
@@ -9300,9 +9168,7 @@
                     .setBoolean(isDelegate)
                     .setStrings(packageName)
                     .write();
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        });
     }
 
     @Override
@@ -10045,8 +9911,7 @@
         enforceDeviceOwner(who);
 
         final int callingUserId = mInjector.userHandleGetCallingUserId();
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
+        return mInjector.binderWithCleanCallingIdentity(() -> {
             String restriction = isManagedProfile(userHandle.getIdentifier())
                     ? UserManager.DISALLOW_REMOVE_MANAGED_PROFILE
                     : UserManager.DISALLOW_REMOVE_USER;
@@ -10056,9 +9921,7 @@
                 return false;
             }
             return mUserManagerInternal.removeUserEvenWhenDisallowed(userHandle.getIdentifier());
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        });
     }
 
     private boolean isAdminAffectedByRestriction(
@@ -10204,8 +10067,7 @@
         Preconditions.checkNotNull(who, "ComponentName is null");
         enforceDeviceOwner(who);
 
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
+        return mInjector.binderWithCleanCallingIdentity(() -> {
             final List<UserInfo> userInfos = mInjector.getUserManager().getUsers(true
                     /*excludeDying*/);
             final List<UserHandle> userHandles = new ArrayList<>();
@@ -10216,9 +10078,7 @@
                 }
             }
             return userHandles;
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        });
     }
 
     @Override
@@ -10227,12 +10087,8 @@
         enforceProfileOrDeviceOwner(who);
 
         final int callingUserId = mInjector.userHandleGetCallingUserId();
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
-            return mInjector.getUserManager().isUserEphemeral(callingUserId);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        return mInjector.binderWithCleanCallingIdentity(
+                () -> mInjector.getUserManager().isUserEphemeral(callingUserId));
     }
 
     @Override
@@ -10242,15 +10098,12 @@
                 DELEGATION_APP_RESTRICTIONS);
 
         final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
-           Bundle bundle = mUserManager.getApplicationRestrictions(packageName, userHandle);
+        return mInjector.binderWithCleanCallingIdentity(() -> {
+            Bundle bundle = mUserManager.getApplicationRestrictions(packageName, userHandle);
            // if no restrictions were saved, mUserManager.getApplicationRestrictions
            // returns null, but DPM method should return an empty Bundle as per JavaDoc
            return bundle != null ? bundle : Bundle.EMPTY;
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        });
     }
 
     @Override
@@ -10384,8 +10237,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 +10272,10 @@
                             userRestrictions, userId);
                 }
             }
+            // Remove deprecated restrictions.
+            for (String deprecatedRestriction: DEPRECATED_USER_RESTRICTIONS) {
+                userRestrictions.remove(deprecatedRestriction);
+            }
             mUserManagerInternal.setDevicePolicyUserRestrictions(originatingUserId,
                     userRestrictions, restrictionOwnerType);
         }
@@ -10871,8 +10728,7 @@
                 actualContactId, isContactIdIgnored, actualDirectoryId, originalIntent);
         final int callingUserId = UserHandle.getCallingUserId();
 
-        final long ident = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             synchronized (getLockObject()) {
                 final int managedUserId = getManagedUserId(callingUserId);
                 if (managedUserId < 0) {
@@ -10888,9 +10744,7 @@
                 ContactsInternal.startQuickContactWithErrorToastForUser(
                         mContext, intent, new UserHandle(managedUserId));
             }
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        });
     }
 
     /**
@@ -11050,8 +10904,7 @@
     }
 
     private void maybeClearLockTaskPolicyLocked() {
-        final long ident = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true);
             for (int i = userInfos.size() - 1; i >= 0; i--) {
                 int userId = userInfos.get(i).id;
@@ -11072,9 +10925,7 @@
                     setLockTaskFeaturesLocked(userId, DevicePolicyManager.LOCK_TASK_FEATURE_NONE);
                 }
             }
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        });
     }
 
     @Override
@@ -11147,12 +10998,8 @@
                 }
             }
 
-            long id = mInjector.binderClearCallingIdentity();
-            try {
-                mInjector.settingsGlobalPutString(setting, value);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(id);
-            }
+            mInjector.binderWithCleanCallingIdentity(
+                    () -> mInjector.settingsGlobalPutString(setting, value));
         }
     }
 
@@ -11272,8 +11119,7 @@
                 }
                 return;
             }
-            long id = mInjector.binderClearCallingIdentity();
-            try {
+            mInjector.binderWithCleanCallingIdentity(() -> {
                 if (Settings.Secure.DEFAULT_INPUT_METHOD.equals(setting)) {
                     final String currentValue = mInjector.settingsSecureGetStringForUser(
                             Settings.Secure.DEFAULT_INPUT_METHOD, callingUserId);
@@ -11289,9 +11135,7 @@
                     saveSettingsLocked(callingUserId);
                 }
                 mInjector.settingsSecurePutStringForUser(setting, value, callingUserId);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(id);
-            }
+            });
         }
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_SECURE_SETTING)
@@ -11333,12 +11177,8 @@
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             int userId = UserHandle.getCallingUserId();
-            long id = mInjector.binderClearCallingIdentity();
-            try {
-                mUserManagerInternal.setUserIcon(userId, icon);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(id);
-            }
+            mInjector.binderWithCleanCallingIdentity(
+                    () -> mUserManagerInternal.setUserIcon(userId, icon));
         }
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_USER_ICON)
@@ -11737,15 +11577,12 @@
 
         @Override
         public void reportSeparateProfileChallengeChanged(@UserIdInt int userId) {
-            final long ident = mInjector.binderClearCallingIdentity();
-            try {
+            mInjector.binderWithCleanCallingIdentity(() -> {
                 synchronized (getLockObject()) {
                     updateMaximumTimeToLockLocked(userId);
                     updatePasswordQualityCacheForUserGroup(userId);
                 }
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
-            }
+            });
             DevicePolicyEventLogger
                     .createEvent(DevicePolicyEnums.SEPARATE_PROFILE_CHALLENGE_CHANGED)
                     .setBoolean(isSeparateProfileChallengeEnabled(userId))
@@ -12037,8 +11874,7 @@
                 .putExtra(DeviceAdminReceiver.EXTRA_SYSTEM_UPDATE_RECEIVED_TIME,
                         info == null ? -1 : info.getReceivedTime());
 
-        final long ident = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             synchronized (getLockObject()) {
                 // Broadcast to device owner first if there is one.
                 if (mOwners.hasDeviceOwner()) {
@@ -12068,9 +11904,7 @@
                     }
                 }
             }
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        });
     }
 
     @Override
@@ -12194,8 +12028,7 @@
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, DELEGATION_PERMISSION_GRANT);
         }
         synchronized (getLockObject()) {
-            long ident = mInjector.binderClearCallingIdentity();
-            try {
+            return mInjector.binderWithCleanCallingIdentity(() -> {
                 int granted;
                 if (getTargetSdk(callerPackage, user.getIdentifier())
                         < android.os.Build.VERSION_CODES.Q) {
@@ -12230,9 +12063,7 @@
                             ? DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED
                             : DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED;
                 }
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
-            }
+            });
         }
     }
 
@@ -12472,8 +12303,7 @@
         // Make sure caller has DO.
         enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(admin);
 
-        final long ident = mInjector.binderClearCallingIdentity();
-        try {
+        return mInjector.binderWithCleanCallingIdentity(() -> {
             String[] macAddresses = mInjector.getWifiManager().getFactoryMacAddresses();
             if (macAddresses == null) {
                 return null;
@@ -12483,9 +12313,7 @@
                     .setAdmin(admin)
                     .write();
             return macAddresses.length > 0 ? macAddresses[0] : null;
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        });
     }
 
     /**
@@ -12521,8 +12349,7 @@
         Preconditions.checkNotNull(admin);
         // Make sure caller has DO.
         enforceDeviceOwner(admin);
-        long ident = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             // Make sure there are no ongoing calls on the device.
             if (mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
                 throw new IllegalStateException("Cannot be called with ongoing call on the device");
@@ -12532,9 +12359,7 @@
                     .setAdmin(admin)
                     .write();
             mInjector.powerManagerReboot(PowerManager.REBOOT_REQUESTED_BY_DEVICE_OWNER);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        });
     }
 
     @Override
@@ -12771,17 +12596,14 @@
             final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             final int callingUserId = mInjector.userHandleGetCallingUserId();
-            final long identity = mInjector.binderClearCallingIdentity();
-            try {
+            return mInjector.binderWithCleanCallingIdentity(() -> {
                 final List<String> excludedPkgs
                         = removeInvalidPkgsForMeteredDataRestriction(callingUserId, packageNames);
                 admin.meteredDisabledPackages = packageNames;
                 pushMeteredDisabledPackagesLocked(callingUserId);
                 saveSettingsLocked(callingUserId);
                 return excludedPkgs;
-            } finally {
-                mInjector.binderRestoreCallingIdentity(identity);
-            }
+            });
         }
     }
 
@@ -12894,8 +12716,7 @@
                     who.flattenToString(), userId));
 
             // First, set restriction on removing the profile.
-            final long ident = mInjector.binderClearCallingIdentity();
-            try {
+            mInjector.binderWithCleanCallingIdentity(() -> {
                 // Clear restriction as user.
                 UserHandle parentUser = mUserManager.getProfileParent(UserHandle.of(userId));
                 if (!parentUser.isSystem()) {
@@ -12907,9 +12728,7 @@
 
                 mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, true,
                         parentUser);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
-            }
+            });
 
             // markProfileOwnerOfOrganizationOwnedDevice will trigger writing of the profile owner
             // data, no need to do it manually.
@@ -13027,8 +12846,7 @@
     }
 
     private boolean areAllUsersAffiliatedWithDeviceLocked() {
-        final long ident = mInjector.binderClearCallingIdentity();
-        try {
+        return mInjector.binderWithCleanCallingIdentity(() -> {
             final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true);
             for (int i = 0; i < userInfos.size(); i++) {
                 int userId = userInfos.get(i).id;
@@ -13037,11 +12855,8 @@
                     return false;
                 }
             }
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
-
-        return true;
+            return true;
+        });
     }
 
     @Override
@@ -13251,12 +13066,8 @@
     private boolean isCurrentUserDemo() {
         if (UserManager.isDeviceInDemoMode(mContext)) {
             final int userId = mInjector.userHandleGetCallingUserId();
-            final long callingIdentity = mInjector.binderClearCallingIdentity();
-            try {
-                return mUserManager.getUserInfo(userId).isDemo();
-            } finally {
-                mInjector.binderRestoreCallingIdentity(callingIdentity);
-            }
+            return mInjector.binderWithCleanCallingIdentity(
+                    () -> mUserManager.getUserInfo(userId).isDemo());
         }
         return false;
     }
@@ -13472,8 +13283,7 @@
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             final int callingUserId = mInjector.userHandleGetCallingUserId();
-            final long callingIdentity = mInjector.binderClearCallingIdentity();
-            try {
+            return mInjector.binderWithCleanCallingIdentity(() -> {
                 ArrayList<UserHandle> targetUsers = new ArrayList<>();
                 if (!isDeviceOwner(admin, callingUserId)) {
                     // Profile owners can only bind to the device owner.
@@ -13492,9 +13302,7 @@
                 }
 
                 return targetUsers;
-            } finally {
-                mInjector.binderRestoreCallingIdentity(callingIdentity);
-            }
+            });
         }
     }
 
@@ -13535,8 +13343,7 @@
         }
         wtfIfInLock();
 
-        final long token = mInjector.binderClearCallingIdentity();
-        try {
+        return mInjector.binderWithCleanCallingIdentity(() -> {
             final AccountManager am = AccountManager.get(mContext);
             final Account accounts[] = am.getAccountsAsUser(userId);
             if (accounts.length == 0) {
@@ -13574,9 +13381,7 @@
                 Log.e(LOG_TAG, "Found incompatible accounts");
             }
             return !compatible;
-        } finally {
-            mInjector.binderRestoreCallingIdentity(token);
-        }
+        });
     }
 
     private boolean hasAccountFeatures(AccountManager am, Account account, String[] features) {
@@ -13629,8 +13434,7 @@
 
     private void setNetworkLoggingActiveInternal(boolean active) {
         synchronized (getLockObject()) {
-            final long callingIdentity = mInjector.binderClearCallingIdentity();
-            try {
+            mInjector.binderWithCleanCallingIdentity(() -> {
                 if (active) {
                     mNetworkLogger = new NetworkLogger(this, mInjector.getPackageManagerInternal());
                     if (!mNetworkLogger.startNetworkLogging()) {
@@ -13648,9 +13452,7 @@
                     mNetworkLogger = null;
                     mInjector.getNotificationManager().cancel(SystemMessage.NOTE_NETWORK_LOGGING);
                 }
-            } finally {
-                mInjector.binderRestoreCallingIdentity(callingIdentity);
-            }
+            });
         }
     }
 
@@ -13662,12 +13464,8 @@
                 throw new IllegalStateException("logging is not available");
             }
             if (mNetworkLogger != null) {
-                final long ident = mInjector.binderClearCallingIdentity();
-                try {
-                    return mNetworkLogger.forceBatchFinalization();
-                } finally {
-                    mInjector.binderRestoreCallingIdentity(ident);
-                }
+                return mInjector.binderWithCleanCallingIdentity(
+                        () -> mNetworkLogger.forceBatchFinalization());
             }
             return 0;
         }
@@ -13690,15 +13488,12 @@
     @GuardedBy("getLockObject()")
     private void maybeResumeDeviceWideLoggingLocked() {
         if (areAllUsersAffiliatedWithDeviceLocked()) {
-            final long ident = mInjector.binderClearCallingIdentity();
-            try {
+            mInjector.binderWithCleanCallingIdentity(() -> {
                 mSecurityLogMonitor.resume();
                 if (mNetworkLogger != null) {
                     mNetworkLogger.resume();
                 }
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
-            }
+            });
         }
     }
 
@@ -13887,8 +13682,7 @@
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             DevicePolicyData policy = getUserData(userHandle);
-            long ident = mInjector.binderClearCallingIdentity();
-            try {
+            return mInjector.binderWithCleanCallingIdentity(() -> {
                 if (policy.mPasswordTokenHandle != 0) {
                     mLockPatternUtils.removeEscrowToken(policy.mPasswordTokenHandle, userHandle);
                 }
@@ -13896,9 +13690,7 @@
                         userHandle, /*EscrowTokenStateChangeCallback*/ null);
                 saveSettingsLocked(userHandle);
                 return policy.mPasswordTokenHandle != 0;
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
-            }
+            });
         }
     }
 
@@ -13913,16 +13705,13 @@
 
             DevicePolicyData policy = getUserData(userHandle);
             if (policy.mPasswordTokenHandle != 0) {
-                long ident = mInjector.binderClearCallingIdentity();
-                try {
+                return mInjector.binderWithCleanCallingIdentity(() -> {
                     boolean result = mLockPatternUtils.removeEscrowToken(
                             policy.mPasswordTokenHandle, userHandle);
                     policy.mPasswordTokenHandle = 0;
                     saveSettingsLocked(userHandle);
                     return result;
-                } finally {
-                    mInjector.binderRestoreCallingIdentity(ident);
-                }
+                });
             }
         }
         return false;
@@ -13939,13 +13728,9 @@
 
             DevicePolicyData policy = getUserData(userHandle);
             if (policy.mPasswordTokenHandle != 0) {
-                long ident = mInjector.binderClearCallingIdentity();
-                try {
-                    return mLockPatternUtils.isEscrowTokenActive(policy.mPasswordTokenHandle,
-                            userHandle);
-                } finally {
-                    mInjector.binderRestoreCallingIdentity(ident);
-                }
+                return mInjector.binderWithCleanCallingIdentity(
+                        () -> mLockPatternUtils.isEscrowTokenActive(policy.mPasswordTokenHandle,
+                                userHandle));
             }
         }
         return false;
@@ -14315,13 +14100,8 @@
         enforceDeviceOwner(who);
 
         int operatedId = -1;
-        Uri resultUri;
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
-            resultUri = mContext.getContentResolver().insert(DPC_URI, apnSetting.toContentValues());
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        Uri resultUri = mInjector.binderWithCleanCallingIdentity(() ->
+                mContext.getContentResolver().insert(DPC_URI, apnSetting.toContentValues()));
         if (resultUri != null) {
             try {
                 operatedId = Integer.parseInt(resultUri.getLastPathSegment());
@@ -14346,14 +14126,10 @@
         if (apnId < 0) {
             return false;
         }
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
-            return mContext.getContentResolver().update(
-                    Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)),
-                    apnSetting.toContentValues(), null, null) > 0;
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        return mInjector.binderWithCleanCallingIdentity(() ->
+                mContext.getContentResolver().update(
+                        Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)),
+                        apnSetting.toContentValues(), null, null) > 0);
     }
 
     @Override
@@ -14371,14 +14147,9 @@
         if(apnId < 0) {
             return false;
         }
-        int numDeleted = 0;
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
-            numDeleted = mContext.getContentResolver().delete(
-                    Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)), null, null);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        int numDeleted = mInjector.binderWithCleanCallingIdentity(
+                () -> mContext.getContentResolver().delete(
+                        Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)), null, null));
         return numDeleted > 0;
     }
 
@@ -14394,13 +14165,8 @@
     }
 
     private List<ApnSetting> getOverrideApnsUnchecked() {
-        final Cursor cursor;
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
-            cursor = mContext.getContentResolver().query(DPC_URI, null, null, null, null);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        final Cursor cursor = mInjector.binderWithCleanCallingIdentity(
+                () -> mContext.getContentResolver().query(DPC_URI, null, null, null, null));
 
         if (cursor == null) {
             return Collections.emptyList();
@@ -14432,13 +14198,8 @@
     private void setOverrideApnsEnabledUnchecked(boolean enabled) {
         ContentValues value = new ContentValues();
         value.put(ENFORCE_KEY, enabled);
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
-            mContext.getContentResolver().update(
-                    ENFORCE_MANAGED_URI, value, null, null);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        mInjector.binderWithCleanCallingIdentity(() -> mContext.getContentResolver().update(
+                    ENFORCE_MANAGED_URI, value, null, null));
     }
 
     @Override
@@ -14449,14 +14210,9 @@
         Preconditions.checkNotNull(who, "ComponentName is null in isOverrideApnEnabled");
         enforceDeviceOwner(who);
 
-        Cursor enforceCursor;
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
-            enforceCursor = mContext.getContentResolver().query(
-                    ENFORCE_MANAGED_URI, null, null, null, null);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        Cursor enforceCursor = mInjector.binderWithCleanCallingIdentity(
+                () -> mContext.getContentResolver().query(
+                        ENFORCE_MANAGED_URI, null, null, null, null));
 
         if (enforceCursor == null) {
             return false;
@@ -14523,13 +14279,10 @@
     private void putPrivateDnsSettings(@Nullable String mode, @Nullable String host) {
         // Set Private DNS settings using system permissions, as apps cannot write
         // to global settings.
-        long origId = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             mInjector.settingsGlobalPutString(PRIVATE_DNS_MODE, mode);
             mInjector.settingsGlobalPutString(PRIVATE_DNS_SPECIFIER, host);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(origId);
-        }
+        });
     }
 
     @Override
@@ -14615,8 +14368,7 @@
                 .setBoolean(isDeviceAB())
                 .write();
         enforceDeviceOwner(admin);
-        final long id = mInjector.binderClearCallingIdentity();
-        try {
+        mInjector.binderWithCleanCallingIdentity(() -> {
             UpdateInstaller updateInstaller;
             if (isDeviceAB()) {
                 updateInstaller = new AbUpdateInstaller(
@@ -14626,9 +14378,7 @@
                         mContext, updateFileDescriptor, callback, mInjector, mConstants);
             }
             updateInstaller.startInstallUpdate();
-        } finally {
-            mInjector.binderRestoreCallingIdentity(id);
-        }
+        });
     }
 
     private boolean isDeviceAB() {
@@ -14829,8 +14579,7 @@
             throw new SecurityException("Input package name doesn't align with actual "
                     + "calling package.");
         }
-        final long identity = mInjector.binderClearCallingIdentity();
-        try {
+        return mInjector.binderWithCleanCallingIdentity(() -> {
             final int workProfileUserId = getManagedUserId(callingUserId);
             if (workProfileUserId < 0) {
                 return false;
@@ -14854,10 +14603,8 @@
                 Log.e(LOG_TAG, "View event activity not found", e);
                 return false;
             }
-        } finally {
-            mInjector.binderRestoreCallingIdentity(identity);
-        }
-        return true;
+            return true;
+        });
     }
 
     private boolean isCallingFromPackage(String packageName, int callingUid) {
diff --git a/services/incremental/Android.bp b/services/incremental/Android.bp
new file mode 100644
index 0000000..2661925
--- /dev/null
+++ b/services/incremental/Android.bp
@@ -0,0 +1,110 @@
+// 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.
+
+cc_defaults {
+    name: "service.incremental-proto-defaults",
+
+    cpp_std: "c++2a",
+    proto: {
+        type: "lite",
+    },
+}
+
+cc_defaults {
+    name: "service.incremental-defaults",
+    defaults: ["service.incremental-proto-defaults"],
+    local_include_dirs: ["include/"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-Wno-unused-parameter",
+    ],
+
+    static_libs: [
+        "libbase",
+        "libext2_uuid",
+        "libdataloader_aidl-cpp",
+        "libincremental_aidl-cpp",
+        "libincremental_manager_aidl-cpp",
+        "libnativehelper",
+        "libprotobuf-cpp-lite",
+        "service.incremental.proto",
+        "libutils",
+        "libvold_binder",
+    ],
+    shared_libs: [
+        "libandroidfw",
+        "libbinder",
+        "libincfs",
+        "liblog",
+        "libz",
+        "libziparchive",
+    ],
+}
+
+filegroup {
+    name: "service.incremental_srcs",
+    srcs: [
+        "incremental_service.c",
+        "IncrementalService.cpp",
+        "BinderIncrementalService.cpp",
+        "path.cpp",
+        "ServiceWrappers.cpp",
+    ],
+}
+
+cc_library {
+    name: "service.incremental",
+    defaults: [
+        "service.incremental-defaults",
+        "linux_bionic_supported",
+    ],
+
+    export_include_dirs: ["include/",],
+    srcs: [
+        ":service.incremental_srcs",
+    ],
+}
+
+cc_library_headers {
+    name: "service.incremental_headers",
+    export_include_dirs: ["include/",],
+}
+
+cc_library_static {
+    name: "service.incremental.proto",
+    defaults: ["service.incremental-proto-defaults"],
+    proto: {
+        export_proto_headers: true,
+    },
+
+    srcs: [
+        "Metadata.proto",
+    ],
+}
+
+cc_test {
+    name: "service.incremental_test",
+    defaults: ["service.incremental-defaults"],
+    test_suites: ["device-tests"],
+    srcs: [
+        ":service.incremental_srcs",
+        "test/IncrementalServiceTest.cpp",
+        "test/path_test.cpp",
+    ],
+    static_libs: [
+        "libgmock",
+    ]
+}
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
new file mode 100644
index 0000000..bb26c1f
--- /dev/null
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -0,0 +1,230 @@
+/*
+ * 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 "BinderIncrementalService.h"
+
+#include <binder/IResultReceiver.h>
+#include <incfs.h>
+
+#include "ServiceWrappers.h"
+#include "jni.h"
+#include "nativehelper/JNIHelp.h"
+#include "path.h"
+
+using namespace std::literals;
+using namespace android::incremental;
+
+namespace android::os::incremental {
+
+static constexpr auto kAndroidDataEnv = "ANDROID_DATA"sv;
+static constexpr auto kDataDir = "/data"sv;
+static constexpr auto kIncrementalSubDir = "incremental"sv;
+
+static std::string getIncrementalDir() {
+    const char* dataDir = getenv(kAndroidDataEnv.data());
+    if (!dataDir || !*dataDir) {
+        dataDir = kDataDir.data();
+    }
+    return path::normalize(path::join(dataDir, kIncrementalSubDir));
+}
+
+static bool incFsEnabled() {
+    // TODO(b/136132412): use vold to check /sys/fs/incfs/version (per selinux compliance)
+    return incfs::enabled();
+}
+
+static bool incFsVersionValid(const sp<IVold>& vold) {
+    int version = -1;
+    auto status = vold->incFsVersion(&version);
+    if (!status.isOk() || version <= 0) {
+        return false;
+    }
+    return true;
+}
+
+BinderIncrementalService::BinderIncrementalService(const sp<IServiceManager>& sm)
+      : mImpl(RealServiceManager(sm), getIncrementalDir()) {}
+
+BinderIncrementalService* BinderIncrementalService::start() {
+    if (!incFsEnabled()) {
+        return nullptr;
+    }
+
+    IPCThreadState::self()->disableBackgroundScheduling(true);
+    sp<IServiceManager> sm(defaultServiceManager());
+    if (!sm) {
+        return nullptr;
+    }
+
+    sp<IBinder> voldBinder(sm->getService(String16("vold")));
+    if (voldBinder == nullptr) {
+        return nullptr;
+    }
+    sp<IVold> vold = interface_cast<IVold>(voldBinder);
+    if (!incFsVersionValid(vold)) {
+        return nullptr;
+    }
+
+    sp<BinderIncrementalService> self(new BinderIncrementalService(sm));
+    status_t ret = sm->addService(String16{getServiceName()}, self);
+    if (ret != android::OK) {
+        return nullptr;
+    }
+    sp<ProcessState> ps(ProcessState::self());
+    ps->startThreadPool();
+    ps->giveThreadPoolName();
+    return self.get();
+}
+
+status_t BinderIncrementalService::dump(int fd, const Vector<String16>& args) {
+    return OK;
+}
+
+void BinderIncrementalService::onSystemReady() {
+    mImpl.onSystemReady();
+}
+
+static binder::Status ok() {
+    return binder::Status::ok();
+}
+
+binder::Status BinderIncrementalService::openStorage(const std::string& path,
+                                                     int32_t* _aidl_return) {
+    *_aidl_return = mImpl.openStorage(path);
+    return ok();
+}
+
+binder::Status BinderIncrementalService::createStorage(
+        const std::string& path, const DataLoaderParamsParcel& params,
+        int32_t createMode, int32_t* _aidl_return) {
+    *_aidl_return =
+            mImpl.createStorage(path, const_cast<DataLoaderParamsParcel&&>(params),
+                                android::incremental::IncrementalService::CreateOptions(
+                                        createMode));
+    return ok();
+}
+
+binder::Status BinderIncrementalService::createLinkedStorage(const std::string& path,
+                                                             int32_t otherStorageId,
+                                                             int32_t createMode,
+                                                             int32_t* _aidl_return) {
+    *_aidl_return =
+            mImpl.createLinkedStorage(path, otherStorageId,
+                                      android::incremental::IncrementalService::CreateOptions(
+                                              createMode));
+    return ok();
+}
+
+binder::Status BinderIncrementalService::makeBindMount(int32_t storageId,
+                                                       const std::string& pathUnderStorage,
+                                                       const std::string& targetFullPath,
+                                                       int32_t bindType, int32_t* _aidl_return) {
+    *_aidl_return = mImpl.bind(storageId, pathUnderStorage, targetFullPath,
+                               android::incremental::IncrementalService::BindKind(bindType));
+    return ok();
+}
+
+binder::Status BinderIncrementalService::deleteBindMount(int32_t storageId,
+                                                         const std::string& targetFullPath,
+                                                         int32_t* _aidl_return) {
+    *_aidl_return = mImpl.unbind(storageId, targetFullPath);
+    return ok();
+}
+
+binder::Status BinderIncrementalService::deleteStorage(int32_t storageId) {
+    mImpl.deleteStorage(storageId);
+    return ok();
+}
+
+binder::Status BinderIncrementalService::makeDirectory(int32_t storageId,
+                                                       const std::string& pathUnderStorage,
+                                                       int32_t* _aidl_return) {
+    auto inode = mImpl.makeDir(storageId, pathUnderStorage);
+    *_aidl_return = inode < 0 ? inode : 0;
+    return ok();
+}
+
+binder::Status BinderIncrementalService::makeDirectories(int32_t storageId,
+                                                         const std::string& pathUnderStorage,
+                                                         int32_t* _aidl_return) {
+    auto inode = mImpl.makeDirs(storageId, pathUnderStorage);
+    *_aidl_return = inode < 0 ? inode : 0;
+    return ok();
+}
+
+binder::Status BinderIncrementalService::makeFile(int32_t storageId,
+                                                  const std::string& pathUnderStorage, int64_t size,
+                                                  const std::vector<uint8_t>& metadata,
+                                                  int32_t* _aidl_return) {
+    auto inode = mImpl.makeFile(storageId, pathUnderStorage, size,
+                                {(const char*)metadata.data(), metadata.size()}, {});
+    *_aidl_return = inode < 0 ? inode : 0;
+    return ok();
+}
+binder::Status BinderIncrementalService::makeFileFromRange(
+        int32_t storageId, const std::string& pathUnderStorage,
+        const std::string& sourcePathUnderStorage, int64_t start, int64_t end,
+        int32_t* _aidl_return) {
+    // TODO(b/136132412): implement this
+    *_aidl_return = -1;
+    return ok();
+}
+binder::Status BinderIncrementalService::makeLink(int32_t sourceStorageId,
+                                                  const std::string& relativeSourcePath,
+                                                  int32_t destStorageId,
+                                                  const std::string& relativeDestPath,
+                                                  int32_t* _aidl_return) {
+    auto sourceInode = mImpl.nodeFor(sourceStorageId, relativeSourcePath);
+    auto [targetParentInode, name] = mImpl.parentAndNameFor(destStorageId, relativeDestPath);
+    *_aidl_return = mImpl.link(sourceStorageId, sourceInode, targetParentInode, name);
+    return ok();
+}
+binder::Status BinderIncrementalService::unlink(int32_t storageId,
+                                                const std::string& pathUnderStorage,
+                                                int32_t* _aidl_return) {
+    auto [parentNode, name] = mImpl.parentAndNameFor(storageId, pathUnderStorage);
+    *_aidl_return = mImpl.unlink(storageId, parentNode, name);
+    return ok();
+}
+binder::Status BinderIncrementalService::isFileRangeLoaded(int32_t storageId,
+                                                           const std::string& relativePath,
+                                                           int64_t start, int64_t end,
+                                                           bool* _aidl_return) {
+    *_aidl_return = false;
+    return ok();
+}
+binder::Status BinderIncrementalService::getFileMetadata(int32_t storageId,
+                                                         const std::string& relativePath,
+                                                         std::vector<uint8_t>* _aidl_return) {
+    auto inode = mImpl.nodeFor(storageId, relativePath);
+    auto metadata = mImpl.getMetadata(storageId, inode);
+    _aidl_return->assign(metadata.begin(), metadata.end());
+    return ok();
+}
+binder::Status BinderIncrementalService::startLoading(int32_t storageId, bool* _aidl_return) {
+    *_aidl_return = mImpl.startLoading(storageId);
+    return ok();
+}
+} // namespace android::os::incremental
+
+jlong Incremental_IncrementalService_Start() {
+    return (jlong)android::os::incremental::BinderIncrementalService::start();
+}
+void Incremental_IncrementalService_OnSystemReady(jlong self) {
+    if (self) {
+        ((android::os::incremental::BinderIncrementalService*)self)->onSystemReady();
+    }
+}
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
new file mode 100644
index 0000000..37c9661d
--- /dev/null
+++ b/services/incremental/BinderIncrementalService.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <binder/BinderService.h>
+#include <binder/IServiceManager.h>
+
+#include "IncrementalService.h"
+#include "android/os/incremental/BnIncrementalManagerNative.h"
+#include "incremental_service.h"
+
+namespace android::os::incremental {
+
+class BinderIncrementalService : public BnIncrementalManagerNative,
+                                 public BinderService<BinderIncrementalService> {
+public:
+    BinderIncrementalService(const sp<IServiceManager> &sm);
+
+    static BinderIncrementalService *start();
+    static const char16_t *getServiceName() { return u"incremental_service"; }
+    status_t dump(int fd, const Vector<String16> &args) final;
+
+    void onSystemReady();
+    void onInvalidStorage(int mountId);
+
+    binder::Status openStorage(const std::string &path, int32_t *_aidl_return) final;
+    binder::Status createStorage(
+            const std::string &path,
+            const ::android::content::pm::DataLoaderParamsParcel &params,
+            int32_t createMode, int32_t *_aidl_return) final;
+    binder::Status createLinkedStorage(const std::string &path, int32_t otherStorageId,
+                                       int32_t createMode, int32_t *_aidl_return) final;
+    binder::Status makeBindMount(int32_t storageId, const std::string &pathUnderStorage,
+                                 const std::string &targetFullPath, int32_t bindType,
+                                 int32_t *_aidl_return) final;
+    binder::Status deleteBindMount(int32_t storageId, const std::string &targetFullPath,
+                                   int32_t *_aidl_return) final;
+    binder::Status deleteStorage(int32_t storageId) final;
+    binder::Status makeDirectory(int32_t storageId, const std::string &pathUnderStorage,
+                                 int32_t *_aidl_return) final;
+    binder::Status makeDirectories(int32_t storageId, const std::string &pathUnderStorage,
+                                   int32_t *_aidl_return) final;
+    binder::Status makeFile(int32_t storageId, const std::string &pathUnderStorage, int64_t size,
+                            const std::vector<uint8_t> &metadata, int32_t *_aidl_return) final;
+    binder::Status makeFileFromRange(int32_t storageId, const std::string &pathUnderStorage,
+                                     const std::string &sourcePathUnderStorage, int64_t start,
+                                     int64_t end, int32_t *_aidl_return);
+    binder::Status makeLink(int32_t sourceStorageId, const std::string &relativeSourcePath,
+                            int32_t destStorageId, const std::string &relativeDestPath,
+                            int32_t *_aidl_return) final;
+    binder::Status unlink(int32_t storageId, const std::string &pathUnderStorage,
+                          int32_t *_aidl_return) final;
+    binder::Status isFileRangeLoaded(int32_t storageId, const std::string &relativePath,
+                                     int64_t start, int64_t end, bool *_aidl_return) final;
+    binder::Status getFileMetadata(int32_t storageId, const std::string &relativePath,
+                                   std::vector<uint8_t> *_aidl_return) final;
+    binder::Status startLoading(int32_t storageId, bool *_aidl_return) final;
+
+private:
+    android::incremental::IncrementalService mImpl;
+};
+
+} // namespace android::os::incremental
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
new file mode 100644
index 0000000..c43328f
--- /dev/null
+++ b/services/incremental/IncrementalService.cpp
@@ -0,0 +1,1040 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "IncrementalService"
+
+#include "IncrementalService.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android/content/pm/IDataLoaderStatusListener.h>
+#include <android/os/IVold.h>
+#include <androidfw/ZipFileRO.h>
+#include <androidfw/ZipUtils.h>
+#include <binder/BinderService.h>
+#include <binder/ParcelFileDescriptor.h>
+#include <binder/Status.h>
+#include <sys/stat.h>
+#include <uuid/uuid.h>
+#include <zlib.h>
+
+#include <iterator>
+#include <span>
+#include <stack>
+#include <thread>
+#include <type_traits>
+
+#include "Metadata.pb.h"
+
+using namespace std::literals;
+using namespace android::content::pm;
+
+namespace android::incremental {
+
+namespace {
+
+using IncrementalFileSystemControlParcel =
+        ::android::os::incremental::IncrementalFileSystemControlParcel;
+
+struct Constants {
+    static constexpr auto backing = "backing_store"sv;
+    static constexpr auto mount = "mount"sv;
+    static constexpr auto image = "incfs.img"sv;
+    static constexpr auto storagePrefix = "st"sv;
+    static constexpr auto mountpointMdPrefix = ".mountpoint."sv;
+    static constexpr auto infoMdName = ".info"sv;
+};
+
+static const Constants& constants() {
+    static Constants c;
+    return c;
+}
+
+template <base::LogSeverity level = base::ERROR>
+bool mkdirOrLog(std::string_view name, int mode = 0770, bool allowExisting = true) {
+    auto cstr = path::c_str(name);
+    if (::mkdir(cstr, mode)) {
+        if (errno != EEXIST) {
+            PLOG(level) << "Can't create directory '" << name << '\'';
+            return false;
+        }
+        struct stat st;
+        if (::stat(cstr, &st) || !S_ISDIR(st.st_mode)) {
+            PLOG(level) << "Path exists but is not a directory: '" << name << '\'';
+            return false;
+        }
+    }
+    return true;
+}
+
+static std::string toMountKey(std::string_view path) {
+    if (path.empty()) {
+        return "@none";
+    }
+    if (path == "/"sv) {
+        return "@root";
+    }
+    if (path::isAbsolute(path)) {
+        path.remove_prefix(1);
+    }
+    std::string res(path);
+    std::replace(res.begin(), res.end(), '/', '_');
+    std::replace(res.begin(), res.end(), '@', '_');
+    return res;
+}
+
+static std::pair<std::string, std::string> makeMountDir(std::string_view incrementalDir,
+                                                        std::string_view path) {
+    auto mountKey = toMountKey(path);
+    const auto prefixSize = mountKey.size();
+    for (int counter = 0; counter < 1000;
+         mountKey.resize(prefixSize), base::StringAppendF(&mountKey, "%d", counter++)) {
+        auto mountRoot = path::join(incrementalDir, mountKey);
+        if (mkdirOrLog(mountRoot, 0770, false)) {
+            return {mountKey, mountRoot};
+        }
+    }
+    return {};
+}
+
+template <class ProtoMessage, class Control>
+static ProtoMessage parseFromIncfs(const IncFsWrapper* incfs, Control&& control,
+                                   std::string_view path) {
+    struct stat st;
+    if (::stat(path::c_str(path), &st)) {
+        return {};
+    }
+    auto md = incfs->getMetadata(control, st.st_ino);
+    ProtoMessage message;
+    return message.ParseFromArray(md.data(), md.size()) ? message : ProtoMessage{};
+}
+
+static bool isValidMountTarget(std::string_view path) {
+    return path::isAbsolute(path) && path::isEmptyDir(path).value_or(true);
+}
+
+std::string makeBindMdName() {
+    static constexpr auto uuidStringSize = 36;
+
+    uuid_t guid;
+    uuid_generate(guid);
+
+    std::string name;
+    const auto prefixSize = constants().mountpointMdPrefix.size();
+    name.reserve(prefixSize + uuidStringSize);
+
+    name = constants().mountpointMdPrefix;
+    name.resize(prefixSize + uuidStringSize);
+    uuid_unparse(guid, name.data() + prefixSize);
+
+    return name;
+}
+} // namespace
+
+IncrementalService::IncFsMount::~IncFsMount() {
+    incrementalService.mIncrementalManager->destroyDataLoader(mountId);
+    control.reset();
+    LOG(INFO) << "Unmounting and cleaning up mount " << mountId << " with root '" << root << '\'';
+    for (auto&& [target, _] : bindPoints) {
+        LOG(INFO) << "\tbind: " << target;
+        incrementalService.mVold->unmountIncFs(target);
+    }
+    LOG(INFO) << "\troot: " << root;
+    incrementalService.mVold->unmountIncFs(path::join(root, constants().mount));
+    cleanupFilesystem(root);
+}
+
+auto IncrementalService::IncFsMount::makeStorage(StorageId id) -> StorageMap::iterator {
+    metadata::Storage st;
+    st.set_id(id);
+    auto metadata = st.SerializeAsString();
+
+    std::string name;
+    for (int no = nextStorageDirNo.fetch_add(1, std::memory_order_relaxed), i = 0;
+         i < 1024 && no >= 0; no = nextStorageDirNo.fetch_add(1, std::memory_order_relaxed), ++i) {
+        name.clear();
+        base::StringAppendF(&name, "%.*s%d", int(constants().storagePrefix.size()),
+                            constants().storagePrefix.data(), no);
+        if (auto node =
+                    incrementalService.mIncFs->makeDir(control, name, INCFS_ROOT_INODE, metadata);
+            node >= 0) {
+            std::lock_guard l(lock);
+            return storages.insert_or_assign(id, Storage{std::move(name), node}).first;
+        }
+    }
+    nextStorageDirNo = 0;
+    return storages.end();
+}
+
+void IncrementalService::IncFsMount::cleanupFilesystem(std::string_view root) {
+    ::unlink(path::join(root, constants().backing, constants().image).c_str());
+    ::rmdir(path::join(root, constants().backing).c_str());
+    ::rmdir(path::join(root, constants().mount).c_str());
+    ::rmdir(path::c_str(root));
+}
+
+IncrementalService::IncrementalService(const ServiceManagerWrapper& sm, std::string_view rootDir)
+      : mVold(sm.getVoldService()),
+        mIncrementalManager(sm.getIncrementalManager()),
+        mIncFs(sm.getIncFs()),
+        mIncrementalDir(rootDir) {
+    if (!mVold) {
+        LOG(FATAL) << "Vold service is unavailable";
+    }
+    if (!mIncrementalManager) {
+        LOG(FATAL) << "IncrementalManager service is unavailable";
+    }
+    // TODO(b/136132412): check that root dir should already exist
+    // TODO(b/136132412): enable mount existing dirs after SELinux rules are merged
+    // mountExistingImages();
+}
+
+IncrementalService::~IncrementalService() = default;
+
+std::optional<std::future<void>> IncrementalService::onSystemReady() {
+    std::promise<void> threadFinished;
+    if (mSystemReady.exchange(true)) {
+        return {};
+    }
+
+    std::vector<IfsMountPtr> mounts;
+    {
+        std::lock_guard l(mLock);
+        mounts.reserve(mMounts.size());
+        for (auto&& [id, ifs] : mMounts) {
+            if (ifs->mountId == id) {
+                mounts.push_back(ifs);
+            }
+        }
+    }
+
+    std::thread([this, mounts = std::move(mounts)]() {
+        std::vector<IfsMountPtr> failedLoaderMounts;
+        for (auto&& ifs : mounts) {
+            if (prepareDataLoader(*ifs, nullptr)) {
+                LOG(INFO) << "Successfully started data loader for mount " << ifs->mountId;
+            } else {
+                LOG(WARNING) << "Failed to start data loader for mount " << ifs->mountId;
+                failedLoaderMounts.push_back(std::move(ifs));
+            }
+        }
+
+        while (!failedLoaderMounts.empty()) {
+            LOG(WARNING) << "Deleting failed mount " << failedLoaderMounts.back()->mountId;
+            deleteStorage(*failedLoaderMounts.back());
+            failedLoaderMounts.pop_back();
+        }
+        mPrepareDataLoaders.set_value_at_thread_exit();
+    }).detach();
+    return mPrepareDataLoaders.get_future();
+}
+
+auto IncrementalService::getStorageSlotLocked() -> MountMap::iterator {
+    for (;;) {
+        if (mNextId == kMaxStorageId) {
+            mNextId = 0;
+        }
+        auto id = ++mNextId;
+        auto [it, inserted] = mMounts.try_emplace(id, nullptr);
+        if (inserted) {
+            return it;
+        }
+    }
+}
+
+StorageId IncrementalService::createStorage(std::string_view mountPoint,
+                                            DataLoaderParamsParcel&& dataLoaderParams,
+                                            CreateOptions options) {
+    LOG(INFO) << "createStorage: " << mountPoint << " | " << int(options);
+    if (!path::isAbsolute(mountPoint)) {
+        LOG(ERROR) << "path is not absolute: " << mountPoint;
+        return kInvalidStorageId;
+    }
+
+    auto mountNorm = path::normalize(mountPoint);
+    {
+        const auto id = findStorageId(mountNorm);
+        if (id != kInvalidStorageId) {
+            if (options & CreateOptions::OpenExisting) {
+                LOG(INFO) << "Opened existing storage " << id;
+                return id;
+            }
+            LOG(ERROR) << "Directory " << mountPoint << " is already mounted at storage " << id;
+            return kInvalidStorageId;
+        }
+    }
+
+    if (!(options & CreateOptions::CreateNew)) {
+        LOG(ERROR) << "not requirested create new storage, and it doesn't exist: " << mountPoint;
+        return kInvalidStorageId;
+    }
+
+    if (!path::isEmptyDir(mountNorm)) {
+        LOG(ERROR) << "Mounting over existing non-empty directory is not supported: " << mountNorm;
+        return kInvalidStorageId;
+    }
+    auto [mountKey, mountRoot] = makeMountDir(mIncrementalDir, mountNorm);
+    if (mountRoot.empty()) {
+        LOG(ERROR) << "Bad mount point";
+        return kInvalidStorageId;
+    }
+    // Make sure the code removes all crap it may create while still failing.
+    auto firstCleanup = [](const std::string* ptr) { IncFsMount::cleanupFilesystem(*ptr); };
+    auto firstCleanupOnFailure =
+            std::unique_ptr<std::string, decltype(firstCleanup)>(&mountRoot, firstCleanup);
+
+    auto mountTarget = path::join(mountRoot, constants().mount);
+    if (!mkdirOrLog(path::join(mountRoot, constants().backing)) || !mkdirOrLog(mountTarget)) {
+        return kInvalidStorageId;
+    }
+
+    const auto image = path::join(mountRoot, constants().backing, constants().image);
+    IncFsMount::Control control;
+    {
+        std::lock_guard l(mMountOperationLock);
+        IncrementalFileSystemControlParcel controlParcel;
+        auto status = mVold->mountIncFs(image, mountTarget, incfs::truncate, &controlParcel);
+        if (!status.isOk()) {
+            LOG(ERROR) << "Vold::mountIncFs() failed: " << status.toString8();
+            return kInvalidStorageId;
+        }
+        if (!controlParcel.cmd || !controlParcel.log) {
+            LOG(ERROR) << "Vold::mountIncFs() returned invalid control parcel.";
+            return kInvalidStorageId;
+        }
+        control.cmdFd = controlParcel.cmd->release();
+        control.logFd = controlParcel.log->release();
+    }
+
+    std::unique_lock l(mLock);
+    const auto mountIt = getStorageSlotLocked();
+    const auto mountId = mountIt->first;
+    l.unlock();
+
+    auto ifs =
+            std::make_shared<IncFsMount>(std::move(mountRoot), mountId, std::move(control), *this);
+    // Now it's the |ifs|'s responsibility to clean up after itself, and the only cleanup we need
+    // is the removal of the |ifs|.
+    firstCleanupOnFailure.release();
+
+    auto secondCleanup = [this, &l](auto itPtr) {
+        if (!l.owns_lock()) {
+            l.lock();
+        }
+        mMounts.erase(*itPtr);
+    };
+    auto secondCleanupOnFailure =
+            std::unique_ptr<decltype(mountIt), decltype(secondCleanup)>(&mountIt, secondCleanup);
+
+    const auto storageIt = ifs->makeStorage(ifs->mountId);
+    if (storageIt == ifs->storages.end()) {
+        LOG(ERROR) << "Can't create default storage directory";
+        return kInvalidStorageId;
+    }
+
+    {
+        metadata::Mount m;
+        m.mutable_storage()->set_id(ifs->mountId);
+        m.mutable_loader()->set_package_name(dataLoaderParams.packageName);
+        m.mutable_loader()->set_arguments(dataLoaderParams.staticArgs);
+        const auto metadata = m.SerializeAsString();
+        m.mutable_loader()->release_arguments();
+        m.mutable_loader()->release_package_name();
+        if (auto err = mIncFs->makeFile(ifs->control, constants().infoMdName, INCFS_ROOT_INODE, 0,
+                                        metadata);
+            err < 0) {
+            LOG(ERROR) << "Saving mount metadata failed: " << -err;
+            return kInvalidStorageId;
+        }
+    }
+
+    const auto bk =
+            (options & CreateOptions::PermanentBind) ? BindKind::Permanent : BindKind::Temporary;
+    if (auto err = addBindMount(*ifs, storageIt->first, std::string(storageIt->second.name),
+                                std::move(mountNorm), bk, l);
+        err < 0) {
+        LOG(ERROR) << "adding bind mount failed: " << -err;
+        return kInvalidStorageId;
+    }
+
+    // Done here as well, all data structures are in good state.
+    secondCleanupOnFailure.release();
+
+    if (!prepareDataLoader(*ifs, &dataLoaderParams)) {
+        LOG(ERROR) << "prepareDataLoader() failed";
+        deleteStorageLocked(*ifs, std::move(l));
+        return kInvalidStorageId;
+    }
+
+    mountIt->second = std::move(ifs);
+    l.unlock();
+    LOG(INFO) << "created storage " << mountId;
+    return mountId;
+}
+
+StorageId IncrementalService::createLinkedStorage(std::string_view mountPoint,
+                                                  StorageId linkedStorage,
+                                                  IncrementalService::CreateOptions options) {
+    if (!isValidMountTarget(mountPoint)) {
+        LOG(ERROR) << "Mount point is invalid or missing";
+        return kInvalidStorageId;
+    }
+
+    std::unique_lock l(mLock);
+    const auto& ifs = getIfsLocked(linkedStorage);
+    if (!ifs) {
+        LOG(ERROR) << "Ifs unavailable";
+        return kInvalidStorageId;
+    }
+
+    const auto mountIt = getStorageSlotLocked();
+    const auto storageId = mountIt->first;
+    const auto storageIt = ifs->makeStorage(storageId);
+    if (storageIt == ifs->storages.end()) {
+        LOG(ERROR) << "Can't create a new storage";
+        mMounts.erase(mountIt);
+        return kInvalidStorageId;
+    }
+
+    l.unlock();
+
+    const auto bk =
+            (options & CreateOptions::PermanentBind) ? BindKind::Permanent : BindKind::Temporary;
+    if (auto err = addBindMount(*ifs, storageIt->first, std::string(storageIt->second.name),
+                                path::normalize(mountPoint), bk, l);
+        err < 0) {
+        LOG(ERROR) << "bindMount failed with error: " << err;
+        return kInvalidStorageId;
+    }
+
+    mountIt->second = ifs;
+    return storageId;
+}
+
+IncrementalService::BindPathMap::const_iterator IncrementalService::findStorageLocked(
+        std::string_view path) const {
+    auto bindPointIt = mBindsByPath.upper_bound(path);
+    if (bindPointIt == mBindsByPath.begin()) {
+        return mBindsByPath.end();
+    }
+    --bindPointIt;
+    if (!path::startsWith(path, bindPointIt->first)) {
+        return mBindsByPath.end();
+    }
+    return bindPointIt;
+}
+
+StorageId IncrementalService::findStorageId(std::string_view path) const {
+    std::lock_guard l(mLock);
+    auto it = findStorageLocked(path);
+    if (it == mBindsByPath.end()) {
+        return kInvalidStorageId;
+    }
+    return it->second->second.storage;
+}
+
+void IncrementalService::deleteStorage(StorageId storageId) {
+    const auto ifs = getIfs(storageId);
+    if (!ifs) {
+        return;
+    }
+    deleteStorage(*ifs);
+}
+
+void IncrementalService::deleteStorage(IncrementalService::IncFsMount& ifs) {
+    std::unique_lock l(ifs.lock);
+    deleteStorageLocked(ifs, std::move(l));
+}
+
+void IncrementalService::deleteStorageLocked(IncrementalService::IncFsMount& ifs,
+                                             std::unique_lock<std::mutex>&& ifsLock) {
+    const auto storages = std::move(ifs.storages);
+    // Don't move the bind points out: Ifs's dtor will use them to unmount everything.
+    const auto bindPoints = ifs.bindPoints;
+    ifsLock.unlock();
+
+    std::lock_guard l(mLock);
+    for (auto&& [id, _] : storages) {
+        if (id != ifs.mountId) {
+            mMounts.erase(id);
+        }
+    }
+    for (auto&& [path, _] : bindPoints) {
+        mBindsByPath.erase(path);
+    }
+    mMounts.erase(ifs.mountId);
+}
+
+StorageId IncrementalService::openStorage(std::string_view pathInMount) {
+    if (!path::isAbsolute(pathInMount)) {
+        return kInvalidStorageId;
+    }
+
+    return findStorageId(path::normalize(pathInMount));
+}
+
+Inode IncrementalService::nodeFor(StorageId storage, std::string_view subpath) const {
+    const auto ifs = getIfs(storage);
+    if (!ifs) {
+        return -1;
+    }
+    std::unique_lock l(ifs->lock);
+    auto storageIt = ifs->storages.find(storage);
+    if (storageIt == ifs->storages.end()) {
+        return -1;
+    }
+    if (subpath.empty() || subpath == "."sv) {
+        return storageIt->second.node;
+    }
+    auto path = path::join(ifs->root, constants().mount, storageIt->second.name, subpath);
+    l.unlock();
+    struct stat st;
+    if (::stat(path.c_str(), &st)) {
+        return -1;
+    }
+    return st.st_ino;
+}
+
+std::pair<Inode, std::string_view> IncrementalService::parentAndNameFor(
+        StorageId storage, std::string_view subpath) const {
+    auto name = path::basename(subpath);
+    if (name.empty()) {
+        return {-1, {}};
+    }
+    auto dir = path::dirname(subpath);
+    if (dir.empty() || dir == "/"sv) {
+        return {-1, {}};
+    }
+    auto inode = nodeFor(storage, dir);
+    return {inode, name};
+}
+
+IncrementalService::IfsMountPtr IncrementalService::getIfs(StorageId storage) const {
+    std::lock_guard l(mLock);
+    return getIfsLocked(storage);
+}
+
+const IncrementalService::IfsMountPtr& IncrementalService::getIfsLocked(StorageId storage) const {
+    auto it = mMounts.find(storage);
+    if (it == mMounts.end()) {
+        static const IfsMountPtr kEmpty = {};
+        return kEmpty;
+    }
+    return it->second;
+}
+
+int IncrementalService::bind(StorageId storage, std::string_view sourceSubdir,
+                             std::string_view target, BindKind kind) {
+    if (!isValidMountTarget(target)) {
+        return -EINVAL;
+    }
+
+    const auto ifs = getIfs(storage);
+    if (!ifs) {
+        return -EINVAL;
+    }
+    std::unique_lock l(ifs->lock);
+    const auto storageInfo = ifs->storages.find(storage);
+    if (storageInfo == ifs->storages.end()) {
+        return -EINVAL;
+    }
+    auto source = path::join(storageInfo->second.name, sourceSubdir);
+    l.unlock();
+    std::unique_lock l2(mLock, std::defer_lock);
+    return addBindMount(*ifs, storage, std::move(source), path::normalize(target), kind, l2);
+}
+
+int IncrementalService::unbind(StorageId storage, std::string_view target) {
+    if (!path::isAbsolute(target)) {
+        return -EINVAL;
+    }
+
+    LOG(INFO) << "Removing bind point " << target;
+
+    // Here we should only look up by the exact target, not by a subdirectory of any existing mount,
+    // otherwise there's a chance to unmount something completely unrelated
+    const auto norm = path::normalize(target);
+    std::unique_lock l(mLock);
+    const auto storageIt = mBindsByPath.find(norm);
+    if (storageIt == mBindsByPath.end() || storageIt->second->second.storage != storage) {
+        return -EINVAL;
+    }
+    const auto bindIt = storageIt->second;
+    const auto storageId = bindIt->second.storage;
+    const auto ifs = getIfsLocked(storageId);
+    if (!ifs) {
+        LOG(ERROR) << "Internal error: storageId " << storageId << " for bound path " << target
+                   << " is missing";
+        return -EFAULT;
+    }
+    mBindsByPath.erase(storageIt);
+    l.unlock();
+
+    mVold->unmountIncFs(bindIt->first);
+    std::unique_lock l2(ifs->lock);
+    if (ifs->bindPoints.size() <= 1) {
+        ifs->bindPoints.clear();
+        deleteStorageLocked(*ifs, std::move(l2));
+    } else {
+        const std::string savedFile = std::move(bindIt->second.savedFilename);
+        ifs->bindPoints.erase(bindIt);
+        l2.unlock();
+        if (!savedFile.empty()) {
+            mIncFs->unlink(ifs->control, INCFS_ROOT_INODE, savedFile);
+        }
+    }
+    return 0;
+}
+
+Inode IncrementalService::makeFile(StorageId storageId, std::string_view pathUnderStorage,
+                                   long size, std::string_view metadata,
+                                   std::string_view signature) {
+    (void)signature;
+    auto [parentInode, name] = parentAndNameFor(storageId, pathUnderStorage);
+    if (parentInode < 0) {
+        return -EINVAL;
+    }
+    if (auto ifs = getIfs(storageId)) {
+        auto inode = mIncFs->makeFile(ifs->control, name, parentInode, size, metadata);
+        if (inode < 0) {
+            return inode;
+        }
+        auto metadataBytes = std::vector<uint8_t>();
+        if (metadata.data() != nullptr && metadata.size() > 0) {
+            metadataBytes.insert(metadataBytes.end(), &metadata.data()[0],
+                                 &metadata.data()[metadata.size()]);
+        }
+        mIncrementalManager->newFileForDataLoader(ifs->mountId, inode, metadataBytes);
+        return inode;
+    }
+    return -EINVAL;
+}
+
+Inode IncrementalService::makeDir(StorageId storageId, std::string_view pathUnderStorage,
+                                  std::string_view metadata) {
+    auto [parentInode, name] = parentAndNameFor(storageId, pathUnderStorage);
+    if (parentInode < 0) {
+        return -EINVAL;
+    }
+    if (auto ifs = getIfs(storageId)) {
+        return mIncFs->makeDir(ifs->control, name, parentInode, metadata);
+    }
+    return -EINVAL;
+}
+
+Inode IncrementalService::makeDirs(StorageId storageId, std::string_view pathUnderStorage,
+                                   std::string_view metadata) {
+    const auto ifs = getIfs(storageId);
+    if (!ifs) {
+        return -EINVAL;
+    }
+    std::string_view parentDir(pathUnderStorage);
+    auto p = parentAndNameFor(storageId, pathUnderStorage);
+    std::stack<std::string> pathsToCreate;
+    while (p.first < 0) {
+        parentDir = path::dirname(parentDir);
+        pathsToCreate.emplace(parentDir);
+        p = parentAndNameFor(storageId, parentDir);
+    }
+    Inode inode;
+    while (!pathsToCreate.empty()) {
+        p = parentAndNameFor(storageId, pathsToCreate.top());
+        pathsToCreate.pop();
+        inode = mIncFs->makeDir(ifs->control, p.second, p.first, metadata);
+        if (inode < 0) {
+            return inode;
+        }
+    }
+    return mIncFs->makeDir(ifs->control, path::basename(pathUnderStorage), inode, metadata);
+}
+
+int IncrementalService::link(StorageId storage, Inode item, Inode newParent,
+                             std::string_view newName) {
+    if (auto ifs = getIfs(storage)) {
+        return mIncFs->link(ifs->control, item, newParent, newName);
+    }
+    return -EINVAL;
+}
+
+int IncrementalService::unlink(StorageId storage, Inode parent, std::string_view name) {
+    if (auto ifs = getIfs(storage)) {
+        return mIncFs->unlink(ifs->control, parent, name);
+    }
+    return -EINVAL;
+}
+
+int IncrementalService::addBindMount(IncFsMount& ifs, StorageId storage, std::string&& sourceSubdir,
+                                     std::string&& target, BindKind kind,
+                                     std::unique_lock<std::mutex>& mainLock) {
+    if (!isValidMountTarget(target)) {
+        return -EINVAL;
+    }
+
+    std::string mdFileName;
+    if (kind != BindKind::Temporary) {
+        metadata::BindPoint bp;
+        bp.set_storage_id(storage);
+        bp.set_allocated_dest_path(&target);
+        bp.set_allocated_source_subdir(&sourceSubdir);
+        const auto metadata = bp.SerializeAsString();
+        bp.release_source_subdir();
+        bp.release_dest_path();
+        mdFileName = makeBindMdName();
+        auto node = mIncFs->makeFile(ifs.control, mdFileName, INCFS_ROOT_INODE, 0, metadata);
+        if (node < 0) {
+            return int(node);
+        }
+    }
+
+    return addBindMountWithMd(ifs, storage, std::move(mdFileName), std::move(sourceSubdir),
+                              std::move(target), kind, mainLock);
+}
+
+int IncrementalService::addBindMountWithMd(IncrementalService::IncFsMount& ifs, StorageId storage,
+                                           std::string&& metadataName, std::string&& sourceSubdir,
+                                           std::string&& target, BindKind kind,
+                                           std::unique_lock<std::mutex>& mainLock) {
+    LOG(INFO) << "Adding bind mount: " << sourceSubdir << " -> " << target;
+    {
+        auto path = path::join(ifs.root, constants().mount, sourceSubdir);
+        std::lock_guard l(mMountOperationLock);
+        const auto status = mVold->bindMount(path, target);
+        if (!status.isOk()) {
+            LOG(ERROR) << "Calling Vold::bindMount() failed: " << status.toString8();
+            return status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC
+                    ? status.serviceSpecificErrorCode() > 0 ? -status.serviceSpecificErrorCode()
+                                                            : status.serviceSpecificErrorCode() == 0
+                                    ? -EFAULT
+                                    : status.serviceSpecificErrorCode()
+                    : -EIO;
+        }
+    }
+
+    if (!mainLock.owns_lock()) {
+        mainLock.lock();
+    }
+    std::lock_guard l(ifs.lock);
+    const auto [it, _] =
+            ifs.bindPoints.insert_or_assign(target,
+                                            IncFsMount::Bind{storage, std::move(metadataName),
+                                                             std::move(sourceSubdir), kind});
+    mBindsByPath[std::move(target)] = it;
+    return 0;
+}
+
+RawMetadata IncrementalService::getMetadata(StorageId storage, Inode node) const {
+    const auto ifs = getIfs(storage);
+    if (!ifs) {
+        return {};
+    }
+    return mIncFs->getMetadata(ifs->control, node);
+}
+
+std::vector<std::string> IncrementalService::listFiles(StorageId storage) const {
+    const auto ifs = getIfs(storage);
+    if (!ifs) {
+        return {};
+    }
+
+    std::unique_lock l(ifs->lock);
+    auto subdirIt = ifs->storages.find(storage);
+    if (subdirIt == ifs->storages.end()) {
+        return {};
+    }
+    auto dir = path::join(ifs->root, constants().mount, subdirIt->second.name);
+    l.unlock();
+
+    const auto prefixSize = dir.size() + 1;
+    std::vector<std::string> todoDirs{std::move(dir)};
+    std::vector<std::string> result;
+    do {
+        auto currDir = std::move(todoDirs.back());
+        todoDirs.pop_back();
+
+        auto d =
+                std::unique_ptr<DIR, decltype(&::closedir)>(::opendir(currDir.c_str()), ::closedir);
+        while (auto e = ::readdir(d.get())) {
+            if (e->d_type == DT_REG) {
+                result.emplace_back(
+                        path::join(std::string_view(currDir).substr(prefixSize), e->d_name));
+                continue;
+            }
+            if (e->d_type == DT_DIR) {
+                if (e->d_name == "."sv || e->d_name == ".."sv) {
+                    continue;
+                }
+                todoDirs.emplace_back(path::join(currDir, e->d_name));
+                continue;
+            }
+        }
+    } while (!todoDirs.empty());
+    return result;
+}
+
+bool IncrementalService::startLoading(StorageId storage) const {
+    const auto ifs = getIfs(storage);
+    if (!ifs) {
+        return false;
+    }
+    bool started = false;
+    std::unique_lock l(ifs->lock);
+    if (ifs->dataLoaderStatus != IDataLoaderStatusListener::DATA_LOADER_READY) {
+        if (ifs->dataLoaderReady.wait_for(l, Seconds(5)) == std::cv_status::timeout) {
+            LOG(ERROR) << "Timeout waiting for data loader to be ready";
+            return false;
+        }
+    }
+    auto status = mIncrementalManager->startDataLoader(ifs->mountId, &started);
+    if (!status.isOk()) {
+        return false;
+    }
+    return started;
+}
+
+void IncrementalService::mountExistingImages() {
+    auto d = std::unique_ptr<DIR, decltype(&::closedir)>(::opendir(mIncrementalDir.c_str()),
+                                                         ::closedir);
+    while (auto e = ::readdir(d.get())) {
+        if (e->d_type != DT_DIR) {
+            continue;
+        }
+        if (e->d_name == "."sv || e->d_name == ".."sv) {
+            continue;
+        }
+        auto root = path::join(mIncrementalDir, e->d_name);
+        if (!mountExistingImage(root, e->d_name)) {
+            IncFsMount::cleanupFilesystem(root);
+        }
+    }
+}
+
+bool IncrementalService::mountExistingImage(std::string_view root, std::string_view key) {
+    LOG(INFO) << "Trying to mount: " << key;
+
+    auto mountTarget = path::join(root, constants().mount);
+    const auto image = path::join(root, constants().backing, constants().image);
+
+    IncFsMount::Control control;
+    IncrementalFileSystemControlParcel controlParcel;
+    auto status = mVold->mountIncFs(image, mountTarget, 0, &controlParcel);
+    if (!status.isOk()) {
+        LOG(ERROR) << "Vold::mountIncFs() failed: " << status.toString8();
+        return false;
+    }
+    if (controlParcel.cmd) {
+        control.cmdFd = controlParcel.cmd->release();
+    }
+    if (controlParcel.log) {
+        control.logFd = controlParcel.log->release();
+    }
+
+    auto ifs = std::make_shared<IncFsMount>(std::string(root), -1, std::move(control), *this);
+
+    auto m = parseFromIncfs<metadata::Mount>(mIncFs.get(), ifs->control,
+                                             path::join(mountTarget, constants().infoMdName));
+    if (!m.has_loader() || !m.has_storage()) {
+        LOG(ERROR) << "Bad mount metadata in mount at " << root;
+        return false;
+    }
+
+    ifs->mountId = m.storage().id();
+    mNextId = std::max(mNextId, ifs->mountId + 1);
+
+    std::vector<std::pair<std::string, metadata::BindPoint>> bindPoints;
+    auto d = std::unique_ptr<DIR, decltype(&::closedir)>(::opendir(path::c_str(mountTarget)),
+                                                         ::closedir);
+    while (auto e = ::readdir(d.get())) {
+        if (e->d_type == DT_REG) {
+            auto name = std::string_view(e->d_name);
+            if (name.starts_with(constants().mountpointMdPrefix)) {
+                bindPoints.emplace_back(name,
+                                        parseFromIncfs<metadata::BindPoint>(mIncFs.get(),
+                                                                            ifs->control,
+                                                                            path::join(mountTarget,
+                                                                                       name)));
+                if (bindPoints.back().second.dest_path().empty() ||
+                    bindPoints.back().second.source_subdir().empty()) {
+                    bindPoints.pop_back();
+                    mIncFs->unlink(ifs->control, INCFS_ROOT_INODE, name);
+                }
+            }
+        } else if (e->d_type == DT_DIR) {
+            if (e->d_name == "."sv || e->d_name == ".."sv) {
+                continue;
+            }
+            auto name = std::string_view(e->d_name);
+            if (name.starts_with(constants().storagePrefix)) {
+                auto md = parseFromIncfs<metadata::Storage>(mIncFs.get(), ifs->control,
+                                                            path::join(mountTarget, name));
+                auto [_, inserted] = mMounts.try_emplace(md.id(), ifs);
+                if (!inserted) {
+                    LOG(WARNING) << "Ignoring storage with duplicate id " << md.id()
+                                 << " for mount " << root;
+                    continue;
+                }
+                ifs->storages.insert_or_assign(md.id(),
+                                               IncFsMount::Storage{std::string(name),
+                                                                   Inode(e->d_ino)});
+                mNextId = std::max(mNextId, md.id() + 1);
+            }
+        }
+    }
+
+    if (ifs->storages.empty()) {
+        LOG(WARNING) << "No valid storages in mount " << root;
+        return false;
+    }
+
+    int bindCount = 0;
+    for (auto&& bp : bindPoints) {
+        std::unique_lock l(mLock, std::defer_lock);
+        bindCount += !addBindMountWithMd(*ifs, bp.second.storage_id(), std::move(bp.first),
+                                         std::move(*bp.second.mutable_source_subdir()),
+                                         std::move(*bp.second.mutable_dest_path()),
+                                         BindKind::Permanent, l);
+    }
+
+    if (bindCount == 0) {
+        LOG(WARNING) << "No valid bind points for mount " << root;
+        deleteStorage(*ifs);
+        return false;
+    }
+
+    DataLoaderParamsParcel dlParams;
+    dlParams.packageName = std::move(*m.mutable_loader()->mutable_package_name());
+    dlParams.staticArgs = std::move(*m.mutable_loader()->mutable_arguments());
+    if (!prepareDataLoader(*ifs, &dlParams)) {
+        deleteStorage(*ifs);
+        return false;
+    }
+
+    mMounts[ifs->mountId] = std::move(ifs);
+    return true;
+}
+
+bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs,
+                                           DataLoaderParamsParcel* params) {
+    if (!mSystemReady.load(std::memory_order_relaxed)) {
+        std::unique_lock l(ifs.lock);
+        if (params) {
+            if (ifs.savedDataLoaderParams) {
+                LOG(WARNING) << "Trying to pass second set of data loader parameters, ignored it";
+            } else {
+                ifs.savedDataLoaderParams = std::move(*params);
+            }
+        } else {
+            if (!ifs.savedDataLoaderParams) {
+                LOG(ERROR) << "Mount " << ifs.mountId
+                           << " is broken: no data loader params (system is not ready yet)";
+                return false;
+            }
+        }
+        return true; // eventually...
+    }
+    if (base::GetBoolProperty("incremental.skip_loader", false)) {
+        LOG(INFO) << "Skipped data loader because of incremental.skip_loader property";
+        std::unique_lock l(ifs.lock);
+        ifs.savedDataLoaderParams.reset();
+        return true;
+    }
+
+    std::unique_lock l(ifs.lock);
+    if (ifs.dataLoaderStatus == IDataLoaderStatusListener::DATA_LOADER_READY) {
+        LOG(INFO) << "Skipped data loader preparation because it already exists";
+        return true;
+    }
+
+    auto* dlp = params ? params
+                       : ifs.savedDataLoaderParams ? &ifs.savedDataLoaderParams.value() : nullptr;
+    if (!dlp) {
+        LOG(ERROR) << "Mount " << ifs.mountId << " is broken: no data loader params";
+        return false;
+    }
+    FileSystemControlParcel fsControlParcel;
+    fsControlParcel.incremental = std::make_unique<IncrementalFileSystemControlParcel>();
+    fsControlParcel.incremental->cmd =
+            std::make_unique<os::ParcelFileDescriptor>(base::unique_fd(::dup(ifs.control.cmdFd)));
+    fsControlParcel.incremental->log =
+            std::make_unique<os::ParcelFileDescriptor>(base::unique_fd(::dup(ifs.control.logFd)));
+    sp<IncrementalDataLoaderListener> listener = new IncrementalDataLoaderListener(*this);
+    bool created = false;
+    auto status = mIncrementalManager->prepareDataLoader(ifs.mountId, fsControlParcel, *dlp,
+                                                         listener, &created);
+    if (!status.isOk() || !created) {
+        LOG(ERROR) << "Failed to create a data loader for mount " << ifs.mountId;
+        return false;
+    }
+    ifs.savedDataLoaderParams.reset();
+    return true;
+}
+
+binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId,
+                                                                                  int newStatus) {
+    std::unique_lock l(incrementalService.mLock);
+    const auto& ifs = incrementalService.getIfsLocked(mountId);
+    if (!ifs) {
+        LOG(WARNING) << "Received data loader status " << int(newStatus) << " for unknown mount "
+                     << mountId;
+        return binder::Status::ok();
+    }
+    ifs->dataLoaderStatus = newStatus;
+    switch (newStatus) {
+        case IDataLoaderStatusListener::DATA_LOADER_NO_CONNECTION: {
+            auto now = Clock::now();
+            if (ifs->connectionLostTime.time_since_epoch().count() == 0) {
+                ifs->connectionLostTime = now;
+                break;
+            }
+            auto duration =
+                    std::chrono::duration_cast<Seconds>(now - ifs->connectionLostTime).count();
+            if (duration >= 10) {
+                incrementalService.mIncrementalManager->showHealthBlockedUI(mountId);
+            }
+            break;
+        }
+        case IDataLoaderStatusListener::DATA_LOADER_READY: {
+            ifs->dataLoaderReady.notify_one();
+            break;
+        }
+        case IDataLoaderStatusListener::DATA_LOADER_NOT_READY: {
+            ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_STOPPED;
+            incrementalService.deleteStorageLocked(*ifs, std::move(l));
+            break;
+        }
+        case IDataLoaderStatusListener::DATA_LOADER_RUNNING: {
+            break;
+        }
+        case IDataLoaderStatusListener::DATA_LOADER_CONNECTION_OK: {
+            ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_RUNNING;
+            break;
+        }
+        case IDataLoaderStatusListener::DATA_LOADER_STOPPED: {
+            break;
+        }
+        default: {
+            LOG(WARNING) << "Unknown data loader status: " << newStatus
+                         << " for mount: " << mountId;
+            break;
+        }
+    }
+
+    return binder::Status::ok();
+}
+
+} // namespace android::incremental
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
new file mode 100644
index 0000000..a03ffa0
--- /dev/null
+++ b/services/incremental/IncrementalService.h
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <android/os/incremental/IIncrementalManager.h>
+#include <android/content/pm/DataLoaderParamsParcel.h>
+#include <binder/IServiceManager.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
+#include <atomic>
+#include <chrono>
+#include <future>
+#include <limits>
+#include <map>
+#include <mutex>
+#include <string>
+#include <string_view>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include "ServiceWrappers.h"
+#include "android/content/pm/BnDataLoaderStatusListener.h"
+#include "incfs.h"
+#include "path.h"
+
+using namespace android::os::incremental;
+
+namespace android::os {
+class IVold;
+}
+
+namespace android::incremental {
+
+using MountId = int;
+using StorageId = int;
+using Inode = incfs::Inode;
+using BlockIndex = incfs::BlockIndex;
+using RawMetadata = incfs::RawMetadata;
+using Clock = std::chrono::steady_clock;
+using TimePoint = std::chrono::time_point<Clock>;
+using Seconds = std::chrono::seconds;
+
+class IncrementalService {
+public:
+    explicit IncrementalService(const ServiceManagerWrapper& sm, std::string_view rootDir);
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+    ~IncrementalService();
+#pragma GCC diagnostic pop
+
+    static constexpr StorageId kInvalidStorageId = -1;
+    static constexpr StorageId kMaxStorageId = std::numeric_limits<int>::max();
+
+    enum CreateOptions {
+        TemporaryBind = 1,
+        PermanentBind = 2,
+        CreateNew = 4,
+        OpenExisting = 8,
+
+        Default = TemporaryBind | CreateNew
+    };
+
+    enum class BindKind {
+        Temporary = 0,
+        Permanent = 1,
+    };
+
+    std::optional<std::future<void>> onSystemReady();
+
+    StorageId createStorage(std::string_view mountPoint,
+                            DataLoaderParamsParcel&& dataLoaderParams,
+                            CreateOptions options = CreateOptions::Default);
+    StorageId createLinkedStorage(std::string_view mountPoint, StorageId linkedStorage,
+                                  CreateOptions options = CreateOptions::Default);
+    StorageId openStorage(std::string_view pathInMount);
+
+    Inode nodeFor(StorageId storage, std::string_view subpath) const;
+    std::pair<Inode, std::string_view> parentAndNameFor(StorageId storage,
+                                                        std::string_view subpath) const;
+
+    int bind(StorageId storage, std::string_view subdir, std::string_view target, BindKind kind);
+    int unbind(StorageId storage, std::string_view target);
+    void deleteStorage(StorageId storage);
+
+    Inode makeFile(StorageId storage, std::string_view name, long size, std::string_view metadata,
+                   std::string_view signature);
+    Inode makeDir(StorageId storage, std::string_view name, std::string_view metadata = {});
+    Inode makeDirs(StorageId storage, std::string_view name, std::string_view metadata = {});
+
+    int link(StorageId storage, Inode item, Inode newParent, std::string_view newName);
+    int unlink(StorageId storage, Inode parent, std::string_view name);
+
+    bool isRangeLoaded(StorageId storage, Inode file, std::pair<BlockIndex, BlockIndex> range) {
+        return false;
+    }
+
+    RawMetadata getMetadata(StorageId storage, Inode node) const;
+    std::string getSigngatureData(StorageId storage, Inode node) const { return {}; }
+
+    std::vector<std::string> listFiles(StorageId storage) const;
+    bool startLoading(StorageId storage) const;
+
+    class IncrementalDataLoaderListener : public android::content::pm::BnDataLoaderStatusListener {
+    public:
+        IncrementalDataLoaderListener(IncrementalService& incrementalService)
+              : incrementalService(incrementalService) {}
+        // Callbacks interface
+        binder::Status onStatusChanged(MountId mount, int newStatus) override;
+
+    private:
+        IncrementalService& incrementalService;
+    };
+
+private:
+    struct IncFsMount {
+        struct Bind {
+            StorageId storage;
+            std::string savedFilename;
+            std::string sourceDir;
+            BindKind kind;
+        };
+
+        struct Storage {
+            std::string name;
+            Inode node;
+        };
+
+        struct Control {
+            operator IncFsControl() const { return {cmdFd, logFd}; }
+            void reset() {
+                cmdFd.reset();
+                logFd.reset();
+            }
+
+            base::unique_fd cmdFd;
+            base::unique_fd logFd;
+        };
+
+        using BindMap = std::map<std::string, Bind>;
+        using StorageMap = std::unordered_map<StorageId, Storage>;
+
+        mutable std::mutex lock;
+        const std::string root;
+        Control control;
+        /*const*/ MountId mountId;
+        StorageMap storages;
+        BindMap bindPoints;
+        std::optional<DataLoaderParamsParcel> savedDataLoaderParams;
+        std::atomic<int> nextStorageDirNo{0};
+        std::atomic<int> dataLoaderStatus = -1;
+        std::condition_variable dataLoaderReady;
+        TimePoint connectionLostTime = TimePoint();
+        const IncrementalService& incrementalService;
+
+        IncFsMount(std::string root, MountId mountId, Control control,
+                   const IncrementalService& incrementalService)
+              : root(std::move(root)),
+                control(std::move(control)),
+                mountId(mountId),
+                incrementalService(incrementalService) {}
+        IncFsMount(IncFsMount&&) = delete;
+        IncFsMount& operator=(IncFsMount&&) = delete;
+        ~IncFsMount();
+
+        StorageMap::iterator makeStorage(StorageId id);
+
+        static void cleanupFilesystem(std::string_view root);
+    };
+
+    using IfsMountPtr = std::shared_ptr<IncFsMount>;
+    using MountMap = std::unordered_map<MountId, IfsMountPtr>;
+    using BindPathMap = std::map<std::string, IncFsMount::BindMap::iterator, path::PathLess>;
+
+    void mountExistingImages();
+    bool mountExistingImage(std::string_view root, std::string_view key);
+
+    IfsMountPtr getIfs(StorageId storage) const;
+    const IfsMountPtr& getIfsLocked(StorageId storage) const;
+    int addBindMount(IncFsMount& ifs, StorageId storage, std::string&& sourceSubdir,
+                     std::string&& target, BindKind kind, std::unique_lock<std::mutex>& mainLock);
+
+    int addBindMountWithMd(IncFsMount& ifs, StorageId storage, std::string&& metadataName,
+                           std::string&& sourceSubdir, std::string&& target, BindKind kind,
+                           std::unique_lock<std::mutex>& mainLock);
+
+    bool prepareDataLoader(IncFsMount& ifs, DataLoaderParamsParcel* params);
+    BindPathMap::const_iterator findStorageLocked(std::string_view path) const;
+    StorageId findStorageId(std::string_view path) const;
+
+    void deleteStorage(IncFsMount& ifs);
+    void deleteStorageLocked(IncFsMount& ifs, std::unique_lock<std::mutex>&& ifsLock);
+    MountMap::iterator getStorageSlotLocked();
+
+    // Member variables
+    // These are shared pointers for the sake of unit testing
+    std::shared_ptr<VoldServiceWrapper> mVold;
+    std::shared_ptr<IncrementalManagerWrapper> mIncrementalManager;
+    std::shared_ptr<IncFsWrapper> mIncFs;
+    const std::string mIncrementalDir;
+
+    mutable std::mutex mLock;
+    mutable std::mutex mMountOperationLock;
+    MountMap mMounts;
+    BindPathMap mBindsByPath;
+
+    std::atomic_bool mSystemReady = false;
+    StorageId mNextId = 0;
+    std::promise<void> mPrepareDataLoaders;
+};
+
+} // namespace android::incremental
diff --git a/services/incremental/Metadata.proto b/services/incremental/Metadata.proto
new file mode 100644
index 0000000..0ff3c32
--- /dev/null
+++ b/services/incremental/Metadata.proto
@@ -0,0 +1,23 @@
+syntax = "proto3";
+
+package android.incremental.metadata;
+
+message BindPoint {
+    int32 storage_id = 1;
+    string source_subdir = 2;
+    string dest_path = 3;
+}
+
+message DataLoader {
+    string package_name = 1;
+    string arguments = 2;
+}
+
+message Storage {
+    int32 id = 1;
+}
+
+message Mount {
+    Storage storage = 1;
+    DataLoader loader = 2;
+}
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
new file mode 100644
index 0000000..a79b26a
--- /dev/null
+++ b/services/incremental/ServiceWrappers.cpp
@@ -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.
+ */
+
+#include "ServiceWrappers.h"
+
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <binder/IServiceManager.h>
+#include <utils/String16.h>
+
+#include <string>
+#include <string_view>
+
+using namespace std::literals;
+
+namespace android::os::incremental {
+
+static constexpr auto kVoldServiceName = "vold"sv;
+static constexpr auto kIncrementalManagerName = "incremental"sv;
+
+RealServiceManager::RealServiceManager(const sp<IServiceManager>& serviceManager)
+      : mServiceManager(serviceManager) {}
+
+template <class INTERFACE>
+sp<INTERFACE> RealServiceManager::getRealService(std::string_view serviceName) const {
+    sp<IBinder> binder = mServiceManager->getService(String16(serviceName.data()));
+    if (binder == 0) {
+        return 0;
+    }
+    return interface_cast<INTERFACE>(binder);
+}
+
+std::shared_ptr<VoldServiceWrapper> RealServiceManager::getVoldService() const {
+    sp<os::IVold> vold = RealServiceManager::getRealService<os::IVold>(kVoldServiceName);
+    if (vold != 0) {
+        return std::make_shared<RealVoldService>(vold);
+    }
+    return nullptr;
+}
+
+std::shared_ptr<IncrementalManagerWrapper> RealServiceManager::getIncrementalManager() const {
+    sp<IIncrementalManager> manager =
+            RealServiceManager::getRealService<IIncrementalManager>(kIncrementalManagerName);
+    if (manager != 0) {
+        return std::make_shared<RealIncrementalManager>(manager);
+    }
+    return nullptr;
+}
+
+std::shared_ptr<IncFsWrapper> RealServiceManager::getIncFs() const {
+    return std::make_shared<RealIncFs>();
+}
+
+} // namespace android::os::incremental
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
new file mode 100644
index 0000000..5704582
--- /dev/null
+++ b/services/incremental/ServiceWrappers.h
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <android/content/pm/DataLoaderParamsParcel.h>
+#include <android/content/pm/FileSystemControlParcel.h>
+#include <android/content/pm/IDataLoaderStatusListener.h>
+#include <android/os/IVold.h>
+#include <android/os/incremental/IIncrementalManager.h>
+#include <binder/IServiceManager.h>
+#include <incfs.h>
+
+#include <string>
+#include <string_view>
+
+using namespace android::incfs;
+using namespace android::content::pm;
+
+namespace android::os::incremental {
+
+// --- Wrapper interfaces ---
+
+class VoldServiceWrapper {
+public:
+    virtual ~VoldServiceWrapper(){};
+    virtual binder::Status mountIncFs(const std::string& imagePath, const std::string& targetDir,
+                                      int32_t flags,
+                                      IncrementalFileSystemControlParcel* _aidl_return) const = 0;
+    virtual binder::Status unmountIncFs(const std::string& dir) const = 0;
+    virtual binder::Status bindMount(const std::string& sourceDir,
+                                     const std::string& targetDir) const = 0;
+};
+
+class IncrementalManagerWrapper {
+public:
+    virtual ~IncrementalManagerWrapper() {}
+    virtual binder::Status prepareDataLoader(
+            int32_t mountId, const FileSystemControlParcel& control,
+            const DataLoaderParamsParcel& params,
+            const sp<IDataLoaderStatusListener>& listener,
+            bool* _aidl_return) const = 0;
+    virtual binder::Status startDataLoader(int32_t mountId, bool* _aidl_return) const = 0;
+    virtual binder::Status destroyDataLoader(int32_t mountId) const = 0;
+    virtual binder::Status newFileForDataLoader(int32_t mountId, int64_t inode,
+                                                const ::std::vector<uint8_t>& metadata) const = 0;
+    virtual binder::Status showHealthBlockedUI(int32_t mountId) const = 0;
+};
+
+class IncFsWrapper {
+public:
+    virtual ~IncFsWrapper() {}
+    virtual Inode makeFile(Control control, std::string_view name, Inode parent, Size size,
+                           std::string_view metadata) const = 0;
+    virtual Inode makeDir(Control control, std::string_view name, Inode parent,
+                          std::string_view metadata, int mode = 0555) const = 0;
+    virtual RawMetadata getMetadata(Control control, Inode inode) const = 0;
+    virtual ErrorCode link(Control control, Inode item, Inode targetParent,
+                           std::string_view name) const = 0;
+    virtual ErrorCode unlink(Control control, Inode parent, std::string_view name) const = 0;
+    virtual ErrorCode writeBlocks(Control control, const incfs_new_data_block blocks[],
+                                  int blocksCount) const = 0;
+};
+
+class ServiceManagerWrapper {
+public:
+    virtual ~ServiceManagerWrapper() {}
+    virtual std::shared_ptr<VoldServiceWrapper> getVoldService() const = 0;
+    virtual std::shared_ptr<IncrementalManagerWrapper> getIncrementalManager() const = 0;
+    virtual std::shared_ptr<IncFsWrapper> getIncFs() const = 0;
+};
+
+// --- Real stuff ---
+
+class RealVoldService : public VoldServiceWrapper {
+public:
+    RealVoldService(const sp<os::IVold> vold) : mInterface(vold) {}
+    ~RealVoldService() = default;
+    binder::Status mountIncFs(const std::string& imagePath, const std::string& targetDir,
+                              int32_t flags,
+                              IncrementalFileSystemControlParcel* _aidl_return) const override {
+        return mInterface->mountIncFs(imagePath, targetDir, flags, _aidl_return);
+    }
+    binder::Status unmountIncFs(const std::string& dir) const override {
+        return mInterface->unmountIncFs(dir);
+    }
+    binder::Status bindMount(const std::string& sourceDir,
+                             const std::string& targetDir) const override {
+        return mInterface->bindMount(sourceDir, targetDir);
+    }
+
+private:
+    sp<os::IVold> mInterface;
+};
+
+class RealIncrementalManager : public IncrementalManagerWrapper {
+public:
+    RealIncrementalManager(const sp<os::incremental::IIncrementalManager> manager)
+          : mInterface(manager) {}
+    ~RealIncrementalManager() = default;
+    binder::Status prepareDataLoader(
+            int32_t mountId, const FileSystemControlParcel& control,
+            const DataLoaderParamsParcel& params,
+            const sp<IDataLoaderStatusListener>& listener,
+            bool* _aidl_return) const override {
+        return mInterface->prepareDataLoader(mountId, control, params, listener, _aidl_return);
+    }
+    binder::Status startDataLoader(int32_t mountId, bool* _aidl_return) const override {
+        return mInterface->startDataLoader(mountId, _aidl_return);
+    }
+    binder::Status destroyDataLoader(int32_t mountId) const override {
+        return mInterface->destroyDataLoader(mountId);
+    }
+    binder::Status newFileForDataLoader(int32_t mountId, int64_t inode,
+                                        const ::std::vector<uint8_t>& metadata) const override {
+        return mInterface->newFileForDataLoader(mountId, inode, metadata);
+    }
+    binder::Status showHealthBlockedUI(int32_t mountId) const override {
+        return mInterface->showHealthBlockedUI(mountId);
+    }
+
+private:
+    sp<os::incremental::IIncrementalManager> mInterface;
+};
+
+class RealServiceManager : public ServiceManagerWrapper {
+public:
+    RealServiceManager(const sp<IServiceManager>& serviceManager);
+    ~RealServiceManager() = default;
+    std::shared_ptr<VoldServiceWrapper> getVoldService() const override;
+    std::shared_ptr<IncrementalManagerWrapper> getIncrementalManager() const override;
+    std::shared_ptr<IncFsWrapper> getIncFs() const override;
+
+private:
+    template <class INTERFACE>
+    sp<INTERFACE> getRealService(std::string_view serviceName) const;
+    sp<android::IServiceManager> mServiceManager;
+};
+
+class RealIncFs : public IncFsWrapper {
+public:
+    RealIncFs() = default;
+    ~RealIncFs() = default;
+    Inode makeFile(Control control, std::string_view name, Inode parent, Size size,
+                   std::string_view metadata) const override {
+        return incfs::makeFile(control, name, parent, size, metadata);
+    }
+    Inode makeDir(Control control, std::string_view name, Inode parent, std::string_view metadata,
+                  int mode) const override {
+        return incfs::makeDir(control, name, parent, metadata, mode);
+    }
+    RawMetadata getMetadata(Control control, Inode inode) const override {
+        return incfs::getMetadata(control, inode);
+    }
+    ErrorCode link(Control control, Inode item, Inode targetParent,
+                   std::string_view name) const override {
+        return incfs::link(control, item, targetParent, name);
+    }
+    ErrorCode unlink(Control control, Inode parent, std::string_view name) const override {
+        return incfs::unlink(control, parent, name);
+    }
+    ErrorCode writeBlocks(Control control, const incfs_new_data_block blocks[],
+                          int blocksCount) const override {
+        return incfs::writeBlocks(control, blocks, blocksCount);
+    }
+};
+
+} // namespace android::os::incremental
diff --git a/services/incremental/include/incremental_service.h b/services/incremental/include/incremental_service.h
new file mode 100644
index 0000000..7109d95
--- /dev/null
+++ b/services/incremental/include/incremental_service.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_INCREMENTAL_SERVICE_H
+#define ANDROID_INCREMENTAL_SERVICE_H
+
+#include <sys/cdefs.h>
+#include <jni.h>
+
+__BEGIN_DECLS
+
+#define INCREMENTAL_LIBRARY_NAME "service.incremental.so"
+
+jlong Incremental_IncrementalService_Start();
+void Incremental_IncrementalService_OnSystemReady(jlong self);
+
+__END_DECLS
+
+#endif  // ANDROID_INCREMENTAL_SERVICE_H
diff --git a/services/incremental/incremental_service.c b/services/incremental/incremental_service.c
new file mode 100644
index 0000000..f6ea59e
--- /dev/null
+++ b/services/incremental/incremental_service.c
@@ -0,0 +1,17 @@
+/*
+ * 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 "incremental_service.h"
diff --git a/services/incremental/path.cpp b/services/incremental/path.cpp
new file mode 100644
index 0000000..c529d61
--- /dev/null
+++ b/services/incremental/path.cpp
@@ -0,0 +1,178 @@
+/*
+ * 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 "path.h"
+
+#include <android-base/strings.h>
+#include <android-base/logging.h>
+
+#include <algorithm>
+#include <iterator>
+#include <limits>
+#include <memory>
+
+#include <dirent.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+using namespace std::literals;
+
+namespace android::incremental::path {
+
+bool PathCharsLess::operator()(char l, char r) const {
+    int ll = l == '/' ? std::numeric_limits<char>::min() - 1 : l;
+    int rr = r == '/' ? std::numeric_limits<char>::min() - 1 : r;
+    return ll < rr;
+}
+
+bool PathLess::operator()(std::string_view l, std::string_view r) const {
+    return std::lexicographical_compare(std::begin(l), std::end(l), std::begin(r), std::end(r),
+                                        PathCharsLess());
+}
+
+void details::append_next_path(std::string& target, std::string_view path) {
+    if (path.empty()) {
+        return;
+    }
+    if (!target.empty()) {
+        target.push_back('/');
+    }
+    target += path;
+}
+
+bool isAbsolute(std::string_view path) {
+    return !path.empty() && path[0] == '/';
+}
+
+std::string normalize(std::string_view path) {
+    if (path.empty()) {
+        return {};
+    }
+    if (path.starts_with("../"sv)) {
+        return {};
+    }
+
+    std::string result;
+    if (isAbsolute(path)) {
+        path.remove_prefix(1);
+    } else {
+        char buffer[PATH_MAX];
+        if (!::getcwd(buffer, sizeof(buffer))) {
+            return {};
+        }
+        result += buffer;
+    }
+
+    size_t start = 0;
+    size_t end = 0;
+    for (; end != path.npos; start = end + 1) {
+        end = path.find('/', start);
+        // Next component, excluding the separator
+        auto part = path.substr(start, end - start);
+        if (part.empty() || part == "."sv) {
+            continue;
+        }
+        if (part == ".."sv) {
+            if (result.empty()) {
+                return {};
+            }
+            auto lastPos = result.rfind('/');
+            if (lastPos == result.npos) {
+                result.clear();
+            } else {
+                result.resize(lastPos);
+            }
+            continue;
+        }
+        result += '/';
+        result += part;
+    }
+
+    return result;
+}
+
+std::string_view basename(std::string_view path) {
+    if (path.empty()) {
+        return {};
+    }
+    if (path == "/"sv) {
+        return "/"sv;
+    }
+    auto pos = path.rfind('/');
+    while (!path.empty() && pos == path.size() - 1) {
+        path.remove_suffix(1);
+        pos = path.rfind('/');
+    }
+    if (pos == path.npos) {
+        return path.empty() ? "/"sv : path;
+    }
+    return path.substr(pos + 1);
+}
+
+std::string_view dirname(std::string_view path) {
+    if (path.empty()) {
+        return {};
+    }
+    if (path == "/"sv) {
+        return "/"sv;
+    }
+    const auto pos = path.rfind('/');
+    if (pos == 0) {
+        return "/"sv;
+    }
+    if (pos == path.npos) {
+        return "."sv;
+    }
+    return path.substr(0, pos);
+}
+
+details::CStrWrapper::CStrWrapper(std::string_view sv) {
+    if (sv[sv.size()] == '\0') {
+        mCstr = sv.data();
+    } else {
+        mCopy.emplace(sv);
+        mCstr = mCopy->c_str();
+    }
+}
+
+std::optional<bool> isEmptyDir(std::string_view dir) {
+    const auto d = std::unique_ptr<DIR, decltype(&::closedir)>{::opendir(c_str(dir)), ::closedir};
+    if (!d) {
+        if (errno == EPERM || errno == EACCES) {
+            return std::nullopt;
+        }
+        return false;
+    }
+    while (auto entry = ::readdir(d.get())) {
+        if (entry->d_type != DT_DIR) {
+            return false;
+        }
+        if (entry->d_name != "."sv && entry->d_name != ".."sv) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool startsWith(std::string_view path, std::string_view prefix) {
+    if (!base::StartsWith(path, prefix)) {
+        return false;
+    }
+    return path.size() == prefix.size() || path[prefix.size()] == '/';
+}
+
+} // namespace android::incremental::path
diff --git a/services/incremental/path.h b/services/incremental/path.h
new file mode 100644
index 0000000..a1f4b8e
--- /dev/null
+++ b/services/incremental/path.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <optional>
+#include <string>
+#include <string_view>
+
+namespace android::incremental::path {
+
+namespace details {
+
+class CStrWrapper {
+public:
+    CStrWrapper(std::string_view sv);
+
+    CStrWrapper(const CStrWrapper&) = delete;
+    void operator=(const CStrWrapper&) = delete;
+    CStrWrapper(CStrWrapper&&) = delete;
+    void operator=(CStrWrapper&&) = delete;
+
+    const char* get() const { return mCstr; }
+    operator const char*() const { return get(); }
+
+private:
+    const char* mCstr;
+    std::optional<std::string> mCopy;
+};
+
+void append_next_path(std::string& res, std::string_view c);
+
+} // namespace details
+
+//
+// An std::map<> comparator that makes all nested paths to be ordered before the parents.
+//
+
+struct PathCharsLess {
+    bool operator()(char l, char r) const;
+};
+
+struct PathLess {
+    using is_transparent = void;
+    bool operator()(std::string_view l, std::string_view r) const;
+};
+
+//
+// Returns a zero-terminated version of a passed string view
+// Only makes a copy if it wasn't zero-terminated already
+// Useful for passing string view parameters to system functions.
+//
+inline details::CStrWrapper c_str(std::string_view sv) {
+    return {sv};
+}
+
+bool isAbsolute(std::string_view path);
+std::string normalize(std::string_view path);
+std::string_view dirname(std::string_view path);
+std::string_view basename(std::string_view path);
+std::optional<bool> isEmptyDir(std::string_view dir);
+bool startsWith(std::string_view path, std::string_view prefix);
+
+template <class... Paths>
+std::string join(std::string_view first, std::string_view second, Paths&&... paths) {
+    std::string result;
+    {
+        using std::size;
+        result.reserve(first.size() + second.size() + 1 + (sizeof...(paths) + ... + size(paths)));
+    }
+    result.assign(first);
+    (details::append_next_path(result, second), ..., details::append_next_path(result, paths));
+    return result;
+}
+
+} // namespace android::incremental::path
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
new file mode 100644
index 0000000..f6b123d
--- /dev/null
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -0,0 +1,461 @@
+/*
+ * 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-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <binder/ParcelFileDescriptor.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+
+#include <future>
+
+#include "IncrementalService.h"
+#include "Metadata.pb.h"
+#include "ServiceWrappers.h"
+
+using namespace testing;
+using namespace android::incremental;
+using namespace std::literals;
+using testing::_;
+using testing::Invoke;
+using testing::NiceMock;
+
+#undef LOG_TAG
+#define LOG_TAG "IncrementalServiceTest"
+
+using namespace android::incfs;
+using namespace android::content::pm;
+
+namespace android::os::incremental {
+
+class MockVoldService : public VoldServiceWrapper {
+public:
+    MOCK_CONST_METHOD4(mountIncFs,
+                       binder::Status(const std::string& imagePath, const std::string& targetDir,
+                                      int32_t flags,
+                                      IncrementalFileSystemControlParcel* _aidl_return));
+    MOCK_CONST_METHOD1(unmountIncFs, binder::Status(const std::string& dir));
+    MOCK_CONST_METHOD2(bindMount,
+                       binder::Status(const std::string& sourceDir, const std::string& argetDir));
+
+    void mountIncFsFails() {
+        ON_CALL(*this, mountIncFs(_, _, _, _))
+                .WillByDefault(
+                        Return(binder::Status::fromExceptionCode(1, String8("failed to mount"))));
+    }
+    void mountIncFsInvalidControlParcel() {
+        ON_CALL(*this, mountIncFs(_, _, _, _))
+                .WillByDefault(Invoke(this, &MockVoldService::getInvalidControlParcel));
+    }
+    void mountIncFsSuccess() {
+        ON_CALL(*this, mountIncFs(_, _, _, _))
+                .WillByDefault(Invoke(this, &MockVoldService::incFsSuccess));
+    }
+    void bindMountFails() {
+        ON_CALL(*this, bindMount(_, _))
+                .WillByDefault(Return(
+                        binder::Status::fromExceptionCode(1, String8("failed to bind-mount"))));
+    }
+    void bindMountSuccess() {
+        ON_CALL(*this, bindMount(_, _)).WillByDefault(Return(binder::Status::ok()));
+    }
+    binder::Status getInvalidControlParcel(const std::string& imagePath,
+                                           const std::string& targetDir, int32_t flags,
+                                           IncrementalFileSystemControlParcel* _aidl_return) {
+        _aidl_return->cmd = nullptr;
+        _aidl_return->log = nullptr;
+        return binder::Status::ok();
+    }
+    binder::Status incFsSuccess(const std::string& imagePath, const std::string& targetDir,
+                                int32_t flags, IncrementalFileSystemControlParcel* _aidl_return) {
+        _aidl_return->cmd = std::make_unique<os::ParcelFileDescriptor>(std::move(cmdFd));
+        _aidl_return->log = std::make_unique<os::ParcelFileDescriptor>(std::move(logFd));
+        return binder::Status::ok();
+    }
+
+private:
+    TemporaryFile cmdFile;
+    TemporaryFile logFile;
+    base::unique_fd cmdFd;
+    base::unique_fd logFd;
+};
+
+class MockIncrementalManager : public IncrementalManagerWrapper {
+public:
+    MOCK_CONST_METHOD5(prepareDataLoader,
+                       binder::Status(int32_t mountId, const FileSystemControlParcel& control,
+                                      const DataLoaderParamsParcel& params,
+                                      const sp<IDataLoaderStatusListener>& listener,
+                                      bool* _aidl_return));
+    MOCK_CONST_METHOD2(startDataLoader, binder::Status(int32_t mountId, bool* _aidl_return));
+    MOCK_CONST_METHOD1(destroyDataLoader, binder::Status(int32_t mountId));
+    MOCK_CONST_METHOD3(newFileForDataLoader,
+                       binder::Status(int32_t mountId, int64_t inode,
+                                      const ::std::vector<uint8_t>& metadata));
+    MOCK_CONST_METHOD1(showHealthBlockedUI, binder::Status(int32_t mountId));
+
+    binder::Status prepareDataLoaderOk(int32_t mountId, const FileSystemControlParcel& control,
+                                       const DataLoaderParamsParcel& params,
+                                       const sp<IDataLoaderStatusListener>& listener,
+                                       bool* _aidl_return) {
+        mId = mountId;
+        mListener = listener;
+        *_aidl_return = true;
+        return binder::Status::ok();
+    }
+
+    binder::Status startDataLoaderOk(int32_t mountId, bool* _aidl_return) {
+        *_aidl_return = true;
+        return binder::Status::ok();
+    }
+
+    void prepareDataLoaderFails() {
+        ON_CALL(*this, prepareDataLoader(_, _, _, _, _))
+                .WillByDefault(Return(
+                        (binder::Status::fromExceptionCode(1, String8("failed to prepare")))));
+    }
+    void prepareDataLoaderSuccess() {
+        ON_CALL(*this, prepareDataLoader(_, _, _, _, _))
+                .WillByDefault(Invoke(this, &MockIncrementalManager::prepareDataLoaderOk));
+    }
+    void startDataLoaderSuccess() {
+        ON_CALL(*this, startDataLoader(_, _))
+                .WillByDefault(Invoke(this, &MockIncrementalManager::startDataLoaderOk));
+    }
+    void setDataLoaderStatusNotReady() {
+        mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_NOT_READY);
+    }
+    void setDataLoaderStatusReady() {
+        mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_READY);
+    }
+
+private:
+    int mId;
+    sp<IDataLoaderStatusListener> mListener;
+};
+
+class MockIncFs : public IncFsWrapper {
+public:
+    MOCK_CONST_METHOD5(makeFile,
+                       Inode(Control control, std::string_view name, Inode parent, Size size,
+                             std::string_view metadata));
+    MOCK_CONST_METHOD5(makeDir,
+                       Inode(Control control, std::string_view name, Inode parent,
+                             std::string_view metadata, int mode));
+    MOCK_CONST_METHOD2(getMetadata, RawMetadata(Control control, Inode inode));
+    MOCK_CONST_METHOD4(link,
+                       ErrorCode(Control control, Inode item, Inode targetParent,
+                                 std::string_view name));
+    MOCK_CONST_METHOD3(unlink, ErrorCode(Control control, Inode parent, std::string_view name));
+    MOCK_CONST_METHOD3(writeBlocks,
+                       ErrorCode(Control control, const incfs_new_data_block blocks[],
+                                 int blocksCount));
+
+    void makeFileFails() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(-1)); }
+    void makeFileSuccess() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(0)); }
+    RawMetadata getMountInfoMetadata(Control control, Inode inode) {
+        metadata::Mount m;
+        m.mutable_storage()->set_id(100);
+        m.mutable_loader()->set_package_name("com.test");
+        m.mutable_loader()->set_arguments("com.uri");
+        const auto metadata = m.SerializeAsString();
+        m.mutable_loader()->release_arguments();
+        m.mutable_loader()->release_package_name();
+        return std::vector<char>(metadata.begin(), metadata.end());
+    }
+    RawMetadata getStorageMetadata(Control control, Inode inode) {
+        metadata::Storage st;
+        st.set_id(100);
+        auto metadata = st.SerializeAsString();
+        return std::vector<char>(metadata.begin(), metadata.end());
+    }
+    RawMetadata getBindPointMetadata(Control control, Inode inode) {
+        metadata::BindPoint bp;
+        std::string destPath = "dest";
+        std::string srcPath = "src";
+        bp.set_storage_id(100);
+        bp.set_allocated_dest_path(&destPath);
+        bp.set_allocated_source_subdir(&srcPath);
+        const auto metadata = bp.SerializeAsString();
+        bp.release_source_subdir();
+        bp.release_dest_path();
+        return std::vector<char>(metadata.begin(), metadata.end());
+    }
+};
+
+class MockServiceManager : public ServiceManagerWrapper {
+public:
+    MockServiceManager(std::shared_ptr<MockVoldService> vold,
+                       std::shared_ptr<MockIncrementalManager> manager,
+                       std::shared_ptr<MockIncFs> incfs)
+          : mVold(vold), mIncrementalManager(manager), mIncFs(incfs) {}
+    std::shared_ptr<VoldServiceWrapper> getVoldService() const override { return mVold; }
+    std::shared_ptr<IncrementalManagerWrapper> getIncrementalManager() const override {
+        return mIncrementalManager;
+    }
+    std::shared_ptr<IncFsWrapper> getIncFs() const override { return mIncFs; }
+
+private:
+    std::shared_ptr<MockVoldService> mVold;
+    std::shared_ptr<MockIncrementalManager> mIncrementalManager;
+    std::shared_ptr<MockIncFs> mIncFs;
+};
+
+// --- IncrementalServiceTest ---
+
+static Inode inode(std::string_view path) {
+    struct stat st;
+    if (::stat(path::c_str(path), &st)) {
+        return -1;
+    }
+    return st.st_ino;
+}
+
+class IncrementalServiceTest : public testing::Test {
+public:
+    void SetUp() override {
+        mVold = std::make_shared<NiceMock<MockVoldService>>();
+        mIncrementalManager = std::make_shared<NiceMock<MockIncrementalManager>>();
+        mIncFs = std::make_shared<NiceMock<MockIncFs>>();
+        MockServiceManager serviceManager = MockServiceManager(mVold, mIncrementalManager, mIncFs);
+        mIncrementalService = std::make_unique<IncrementalService>(serviceManager, mRootDir.path);
+        mDataLoaderParcel.packageName = "com.test";
+        mDataLoaderParcel.staticArgs = "uri";
+        mIncrementalService->onSystemReady();
+    }
+
+    void setUpExistingMountDir(const std::string& rootDir) {
+        const auto dir = rootDir + "/dir1";
+        const auto mountDir = dir + "/mount";
+        const auto backingDir = dir + "/backing_store";
+        const auto storageDir = mountDir + "/st0";
+        ASSERT_EQ(0, mkdir(dir.c_str(), 0755));
+        ASSERT_EQ(0, mkdir(mountDir.c_str(), 0755));
+        ASSERT_EQ(0, mkdir(backingDir.c_str(), 0755));
+        ASSERT_EQ(0, mkdir(storageDir.c_str(), 0755));
+        const auto mountInfoFile = rootDir + "/dir1/mount/.info";
+        const auto mountPointsFile = rootDir + "/dir1/mount/.mountpoint.abcd";
+        ASSERT_TRUE(base::WriteStringToFile("info", mountInfoFile));
+        ASSERT_TRUE(base::WriteStringToFile("mounts", mountPointsFile));
+        ASSERT_GE(inode(mountInfoFile), 0);
+        ASSERT_GE(inode(mountPointsFile), 0);
+        ON_CALL(*mIncFs, getMetadata(_, inode(mountInfoFile)))
+                .WillByDefault(Invoke(mIncFs.get(), &MockIncFs::getMountInfoMetadata));
+        ON_CALL(*mIncFs, getMetadata(_, inode(mountPointsFile)))
+                .WillByDefault(Invoke(mIncFs.get(), &MockIncFs::getBindPointMetadata));
+        ON_CALL(*mIncFs, getMetadata(_, inode(rootDir + "/dir1/mount/st0")))
+                .WillByDefault(Invoke(mIncFs.get(), &MockIncFs::getStorageMetadata));
+    }
+
+protected:
+    std::shared_ptr<NiceMock<MockVoldService>> mVold;
+    std::shared_ptr<NiceMock<MockIncFs>> mIncFs;
+    std::shared_ptr<NiceMock<MockIncrementalManager>> mIncrementalManager;
+    std::unique_ptr<IncrementalService> mIncrementalService;
+    TemporaryDir mRootDir;
+    DataLoaderParamsParcel mDataLoaderParcel;
+};
+
+/*
+TEST_F(IncrementalServiceTest, testBootMountExistingImagesSuccess) {
+    TemporaryDir tempDir;
+    setUpExistingMountDir(tempDir.path);
+    mVold->mountIncFsSuccess();
+    mVold->bindMountSuccess();
+    mIncrementalManager->prepareDataLoaderSuccess();
+    ON_CALL(*mIncrementalManager, destroyDataLoader(_)).WillByDefault(Return(binder::Status::ok()));
+
+    EXPECT_CALL(*mVold, mountIncFs(_, _, _, _)).Times(1);
+    EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(1);
+
+    MockServiceManager serviceManager = MockServiceManager(mVold, mIncrementalManager, mIncFs);
+    std::unique_ptr<IncrementalService> incrementalService =
+            std::make_unique<IncrementalService>(serviceManager, tempDir.path);
+    auto finished = incrementalService->onSystemReady();
+    if (finished) {
+        finished->wait();
+    }
+}
+*/
+
+TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsFails) {
+    mVold->mountIncFsFails();
+    EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(0);
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                               IncrementalService::CreateOptions::CreateNew);
+    ASSERT_LT(storageId, 0);
+}
+
+TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsInvalidControlParcel) {
+    mVold->mountIncFsInvalidControlParcel();
+    EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(0);
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                               IncrementalService::CreateOptions::CreateNew);
+    ASSERT_LT(storageId, 0);
+}
+
+TEST_F(IncrementalServiceTest, testCreateStorageMakeFileFails) {
+    mVold->mountIncFsSuccess();
+    mIncFs->makeFileFails();
+    EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(0);
+    EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
+    EXPECT_CALL(*mVold, unmountIncFs(_));
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                               IncrementalService::CreateOptions::CreateNew);
+    ASSERT_LT(storageId, 0);
+}
+
+TEST_F(IncrementalServiceTest, testCreateStorageBindMountFails) {
+    mVold->mountIncFsSuccess();
+    mIncFs->makeFileSuccess();
+    mVold->bindMountFails();
+    EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(0);
+    EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
+    EXPECT_CALL(*mVold, unmountIncFs(_));
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                               IncrementalService::CreateOptions::CreateNew);
+    ASSERT_LT(storageId, 0);
+}
+
+TEST_F(IncrementalServiceTest, testCreateStoragePrepareDataLoaderFails) {
+    mVold->mountIncFsSuccess();
+    mIncFs->makeFileSuccess();
+    mVold->bindMountSuccess();
+    mIncrementalManager->prepareDataLoaderFails();
+    EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
+    EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                               IncrementalService::CreateOptions::CreateNew);
+    ASSERT_LT(storageId, 0);
+}
+
+TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) {
+    mVold->mountIncFsSuccess();
+    mIncFs->makeFileSuccess();
+    mVold->bindMountSuccess();
+    mIncrementalManager->prepareDataLoaderSuccess();
+    EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
+    EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                               IncrementalService::CreateOptions::CreateNew);
+    ASSERT_GE(storageId, 0);
+    mIncrementalService->deleteStorage(storageId);
+}
+
+TEST_F(IncrementalServiceTest, testOnStatusNotReady) {
+    mVold->mountIncFsSuccess();
+    mIncFs->makeFileSuccess();
+    mVold->bindMountSuccess();
+    mIncrementalManager->prepareDataLoaderSuccess();
+    EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
+    EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                               IncrementalService::CreateOptions::CreateNew);
+    ASSERT_GE(storageId, 0);
+    mIncrementalManager->setDataLoaderStatusNotReady();
+}
+
+TEST_F(IncrementalServiceTest, testStartDataLoaderSuccess) {
+    mVold->mountIncFsSuccess();
+    mIncFs->makeFileSuccess();
+    mVold->bindMountSuccess();
+    mIncrementalManager->prepareDataLoaderSuccess();
+    mIncrementalManager->startDataLoaderSuccess();
+    EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
+    EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                               IncrementalService::CreateOptions::CreateNew);
+    ASSERT_GE(storageId, 0);
+    mIncrementalManager->setDataLoaderStatusReady();
+    ASSERT_TRUE(mIncrementalService->startLoading(storageId));
+}
+
+TEST_F(IncrementalServiceTest, testMakeDirectory) {
+    mVold->mountIncFsSuccess();
+    mIncFs->makeFileSuccess();
+    mVold->bindMountSuccess();
+    mIncrementalManager->prepareDataLoaderSuccess();
+    mIncrementalManager->startDataLoaderSuccess();
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                               IncrementalService::CreateOptions::CreateNew);
+    std::string_view dir_path("test");
+    EXPECT_CALL(*mIncFs, makeDir(_, dir_path, _, _, _));
+    int fileIno = mIncrementalService->makeDir(storageId, dir_path, "");
+    ASSERT_GE(fileIno, 0);
+}
+
+TEST_F(IncrementalServiceTest, testMakeDirectoryNoParent) {
+    mVold->mountIncFsSuccess();
+    mIncFs->makeFileSuccess();
+    mVold->bindMountSuccess();
+    mIncrementalManager->prepareDataLoaderSuccess();
+    mIncrementalManager->startDataLoaderSuccess();
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                               IncrementalService::CreateOptions::CreateNew);
+    std::string_view first("first");
+    std::string_view second("second");
+    std::string dir_path = std::string(first) + "/" + std::string(second);
+    EXPECT_CALL(*mIncFs, makeDir(_, first, _, _, _)).Times(0);
+    EXPECT_CALL(*mIncFs, makeDir(_, second, _, _, _)).Times(0);
+    int fileIno = mIncrementalService->makeDir(storageId, dir_path, "");
+    ASSERT_LT(fileIno, 0);
+}
+
+TEST_F(IncrementalServiceTest, testMakeDirectories) {
+    mVold->mountIncFsSuccess();
+    mIncFs->makeFileSuccess();
+    mVold->bindMountSuccess();
+    mIncrementalManager->prepareDataLoaderSuccess();
+    mIncrementalManager->startDataLoaderSuccess();
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                               IncrementalService::CreateOptions::CreateNew);
+    std::string_view first("first");
+    std::string_view second("second");
+    std::string_view third("third");
+    InSequence seq;
+    EXPECT_CALL(*mIncFs, makeDir(_, first, _, _, _));
+    EXPECT_CALL(*mIncFs, makeDir(_, second, _, _, _));
+    EXPECT_CALL(*mIncFs, makeDir(_, third, _, _, _));
+    std::string dir_path =
+            std::string(first) + "/" + std::string(second) + "/" + std::string(third);
+    int fileIno = mIncrementalService->makeDirs(storageId, dir_path, "");
+    ASSERT_GE(fileIno, 0);
+}
+} // namespace android::os::incremental
diff --git a/services/incremental/test/path_test.cpp b/services/incremental/test/path_test.cpp
new file mode 100644
index 0000000..cbe479e1
--- /dev/null
+++ b/services/incremental/test/path_test.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../path.h"
+
+#include <gtest/gtest.h>
+
+using namespace std::literals;
+
+namespace android::incremental::path {
+
+TEST(Path, Normalize) {
+    EXPECT_STREQ("", normalize("").c_str());
+    EXPECT_STREQ("/data/app/com.snapchat.android-evzhnJDgPOq8VcxwEkSY5g==/base.apk",
+                 normalize("/data/app/com.snapchat.android-evzhnJDgPOq8VcxwEkSY5g==/base.apk")
+                         .c_str());
+    EXPECT_STREQ("/a/b", normalize("/a/c/../b").c_str());
+}
+
+TEST(Path, Comparator) {
+    EXPECT_TRUE(PathLess()("/a", "/aa"));
+    EXPECT_TRUE(PathLess()("/a/b", "/aa/b"));
+    EXPECT_TRUE(PathLess()("/a", "/a/b"));
+    EXPECT_TRUE(PathLess()("/a/b"sv, "/a\0"sv));
+    EXPECT_TRUE(!PathLess()("/aa/b", "/a/b"));
+    EXPECT_TRUE(!PathLess()("/a/b", "/a/b"));
+    EXPECT_TRUE(!PathLess()("/a/b", "/a"));
+}
+
+} // namespace android::incremental::path
diff --git a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
index 1e27007..f0758dd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
@@ -44,7 +44,6 @@
 import android.app.IActivityManager;
 import android.app.IUidObserver;
 import android.app.usage.UsageStatsManager;
-import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -82,6 +81,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Random;
@@ -690,11 +690,11 @@
         entries.add(new OpEntry(
                 AppOpsManager.OP_ACCESS_NOTIFICATIONS,
                 AppOpsManager.MODE_IGNORED,
-                new Pair[0]));
+                Collections.emptyMap()));
         entries.add(new OpEntry(
                 AppStateTracker.TARGET_OP,
                 AppOpsManager.MODE_IGNORED,
-                new Pair[0]));
+                Collections.emptyMap()));
 
         ops.add(new PackageOps(PACKAGE_1, UID_1, entries));
 
@@ -703,7 +703,7 @@
         entries.add(new OpEntry(
                 AppStateTracker.TARGET_OP,
                 AppOpsManager.MODE_IGNORED,
-                new Pair[0]));
+                Collections.emptyMap()));
 
         ops.add(new PackageOps(PACKAGE_2, UID_2, entries));
 
@@ -712,7 +712,7 @@
         entries.add(new OpEntry(
                 AppStateTracker.TARGET_OP,
                 AppOpsManager.MODE_ALLOWED,
-                new Pair[0]));
+                Collections.emptyMap()));
 
         ops.add(new PackageOps(PACKAGE_1, UID_10_1, entries));
 
@@ -721,11 +721,11 @@
         entries.add(new OpEntry(
                 AppStateTracker.TARGET_OP,
                 AppOpsManager.MODE_IGNORED,
-                new Pair[0]));
+                Collections.emptyMap()));
         entries.add(new OpEntry(
                 AppOpsManager.OP_ACCESS_NOTIFICATIONS,
                 AppOpsManager.MODE_IGNORED,
-                new Pair[0]));
+                Collections.emptyMap()));
 
         ops.add(new PackageOps(PACKAGE_3, UID_10_3, entries));
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index fa209a7a..529339e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -20,6 +20,7 @@
 import static android.app.AppOpsManager.MODE_ERRORED;
 import static android.app.AppOpsManager.MODE_FOREGROUND;
 import static android.app.AppOpsManager.OP_COARSE_LOCATION;
+import static android.app.AppOpsManager.OP_FLAGS_ALL;
 import static android.app.AppOpsManager.OP_READ_SMS;
 import static android.app.AppOpsManager.OP_WIFI_SCAN;
 import static android.app.AppOpsManager.OP_WRITE_SMS;
@@ -465,11 +466,11 @@
                 assertWithMessage("Unexpected mode").that(mode).isEqualTo(opEntry.getMode());
                 if (minMillis > 0) {
                     assertWithMessage("Unexpected timestamp")
-                            .that(opEntry.getTime()).isAtLeast(minMillis);
+                            .that(opEntry.getLastAccessTime(OP_FLAGS_ALL)).isAtLeast(minMillis);
                 }
                 if (minRejectMillis > 0) {
-                    assertWithMessage("Unexpected rejection timestamp")
-                            .that(opEntry.getRejectTime()).isAtLeast(minRejectMillis);
+                    assertWithMessage("Unexpected rejection timestamp").that(
+                            opEntry.getLastRejectTime(OP_FLAGS_ALL)).isAtLeast(minRejectMillis);
                 }
             }
         }
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/RuleIndexingDetailsIdentifierTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java
index b25f3bc..90ec19e 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java
@@ -138,16 +138,14 @@
         List<Rule> ruleList = new ArrayList();
         ruleList.add(RULE_WITH_PACKAGE_NAME);
 
-        Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
+        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).keySet()).containsExactly(SAMPLE_PACKAGE_NAME);
-        assertThat(result.get(PACKAGE_NAME_INDEXED).get(SAMPLE_PACKAGE_NAME))
-                .containsExactly(RULE_WITH_PACKAGE_NAME);
+        assertThat(result.get(PACKAGE_NAME_INDEXED)).containsExactly(RULE_WITH_PACKAGE_NAME);
     }
 
     @Test
@@ -155,16 +153,13 @@
         List<Rule> ruleList = new ArrayList();
         ruleList.add(RULE_WITH_APP_CERTIFICATE);
 
-        Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
+        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).keySet())
-                .containsExactly(SAMPLE_APP_CERTIFICATE);
-        assertThat(result.get(APP_CERTIFICATE_INDEXED).get(SAMPLE_APP_CERTIFICATE))
-                .containsExactly(RULE_WITH_APP_CERTIFICATE);
+        assertThat(result.get(APP_CERTIFICATE_INDEXED)).containsExactly(RULE_WITH_APP_CERTIFICATE);
     }
 
     @Test
@@ -172,15 +167,13 @@
         List<Rule> ruleList = new ArrayList();
         ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS);
 
-        Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
+        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).keySet()).containsExactly("N/A");
-        assertThat(result.get(NOT_INDEXED).get("N/A"))
-                .containsExactly(RULE_WITH_INSTALLER_RESTRICTIONS);
+        assertThat(result.get(NOT_INDEXED)).containsExactly(RULE_WITH_INSTALLER_RESTRICTIONS);
     }
 
     @Test
@@ -188,15 +181,13 @@
         List<Rule> ruleList = new ArrayList();
         ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS);
 
-        Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
+        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).keySet()).containsExactly("N/A");
-        assertThat(result.get(NOT_INDEXED).get("N/A"))
-                .containsExactly(RULE_WITH_NONSTRING_RESTRICTIONS);
+        assertThat(result.get(NOT_INDEXED)).containsExactly(RULE_WITH_NONSTRING_RESTRICTIONS);
     }
 
     @Test
@@ -215,41 +206,79 @@
         List<Rule> ruleList = new ArrayList();
         ruleList.add(negatedRule);
 
-        Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
+        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).keySet()).containsExactly("N/A");
-        assertThat(result.get(NOT_INDEXED).get("N/A")).containsExactly(negatedRule);
+        assertThat(result.get(NOT_INDEXED)).containsExactly(negatedRule);
     }
 
     @Test
-    public void getIndexType_allRulesTogether() {
+    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(RULE_WITH_PACKAGE_NAME);
-        ruleList.add(RULE_WITH_APP_CERTIFICATE);
+        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, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
+        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).keySet()).containsExactly(SAMPLE_PACKAGE_NAME);
-        assertThat(result.get(PACKAGE_NAME_INDEXED).get(SAMPLE_PACKAGE_NAME))
-                .containsExactly(RULE_WITH_PACKAGE_NAME);
+        // 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);
 
-        assertThat(result.get(APP_CERTIFICATE_INDEXED).keySet())
-                .containsExactly(SAMPLE_APP_CERTIFICATE);
-        assertThat(result.get(APP_CERTIFICATE_INDEXED).get(SAMPLE_APP_CERTIFICATE))
-                .containsExactly(RULE_WITH_APP_CERTIFICATE);
+        // 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).keySet()).containsExactly("N/A");
-        assertThat(result.get(NOT_INDEXED).get("N/A")).containsExactly(
-                RULE_WITH_INSTALLER_RESTRICTIONS, RULE_WITH_NONSTRING_RESTRICTIONS);
+        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() {
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/timedetector/ArrayMapWithHistoryTest.java b/services/tests/servicestests/src/com/android/server/timedetector/ArrayMapWithHistoryTest.java
new file mode 100644
index 0000000..b6eea46
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/ArrayMapWithHistoryTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.timedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.util.ArrayMap;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.timezonedetector.ArrayMapWithHistory;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.StringWriter;
+import java.util.concurrent.Callable;
+
+@RunWith(AndroidJUnit4.class)
+public class ArrayMapWithHistoryTest {
+
+    @Test
+    public void testValueHistoryBehavior() {
+        // Create a map that will retain 2 values per key.
+        ArrayMapWithHistory<String, String> historyMap = new ArrayMapWithHistory<>(2 /* history */);
+        ArrayMap<String, String> arrayMap = new ArrayMap<>();
+
+        compareGetAndSizeForKeys(historyMap, arrayMap, entry("K1", null));
+
+        assertEquals(0, historyMap.getHistoryCountForKeyForTests("K1"));
+        assertToStringAndDumpNotNull(historyMap);
+
+        putAndCompareReturnValue(historyMap, arrayMap, "K1", "V1");
+        compareGetAndSizeForKeys(historyMap, arrayMap, entry("K1", "V1"));
+        compareKeyAtAndValueAtForIndex(0, historyMap, arrayMap);
+
+        assertEquals(1, historyMap.getHistoryCountForKeyForTests("K1"));
+        assertToStringAndDumpNotNull(historyMap);
+
+        // put() a new value for the same key.
+        putAndCompareReturnValue(historyMap, arrayMap, "K1", "V2");
+        compareGetAndSizeForKeys(historyMap, arrayMap, entry("K1", "V2"));
+        compareKeyAtAndValueAtForIndex(0, historyMap, arrayMap);
+
+        assertEquals(2, historyMap.getHistoryCountForKeyForTests("K1"));
+        assertToStringAndDumpNotNull(historyMap);
+
+        // put() a new value for the same key. We should have hit the limit of "2 values retained
+        // per key".
+        putAndCompareReturnValue(historyMap, arrayMap, "K1", "V3");
+        compareGetAndSizeForKeys(historyMap, arrayMap, entry("K1", "V3"));
+        compareKeyAtAndValueAtForIndex(0, historyMap, arrayMap);
+
+        assertEquals(2, historyMap.getHistoryCountForKeyForTests("K1"));
+        assertToStringAndDumpNotNull(historyMap);
+    }
+
+    @Test
+    public void testMapBehavior() throws Exception {
+        ArrayMapWithHistory<String, String> historyMap = new ArrayMapWithHistory<>(2);
+        ArrayMap<String, String> arrayMap = new ArrayMap<>();
+
+        compareGetAndSizeForKeys(historyMap, arrayMap, entry("K1", null), entry("K2", null));
+        assertIndexAccessThrowsException(0, historyMap, arrayMap);
+
+        assertEquals(0, historyMap.getHistoryCountForKeyForTests("K1"));
+        assertEquals(0, historyMap.getHistoryCountForKeyForTests("K2"));
+
+        putAndCompareReturnValue(historyMap, arrayMap, "K1", "V1");
+        compareGetAndSizeForKeys(historyMap, arrayMap, entry("K1", "V1"), entry("K2", null));
+        compareKeyAtAndValueAtForIndex(0, historyMap, arrayMap);
+        // TODO Restore after http://b/146563025 is fixed and ArrayMap behaves properly in tests.
+        // assertIndexAccessThrowsException(1, historyMap, arrayMap);
+
+        assertEquals(1, historyMap.getHistoryCountForKeyForTests("K1"));
+        assertToStringAndDumpNotNull(historyMap);
+
+        putAndCompareReturnValue(historyMap, arrayMap, "K2", "V2");
+        compareGetAndSizeForKeys(historyMap, arrayMap, entry("K1", "V1"), entry("K2", "V2"));
+        compareKeyAtAndValueAtForIndex(0, historyMap, arrayMap);
+        compareKeyAtAndValueAtForIndex(1, historyMap, arrayMap);
+        // TODO Restore after http://b/146563025 is fixed and ArrayMap behaves properly in tests.
+        // assertIndexAccessThrowsException(2, historyMap, arrayMap);
+
+        assertEquals(1, historyMap.getHistoryCountForKeyForTests("K1"));
+        assertEquals(1, historyMap.getHistoryCountForKeyForTests("K2"));
+        assertToStringAndDumpNotNull(historyMap);
+    }
+
+    private static String dumpHistoryMap(ArrayMapWithHistory<?, ?> historyMap) {
+        StringWriter stringWriter = new StringWriter();
+        try (IndentingPrintWriter ipw = new IndentingPrintWriter(stringWriter, " ")) {
+            historyMap.dump(ipw);
+            return stringWriter.toString();
+        }
+    }
+
+    private static <K, V> void putAndCompareReturnValue(ArrayMapWithHistory<K, V> historyMap,
+            ArrayMap<K, V> arrayMap, K key, V value) {
+        assertEquals(arrayMap.put(key, value), historyMap.put(key, value));
+    }
+
+    private static class Entry<K, V> {
+        public final K key;
+        public final V value;
+
+        Entry(K key, V value) {
+            this.key = key;
+            this.value = value;
+        }
+    }
+
+    private static <K, V> Entry<K, V> entry(K key, V value) {
+        return new Entry<>(key, value);
+    }
+
+    @SafeVarargs
+    private static <K, V> void compareGetAndSizeForKeys(ArrayMapWithHistory<K, V> historyMap,
+            ArrayMap<K, V> arrayMap, Entry<K, V>... expectedEntries) {
+        for (Entry<K, V> expectedEntry : expectedEntries) {
+            assertEquals(arrayMap.get(expectedEntry.key), historyMap.get(expectedEntry.key));
+            assertEquals(expectedEntry.value, historyMap.get(expectedEntry.key));
+        }
+        assertEquals(arrayMap.size(), historyMap.size());
+    }
+
+    private static void compareKeyAtAndValueAtForIndex(
+            int index, ArrayMapWithHistory<?, ?> historyMap, ArrayMap<?, ?> arrayMap) {
+        assertEquals(arrayMap.keyAt(index), historyMap.keyAt(index));
+        assertEquals(arrayMap.valueAt(index), historyMap.valueAt(index));
+    }
+
+    private static void assertIndexAccessThrowsException(
+            int index, ArrayMapWithHistory<?, ?> historyMap, ArrayMap<?, ?> arrayMap)
+            throws Exception {
+        assertThrowsArrayIndexOutOfBoundsException(
+                "ArrayMap.keyAt(" + index + ")", () -> arrayMap.keyAt(index));
+        assertThrowsArrayIndexOutOfBoundsException(
+                "ArrayMapWithHistory.keyAt(" + index + ")", () -> historyMap.keyAt(index));
+        assertThrowsArrayIndexOutOfBoundsException(
+                "ArrayMap.keyAt(" + index + ")", () -> arrayMap.valueAt(index));
+        assertThrowsArrayIndexOutOfBoundsException(
+                "ArrayMapWithHistory.keyAt(" + index + ")", () -> historyMap.valueAt(index));
+    }
+
+    private static void assertThrowsArrayIndexOutOfBoundsException(
+            String description, Callable<?> callable) throws Exception {
+        try {
+            callable.call();
+            fail("Expected exception for " + description);
+        } catch (ArrayIndexOutOfBoundsException expected) {
+            // This is fine.
+        } catch (Exception e) {
+            // Any other exception is just rethrown.
+            throw e;
+        }
+    }
+
+    private static void assertToStringAndDumpNotNull(ArrayMapWithHistory<?, ?> historyMap) {
+        assertNotNull(historyMap.toString());
+        assertNotNull(dumpHistoryMap(historyMap));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/ReferenceWithHistoryTest.java b/services/tests/servicestests/src/com/android/server/timedetector/ReferenceWithHistoryTest.java
new file mode 100644
index 0000000..ce72499
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/ReferenceWithHistoryTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.timezonedetector.ReferenceWithHistory;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.StringWriter;
+
+@RunWith(AndroidJUnit4.class)
+public class ReferenceWithHistoryTest {
+
+    @Test
+    public void testBasicReferenceBehavior() {
+        // Create a reference that will retain 2 history values.
+        ReferenceWithHistory<String> referenceWithHistory =
+                new ReferenceWithHistory<>(2 /* history */);
+        TestRef<String> reference = new TestRef<>();
+
+        // Check unset behavior.
+        compareGet(referenceWithHistory, reference, null);
+        assertNotNull(dumpReferenceWithHistory(referenceWithHistory));
+        compareToString(referenceWithHistory, reference, "null");
+
+        // Try setting null.
+        setAndCompareReturnValue(referenceWithHistory, reference, null);
+        compareGet(referenceWithHistory, reference, null);
+        assertNotNull(dumpReferenceWithHistory(referenceWithHistory));
+        compareToString(referenceWithHistory, reference, "null");
+
+        // Try setting a non-null value.
+        setAndCompareReturnValue(referenceWithHistory, reference, "Foo");
+        compareGet(referenceWithHistory, reference, "Foo");
+        assertNotNull(dumpReferenceWithHistory(referenceWithHistory));
+        compareToString(referenceWithHistory, reference, "Foo");
+
+        // Try setting null again.
+        setAndCompareReturnValue(referenceWithHistory, reference, "Foo");
+        compareGet(referenceWithHistory, reference, "Foo");
+        assertNotNull(dumpReferenceWithHistory(referenceWithHistory));
+        compareToString(referenceWithHistory, reference, "Foo");
+
+        // Try a non-null value again.
+        setAndCompareReturnValue(referenceWithHistory, reference, "Bar");
+        compareGet(referenceWithHistory, reference, "Bar");
+        assertNotNull(dumpReferenceWithHistory(referenceWithHistory));
+        compareToString(referenceWithHistory, reference, "Bar");
+    }
+
+    @Test
+    public void testValueHistoryBehavior() {
+        // Create a reference that will retain 2 history values.
+        ReferenceWithHistory<String> referenceWithHistory =
+                new ReferenceWithHistory<>(2 /* history */);
+        TestRef<String> reference = new TestRef<>();
+
+        // Assert behavior before anything is set.
+        assertEquals(0, referenceWithHistory.getHistoryCount());
+
+        // Set a value (1).
+        setAndCompareReturnValue(referenceWithHistory, reference, "V1");
+        assertEquals(1, referenceWithHistory.getHistoryCount());
+
+        // Set a value (2).
+        setAndCompareReturnValue(referenceWithHistory, reference, "V2");
+        assertEquals(2, referenceWithHistory.getHistoryCount());
+
+        // Set a value (3).
+        // We should have hit the limit of "2 history values retained per key".
+        setAndCompareReturnValue(referenceWithHistory, reference, "V3");
+        assertEquals(2, referenceWithHistory.getHistoryCount());
+    }
+
+    /**
+     * A simple class that has the same behavior as ReferenceWithHistory without the history. Used
+     * in tests for comparison.
+     */
+    private static class TestRef<V> {
+        private V mValue;
+
+        public V get() {
+            return mValue;
+        }
+
+        public V set(V value) {
+            V previous = mValue;
+            mValue = value;
+            return previous;
+        }
+
+        public String toString() {
+            return String.valueOf(mValue);
+        }
+    }
+
+    private static void compareGet(
+            ReferenceWithHistory<?> referenceWithHistory, TestRef<?> reference, Object value) {
+        assertEquals(reference.get(), referenceWithHistory.get());
+        assertEquals(value, reference.get());
+    }
+
+    private static <T> void setAndCompareReturnValue(
+            ReferenceWithHistory<T> referenceWithHistory, TestRef<T> reference, T newValue) {
+        assertEquals(reference.set(newValue), referenceWithHistory.set(newValue));
+    }
+
+    private static void compareToString(
+            ReferenceWithHistory<?> referenceWithHistory, TestRef<?> reference, String expected) {
+        assertEquals(reference.toString(), referenceWithHistory.toString());
+        assertEquals(expected, referenceWithHistory.toString());
+    }
+
+    private static String dumpReferenceWithHistory(ReferenceWithHistory<?> referenceWithHistory) {
+        StringWriter stringWriter = new StringWriter();
+        try (IndentingPrintWriter ipw = new IndentingPrintWriter(stringWriter, " ")) {
+            referenceWithHistory.dump(ipw);
+            return stringWriter.toString();
+        }
+    }
+}
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/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/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/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java
index ea641f8..8b8c86b 100644
--- a/telecomm/java/android/telecom/AudioState.java
+++ b/telecomm/java/android/telecom/AudioState.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index a8852a8..86ad795 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -20,11 +20,12 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 
 import com.android.internal.telecom.IVideoProvider;
diff --git a/telecomm/java/android/telecom/CallerInfo.java b/telecomm/java/android/telecom/CallerInfo.java
index fb6f994..a5d25e2 100644
--- a/telecomm/java/android/telecom/CallerInfo.java
+++ b/telecomm/java/android/telecom/CallerInfo.java
@@ -17,7 +17,7 @@
 package android.telecom;
 
 import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -41,8 +41,8 @@
 import com.android.i18n.phonenumbers.PhoneNumberUtil;
 import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
 import com.android.i18n.phonenumbers.geocoding.PhoneNumberOfflineGeocoder;
-import com.android.internal.annotations.VisibleForTesting;
 
+import com.android.internal.annotations.VisibleForTesting;
 import java.util.Locale;
 
 
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 2d0b49d..0becaf2 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -21,9 +21,9 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
 import android.app.Notification;
 import android.bluetooth.BluetoothDevice;
-import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.hardware.camera2.CameraManager;
 import android.net.Uri;
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 4f6a9d6..7d4ee76 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -16,7 +16,7 @@
 
 package android.telecom;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Build;
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index be4e2f4..a234bb0 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -16,21 +16,22 @@
 
 package android.telecom;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.telecom.Call.Details.CallDirection;
 
-import com.android.internal.telecom.IVideoProvider;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import com.android.internal.telecom.IVideoProvider;
+
 /**
  * Information about a call that is used between InCallService and Telecom.
  * @hide
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index a427ed6..61a639a1 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -17,8 +17,8 @@
 package android.telecom;
 
 import android.annotation.SystemApi;
+import android.annotation.UnsupportedAppUsage;
 import android.bluetooth.BluetoothDevice;
-import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Bundle;
 import android.util.ArrayMap;
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index e1bcb5f..eb568e0 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.os.Build;
 import android.os.Parcel;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 9cf4803..af3c55a 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -26,7 +26,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index 109e7f8..4a1aa0a 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -16,7 +16,7 @@
 
 package android.telecom;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Handler;
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index 4197f3c..64e6ca3 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -19,6 +19,7 @@
 import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/telephony/common/com/android/internal/telephony/GsmAlphabet.java b/telephony/common/com/android/internal/telephony/GsmAlphabet.java
index 22cbdaa0..5fb4e90 100644
--- a/telephony/common/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/common/com/android/internal/telephony/GsmAlphabet.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.content.res.Resources;
 import android.os.Build;
 import android.telephony.Rlog;
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index 9671488..70ce1bf 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -20,7 +20,6 @@
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.app.role.RoleManager;
-import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -48,6 +47,8 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
diff --git a/telephony/common/com/android/internal/telephony/SmsConstants.java b/telephony/common/com/android/internal/telephony/SmsConstants.java
index 3aa8bbf..19f52b0 100644
--- a/telephony/common/com/android/internal/telephony/SmsConstants.java
+++ b/telephony/common/com/android/internal/telephony/SmsConstants.java
@@ -15,7 +15,7 @@
  */
 package com.android.internal.telephony;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 
 /**
  * SMS Constants and must be the same as the corresponding
diff --git a/telephony/common/com/android/internal/telephony/SmsNumberUtils.java b/telephony/common/com/android/internal/telephony/SmsNumberUtils.java
index 367aad1..06c08f5 100644
--- a/telephony/common/com/android/internal/telephony/SmsNumberUtils.java
+++ b/telephony/common/com/android/internal/telephony/SmsNumberUtils.java
@@ -20,8 +20,8 @@
 import android.database.Cursor;
 import android.database.SQLException;
 import android.os.Binder;
-import android.os.Build;
 import android.os.PersistableBundle;
+import android.os.SystemProperties;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.Rlog;
@@ -43,7 +43,7 @@
  */
 public class SmsNumberUtils {
     private static final String TAG = "SmsNumberUtils";
-    private static final boolean DBG = Build.IS_DEBUGGABLE;
+    private static final boolean DBG = SystemProperties.getInt("ro.debuggable", 0) == 1;
 
     private static final String PLUS_SIGN = "+";
 
diff --git a/telephony/common/com/google/android/mms/ContentType.java b/telephony/common/com/google/android/mms/ContentType.java
index 4a971dd..12e4b7e 100644
--- a/telephony/common/com/google/android/mms/ContentType.java
+++ b/telephony/common/com/google/android/mms/ContentType.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import java.util.ArrayList;
 
diff --git a/telephony/common/com/google/android/mms/InvalidHeaderValueException.java b/telephony/common/com/google/android/mms/InvalidHeaderValueException.java
index 55087ff..2836c30 100644
--- a/telephony/common/com/google/android/mms/InvalidHeaderValueException.java
+++ b/telephony/common/com/google/android/mms/InvalidHeaderValueException.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 /**
  * Thrown when an invalid header value was set.
diff --git a/telephony/common/com/google/android/mms/MmsException.java b/telephony/common/com/google/android/mms/MmsException.java
index 24bceb3..5be33ed 100644
--- a/telephony/common/com/google/android/mms/MmsException.java
+++ b/telephony/common/com/google/android/mms/MmsException.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 /**
  * A generic exception that is thrown by the Mms client.
diff --git a/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java b/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java
index 8693385..ae447d7 100644
--- a/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java
+++ b/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import com.google.android.mms.InvalidHeaderValueException;
 
diff --git a/telephony/common/com/google/android/mms/pdu/Base64.java b/telephony/common/com/google/android/mms/pdu/Base64.java
index 0d6a46a..483fa7f 100644
--- a/telephony/common/com/google/android/mms/pdu/Base64.java
+++ b/telephony/common/com/google/android/mms/pdu/Base64.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 public class Base64 {
     /**
diff --git a/telephony/common/com/google/android/mms/pdu/CharacterSets.java b/telephony/common/com/google/android/mms/pdu/CharacterSets.java
index 5172b7b..27da35e 100644
--- a/telephony/common/com/google/android/mms/pdu/CharacterSets.java
+++ b/telephony/common/com/google/android/mms/pdu/CharacterSets.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import java.io.UnsupportedEncodingException;
 import java.util.HashMap;
diff --git a/telephony/common/com/google/android/mms/pdu/DeliveryInd.java b/telephony/common/com/google/android/mms/pdu/DeliveryInd.java
index 8fb6a75..7093ac6 100644
--- a/telephony/common/com/google/android/mms/pdu/DeliveryInd.java
+++ b/telephony/common/com/google/android/mms/pdu/DeliveryInd.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import com.google.android.mms.InvalidHeaderValueException;
 
diff --git a/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java
index 8c0380f..4166275 100644
--- a/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java
+++ b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java
@@ -17,9 +17,10 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Log;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
diff --git a/telephony/common/com/google/android/mms/pdu/GenericPdu.java b/telephony/common/com/google/android/mms/pdu/GenericPdu.java
index 320b13f..ebf16ac 100644
--- a/telephony/common/com/google/android/mms/pdu/GenericPdu.java
+++ b/telephony/common/com/google/android/mms/pdu/GenericPdu.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import com.google.android.mms.InvalidHeaderValueException;
 
diff --git a/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java b/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java
index 42a89c6..e108f76 100644
--- a/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java
+++ b/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import com.google.android.mms.InvalidHeaderValueException;
 
diff --git a/telephony/common/com/google/android/mms/pdu/NotificationInd.java b/telephony/common/com/google/android/mms/pdu/NotificationInd.java
index ca4615c..b561bd4 100644
--- a/telephony/common/com/google/android/mms/pdu/NotificationInd.java
+++ b/telephony/common/com/google/android/mms/pdu/NotificationInd.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import com.google.android.mms.InvalidHeaderValueException;
 
diff --git a/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java b/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java
index ebd81af..3c70f86 100644
--- a/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java
+++ b/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import com.google.android.mms.InvalidHeaderValueException;
 
diff --git a/telephony/common/com/google/android/mms/pdu/PduBody.java b/telephony/common/com/google/android/mms/pdu/PduBody.java
index f7f285f..51914e4 100644
--- a/telephony/common/com/google/android/mms/pdu/PduBody.java
+++ b/telephony/common/com/google/android/mms/pdu/PduBody.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import java.util.HashMap;
 import java.util.Map;
diff --git a/telephony/common/com/google/android/mms/pdu/PduComposer.java b/telephony/common/com/google/android/mms/pdu/PduComposer.java
index b8b212c..e24bf21 100644
--- a/telephony/common/com/google/android/mms/pdu/PduComposer.java
+++ b/telephony/common/com/google/android/mms/pdu/PduComposer.java
@@ -17,11 +17,12 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.text.TextUtils;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import java.io.ByteArrayOutputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
diff --git a/telephony/common/com/google/android/mms/pdu/PduContentTypes.java b/telephony/common/com/google/android/mms/pdu/PduContentTypes.java
index 57141fe..8551b2f 100644
--- a/telephony/common/com/google/android/mms/pdu/PduContentTypes.java
+++ b/telephony/common/com/google/android/mms/pdu/PduContentTypes.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 public class PduContentTypes {
     /**
diff --git a/telephony/common/com/google/android/mms/pdu/PduHeaders.java b/telephony/common/com/google/android/mms/pdu/PduHeaders.java
index 3e62184..b524464 100644
--- a/telephony/common/com/google/android/mms/pdu/PduHeaders.java
+++ b/telephony/common/com/google/android/mms/pdu/PduHeaders.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import com.google.android.mms.InvalidHeaderValueException;
 
diff --git a/telephony/common/com/google/android/mms/pdu/PduParser.java b/telephony/common/com/google/android/mms/pdu/PduParser.java
index 5340245..f483994 100755
--- a/telephony/common/com/google/android/mms/pdu/PduParser.java
+++ b/telephony/common/com/google/android/mms/pdu/PduParser.java
@@ -17,9 +17,10 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Log;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import com.google.android.mms.ContentType;
 import com.google.android.mms.InvalidHeaderValueException;
 
diff --git a/telephony/common/com/google/android/mms/pdu/PduPart.java b/telephony/common/com/google/android/mms/pdu/PduPart.java
index 8dd976b..09b7751 100644
--- a/telephony/common/com/google/android/mms/pdu/PduPart.java
+++ b/telephony/common/com/google/android/mms/pdu/PduPart.java
@@ -17,9 +17,10 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
 import android.net.Uri;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import java.util.HashMap;
 import java.util.Map;
 
diff --git a/telephony/common/com/google/android/mms/pdu/PduPersister.java b/telephony/common/com/google/android/mms/pdu/PduPersister.java
index 2295928..b237705 100755
--- a/telephony/common/com/google/android/mms/pdu/PduPersister.java
+++ b/telephony/common/com/google/android/mms/pdu/PduPersister.java
@@ -17,7 +17,6 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
@@ -40,6 +39,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import com.google.android.mms.ContentType;
 import com.google.android.mms.InvalidHeaderValueException;
 import com.google.android.mms.MmsException;
diff --git a/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java b/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java
index 4e1d7f5..9d6535c 100644
--- a/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java
+++ b/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import java.io.ByteArrayOutputStream;
 
diff --git a/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java b/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java
index 4ba3c71..e38c62d 100644
--- a/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java
+++ b/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import com.google.android.mms.InvalidHeaderValueException;
 
diff --git a/telephony/common/com/google/android/mms/pdu/ReadRecInd.java b/telephony/common/com/google/android/mms/pdu/ReadRecInd.java
index 37ccfb9..9696bc2 100644
--- a/telephony/common/com/google/android/mms/pdu/ReadRecInd.java
+++ b/telephony/common/com/google/android/mms/pdu/ReadRecInd.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import com.google.android.mms.InvalidHeaderValueException;
 
diff --git a/telephony/common/com/google/android/mms/pdu/RetrieveConf.java b/telephony/common/com/google/android/mms/pdu/RetrieveConf.java
index 260adfc..03755af 100644
--- a/telephony/common/com/google/android/mms/pdu/RetrieveConf.java
+++ b/telephony/common/com/google/android/mms/pdu/RetrieveConf.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import com.google.android.mms.InvalidHeaderValueException;
 
diff --git a/telephony/common/com/google/android/mms/pdu/SendConf.java b/telephony/common/com/google/android/mms/pdu/SendConf.java
index 7799238..b859827 100644
--- a/telephony/common/com/google/android/mms/pdu/SendConf.java
+++ b/telephony/common/com/google/android/mms/pdu/SendConf.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import com.google.android.mms.InvalidHeaderValueException;
 
diff --git a/telephony/common/com/google/android/mms/pdu/SendReq.java b/telephony/common/com/google/android/mms/pdu/SendReq.java
index 6e2f2da..c1b7f93 100644
--- a/telephony/common/com/google/android/mms/pdu/SendReq.java
+++ b/telephony/common/com/google/android/mms/pdu/SendReq.java
@@ -17,9 +17,10 @@
 
 package com.google.android.mms.pdu;
 
-import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Log;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import com.google.android.mms.InvalidHeaderValueException;
 
 public class SendReq extends MultimediaMessagePdu {
diff --git a/telephony/common/com/google/android/mms/util/AbstractCache.java b/telephony/common/com/google/android/mms/util/AbstractCache.java
index 25862e7..ab5d48a 100644
--- a/telephony/common/com/google/android/mms/util/AbstractCache.java
+++ b/telephony/common/com/google/android/mms/util/AbstractCache.java
@@ -17,9 +17,10 @@
 
 package com.google.android.mms.util;
 
-import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Log;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import java.util.HashMap;
 
 public abstract class AbstractCache<K, V> {
diff --git a/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java b/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java
index 0f9390d..118de46 100644
--- a/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java
+++ b/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java
@@ -17,11 +17,12 @@
 
 package com.google.android.mms.util;
 
-import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.drm.DrmManagerClient;
 import android.util.Log;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 public class DownloadDrmHelper {
     private static final String TAG = "DownloadDrmHelper";
 
diff --git a/telephony/common/com/google/android/mms/util/DrmConvertSession.java b/telephony/common/com/google/android/mms/util/DrmConvertSession.java
index 156c7ad..0e8ec91 100644
--- a/telephony/common/com/google/android/mms/util/DrmConvertSession.java
+++ b/telephony/common/com/google/android/mms/util/DrmConvertSession.java
@@ -16,13 +16,14 @@
  */
 package com.google.android.mms.util;
 
-import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.drm.DrmConvertedStatus;
 import android.drm.DrmManagerClient;
 import android.provider.Downloads;
 import android.util.Log;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.RandomAccessFile;
diff --git a/telephony/common/com/google/android/mms/util/PduCache.java b/telephony/common/com/google/android/mms/util/PduCache.java
index c380d6b..94e3894 100644
--- a/telephony/common/com/google/android/mms/util/PduCache.java
+++ b/telephony/common/com/google/android/mms/util/PduCache.java
@@ -17,13 +17,14 @@
 
 package com.google.android.mms.util;
 
-import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentUris;
 import android.content.UriMatcher;
 import android.net.Uri;
 import android.provider.Telephony.Mms;
 import android.util.Log;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import java.util.HashMap;
 import java.util.HashSet;
 
diff --git a/telephony/common/com/google/android/mms/util/PduCacheEntry.java b/telephony/common/com/google/android/mms/util/PduCacheEntry.java
index a4a25d2..1ecd1bf 100644
--- a/telephony/common/com/google/android/mms/util/PduCacheEntry.java
+++ b/telephony/common/com/google/android/mms/util/PduCacheEntry.java
@@ -17,7 +17,7 @@
 
 package com.google.android.mms.util;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import com.google.android.mms.pdu.GenericPdu;
 
diff --git a/telephony/common/com/google/android/mms/util/SqliteWrapper.java b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
index 31fe4d7..2dd1dc1 100644
--- a/telephony/common/com/google/android/mms/util/SqliteWrapper.java
+++ b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
@@ -18,7 +18,6 @@
 package com.google.android.mms.util;
 
 import android.app.ActivityManager;
-import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -28,6 +27,8 @@
 import android.util.Log;
 import android.widget.Toast;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 public final class SqliteWrapper {
     private static final String TAG = "SqliteWrapper";
     private static final String SQLITE_EXCEPTION_DETAIL_MESSAGE
diff --git a/telephony/java/android/service/euicc/EuiccProfileInfo.java b/telephony/java/android/service/euicc/EuiccProfileInfo.java
index 8450a90..6c357cc 100644
--- a/telephony/java/android/service/euicc/EuiccProfileInfo.java
+++ b/telephony/java/android/service/euicc/EuiccProfileInfo.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.service.carrier.CarrierIdentifier;
diff --git a/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
index 2382f65..c7a9851 100644
--- a/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
+++ b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
@@ -17,7 +17,7 @@
 
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.euicc.DownloadableSubscription;
diff --git a/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
index d0fb511..abd4065 100644
--- a/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
+++ b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
@@ -17,7 +17,7 @@
 
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.euicc.DownloadableSubscription;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index b086506..ed1bff7 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -24,7 +24,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.PersistableBundle;
@@ -3048,16 +3048,18 @@
             "data_switch_validation_timeout_long";
 
     /**
-     * GPS configs. See android.hardware.gnss@1.0 IGnssConfiguration.
-     * @hide
+     * GPS configs. See the GNSS HAL documentation for more details.
      */
     public static final class Gps {
+        private Gps() {}
+
         /** Prefix of all Gps.KEY_* constants. */
         public static final String KEY_PREFIX = "gps.";
 
         /**
          * Location information during (and after) an emergency call is only provided over control
          * plane signaling from the network.
+         * @hide
          */
         public static final int SUPL_EMERGENCY_MODE_TYPE_CP_ONLY = 0;
 
@@ -3065,6 +3067,7 @@
          * Location information during (and after) an emergency call is provided over the data
          * plane and serviced by the framework GNSS service, but if it fails, the carrier also
          * supports control plane backup signaling.
+         * @hide
          */
         public static final int SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK = 1;
 
@@ -3072,6 +3075,7 @@
          * Location information during (and after) an emergency call is provided over the data plane
          * and serviced by the framework GNSS service only. There is no backup signalling over the
          * control plane if it fails.
+         * @hide
          */
         public static final int SUPL_EMERGENCY_MODE_TYPE_DP_ONLY = 2;
 
@@ -3088,10 +3092,14 @@
         /**
          * SUPL server host for SET Initiated & non-ES Network-Initiated SUPL requests.
          * Default to supl.google.com
+         * @hide
          */
         public static final String KEY_SUPL_HOST_STRING = KEY_PREFIX + "supl_host";
 
-        /** SUPL server port. Default to 7275. */
+        /**
+         * SUPL server port. Default to 7275.
+         * @hide
+         */
         public static final String KEY_SUPL_PORT_STRING = KEY_PREFIX + "supl_port";
 
         /**
@@ -3099,6 +3107,7 @@
          * with bits 0:7 representing a service indicator field, bits 8:15
          * representing the minor version and bits 16:23 representing the
          * major version. Default to 0x20000.
+         * @hide
          */
         public static final String KEY_SUPL_VER_STRING = KEY_PREFIX + "supl_ver";
 
@@ -3106,6 +3115,7 @@
          * SUPL_MODE configuration bit mask
          * 1 - Mobile Station Based. This is default.
          * 2 - Mobile Station Assisted.
+         * @hide
          */
         public static final String KEY_SUPL_MODE_STRING = KEY_PREFIX + "supl_mode";
 
@@ -3114,6 +3124,7 @@
          * (e.g. E911), and SUPL non-ES requests to only outside of non user emergency sessions.
          * 0 - no.
          * 1 - yes. This is default.
+         * @hide
          */
         public static final String KEY_SUPL_ES_STRING = KEY_PREFIX + "supl_es";
 
@@ -3122,6 +3133,7 @@
          * 0 - Radio Resource Location Protocol in user plane and control plane. This is default.
          * 1 - Enable LTE Positioning Protocol in user plane.
          * 2 - Enable LTE Positioning Protocol in control plane.
+         * @hide
          */
         public static final String KEY_LPP_PROFILE_STRING = KEY_PREFIX + "lpp_profile";
 
@@ -3129,6 +3141,7 @@
          * Determine whether to use emergency PDN for emergency SUPL.
          * 0 - no.
          * 1 - yes. This is default.
+         * @hide
          */
         public static final String KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING =
                 KEY_PREFIX + "use_emergency_pdn_for_emergency_supl";
@@ -3139,6 +3152,7 @@
          * 1 - Use A-GLONASS in Radio Resource Control(RRC) control-plane.
          * 2 - Use A-GLONASS in Radio Resource Location user-plane.
          * 4 - Use A-GLONASS in LTE Positioning Protocol User plane.
+         * @hide
          */
         public static final String KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING =
                 KEY_PREFIX + "a_glonass_pos_protocol_select";
@@ -3150,11 +3164,13 @@
          * "1" - Lock Mobile Originated GPS functionalities.
          * "2" - Lock Network initiated GPS functionalities.
          * "3" - Lock both. This is default.
+         * @hide
          */
         public static final String KEY_GPS_LOCK_STRING = KEY_PREFIX + "gps_lock";
 
         /**
          * Control Plane / SUPL NI emergency extension time in seconds. Default to "0".
+         * @hide
          */
         public static final String KEY_ES_EXTENSION_SEC_STRING = KEY_PREFIX + "es_extension_sec";
 
@@ -3163,6 +3179,7 @@
          * the non-framework entities requesting location directly from GNSS without involving
          * the framework, as managed by IGnssVisibilityControl.hal. For example,
          * "com.example.mdt com.example.ims".
+         * @hide
          */
         public static final String KEY_NFW_PROXY_APPS_STRING = KEY_PREFIX + "nfw_proxy_apps";
 
@@ -3178,6 +3195,7 @@
          * {@link #SUPL_EMERGENCY_MODE_TYPE_CP_ONLY}.
          * <p>
          * The default value for this configuration is {@link #SUPL_EMERGENCY_MODE_TYPE_CP_ONLY}.
+         * @hide
          */
         public static final String KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT = KEY_PREFIX
                 + "es_supl_control_plane_support_int";
@@ -3189,6 +3207,7 @@
          * <p>
          * A string array of PLMNs that do not support a control-plane mechanism for getting a
          * user's location for SUPL ES.
+         * @hide
          */
         public static final String KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY =
                 KEY_PREFIX + "es_supl_data_plane_only_roaming_plmn_string_array";
diff --git a/telephony/java/android/telephony/CbGeoUtils.java b/telephony/java/android/telephony/CbGeoUtils.java
index 7314edd..84be4e8 100644
--- a/telephony/java/android/telephony/CbGeoUtils.java
+++ b/telephony/java/android/telephony/CbGeoUtils.java
@@ -26,7 +26,6 @@
 import java.util.List;
 import java.util.stream.Collectors;
 
-
 /**
  * This utils class is used for geo-fencing of CellBroadcast messages and is used by the cell
  * broadcast module.
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index f0c0dde..25c6577 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -17,7 +17,7 @@
 package android.telephony;
 
 import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.telephony.gsm.GsmCellLocation;
 import android.text.TextUtils;
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 9bd33c1..997b19f 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -17,7 +17,7 @@
 package android.telephony;
 
 import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
 import android.telephony.gsm.GsmCellLocation;
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 740622d..f08e1ec 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -912,9 +912,9 @@
      * <p>
      * Contains {@link #EXTRA_SUBSCRIPTION_INDEX} to indicate which subscription
      * changed.
-     *
      * @hide
      */
+    @SystemApi
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS)
     public static final String ACTION_SUBSCRIPTION_PLANS_CHANGED
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 2082795..60fda09 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1475,14 +1475,68 @@
      * <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.
+     * <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
@@ -11850,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/Sms7BitEncodingTranslator.java b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
index dcea9bb..d672642 100644
--- a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
+++ b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
@@ -18,11 +18,11 @@
 
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
-import android.os.Build;
 import android.telephony.Rlog;
 import android.util.SparseIntArray;
 
 import com.android.internal.telephony.cdma.sms.UserData;
+import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.internal.telephony.util.XmlUtils;
 
 import dalvik.annotation.compat.UnsupportedAppUsage;
@@ -30,7 +30,7 @@
 public class Sms7BitEncodingTranslator {
     private static final String TAG = "Sms7BitEncodingTranslator";
     @UnsupportedAppUsage
-    private static final boolean DBG = Build.IS_DEBUGGABLE ;
+    private static final boolean DBG = TelephonyUtils.IS_DEBUGGABLE;
     private static boolean mIs7BitTranslationTableLoaded = false;
     private static SparseIntArray mTranslationTable = null;
     @UnsupportedAppUsage
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 8e1a78c..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
@@ -234,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/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/Resource.h b/tools/aapt2/Resource.h
index 67ba895..c49c370 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -147,10 +147,11 @@
   ResourceId(uint32_t res_id);  // NOLINT(google-explicit-constructor)
   ResourceId(uint8_t p, uint8_t t, uint16_t e);
 
-  bool is_valid() const;
+  // Returns true if the ID is a valid ID that is not dynamic (package ID cannot be 0)
+  bool is_valid_static() const;
 
   // Returns true if the ID is a valid ID or dynamic ID (package ID can be 0).
-  bool is_valid_dynamic() const;
+  bool is_valid() const;
 
   uint8_t package_id() const;
   uint8_t type_id() const;
@@ -233,11 +234,11 @@
 inline ResourceId::ResourceId(uint8_t p, uint8_t t, uint16_t e)
     : id((p << 24) | (t << 16) | e) {}
 
-inline bool ResourceId::is_valid() const {
+inline bool ResourceId::is_valid_static() const {
   return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
 }
 
-inline bool ResourceId::is_valid_dynamic() const {
+inline bool ResourceId::is_valid() const {
   return (id & 0x00ff0000u) != 0;
 }
 
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 1773b5a..e0a9a31 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -398,7 +398,7 @@
 
   // Check for package names appearing twice with two different package ids
   ResourceTablePackage* package = FindOrCreatePackage(name.package);
-  if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
+  if (res_id.is_valid() && package->id && package->id.value() != res_id.package_id()) {
     diag->Error(DiagMessage(source)
                     << "trying to add resource '" << name << "' with ID " << res_id
                     << " but package '" << package->name << "' already has ID "
@@ -407,9 +407,9 @@
   }
 
   // Whether or not to error on duplicate resources
-  bool check_id = validate_resources_ && res_id.is_valid_dynamic();
+  bool check_id = validate_resources_ && res_id.is_valid();
   // Whether or not to create a duplicate resource if the id does not match
-  bool use_id = !validate_resources_ && res_id.is_valid_dynamic();
+  bool use_id = !validate_resources_ && res_id.is_valid();
 
   ResourceTableType* type = package->FindOrCreateType(name.type, use_id ? res_id.type_id()
                                                                         : Maybe<uint8_t>());
@@ -463,7 +463,7 @@
     }
   }
 
-  if (res_id.is_valid_dynamic()) {
+  if (res_id.is_valid()) {
     package->id = res_id.package_id();
     type->id = res_id.type_id();
     entry->id = res_id.entry_id();
@@ -504,7 +504,7 @@
 
   // Check for package names appearing twice with two different package ids
   ResourceTablePackage* package = FindOrCreatePackage(name.package);
-  if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) {
+  if (res_id.is_valid() && package->id && package->id.value() != res_id.package_id()) {
     diag->Error(DiagMessage(source)
                     << "trying to add resource '" << name << "' with ID " << res_id
                     << " but package '" << package->name << "' already has ID "
@@ -513,9 +513,9 @@
   }
 
   // Whether or not to error on duplicate resources
-  bool check_id = validate_resources_ && res_id.is_valid_dynamic();
+  bool check_id = validate_resources_ && res_id.is_valid();
   // Whether or not to create a duplicate resource if the id does not match
-  bool use_id = !validate_resources_ && res_id.is_valid_dynamic();
+  bool use_id = !validate_resources_ && res_id.is_valid();
 
   ResourceTableType* type = package->FindOrCreateType(name.type, use_id ? res_id.type_id()
                                                                         : Maybe<uint8_t>());
@@ -541,7 +541,7 @@
     return false;
   }
 
-  if (res_id.is_valid_dynamic()) {
+  if (res_id.is_valid()) {
     package->id = res_id.package_id();
     type->id = res_id.type_id();
     entry->id = res_id.entry_id();
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 03009aa..3623b11 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -516,7 +516,7 @@
   if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
     if (value.dataType == android::Res_value::TYPE_INT_HEX) {
       ResourceId id(value.data);
-      if (id.is_valid_dynamic()) {
+      if (id.is_valid()) {
         return id;
       }
     }
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 34b46c5..4f0fa8a 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -117,7 +117,7 @@
 
 bool Reference::Flatten(android::Res_value* out_value) const {
   const ResourceId resid = id.value_or_default(ResourceId(0));
-  const bool dynamic = resid.is_valid_dynamic() && is_dynamic;
+  const bool dynamic = resid.is_valid() && is_dynamic;
 
   if (reference_type == Reference::Type::kResource) {
     if (dynamic) {
@@ -159,7 +159,7 @@
     *out << name.value();
   }
 
-  if (id && id.value().is_valid_dynamic()) {
+  if (id && id.value().is_valid()) {
     if (name) {
       *out << " ";
     }
@@ -196,7 +196,7 @@
       printer->Print("/");
       printer->Print(name.entry);
     }
-  } else if (ref.id && ref.id.value().is_valid_dynamic()) {
+  } else if (ref.id && ref.id.value().is_valid()) {
     printer->Print(ref.id.value().to_string());
   }
 }
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index bc09f19..83e20b5 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -340,7 +340,7 @@
     }
 
     res_id = asset_manager_.GetResourceId(real_name.to_string());
-    if (res_id.is_valid() && asset_manager_.GetResourceFlags(res_id.id, &type_spec_flags)) {
+    if (res_id.is_valid_static() && asset_manager_.GetResourceFlags(res_id.id, &type_spec_flags)) {
       found = true;
       return false;
     }
@@ -379,7 +379,7 @@
 
 std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById(
     ResourceId id) {
-  if (!id.is_valid()) {
+  if (!id.is_valid_static()) {
     // Exit early and avoid the error logs from AssetManager.
     return {};
   }
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/aware/Characteristics.java b/wifi/java/android/net/wifi/aware/Characteristics.java
index e2cf4dc..d5fd48e 100644
--- a/wifi/java/android/net/wifi/aware/Characteristics.java
+++ b/wifi/java/android/net/wifi/aware/Characteristics.java
@@ -16,10 +16,14 @@
 
 package android.net.wifi.aware;
 
+import android.annotation.IntDef;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * The characteristics of the Wi-Fi Aware implementation.
  */
@@ -31,6 +35,8 @@
             "key_max_service_specific_info_length";
     /** @hide */
     public static final String KEY_MAX_MATCH_FILTER_LENGTH = "key_max_match_filter_length";
+    /** @hide */
+    public static final String KEY_SUPPORTED_CIPHER_SUITES = "key_supported_cipher_suites";
 
     private Bundle mCharacteristics = new Bundle();
 
@@ -71,12 +77,41 @@
      * {@link PublishConfig.Builder#setMatchFilter(java.util.List)} and
      * {@link SubscribeConfig.Builder#setMatchFilter(java.util.List)}.
      *
-     * @return A positive integer, maximum legngth of byte array for Aware discovery match filter.
+     * @return A positive integer, maximum length of byte array for Aware discovery match filter.
      */
     public int getMaxMatchFilterLength() {
         return mCharacteristics.getInt(KEY_MAX_MATCH_FILTER_LENGTH);
     }
 
+    /** @hide */
+    @IntDef(flag = true, prefix = { "WIFI_AWARE_CIPHER_SUITE_" }, value = {
+            WIFI_AWARE_CIPHER_SUITE_NCS_SK_128,
+            WIFI_AWARE_CIPHER_SUITE_NCS_SK_256,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WifiAwareCipherSuites {}
+
+    /**
+     * Wi-Fi Aware supported ciphier suite representing NCS SK 128: 128 bit shared-key.
+     */
+    public static final int WIFI_AWARE_CIPHER_SUITE_NCS_SK_128 = 1 << 0;
+
+    /**
+     * Wi-Fi Aware supported ciphier suite representing NCS SK 256: 256 bit shared-key.
+     */
+    public static final int WIFI_AWARE_CIPHER_SUITE_NCS_SK_256 = 1 << 1;
+
+    /**
+     * Returns the set of cipher suites supported by the device for use in Wi-Fi Aware data-paths.
+     * The device automatically picks the strongest cipher suite when initiating a data-path setup.
+     *
+     * @return A set of flags from {@link #WIFI_AWARE_CIPHER_SUITE_NCS_SK_128}, or
+     * {@link #WIFI_AWARE_CIPHER_SUITE_NCS_SK_256}.
+     */
+    public @WifiAwareCipherSuites int getSupportedCipherSuites() {
+        return mCharacteristics.getInt(KEY_SUPPORTED_CIPHER_SUITES);
+    }
+
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeBundle(mCharacteristics);
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.
      */