Merge "Add strings for TV standby function"
diff --git a/.gitignore b/.gitignore
index 481c592..c47cc8b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 .idea
 *.iml
 *.sw*
+gen/
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 7687270..4ef6c5e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -798,7 +798,10 @@
         "--multi-dex",
     ],
 
-    plugins: ["view-inspector-annotation-processor"],
+    plugins: [
+        "view-inspector-annotation-processor",
+        "staledataclass-annotation-processor",
+    ],
 }
 
 filegroup {
@@ -838,14 +841,26 @@
     name: "framework",
     defaults: ["framework-defaults"],
     javac_shard_size: 150,
+    required: [
+        "framework-platform-compat-config",
+        "libcore-platform-compat-config",
+    ],
 }
 
 java_library {
     name: "framework-annotation-proc",
     defaults: ["framework-defaults"],
     installable: false,
-    // Use UsedByApps annotation processor
-    plugins: ["unsupportedappusage-annotation-processor"],
+    plugins: [
+        "unsupportedappusage-annotation-processor",
+        "compat-changeid-annotation-processor",
+    ],
+}
+
+platform_compat_config {
+    name: "framework-platform-compat-config",
+    prefix: "framework",
+    src: ":framework-annotation-proc",
 }
 
 // A library including just UnsupportedAppUsage.java classes.
diff --git a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
index 4e2b281..2b6f455 100644
--- a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
@@ -26,6 +26,7 @@
 import static org.hamcrest.core.Is.is;
 
 import android.app.Activity;
+import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityTaskManager;
 import android.app.IActivityTaskManager;
 import android.content.ComponentName;
@@ -216,7 +217,7 @@
             }
 
             @Override
-            public void onAnimationCanceled(boolean deferredWithScreenshot) throws RemoteException {
+            public void onAnimationCanceled(TaskSnapshot taskSnapshot) throws RemoteException {
                 Assume.assumeNoException(
                         new AssertionError("onAnimationCanceled should not be called"));
             }
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index 2fe0ee7..4b7a7f6 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -15,6 +15,8 @@
  */
 package android.multiuser;
 
+import static org.junit.Assume.assumeTrue;
+
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.AppGlobals;
@@ -86,7 +88,9 @@
     private UserManager mUm;
     private ActivityManager mAm;
     private IActivityManager mIam;
+    private PackageManager mPm;
     private ArrayList<Integer> mUsersToRemove;
+    private boolean mHasManagedUserFeature;
 
     private final BenchmarkRunner mRunner = new BenchmarkRunner();
     @Rule
@@ -99,6 +103,8 @@
         mAm = context.getSystemService(ActivityManager.class);
         mIam = ActivityManager.getService();
         mUsersToRemove = new ArrayList<>();
+        mPm = context.getPackageManager();
+        mHasManagedUserFeature = mPm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS);
     }
 
     @After
@@ -260,6 +266,8 @@
     /** Tests creating a new profile. */
     @Test
     public void managedProfileCreate() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         while (mRunner.keepRunning()) {
             final int userId = createManagedProfile();
 
@@ -273,6 +281,8 @@
     /** Tests starting (unlocking) a newly-created profile. */
     @Test
     public void managedProfileUnlock() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
@@ -289,6 +299,8 @@
     /** Tests starting (unlocking) an already-created, but no-longer-running, profile. */
     @Test
     public void managedProfileUnlock_stopped() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
@@ -310,6 +322,8 @@
      */
     @Test
     public void managedProfileUnlockAndLaunchApp() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
@@ -334,6 +348,8 @@
      */
     @Test
     public void managedProfileUnlockAndLaunchApp_stopped() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
@@ -357,6 +373,8 @@
     /** Tests installing a pre-existing app in a newly-created profile. */
     @Test
     public void managedProfileInstall() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
@@ -376,6 +394,8 @@
      */
     @Test
     public void managedProfileCreateUnlockInstallAndLaunchApp() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         final String packageName = "perftests.multiuser.apps.dummyapp";
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
@@ -396,6 +416,8 @@
     /** Tests stopping a profile. */
     @Test
     public void managedProfileStopped() throws Exception {
+        assumeTrue(mHasManagedUserFeature);
+
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index bec1947..525fbae 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -480,7 +480,7 @@
             pw.print(mEffectiveInteractiveState ? "ON" : "OFF");
             pw.println();
 
-            pw.print("Last screen ON : ");
+            pw.print("Last screen ON: ");
             TimeUtils.dumpTimeWithDelta(pw, now - nowRealtime + mLastScreenOnRealtime, now);
             pw.println();
 
@@ -509,9 +509,8 @@
     public void dumpProtoLocked(ProtoOutputStream proto, long tag, long now, long nowRealtime) {
         final long token = proto.start(tag);
 
-        proto.write(JobConcurrencyManagerProto.CURRENT_INTERACTIVE,
-                mCurrentInteractiveState);
-        proto.write(JobConcurrencyManagerProto.EFFECTIVE_INTERACTIVE,
+        proto.write(JobConcurrencyManagerProto.CURRENT_INTERACTIVE_STATE, mCurrentInteractiveState);
+        proto.write(JobConcurrencyManagerProto.EFFECTIVE_INTERACTIVE_STATE,
                 mEffectiveInteractiveState);
 
         proto.write(JobConcurrencyManagerProto.TIME_SINCE_LAST_SCREEN_ON_MS,
@@ -521,8 +520,9 @@
 
         mJobCountTracker.dumpProto(proto, JobConcurrencyManagerProto.JOB_COUNT_TRACKER);
 
-        proto.write(JobConcurrencyManagerProto.MEMORY_TRIM_LEVEL,
-                mLastMemoryTrimLevel);
+        proto.write(JobConcurrencyManagerProto.MEMORY_TRIM_LEVEL, mLastMemoryTrimLevel);
+
+        mStatLogger.dumpProto(proto, JobConcurrencyManagerProto.STATS);
 
         proto.end(token);
     }
@@ -676,19 +676,14 @@
                             + " Res BG: %d"
                             + " Starting: %d / %d (%d)"
                             + " Total: %d%s / %d%s (%d%s)",
-                    mConfigNumMaxTotalJobs,
-                    mConfigNumMinBgJobs,
-                    mConfigNumMaxBgJobs,
+                    mConfigNumMaxTotalJobs, mConfigNumMinBgJobs, mConfigNumMaxBgJobs,
 
-                    mNumRunningFgJobs, mNumRunningBgJobs,
-                    mNumRunningFgJobs + mNumRunningBgJobs,
+                    mNumRunningFgJobs, mNumRunningBgJobs, mNumRunningFgJobs + mNumRunningBgJobs,
 
-                    mNumPendingFgJobs, mNumPendingBgJobs,
-                    mNumPendingFgJobs + mNumPendingBgJobs,
+                    mNumPendingFgJobs, mNumPendingBgJobs, mNumPendingFgJobs + mNumPendingBgJobs,
 
                     mNumActualMaxFgJobs, (totalFg <= mConfigNumMaxTotalJobs) ? "" : "*",
                     mNumActualMaxBgJobs, (totalBg <= mConfigNumMaxBgJobs) ? "" : "*",
-
                     mNumActualMaxFgJobs + mNumActualMaxBgJobs,
                     (mNumActualMaxFgJobs + mNumActualMaxBgJobs <= mConfigNumMaxTotalJobs)
                             ? "" : "*",
@@ -716,6 +711,14 @@
             proto.write(JobCountTrackerProto.NUM_PENDING_FG_JOBS, mNumPendingFgJobs);
             proto.write(JobCountTrackerProto.NUM_PENDING_BG_JOBS, mNumPendingBgJobs);
 
+            proto.write(JobCountTrackerProto.NUM_ACTUAL_MAX_FG_JOBS, mNumActualMaxFgJobs);
+            proto.write(JobCountTrackerProto.NUM_ACTUAL_MAX_BG_JOBS, mNumActualMaxBgJobs);
+
+            proto.write(JobCountTrackerProto.NUM_RESERVED_FOR_BG, mNumReservedForBg);
+
+            proto.write(JobCountTrackerProto.NUM_STARTING_FG_JOBS, mNumStartingFgJobs);
+            proto.write(JobCountTrackerProto.NUM_STARTING_BG_JOBS, mNumStartingBgJobs);
+
             proto.end(token);
         }
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 38bb75f..5ba563c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1943,7 +1943,7 @@
                 } catch (RemoteException e) {
                 }
                 if (mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT > 1
-                        && job.getStandbyBucket() != ACTIVE_INDEX
+                        && job.getEffectiveStandbyBucket() != ACTIVE_INDEX
                         && (job.getFirstForceBatchedTimeElapsed() == 0
                         || sElapsedRealtimeClock.millis() - job.getFirstForceBatchedTimeElapsed()
                                 < mConstants.MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS)) {
@@ -3011,6 +3011,8 @@
                     pw.print(job.isReady());
                     pw.print(" user=");
                     pw.print(areUsersStartedLocked(job));
+                    pw.print(" !thermal=");
+                    pw.print(!isJobThermalConstrainedLocked(job));
                     pw.print(" !pending=");
                     pw.print(!mPendingJobs.contains(job));
                     pw.print(" !active=");
@@ -3018,15 +3020,7 @@
                     pw.print(" !backingup=");
                     pw.print(!(mBackingUpUids.indexOfKey(job.getSourceUid()) >= 0));
                     pw.print(" comp=");
-                    boolean componentPresent = false;
-                    try {
-                        componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
-                                job.getServiceComponent(),
-                                PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
-                                job.getUserId()) != null);
-                    } catch (RemoteException e) {
-                    }
-                    pw.print(componentPresent);
+                    pw.print(isComponentUsable(job));
                     pw.println(")");
                 }
             } else {
@@ -3177,27 +3171,24 @@
 
                     job.dump(proto, JobSchedulerServiceDumpProto.RegisteredJob.DUMP, true, nowElapsed);
 
-                    // isReadyToBeExecuted
+                    proto.write(
+                            JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_READY_TO_BE_EXECUTED,
+                            isReadyToBeExecutedLocked(job));
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_READY,
                             job.isReady());
-                    proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_USER_STARTED,
+                    proto.write(JobSchedulerServiceDumpProto.RegisteredJob.ARE_USERS_STARTED,
                             areUsersStartedLocked(job));
+                    proto.write(
+                            JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_THERMAL_CONSTRAINED,
+                            isJobThermalConstrainedLocked(job));
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_PENDING,
                             mPendingJobs.contains(job));
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_CURRENTLY_ACTIVE,
                             isCurrentlyActiveLocked(job));
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_UID_BACKING_UP,
                             mBackingUpUids.indexOfKey(job.getSourceUid()) >= 0);
-                    boolean componentPresent = false;
-                    try {
-                        componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
-                                job.getServiceComponent(),
-                                PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
-                                job.getUserId()) != null);
-                    } catch (RemoteException e) {
-                    }
-                    proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_COMPONENT_PRESENT,
-                            componentPresent);
+                    proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_COMPONENT_USABLE,
+                            isComponentUsable(job));
 
                     proto.end(rjToken);
                 }
@@ -3234,7 +3225,7 @@
                 job.writeToShortProto(proto, PendingJob.INFO);
                 job.dump(proto, PendingJob.DUMP, false, nowElapsed);
                 proto.write(PendingJob.EVALUATED_PRIORITY, evaluateJobPriorityLocked(job));
-                proto.write(PendingJob.ENQUEUED_DURATION_MS, nowUptime - job.madePending);
+                proto.write(PendingJob.PENDING_DURATION_MS, nowUptime - job.madePending);
 
                 proto.end(pjToken);
             }
@@ -3283,6 +3274,8 @@
             }
             mConcurrencyManager.dumpProtoLocked(proto,
                     JobSchedulerServiceDumpProto.CONCURRENCY_MANAGER, now, nowElapsed);
+
+            mJobs.getPersistStats().writeToProto(proto, JobSchedulerServiceDumpProto.PERSIST_STATS);
         }
 
         proto.flush();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index b698e5b..8b61006 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -115,32 +115,27 @@
         final long mToken = proto.start(StateControllerProto.BACKGROUND);
 
         mAppStateTracker.dumpProto(proto,
-                StateControllerProto.BackgroundJobsController.FORCE_APP_STANDBY_TRACKER);
+                StateControllerProto.BackgroundJobsController.APP_STATE_TRACKER);
 
         mService.getJobStore().forEachJob(predicate, (jobStatus) -> {
             final long jsToken =
                     proto.start(StateControllerProto.BackgroundJobsController.TRACKED_JOBS);
 
-            jobStatus.writeToShortProto(proto,
-                    TrackedJob.INFO);
+            jobStatus.writeToShortProto(proto, TrackedJob.INFO);
             final int sourceUid = jobStatus.getSourceUid();
             proto.write(TrackedJob.SOURCE_UID, sourceUid);
             final String sourcePkg = jobStatus.getSourcePackageName();
             proto.write(TrackedJob.SOURCE_PACKAGE_NAME, sourcePkg);
 
-            proto.write(TrackedJob.IS_IN_FOREGROUND,
-                    mAppStateTracker.isUidActive(sourceUid));
+            proto.write(TrackedJob.IS_IN_FOREGROUND, mAppStateTracker.isUidActive(sourceUid));
             proto.write(TrackedJob.IS_WHITELISTED,
                     mAppStateTracker.isUidPowerSaveWhitelisted(sourceUid) ||
                     mAppStateTracker.isUidTempPowerSaveWhitelisted(sourceUid));
 
-            proto.write(
-                    TrackedJob.CAN_RUN_ANY_IN_BACKGROUND,
-                    mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(
-                            sourceUid, sourcePkg));
+            proto.write(TrackedJob.CAN_RUN_ANY_IN_BACKGROUND,
+                    mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(sourceUid, sourcePkg));
 
-            proto.write(
-                    TrackedJob.ARE_CONSTRAINTS_SATISFIED,
+            proto.write(TrackedJob.ARE_CONSTRAINTS_SATISFIED,
                     (jobStatus.satisfiedConstraints &
                             JobStatus.CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0);
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index a67aadf..43e8dfb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -631,6 +631,18 @@
         final long token = proto.start(fieldId);
         final long mToken = proto.start(StateControllerProto.CONNECTIVITY);
 
+        for (int i = 0; i < mRequestedWhitelistJobs.size(); i++) {
+            proto.write(
+                    StateControllerProto.ConnectivityController.REQUESTED_STANDBY_EXCEPTION_UIDS,
+                    mRequestedWhitelistJobs.keyAt(i));
+        }
+        for (int i = 0; i < mAvailableNetworks.size(); i++) {
+            Network network = mAvailableNetworks.valueAt(i);
+            if (network != null) {
+                network.writeToProto(proto,
+                        StateControllerProto.ConnectivityController.AVAILABLE_NETWORKS);
+            }
+        }
         for (int i = 0; i < mTrackedJobs.size(); i++) {
             final ArraySet<JobStatus> jobs = mTrackedJobs.valueAt(i);
             for (int j = 0; j < jobs.size(); j++) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index 127a5c8..0b67971 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -269,8 +269,7 @@
             proto.write(TrackedJob.SOURCE_UID, jobStatus.getSourceUid());
             proto.write(TrackedJob.SOURCE_PACKAGE_NAME, jobStatus.getSourcePackageName());
             proto.write(TrackedJob.ARE_CONSTRAINTS_SATISFIED,
-                    (jobStatus.satisfiedConstraints &
-                        JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0);
+                    (jobStatus.satisfiedConstraints & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0);
             proto.write(TrackedJob.IS_DOZE_WHITELISTED, jobStatus.dozeWhitelisted);
             proto.write(TrackedJob.IS_ALLOWED_IN_DOZE, mAllowInIdleJobs.contains(jobStatus));
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
index e3c311f..d355715 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
@@ -20,7 +20,6 @@
 import android.content.pm.PackageManager;
 import android.os.UserHandle;
 import android.util.ArraySet;
-import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.IndentingPrintWriter;
@@ -120,6 +119,7 @@
         final long mToken = proto.start(StateControllerProto.IDLE);
 
         proto.write(StateControllerProto.IdleController.IS_IDLE, mIdleTracker.isIdle());
+        mIdleTracker.dump(proto, StateControllerProto.IdleController.IDLENESS_TRACKER);
 
         for (int i = 0; i < mTrackedTasks.size(); i++) {
             final JobStatus js = mTrackedTasks.valueAt(i);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index ae4abd6..1133f7b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -16,6 +16,7 @@
 
 package com.android.server.job.controllers;
 
+import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
 
 import android.app.AppGlobals;
@@ -698,6 +699,20 @@
         return UserHandle.getUserId(callingUid);
     }
 
+    /**
+     * Returns an appropriate standby bucket for the job, taking into account any standby
+     * exemptions.
+     */
+    public int getEffectiveStandbyBucket() {
+        if (uidActive || getJob().isExemptedFromAppStandby()) {
+            // Treat these cases as if they're in the ACTIVE bucket so that they get throttled
+            // like other ACTIVE apps.
+            return ACTIVE_INDEX;
+        }
+        return getStandbyBucket();
+    }
+
+    /** Returns the real standby bucket of the job. */
     public int getStandbyBucket() {
         return standbyBucket;
     }
@@ -1591,11 +1606,14 @@
             for (int i=0; i<changedAuthorities.size(); i++) {
                 pw.print(prefix); pw.print("  "); pw.println(changedAuthorities.valueAt(i));
             }
-            if (changedUris != null) {
-                pw.print(prefix); pw.println("Changed URIs:");
-                for (int i=0; i<changedUris.size(); i++) {
-                    pw.print(prefix); pw.print("  "); pw.println(changedUris.valueAt(i));
-                }
+        }
+        if (changedUris != null) {
+            pw.print(prefix);
+            pw.println("Changed URIs:");
+            for (int i = 0; i < changedUris.size(); i++) {
+                pw.print(prefix);
+                pw.print("  ");
+                pw.println(changedUris.valueAt(i));
             }
         }
         if (network != null) {
@@ -1658,7 +1676,6 @@
         proto.write(JobStatusDumpProto.SOURCE_UID, getSourceUid());
         proto.write(JobStatusDumpProto.SOURCE_USER_ID, getSourceUserId());
         proto.write(JobStatusDumpProto.SOURCE_PACKAGE_NAME, getSourcePackageName());
-        proto.write(JobStatusDumpProto.INTERNAL_FLAGS, getInternalFlags());
 
         if (full) {
             final long jiToken = proto.start(JobStatusDumpProto.JOB_INFO);
@@ -1672,6 +1689,8 @@
             proto.write(JobStatusDumpProto.JobInfo.IS_PERSISTED, job.isPersisted());
             proto.write(JobStatusDumpProto.JobInfo.PRIORITY, job.getPriority());
             proto.write(JobStatusDumpProto.JobInfo.FLAGS, job.getFlags());
+            proto.write(JobStatusDumpProto.INTERNAL_FLAGS, getInternalFlags());
+            // Foreground exemption can be determined from internal flags value.
 
             proto.write(JobStatusDumpProto.JobInfo.REQUIRES_CHARGING, job.isRequireCharging());
             proto.write(JobStatusDumpProto.JobInfo.REQUIRES_BATTERY_NOT_LOW, job.isRequireBatteryNotLow());
@@ -1783,6 +1802,8 @@
         proto.write(JobStatusDumpProto.ImplicitConstraints.IS_NOT_DOZING, mReadyNotDozing);
         proto.write(JobStatusDumpProto.ImplicitConstraints.IS_NOT_RESTRICTED_IN_BG,
                 mReadyNotRestrictedInBg);
+        // mReadyDeadlineSatisfied isn't an implicit constraint...and can be determined from other
+        // field values.
         proto.end(icToken);
 
         if (changedAuthorities != null) {
@@ -1801,12 +1822,12 @@
             network.writeToProto(proto, JobStatusDumpProto.NETWORK);
         }
 
-        if (pendingWork != null && pendingWork.size() > 0) {
+        if (pendingWork != null) {
             for (int i = 0; i < pendingWork.size(); i++) {
                 dumpJobWorkItem(proto, JobStatusDumpProto.PENDING_WORK, pendingWork.get(i));
             }
         }
-        if (executingWork != null && executingWork.size() > 0) {
+        if (executingWork != null) {
             for (int i = 0; i < executingWork.size(); i++) {
                 dumpJobWorkItem(proto, JobStatusDumpProto.EXECUTING_WORK, executingWork.get(i));
             }
@@ -1831,6 +1852,8 @@
             proto.write(JobStatusDumpProto.TIME_UNTIL_LATEST_RUNTIME_MS,
                     latestRunTimeElapsedMillis - elapsedRealtimeMillis);
         }
+        proto.write(JobStatusDumpProto.ORIGINAL_LATEST_RUNTIME_ELAPSED,
+                mOriginalLatestRunTimeElapsedMillis);
 
         proto.write(JobStatusDumpProto.NUM_FAILURES, numFailures);
         proto.write(JobStatusDumpProto.LAST_SUCCESSFUL_RUN_TIME, mLastSuccessfulRunTime);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 043cda4..831be0b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -608,7 +608,7 @@
         final boolean isWithinQuota = isWithinQuotaLocked(jobStatus);
         setConstraintSatisfied(jobStatus, isWithinQuota);
         if (!isWithinQuota) {
-            maybeScheduleStartAlarmLocked(userId, pkgName, getEffectiveStandbyBucket(jobStatus));
+            maybeScheduleStartAlarmLocked(userId, pkgName, jobStatus.getEffectiveStandbyBucket());
         }
     }
 
@@ -719,22 +719,9 @@
         return getRemainingExecutionTimeLocked(jobStatus);
     }
 
-    /**
-     * Returns an appropriate standby bucket for the job, taking into account any standby
-     * exemptions.
-     */
-    private int getEffectiveStandbyBucket(@NonNull final JobStatus jobStatus) {
-        if (jobStatus.uidActive || jobStatus.getJob().isExemptedFromAppStandby()) {
-            // Treat these cases as if they're in the ACTIVE bucket so that they get throttled
-            // like other ACTIVE apps.
-            return ACTIVE_INDEX;
-        }
-        return jobStatus.getStandbyBucket();
-    }
-
     @VisibleForTesting
     boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) {
-        final int standbyBucket = getEffectiveStandbyBucket(jobStatus);
+        final int standbyBucket = jobStatus.getEffectiveStandbyBucket();
         // A job is within quota if one of the following is true:
         //   1. it was started while the app was in the TOP state
         //   2. the app is currently in the foreground
@@ -784,7 +771,7 @@
     long getRemainingExecutionTimeLocked(@NonNull final JobStatus jobStatus) {
         return getRemainingExecutionTimeLocked(jobStatus.getSourceUserId(),
                 jobStatus.getSourcePackageName(),
-                getEffectiveStandbyBucket(jobStatus));
+                jobStatus.getEffectiveStandbyBucket());
     }
 
     @VisibleForTesting
@@ -1258,7 +1245,7 @@
                 // finish.
                 changed |= js.setQuotaConstraintSatisfied(true);
             } else if (realStandbyBucket != ACTIVE_INDEX
-                    && realStandbyBucket == getEffectiveStandbyBucket(js)) {
+                    && realStandbyBucket == js.getEffectiveStandbyBucket()) {
                 // An app in the ACTIVE bucket may be out of quota while the job could be in quota
                 // for some reason. Therefore, avoid setting the real value here and check each job
                 // individually.
@@ -2563,7 +2550,7 @@
                 pw.println();
 
                 pw.increaseIndent();
-                pw.print(JobStatus.bucketName(getEffectiveStandbyBucket(js)));
+                pw.print(JobStatus.bucketName(js.getEffectiveStandbyBucket()));
                 pw.print(", ");
                 if (js.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)) {
                     pw.print("within quota");
@@ -2661,21 +2648,35 @@
                     mForegroundUids.keyAt(i));
         }
 
+        for (int i = 0; i < mUidToPackageCache.size(); ++i) {
+            final long upToken = proto.start(
+                    StateControllerProto.QuotaController.UID_TO_PACKAGE_CACHE);
+
+            final int uid = mUidToPackageCache.keyAt(i);
+            ArraySet<String> packages = mUidToPackageCache.get(uid);
+
+            proto.write(StateControllerProto.QuotaController.UidPackageMapping.UID, uid);
+            for (int j = 0; j < packages.size(); ++j) {
+                proto.write(StateControllerProto.QuotaController.UidPackageMapping.PACKAGE_NAMES,
+                        packages.valueAt(j));
+            }
+
+            proto.end(upToken);
+        }
+
         mTrackedJobs.forEach((jobs) -> {
             for (int j = 0; j < jobs.size(); j++) {
                 final JobStatus js = jobs.valueAt(j);
                 if (!predicate.test(js)) {
                     continue;
                 }
-                final long jsToken = proto.start(
-                        StateControllerProto.QuotaController.TRACKED_JOBS);
-                js.writeToShortProto(proto,
-                        StateControllerProto.QuotaController.TrackedJob.INFO);
+                final long jsToken = proto.start(StateControllerProto.QuotaController.TRACKED_JOBS);
+                js.writeToShortProto(proto, StateControllerProto.QuotaController.TrackedJob.INFO);
                 proto.write(StateControllerProto.QuotaController.TrackedJob.SOURCE_UID,
                         js.getSourceUid());
                 proto.write(
                         StateControllerProto.QuotaController.TrackedJob.EFFECTIVE_STANDBY_BUCKET,
-                        getEffectiveStandbyBucket(js));
+                        js.getEffectiveStandbyBucket());
                 proto.write(StateControllerProto.QuotaController.TrackedJob.IS_TOP_STARTED_JOB,
                         mTopStartedJobs.contains(js));
                 proto.write(StateControllerProto.QuotaController.TrackedJob.HAS_QUOTA,
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java
index 82c33f5..1e5b84d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java
@@ -22,9 +22,11 @@
 import android.content.IntentFilter;
 import android.util.Log;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.server.am.ActivityManagerService;
 import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateControllerProto;
 
 import java.io.PrintWriter;
 
@@ -89,6 +91,22 @@
     }
 
     @Override
+    public void dump(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        final long ciToken = proto.start(
+                StateControllerProto.IdleController.IdlenessTracker.CAR_IDLENESS_TRACKER);
+
+        proto.write(StateControllerProto.IdleController.IdlenessTracker.CarIdlenessTracker.IS_IDLE,
+                mIdle);
+        proto.write(
+                StateControllerProto.IdleController.IdlenessTracker.CarIdlenessTracker.IS_GARAGE_MODE_ON,
+                mGarageModeOn);
+
+        proto.end(ciToken);
+        proto.end(token);
+    }
+
+    @Override
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
         logIfDebug("Received action: " + action);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
index a85bd40..f74eb3b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
@@ -23,11 +23,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-
 import android.util.Log;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
 import com.android.server.am.ActivityManagerService;
 import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateControllerProto;
 
 import java.io.PrintWriter;
 
@@ -101,6 +103,25 @@
     }
 
     @Override
+    public void dump(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        final long diToken = proto.start(
+                StateControllerProto.IdleController.IdlenessTracker.DEVICE_IDLENESS_TRACKER);
+
+        proto.write(StateControllerProto.IdleController.IdlenessTracker.DeviceIdlenessTracker.IS_IDLE,
+                mIdle);
+        proto.write(
+                StateControllerProto.IdleController.IdlenessTracker.DeviceIdlenessTracker.IS_SCREEN_ON,
+                mScreenOn);
+        proto.write(
+                StateControllerProto.IdleController.IdlenessTracker.DeviceIdlenessTracker.IS_DOCK_IDLE,
+                mDockIdle);
+
+        proto.end(diToken);
+        proto.end(token);
+    }
+
+    @Override
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
         if (action.equals(Intent.ACTION_SCREEN_ON)
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessTracker.java
index 09f01c2..cdab7e5 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessTracker.java
@@ -17,6 +17,7 @@
 package com.android.server.job.controllers.idle;
 
 import android.content.Context;
+import android.util.proto.ProtoOutputStream;
 
 import java.io.PrintWriter;
 
@@ -43,4 +44,9 @@
      * Dump useful information about tracked idleness-related state in plaintext.
      */
     void dump(PrintWriter pw);
+
+    /**
+     * Dump useful information about tracked idleness-related state to proto.
+     */
+    void dump(ProtoOutputStream proto, long fieldId);
 }
diff --git a/api/current.txt b/api/current.txt
index afacaa8..e11fca8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -641,6 +641,7 @@
     field public static final int footerDividersEnabled = 16843311; // 0x101022f
     field public static final int forceDarkAllowed = 16844172; // 0x101058c
     field public static final int forceHasOverlappingRendering = 16844065; // 0x1010521
+    field public static final int forceQueryable = 16844296; // 0x1010608
     field public static final int forceUriPermissions = 16844191; // 0x101059f
     field public static final int foreground = 16843017; // 0x1010109
     field public static final int foregroundGravity = 16843264; // 0x1010200
@@ -6794,6 +6795,7 @@
     method @WorkerThread public int setGlobalPrivateDnsModeSpecifiedHost(@NonNull android.content.ComponentName, @NonNull String);
     method public void setGlobalSetting(@NonNull android.content.ComponentName, String, String);
     method public void setKeepUninstalledPackages(@Nullable android.content.ComponentName, @NonNull java.util.List<java.lang.String>);
+    method public boolean setKeyGrantForApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String, boolean);
     method public boolean setKeyPairCertificate(@Nullable android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.security.cert.Certificate>, boolean);
     method public boolean setKeyguardDisabled(@NonNull android.content.ComponentName, boolean);
     method public void setKeyguardDisabledFeatures(@NonNull android.content.ComponentName, int);
@@ -9478,47 +9480,62 @@
   }
 
   public class ContentProviderOperation implements android.os.Parcelable {
-    method public android.content.ContentProviderResult apply(android.content.ContentProvider, android.content.ContentProviderResult[], int) throws android.content.OperationApplicationException;
+    method @NonNull public android.content.ContentProviderResult apply(@NonNull android.content.ContentProvider, @NonNull android.content.ContentProviderResult[], int) throws android.content.OperationApplicationException;
     method public int describeContents();
-    method public android.net.Uri getUri();
+    method @NonNull public android.net.Uri getUri();
     method public boolean isAssertQuery();
+    method public boolean isCall();
     method public boolean isDelete();
+    method public boolean isExceptionAllowed();
     method public boolean isInsert();
     method public boolean isReadOperation();
     method public boolean isUpdate();
     method public boolean isWriteOperation();
     method public boolean isYieldAllowed();
-    method public static android.content.ContentProviderOperation.Builder newAssertQuery(android.net.Uri);
-    method public static android.content.ContentProviderOperation.Builder newDelete(android.net.Uri);
-    method public static android.content.ContentProviderOperation.Builder newInsert(android.net.Uri);
-    method public static android.content.ContentProviderOperation.Builder newUpdate(android.net.Uri);
-    method public String[] resolveSelectionArgsBackReferences(android.content.ContentProviderResult[], int);
-    method public android.content.ContentValues resolveValueBackReferences(android.content.ContentProviderResult[], int);
+    method @NonNull public static android.content.ContentProviderOperation.Builder newAssertQuery(@NonNull android.net.Uri);
+    method @NonNull public static android.content.ContentProviderOperation.Builder newCall(@NonNull android.net.Uri, @Nullable String, @Nullable String);
+    method @NonNull public static android.content.ContentProviderOperation.Builder newDelete(@NonNull android.net.Uri);
+    method @NonNull public static android.content.ContentProviderOperation.Builder newInsert(@NonNull android.net.Uri);
+    method @NonNull public static android.content.ContentProviderOperation.Builder newUpdate(@NonNull android.net.Uri);
+    method @Nullable public android.os.Bundle resolveExtrasBackReferences(@NonNull android.content.ContentProviderResult[], int);
+    method @Nullable public String[] resolveSelectionArgsBackReferences(@NonNull android.content.ContentProviderResult[], int);
+    method @Nullable public android.content.ContentValues resolveValueBackReferences(@NonNull android.content.ContentProviderResult[], int);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.content.ContentProviderOperation> CREATOR;
   }
 
   public static class ContentProviderOperation.Builder {
-    method public android.content.ContentProviderOperation build();
-    method public android.content.ContentProviderOperation.Builder withExpectedCount(int);
-    method public android.content.ContentProviderOperation.Builder withSelection(String, String[]);
-    method public android.content.ContentProviderOperation.Builder withSelectionBackReference(int, int);
-    method public android.content.ContentProviderOperation.Builder withValue(String, Object);
-    method public android.content.ContentProviderOperation.Builder withValueBackReference(String, int);
-    method public android.content.ContentProviderOperation.Builder withValueBackReferences(android.content.ContentValues);
-    method public android.content.ContentProviderOperation.Builder withValues(android.content.ContentValues);
-    method public android.content.ContentProviderOperation.Builder withYieldAllowed(boolean);
+    method @NonNull public android.content.ContentProviderOperation build();
+    method @NonNull public android.content.ContentProviderOperation.Builder withExceptionAllowed(boolean);
+    method @NonNull public android.content.ContentProviderOperation.Builder withExpectedCount(int);
+    method @NonNull public android.content.ContentProviderOperation.Builder withExtra(@NonNull String, @Nullable Object);
+    method @NonNull public android.content.ContentProviderOperation.Builder withExtraBackReference(@NonNull String, int);
+    method @NonNull public android.content.ContentProviderOperation.Builder withExtraBackReference(@NonNull String, int, @NonNull String);
+    method @NonNull public android.content.ContentProviderOperation.Builder withExtras(@NonNull android.os.Bundle);
+    method @NonNull public android.content.ContentProviderOperation.Builder withSelection(@Nullable String, @Nullable String[]);
+    method @NonNull public android.content.ContentProviderOperation.Builder withSelectionBackReference(int, int);
+    method @NonNull public android.content.ContentProviderOperation.Builder withSelectionBackReference(int, int, @NonNull String);
+    method @NonNull public android.content.ContentProviderOperation.Builder withValue(@NonNull String, @Nullable Object);
+    method @NonNull public android.content.ContentProviderOperation.Builder withValueBackReference(@NonNull String, int);
+    method @NonNull public android.content.ContentProviderOperation.Builder withValueBackReference(@NonNull String, int, @NonNull String);
+    method @NonNull public android.content.ContentProviderOperation.Builder withValueBackReferences(@NonNull android.content.ContentValues);
+    method @NonNull public android.content.ContentProviderOperation.Builder withValues(@NonNull android.content.ContentValues);
+    method @NonNull public android.content.ContentProviderOperation.Builder withYieldAllowed(boolean);
   }
 
   public class ContentProviderResult implements android.os.Parcelable {
-    ctor public ContentProviderResult(android.net.Uri);
+    ctor public ContentProviderResult(@NonNull android.net.Uri);
     ctor public ContentProviderResult(int);
+    ctor public ContentProviderResult(@NonNull android.os.Bundle);
+    ctor public ContentProviderResult(@NonNull Exception);
     ctor public ContentProviderResult(android.os.Parcel);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.content.ContentProviderResult> CREATOR;
-    field public final Integer count;
-    field public final android.net.Uri uri;
+    field @Nullable public final Integer count;
+    field @Nullable public final Exception exception;
+    field @Nullable public final android.os.Bundle extras;
+    field @Nullable public final android.net.Uri uri;
   }
 
   public class ContentQueryMap extends java.util.Observable {
@@ -40628,8 +40645,9 @@
 package android.security {
 
   public final class AttestedKeyPair {
-    method public java.util.List<java.security.cert.Certificate> getAttestationRecord();
-    method public java.security.KeyPair getKeyPair();
+    ctor public AttestedKeyPair(@Nullable java.security.KeyPair, @Nullable java.security.cert.Certificate[]);
+    method @NonNull public java.util.List<java.security.cert.Certificate> getAttestationRecord();
+    method @Nullable public java.security.KeyPair getKeyPair();
   }
 
   public class ConfirmationAlreadyPresentingException extends java.lang.Exception {
@@ -73166,7 +73184,7 @@
     method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String);
     method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @NonNull java.util.function.Supplier<java.lang.String>);
     method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable Object);
-    method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, Object[]);
+    method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable Object[]);
     method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable Throwable);
     method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable Throwable, @NonNull java.util.function.Supplier<java.lang.String>);
     method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String);
diff --git a/api/removed.txt b/api/removed.txt
index b075f9e..74c1d3c 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -208,7 +208,7 @@
 package android.icu.util {
 
   public class JapaneseCalendar extends android.icu.util.GregorianCalendar {
-    field public static final int CURRENT_ERA;
+    field @Deprecated public static final int CURRENT_ERA;
   }
 
 }
diff --git a/api/system-current.txt b/api/system-current.txt
index 15b694a..18e30ba 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3693,7 +3693,7 @@
 package android.media.session {
 
   public final class MediaSessionManager {
-    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerCallback(@NonNull android.media.session.MediaSessionManager.Callback, @Nullable android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.Callback);
     method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void unregisterCallback(@NonNull android.media.session.MediaSessionManager.Callback);
@@ -7170,6 +7170,14 @@
     field public static final String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string";
   }
 
+  public static final class CarrierConfigManager.Wifi {
+    field public static final String KEY_CARRIER_CONNECTION_MANAGER_PACKAGE_STRING = "wifi.carrier_connection_manager_package_string";
+    field public static final String KEY_CARRIER_PROFILES_VERSION_INT = "wifi.carrier_profiles_version_int";
+    field public static final String KEY_NETWORK_PROFILES_STRING_ARRAY = "wifi.network_profiles_string_array";
+    field public static final String KEY_PASSPOINT_PROFILES_STRING_ARRAY = "wifi.passpoint_profiles_string_array";
+    field public static final String KEY_PREFIX = "wifi.";
+  }
+
   public final class CarrierRestrictionRules implements android.os.Parcelable {
     method @NonNull public java.util.List<java.lang.Boolean> areCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>);
     method public int describeContents();
diff --git a/api/test-current.txt b/api/test-current.txt
index 46a0e1b..6fe79c4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2348,6 +2348,7 @@
     method public static android.net.Uri scanFile(android.content.Context, java.io.File);
     method public static android.net.Uri scanFileFromShell(android.content.Context, java.io.File);
     method public static void scanVolume(android.content.Context, java.io.File);
+    method public static void waitForIdle(android.content.Context);
   }
 
   public final class Settings {
@@ -3042,6 +3043,7 @@
     field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
     field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
     field public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
+    field public static final String USE_BUGREPORT_API = "settings_use_bugreport_api";
   }
 
   public class TimeUtils {
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
index d69dd79..847dda3 100644
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -9,7 +9,6 @@
 #include <androidfw/ResourceTypes.h>
 #include <androidfw/StreamingZipInflater.h>
 #include <androidfw/ZipFileRO.h>
-#include <cutils/jstring.h>
 #include <cutils/properties.h>
 #include <private/android_filesystem_config.h> // for AID_SYSTEM
 #include <utils/SortedVector.h>
@@ -84,15 +83,9 @@
     }
 
     bool check_property(String16 property, String16 value) {
-        const char *prop;
-        const char *val;
-
-        prop = strndup16to8(property.string(), property.size());
         char propBuf[PROPERTY_VALUE_MAX];
-        property_get(prop, propBuf, NULL);
-        val = strndup16to8(value.string(), value.size());
-
-        return (strcmp(propBuf, val) == 0);
+        property_get(String8(property).c_str(), propBuf, NULL);
+        return String8(value) == propBuf;
     }
 
     int parse_overlay_tag(const ResXMLTree& parser, const char *target_package_name,
diff --git a/config/boot-profile.txt b/config/boot-profile.txt
index e69de29..57e06c2 100644
--- a/config/boot-profile.txt
+++ b/config/boot-profile.txt
@@ -0,0 +1,642 @@
+Lcom/android/internal/os/RuntimeInit$MethodAndArgsCaller;->run()V
+Lcom/android/internal/os/ZygoteInit;->main([Ljava/lang/String;)V
+Lcom/android/internal/util/ConcurrentUtils$1$1;->run()V
+Lcom/android/server/SystemConfig;->getInstance()Lcom/android/server/SystemConfig;
+Lcom/android/server/SystemConfig;-><init>()V
+Lcom/android/server/SystemConfig;->readPermissions(Ljava/io/File;I)V
+Lcom/android/server/SystemConfig;->readPermissionsFromXml(Ljava/io/File;I)V
+Lcom/android/internal/os/ProcessCpuTracker;->update()V
+Lcom/android/internal/os/ProcessCpuTracker;->init()V
+Lcom/android/internal/os/ProcessCpuTracker;->collectStats(Ljava/lang/String;IZ[ILjava/util/ArrayList;)[I
+Landroid/content/pm/PackageParser$SigningDetails$Builder;->build()Landroid/content/pm/PackageParser$SigningDetails;
+Landroid/content/pm/PackageParser$SigningDetails;-><init>(Landroid/content/pm/PackageParser$SigningDetails;)V
+Landroid/content/pm/PackageParser$SigningDetails;-><init>([Landroid/content/pm/Signature;I)V
+Landroid/content/pm/PackageParser$SigningDetails;-><init>([Landroid/content/pm/Signature;ILandroid/util/ArraySet;[Landroid/content/pm/Signature;)V
+Landroid/content/pm/PackageParser$SigningDetails;-><init>([Landroid/content/pm/Signature;I[Landroid/content/pm/Signature;)V
+Landroid/util/ArrayMap;->get(Ljava/lang/Object;)Ljava/lang/Object;
+Landroid/util/ArrayMap;->indexOfKey(Ljava/lang/Object;)I
+Landroid/content/pm/Signature;->getPublicKey()Ljava/security/PublicKey;
+Landroid/util/ArrayMap;->indexOf(Ljava/lang/Object;I)I
+Landroid/util/ArrayMap;->indexOfNull()I
+Landroid/util/ArrayMap;->indexOfValue(Ljava/lang/Object;)I
+Lcom/android/internal/os/ProcessCpuTracker;->getName(Lcom/android/internal/os/ProcessCpuTracker$Stats;Ljava/lang/String;)V
+Lcom/android/internal/os/ProcStatsUtil;->readTerminatedProcFile(Ljava/lang/String;B)Ljava/lang/String;
+Lcom/android/internal/os/BatteryStatsImpl;->writeAsyncLocked()V
+Lcom/android/internal/os/BatteryStatsImpl;->writeStatsLocked(Z)V
+Lcom/android/internal/os/BatteryStatsImpl;->writeSummaryToParcel(Landroid/os/Parcel;Z)V
+Landroid/util/SparseArray;->get(I)Ljava/lang/Object;
+Landroid/util/SparseArray;->get(ILjava/lang/Object;)Ljava/lang/Object;
+Lcom/android/internal/os/BatteryStatsImpl;->readLocked()V
+Lcom/android/internal/os/BatteryStatsImpl;->readSummaryFromParcel(Landroid/os/Parcel;)V
+Landroid/util/ArrayMap;->binarySearchHashes([III)I
+Landroid/util/ContainerHelpers;->binarySearch([III)I
+Lcom/android/internal/os/BatteryStatsImpl;->updateCpuTimeLocked(ZZ)V
+Lcom/android/internal/os/KernelCpuUidTimeReader;->readDelta(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V
+Landroid/util/ArrayMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+Landroid/util/ArrayMap;->putAll(Landroid/util/ArrayMap;)V
+Landroid/util/ArrayMap;->putAll(Ljava/util/Map;)V
+Landroid/util/SparseArray;-><init>()V
+Landroid/util/SparseArray;-><init>(I)V
+Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V
+Lcom/android/server/SystemConfig;->readPrivAppPermissions(Lorg/xmlpull/v1/XmlPullParser;Landroid/util/ArrayMap;Landroid/util/ArrayMap;)V
+Landroid/content/pm/Signature;-><init>(Ljava/lang/String;)V
+Landroid/content/pm/Signature;-><init>([B)V
+Landroid/content/pm/Signature;-><init>([Ljava/security/cert/Certificate;)V
+Lcom/android/internal/os/ProcessCpuTracker$Stats;-><init>(IIZ)V
+Lcom/android/internal/os/KernelCpuProcStringReader;->asLongs(Ljava/nio/CharBuffer;[J)I
+Lcom/android/internal/util/XmlUtils;->nextElement(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/internal/util/XmlUtils;->nextElementWithin(Lorg/xmlpull/v1/XmlPullParser;I)Z
+Lcom/android/internal/util/ArrayUtils;->newUnpaddedObjectArray(I)[Ljava/lang/Object;
+Landroid/util/SparseArray;->put(ILjava/lang/Object;)V
+Lcom/android/internal/os/BatteryStatsImpl;->updateKernelWakelocksLocked()V
+Landroid/util/ArraySet;->add(Ljava/lang/Object;)Z
+Landroid/util/ArraySet;->addAll(Landroid/util/ArraySet;)V
+Landroid/util/ArraySet;->addAll(Ljava/util/Collection;)Z
+Lcom/android/internal/os/KernelWakelockReader;->readKernelWakelockStats(Lcom/android/internal/os/KernelWakelockStats;)Lcom/android/internal/os/KernelWakelockStats;
+Lcom/android/internal/util/GrowingArrayUtils;->insert([IIII)[I
+Lcom/android/internal/util/GrowingArrayUtils;->insert([JIIJ)[J
+Lcom/android/internal/util/GrowingArrayUtils;->insert([Ljava/lang/Object;IILjava/lang/Object;)[Ljava/lang/Object;
+Lcom/android/internal/util/GrowingArrayUtils;->insert([ZIIZ)[Z
+HPLcom/android/internal/app/procstats/ProcessStats;-><init>(Landroid/os/Parcel;)V
+Lcom/android/internal/app/procstats/ProcessStats;-><init>(Z)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;-><init>(Lcom/android/internal/os/BatteryStatsImpl;I)V
+Lcom/android/internal/os/KernelWakelockReader;->parseProcWakelocks([BIZLcom/android/internal/os/KernelWakelockStats;)Lcom/android/internal/os/KernelWakelockStats;
+Landroid/content/pm/PackageParser;->getCachedResult(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;IZ)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parsePackageItemInfo(Landroid/content/pm/PackageParser$Package;Landroid/content/pm/PackageItemInfo;[Ljava/lang/String;Ljava/lang/String;Landroid/content/res/TypedArray;ZIIIIII)Z
+Landroid/content/pm/PackageParser;->parsePackageList(Ljava/lang/String;)Ljava/util/Set;
+Landroid/content/pm/PackageParser;->parsePackageLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$PackageLite;
+Landroid/content/pm/PackageParser;->parsePackageSplitNames(Lorg/xmlpull/v1/XmlPullParser;Landroid/util/AttributeSet;)Landroid/util/Pair;
+Lcom/android/internal/os/BatteryStatsImpl$DualTimer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V
+Landroid/content/pm/Signature;->parseHexDigit(I)I
+Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->readWakeSummaryFromParcelLocked(Ljava/lang/String;Landroid/os/Parcel;)V
+Landroid/util/ArraySet;->iterator()Ljava/util/Iterator;
+Landroid/content/pm/PackageParser;->fromCacheEntryStatic([B)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->fromCacheEntry([B)Landroid/content/pm/PackageParser$Package;
+Lcom/android/internal/os/BatteryStatsImpl$Timer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V
+Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidUserSysTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V
+Landroid/os/FileUtils;->bytesToFile(Ljava/lang/String;[B)V
+Landroid/os/StrictMode;->allowThreadDiskReads()Landroid/os/StrictMode$ThreadPolicy;
+Landroid/os/StrictMode;->allowThreadDiskReadsMask()I
+Landroid/content/pm/PackageParser$Package;-><init>(Landroid/os/Parcel;)V
+Landroid/content/pm/PackageParser$Package;-><init>(Ljava/lang/String;)V
+Lcom/android/server/SystemConfig;->addFeature(Ljava/lang/String;I)V
+Landroid/os/StrictMode;->setThreadPolicy(Landroid/os/StrictMode$ThreadPolicy;)V
+Landroid/os/StrictMode;->setThreadPolicyMask(I)V
+Landroid/content/pm/FallbackCategoryProvider;->loadFallbacks()V
+Landroid/os/Parcel$ReadWriteHelper;->writeString(Landroid/os/Parcel;Ljava/lang/String;)V
+Landroid/os/Parcel;->writeString(Ljava/lang/String;)V
+Landroid/os/Parcel;->writeStringArray([Ljava/lang/String;)V
+Landroid/os/Parcel;->writeStringList(Ljava/util/List;)V
+Lcom/android/internal/os/BatteryStatsImpl$Timer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;ILcom/android/internal/os/BatteryStatsImpl$TimeBase;)V
+Lcom/android/internal/os/BatteryStatsImpl$Timer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;ILcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->add(Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V
+Landroid/os/Parcel;->writeInt(I)V
+Landroid/os/Parcel;->writeIntArray([I)V
+Landroid/os/Parcel;->writeInterfaceToken(Ljava/lang/String;)V
+Landroid/content/pm/PackageParser;->parsePublicKey(Ljava/lang/String;)Ljava/security/PublicKey;
+Lcom/android/internal/os/KernelCpuProcStringReader$ProcFileIterator;->nextLine()Ljava/nio/CharBuffer;
+Landroid/util/Xml;->newPullParser()Lorg/xmlpull/v1/XmlPullParser;
+Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->readFreqs(Lcom/android/internal/os/PowerProfile;)[J
+Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->readFreqs(Ljava/lang/String;)[J
+Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V
+Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V
+Landroid/os/HandlerThread;->run()V
+Landroid/os/Looper;->loop()V
+Landroid/util/SparseArray;->size()I
+Landroid/util/ArrayMap;-><init>()V
+Landroid/util/ArrayMap;-><init>(I)V
+Landroid/util/ArrayMap;-><init>(IZ)V
+Landroid/util/ArrayMap;-><init>(Landroid/util/ArrayMap;)V
+Landroid/os/Parcel;->writeLong(J)V
+Landroid/os/Parcel;->writeLongArray([J)V
+Landroid/os/Parcel;->readParcelable(Ljava/lang/ClassLoader;)Landroid/os/Parcelable;
+Landroid/os/Parcel;->readParcelableArray(Ljava/lang/ClassLoader;Ljava/lang/Class;)[Landroid/os/Parcelable;
+Landroid/os/Parcel;->readParcelableCreator(Ljava/lang/ClassLoader;)Landroid/os/Parcelable$Creator;
+Landroid/os/Parcel;->readParcelableList(Ljava/util/List;Ljava/lang/ClassLoader;)Ljava/util/List;
+Lcom/android/internal/os/BatteryStatsImpl$DualTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V
+Landroid/os/SystemProperties;->getBoolean(Ljava/lang/String;Z)Z
+Landroid/content/pm/IntentFilterVerificationInfo;-><init>(Lorg/xmlpull/v1/XmlPullParser;)V
+Landroid/util/ArrayMap;->allocArrays(I)V
+Landroid/os/Parcel;->readInt()I
+Landroid/os/Parcel;->readIntArray([I)V
+Landroid/content/pm/IntentFilterVerificationInfo;->readFromXml(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/internal/util/ArrayUtils;->appendInt([II)[I
+Lcom/android/internal/util/ArrayUtils;->appendInt([IIZ)[I
+Landroid/util/TimingsTraceLog;->traceEnd()V
+Lcom/android/internal/os/BatteryStatsImpl$Timer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Landroid/os/Parcel;->readString()Ljava/lang/String;
+Landroid/os/Parcel;->readStringArray()[Ljava/lang/String;
+Landroid/os/Parcel;->readStringList(Ljava/util/List;)V
+Lcom/android/internal/os/BatteryStatsImpl$OverflowArrayMap;->add(Ljava/lang/String;Ljava/lang/Object;)V
+Lcom/android/internal/os/BatteryStatsImpl;->getKernelWakelockTimerLocked(Ljava/lang/String;)Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;
+Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$DualTimer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Landroid/os/storage/StorageManager;->hasAdoptable()Z
+Landroid/os/Parcel$ReadWriteHelper;->readString(Landroid/os/Parcel;)Ljava/lang/String;
+Landroid/os/Handler;->dispatchMessage(Landroid/os/Message;)V
+Lcom/android/internal/os/BatteryStatsImpl$5;->run()V
+Lcom/android/internal/os/BatteryStatsImpl;->commitPendingDataToDisk(Landroid/os/Parcel;Lcom/android/internal/os/AtomicFile;)V
+Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Landroid/util/ArraySet;->indexOf(Ljava/lang/Object;)I
+Landroid/util/ArraySet;->indexOf(Ljava/lang/Object;I)I
+Landroid/util/ArraySet;->indexOfNull()I
+Landroid/os/Parcel;->readLong()J
+Landroid/os/Parcel;->readLongArray([J)V
+Lcom/android/internal/util/XmlUtils;->skipCurrentTag(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->getServiceStatsLocked(Ljava/lang/String;Ljava/lang/String;)Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg$Serv;
+Landroid/os/StrictMode;->setBlockGuardPolicy(I)V
+Landroid/util/TimingsTraceLog;->logDuration(Ljava/lang/String;J)V
+Landroid/util/Base64;->decode(Ljava/lang/String;I)[B
+Landroid/util/Base64;->decode([BI)[B
+Landroid/util/Base64;->decode([BIII)[B
+Landroid/util/ArrayMap;->valueAt(I)Ljava/lang/Object;
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->getWakelockTimerLocked(Lcom/android/internal/os/BatteryStatsImpl$Uid$Wakelock;I)Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;
+Landroid/util/ArraySet;-><init>()V
+Landroid/util/ArraySet;-><init>(I)V
+Landroid/util/ArraySet;-><init>(Landroid/util/ArraySet;)V
+Landroid/util/ArraySet;-><init>(Ljava/util/Collection;)V
+Lcom/android/internal/os/KernelCpuProcStringReader;->open(Z)Lcom/android/internal/os/KernelCpuProcStringReader$ProcFileIterator;
+Landroid/content/pm/ApplicationInfo;-><init>()V
+Landroid/content/pm/ApplicationInfo;-><init>(Landroid/content/pm/ApplicationInfo;)V
+Landroid/content/pm/ApplicationInfo;-><init>(Landroid/os/Parcel;)V
+Landroid/util/ArraySet;->remove(Ljava/lang/Object;)Z
+Landroid/util/ArraySet;->removeAll(Ljava/util/Collection;)Z
+Landroid/util/ArraySet;->removeAt(I)Ljava/lang/Object;
+Landroid/util/ArraySet;->removeAll(Landroid/util/ArraySet;)Z
+Landroid/content/pm/ApplicationInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/ApplicationInfo;
+Landroid/content/pm/ApplicationInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object;
+Landroid/os/ServiceManagerProxy;->addService(Ljava/lang/String;Landroid/os/IBinder;ZI)V
+Lcom/android/internal/os/PowerProfile;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/os/PowerProfile;-><init>(Landroid/content/Context;Z)V
+Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V
+Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;)V
+Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;ZI)V
+Lcom/android/internal/os/PowerProfile;->readPowerValuesFromXml(Landroid/content/Context;Z)V
+Lcom/android/server/SystemConfig;->readPermission(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)V
+Landroid/content/res/ResourcesImpl;-><init>(Landroid/content/res/AssetManager;Landroid/util/DisplayMetrics;Landroid/content/res/Configuration;Landroid/view/DisplayAdjustments;)V
+Landroid/os/ServiceManager;->getService(Ljava/lang/String;)Landroid/os/IBinder;
+Landroid/os/ServiceManager;->getServiceOrThrow(Ljava/lang/String;)Landroid/os/IBinder;
+Landroid/util/Base64$Decoder;->process([BIIZ)Z
+Lcom/android/internal/util/XmlUtils;->readLongAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)J
+Lcom/android/internal/util/XmlUtils;->readLongAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;J)J
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->getPackageStatsLocked(Ljava/lang/String;)Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg;
+Lcom/android/internal/app/procstats/ProcessStats;->resetCommon()V
+HPLcom/android/internal/app/procstats/ProcessStats;->resetSafely()V
+Landroid/content/res/ResourcesImpl;->updateConfiguration(Landroid/content/res/Configuration;Landroid/util/DisplayMetrics;Landroid/content/res/CompatibilityInfo;)V
+Landroid/content/res/Resources;-><init>()V
+Landroid/content/res/Resources;-><init>(Landroid/content/res/AssetManager;Landroid/util/DisplayMetrics;Landroid/content/res/Configuration;)V
+Landroid/content/res/Resources;-><init>(Ljava/lang/ClassLoader;)V
+Landroid/os/ServiceManager;->rawGetService(Ljava/lang/String;)Landroid/os/IBinder;
+Landroid/util/LongSparseArray;->put(JLjava/lang/Object;)V
+Landroid/util/ArrayMap;->freeArrays([I[Ljava/lang/Object;I)V
+Landroid/util/ArrayMap;->keyAt(I)Ljava/lang/Object;
+Landroid/content/pm/PackageParser$Activity$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/PackageParser$Activity;
+Landroid/content/pm/PackageParser$Activity$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object;
+Landroid/content/pm/PackageParser$Activity;-><init>(Landroid/content/pm/PackageParser$ParseComponentArgs;Landroid/content/pm/ActivityInfo;)V
+Landroid/content/pm/PackageParser$Activity;-><init>(Landroid/os/Parcel;)V
+Landroid/content/res/AssetManager;->setConfiguration(IILjava/lang/String;IIIIIIIIIIIIIII)V
+Lcom/android/internal/os/BatteryStatsImpl$Counter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V
+Lcom/android/internal/os/BatteryStatsImpl$Counter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V
+Landroid/util/ArraySet;->allocArrays(I)V
+Landroid/os/storage/StorageManager;->isFileEncryptedNativeOnly()Z
+Lcom/android/internal/os/BatteryStatsImpl$Counter;->writeSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl;->updateRailStatsLocked()V
+Landroid/os/ServiceManagerProxy;->getService(Ljava/lang/String;)Landroid/os/IBinder;
+Landroid/util/SparseIntArray;-><init>()V
+Landroid/util/SparseIntArray;-><init>(I)V
+Lcom/android/internal/util/XmlUtils;->readIntAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)I
+Lcom/android/internal/util/XmlUtils;->readIntAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;I)I
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Ljava/io/File;Landroid/os/Handler;Lcom/android/internal/os/BatteryStatsImpl$PlatformIdleStateCallback;Lcom/android/internal/os/BatteryStatsImpl$RailEnergyDataCallback;Lcom/android/internal/os/BatteryStatsImpl$UserInfoProvider;)V
+Lcom/android/internal/os/BatteryStatsImpl;-><init>(Ljava/io/File;Landroid/os/Handler;Lcom/android/internal/os/BatteryStatsImpl$PlatformIdleStateCallback;Lcom/android/internal/os/BatteryStatsImpl$RailEnergyDataCallback;Lcom/android/internal/os/BatteryStatsImpl$UserInfoProvider;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->readJobSummaryFromParcelLocked(Ljava/lang/String;Landroid/os/Parcel;)V
+Lcom/android/internal/app/procstats/ProcessStats;->updateFragmentation()V
+Landroid/os/Parcel;->readTypedObject(Landroid/os/Parcelable$Creator;)Ljava/lang/Object;
+Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->getTotalDurationMsLocked(J)J
+Landroid/os/Parcel;->createTypedArray(Landroid/os/Parcelable$Creator;)[Ljava/lang/Object;
+Landroid/os/Parcel;->createTypedArrayList(Landroid/os/Parcelable$Creator;)Ljava/util/ArrayList;
+Landroid/os/Parcel;->createTypedArrayMap(Landroid/os/Parcelable$Creator;)Landroid/util/ArrayMap;
+Landroid/content/pm/PackageParserCacheHelper$ReadHelper;->readString(Landroid/os/Parcel;)Ljava/lang/String;
+Lcom/android/server/LocalServices;->addService(Ljava/lang/Class;Ljava/lang/Object;)V
+Landroid/util/Slog;->d(Ljava/lang/String;Ljava/lang/String;)I
+Landroid/util/TimingsTraceLog;->traceBegin(Ljava/lang/String;)V
+Landroid/content/res/AssetManager;-><init>()V
+Landroid/content/res/AssetManager;->getResourceValue(IILandroid/util/TypedValue;Z)Z
+Landroid/util/LongSparseLongArray;->put(JJ)V
+Lcom/android/internal/os/BatteryStatsImpl$SystemClocks;->uptimeMillis()J
+Landroid/content/res/AssetManager;->setApkAssets([Landroid/content/res/ApkAssets;Z)V
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->readSummaryFromParcelLocked(Landroid/os/Parcel;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;
+Lcom/android/internal/util/XmlUtils;->readBooleanAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)Z
+Lcom/android/internal/util/XmlUtils;->readBooleanAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Z)Z
+Landroid/os/StrictMode$ThreadPolicy;-><init>(ILandroid/os/StrictMode$OnThreadViolationListener;Ljava/util/concurrent/Executor;)V
+Lcom/android/internal/os/KernelCpuSpeedReader;->readDelta()[J
+Lcom/android/internal/os/AtomicFile;->startWrite()Ljava/io/FileOutputStream;
+Landroid/app/ContextImpl;->createSystemUiContext(Landroid/app/ContextImpl;I)Landroid/app/ContextImpl;
+Landroid/app/ActivityThread;->getSystemUiContext()Landroid/app/ContextImpl;
+Landroid/os/Parcel;->recycle()V
+Landroid/util/Slog;->i(Ljava/lang/String;Ljava/lang/String;)I
+Landroid/os/Binder;-><init>()V
+Landroid/os/Binder;-><init>(Ljava/lang/String;)V
+Landroid/content/Context;->getSystemService(Ljava/lang/Class;)Ljava/lang/Object;
+Lcom/android/internal/util/ArrayUtils;->newUnpaddedLongArray(I)[J
+Landroid/content/res/ResourcesImpl;->getValue(ILandroid/util/TypedValue;Z)V
+Landroid/content/res/ResourcesImpl;->getValueForDensity(IILandroid/util/TypedValue;Z)V
+Landroid/util/LongSparseLongArray;-><init>()V
+Landroid/util/LongSparseLongArray;-><init>(I)V
+Landroid/os/BatteryStats$Timer;-><init>()V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->createAggregatedPartialWakelockTimerLocked()Lcom/android/internal/os/BatteryStatsImpl$DualTimer;
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->access$2300(Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->readJobCompletionsFromParcelLocked(Landroid/os/Parcel;)V
+Landroid/util/MapCollections$KeySet;->iterator()Ljava/util/Iterator;
+Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
+Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->writeSummaryToParcel(Landroid/os/Parcel;JJ)V
+Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;->computeRunTimeLocked(J)J
+Landroid/bluetooth/BluetoothAdapter;->getDefaultAdapter()Landroid/bluetooth/BluetoothAdapter;
+Landroid/content/pm/PackageParserCacheHelper$ReadHelper;->startAndInstall()V
+Landroid/content/pm/PackageItemInfo;-><init>(Landroid/content/pm/PackageItemInfo;)V
+Landroid/content/pm/PackageItemInfo;-><init>(Landroid/os/Parcel;)V
+Landroid/content/pm/ActivityInfo;-><init>()V
+Landroid/content/pm/ActivityInfo;-><init>(Landroid/content/pm/ActivityInfo;)V
+Landroid/content/pm/ActivityInfo;-><init>(Landroid/os/Parcel;)V
+Landroid/content/pm/ActivityInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/ActivityInfo;
+Landroid/content/pm/ActivityInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object;
+Landroid/os/BinderProxy;->transact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
+Landroid/os/HandlerThread;->getLooper()Landroid/os/Looper;
+Landroid/os/FileUtils;->$closeResource(Ljava/lang/Throwable;Ljava/lang/AutoCloseable;)V
+Landroid/os/SystemProperties;->digestOf([Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/util/ArrayUtils;->isEmpty(Ljava/util/Collection;)Z
+Lcom/android/internal/util/ArrayUtils;->isEmpty([Ljava/lang/Object;)Z
+Landroid/util/AtomicFile;-><init>(Ljava/io/File;)V
+Landroid/util/AtomicFile;-><init>(Ljava/io/File;Ljava/lang/String;)V
+Landroid/util/LongSparseArray;-><init>()V
+Landroid/util/LongSparseArray;-><init>(I)V
+Landroid/content/res/Resources;->obtainTypedArray(I)Landroid/content/res/TypedArray;
+Landroid/util/AtomicFile;->openRead()Ljava/io/FileInputStream;
+Lcom/android/internal/os/BatteryStatsImpl$TimeBase;-><init>(Z)V
+Lcom/android/internal/os/BatteryStatsImpl$Counter;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->makeProcessState(ILandroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid$3;->instantiateObject()Lcom/android/internal/os/BatteryStatsImpl$DualTimer;
+Lcom/android/internal/os/BatteryStatsImpl$Uid$3;->instantiateObject()Ljava/lang/Object;
+Landroid/content/pm/PackageUserState;-><init>()V
+Landroid/app/ActivityManager;->isLowRamDeviceStatic()Z
+Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidActiveTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V
+Lcom/android/internal/os/BatteryStatsImpl;->updateRpmStatsLocked()V
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;->writeSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Lcom/android/internal/os/KernelMemoryBandwidthStats;->updateStats()V
+Landroid/content/pm/PackageParser;->isCacheUpToDate(Ljava/io/File;Ljava/io/File;)Z
+Landroid/os/StrictMode;->initThreadDefaults(Landroid/content/pm/ApplicationInfo;)V
+Landroid/app/ResourcesManager;->getOrCreateResources(Landroid/os/IBinder;Landroid/content/res/ResourcesKey;Ljava/lang/ClassLoader;)Landroid/content/res/Resources;
+Landroid/app/ResourcesManager;->getOrCreateResourcesForActivityLocked(Landroid/os/IBinder;Ljava/lang/ClassLoader;Landroid/content/res/ResourcesImpl;Landroid/content/res/CompatibilityInfo;)Landroid/content/res/Resources;
+Landroid/app/ResourcesManager;->getOrCreateResourcesLocked(Ljava/lang/ClassLoader;Landroid/content/res/ResourcesImpl;Landroid/content/res/CompatibilityInfo;)Landroid/content/res/Resources;
+Landroid/app/ResourcesManager;->getResources(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ILandroid/content/res/Configuration;Landroid/content/res/CompatibilityInfo;Ljava/lang/ClassLoader;)Landroid/content/res/Resources;
+Landroid/app/ContextImpl;->createResources(Landroid/os/IBinder;Landroid/app/LoadedApk;Ljava/lang/String;ILandroid/content/res/Configuration;Landroid/content/res/CompatibilityInfo;[Ljava/lang/String;)Landroid/content/res/Resources;
+Landroid/app/ContextImpl;->createResources(Landroid/os/IBinder;Landroid/app/LoadedApk;Ljava/lang/String;ILandroid/content/res/Configuration;Landroid/content/res/CompatibilityInfo;)Landroid/content/res/Resources;
+Landroid/app/ContextImpl;->getSystemService(Ljava/lang/String;)Ljava/lang/Object;
+Landroid/app/ContextImpl;->getSystemServiceName(Ljava/lang/Class;)Ljava/lang/String;
+Landroid/app/SystemServiceRegistry$CachedServiceFetcher;->getService(Landroid/app/ContextImpl;)Ljava/lang/Object;
+Landroid/util/TimingsTraceLog;->assertSameThread()V
+Landroid/os/HandlerThread;-><init>(Ljava/lang/String;)V
+Landroid/os/HandlerThread;-><init>(Ljava/lang/String;I)V
+Lcom/android/internal/util/ArrayUtils;->newUnpaddedIntArray(I)[I
+Landroid/content/res/Configuration;-><init>()V
+Landroid/content/res/Configuration;-><init>(Landroid/content/res/Configuration;)V
+Landroid/view/SurfaceControl;->getInternalDisplayToken()Landroid/os/IBinder;
+Landroid/view/SurfaceControl;->getPhysicalDisplayToken(J)Landroid/os/IBinder;
+Landroid/content/res/Resources;->getInteger(I)I
+Landroid/os/Handler;->sendMessageAtTime(Landroid/os/Message;J)Z
+Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->init(JJ)V
+Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->readSummaryFromParcel(Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg;-><init>(Lcom/android/internal/os/BatteryStatsImpl;)V
+Landroid/util/ArraySet;->freeArrays([I[Ljava/lang/Object;I)V
+Landroid/util/ArrayMap;->entrySet()Ljava/util/Set;
+Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidClusterTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V
+Landroid/telephony/TelephonyManager;->getITelephony()Lcom/android/internal/telephony/ITelephony;
+Landroid/telephony/TelephonyManager;->requestModemActivityInfo(Landroid/os/ResultReceiver;)V
+Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->getMaxDurationMsLocked(J)J
+Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->endSample()V
+Lcom/android/internal/os/BatteryStatsImpl;->updateKernelMemoryBandwidthLocked()V
+Landroid/content/pm/ComponentInfo;-><init>()V
+Landroid/content/pm/ComponentInfo;-><init>(Landroid/content/pm/ComponentInfo;)V
+Landroid/content/pm/ComponentInfo;-><init>(Landroid/os/Parcel;)V
+Landroid/view/SurfaceControl;->getDisplayConfigs(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;
+Lcom/android/internal/os/AtomicFile;->finishWrite(Ljava/io/FileOutputStream;)V
+Landroid/app/ResourcesManager;->createResourcesImpl(Landroid/content/res/ResourcesKey;)Landroid/content/res/ResourcesImpl;
+Landroid/app/ContextImpl;->updateDisplay(I)V
+Landroid/hardware/display/DisplayManagerGlobal;->getInstance()Landroid/hardware/display/DisplayManagerGlobal;
+Landroid/app/ResourcesManager;->getAdjustedDisplay(ILandroid/content/res/Resources;)Landroid/view/Display;
+Landroid/app/ResourcesManager;->getAdjustedDisplay(ILandroid/view/DisplayAdjustments;)Landroid/view/Display;
+Landroid/os/Parcel;->readStrongBinder()Landroid/os/IBinder;
+Landroid/app/ContextImpl;->setTheme(I)V
+Landroid/content/IntentFilter;->readFromXml(Lorg/xmlpull/v1/XmlPullParser;)V
+Landroid/text/TextUtils;->getLayoutDirectionFromLocale(Ljava/util/Locale;)I
+Landroid/os/Handler;-><init>()V
+Landroid/os/Handler;-><init>(Landroid/os/Handler$Callback;)V
+Landroid/os/Handler;-><init>(Landroid/os/Handler$Callback;Z)V
+Landroid/os/Handler;-><init>(Landroid/os/Looper;)V
+Landroid/os/Handler;-><init>(Landroid/os/Looper;Landroid/os/Handler$Callback;)V
+Landroid/os/Handler;-><init>(Landroid/os/Looper;Landroid/os/Handler$Callback;Z)V
+Landroid/os/Handler;-><init>(Z)V
+Landroid/os/Binder;->queryLocalInterface(Ljava/lang/String;)Landroid/os/IInterface;
+Landroid/content/pm/PackageParser;->isApkFile(Ljava/io/File;)Z
+Landroid/util/SparseIntArray;->put(II)V
+Landroid/content/pm/ApplicationInfo;->initForUser(I)V
+Landroid/os/BinderProxy;->getInstance(JJ)Landroid/os/BinderProxy;
+Landroid/content/pm/IntentFilterVerificationInfo;->getStringFromXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Landroid/app/SystemServiceRegistry$35;->createService(Landroid/app/ContextImpl;)Landroid/os/PowerManager;
+Landroid/app/SystemServiceRegistry$35;->createService(Landroid/app/ContextImpl;)Ljava/lang/Object;
+Landroid/util/ArrayMap;->containsKey(Ljava/lang/Object;)Z
+Landroid/app/WindowConfiguration;->setToDefaults()V
+Lcom/android/internal/util/MemInfoReader;->readMemInfo()V
+Landroid/util/LongSparseArray;->get(J)Ljava/lang/Object;
+Landroid/util/LongSparseArray;->get(JLjava/lang/Object;)Ljava/lang/Object;
+Landroid/util/Spline;->createSpline([F[F)Landroid/util/Spline;
+Landroid/os/PowerManager;->getDefaultScreenBrightnessSetting()I
+Landroid/view/Display;-><init>(Landroid/hardware/display/DisplayManagerGlobal;ILandroid/view/DisplayInfo;Landroid/content/res/Resources;)V
+Landroid/view/Display;-><init>(Landroid/hardware/display/DisplayManagerGlobal;ILandroid/view/DisplayInfo;Landroid/view/DisplayAdjustments;)V
+Landroid/view/Display;-><init>(Landroid/hardware/display/DisplayManagerGlobal;ILandroid/view/DisplayInfo;Landroid/view/DisplayAdjustments;Landroid/content/res/Resources;)V
+Landroid/net/Uri;->withAppendedPath(Landroid/net/Uri;Ljava/lang/String;)Landroid/net/Uri;
+Landroid/content/res/TypedArray;->obtain(Landroid/content/res/Resources;I)Landroid/content/res/TypedArray;
+Landroid/provider/Settings$System;->getUriFor(Ljava/lang/String;)Landroid/net/Uri;
+Landroid/util/MapCollections$ArrayIterator;->next()Ljava/lang/Object;
+Landroid/view/DisplayAdjustments;-><init>()V
+Landroid/view/DisplayAdjustments;-><init>(Landroid/content/res/Configuration;)V
+Landroid/view/DisplayAdjustments;-><init>(Landroid/view/DisplayAdjustments;)V
+Landroid/hardware/display/DisplayManager;->getOrCreateDisplayLocked(IZ)Landroid/view/Display;
+Landroid/content/res/Resources;->getIntArray(I)[I
+Landroid/content/res/StringBlock;->get(I)Ljava/lang/CharSequence;
+Landroid/content/res/XmlBlock$Parser;->getText()Ljava/lang/String;
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid$Wakelock;-><init>(Lcom/android/internal/os/BatteryStatsImpl;Lcom/android/internal/os/BatteryStatsImpl$Uid;)V
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->readSyncSummaryFromParcelLocked(Ljava/lang/String;Landroid/os/Parcel;)V
+Landroid/hardware/display/DisplayManagerGlobal;->getDisplayInfo(I)Landroid/view/DisplayInfo;
+Landroid/os/FileUtils;->readTextFile(Ljava/io/File;ILjava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/app/procstats/ProcessStats;->buildTimePeriodStartClockStr()V
+Landroid/text/format/DateFormat;->format(Ljava/lang/CharSequence;J)Ljava/lang/CharSequence;
+Landroid/text/format/DateFormat;->format(Ljava/lang/CharSequence;Ljava/util/Calendar;)Ljava/lang/CharSequence;
+Landroid/text/format/DateFormat;->format(Ljava/lang/CharSequence;Ljava/util/Date;)Ljava/lang/CharSequence;
+Landroid/telephony/TelephonyManager;->from(Landroid/content/Context;)Landroid/telephony/TelephonyManager;
+Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->getRealtime(J)J
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->writeSummaryToParcelLocked(Landroid/os/Parcel;Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;)V
+Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->access$2600(Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;Landroid/os/Parcel;)V
+Landroid/os/Parcel;->unmarshall([BII)V
+Landroid/content/pm/PackageParser$Package;->fixupOwner(Ljava/util/List;)V
+Landroid/content/res/Resources;->getBoolean(I)Z
+Landroid/content/res/AssetManager;->getResourceText(I)Ljava/lang/CharSequence;
+Landroid/content/res/AssetManager;->getResourceTextArray(I)[Ljava/lang/CharSequence;
+Landroid/content/res/Resources;->getText(I)Ljava/lang/CharSequence;
+HPLandroid/content/res/Resources;->getText(ILjava/lang/CharSequence;)Ljava/lang/CharSequence;
+Landroid/content/res/Resources;->getTextArray(I)[Ljava/lang/CharSequence;
+Landroid/os/MessageQueue;->next()Landroid/os/Message;
+Landroid/os/Parcel;->marshall()[B
+Lcom/android/internal/logging/EventLogTags;->writeCommitSysConfigFile(Ljava/lang/String;J)V
+Landroid/os/ThreadLocalWorkSource;->restore(J)V
+Landroid/os/Looper;->prepare()V
+Landroid/os/Looper;->prepareMainLooper()V
+Lcom/android/internal/app/procstats/ProcessStats;->splitAndParseNumbers(Ljava/lang/String;)[I
+Landroid/os/Trace;->traceEnd(J)V
+Landroid/os/Parcel;->readExceptionCode()I
+Landroid/os/Parcel;->readException()V
+Landroid/os/Parcel;->readException(ILjava/lang/String;)V
+Lcom/android/internal/util/StatLogger;->logDurationStat(IJ)J
+Landroid/content/res/ResourcesImpl$ThemeImpl;->applyStyle(IZ)V
+Landroid/content/res/Resources$Theme;->applyStyle(IZ)V
+Landroid/content/res/AssetManager;->applyStyleToTheme(JIZ)V
+Landroid/os/Trace;->isTagEnabled(J)Z
+Lcom/android/internal/util/ArrayUtils;->containsAll([Ljava/lang/Object;[Ljava/lang/Object;)Z
+Landroid/os/Trace;->traceBegin(JLjava/lang/String;)V
+Landroid/hardware/display/DisplayManager;-><init>(Landroid/content/Context;)V
+Landroid/os/Bundle;-><init>()V
+Landroid/os/Bundle;-><init>(I)V
+Landroid/os/Bundle;-><init>(Landroid/os/Bundle;)V
+Landroid/os/Bundle;-><init>(Landroid/os/PersistableBundle;)V
+Landroid/content/pm/PackageBackwardCompatibility;->updatePackage(Landroid/content/pm/PackageParser$Package;)V
+Landroid/content/pm/PackageBackwardCompatibility;->modifySharedLibraries(Landroid/content/pm/PackageParser$Package;)V
+Landroid/content/pm/Signature;->areExactMatch([Landroid/content/pm/Signature;[Landroid/content/pm/Signature;)Z
+Lcom/android/internal/util/ArrayUtils;->contains(Ljava/util/Collection;Ljava/lang/Object;)Z
+Lcom/android/internal/util/ArrayUtils;->contains([II)Z
+Lcom/android/internal/util/ArrayUtils;->contains([Ljava/lang/Object;Ljava/lang/Object;)Z
+Lcom/android/internal/util/ConcurrentUtils$1;->newThread(Ljava/lang/Runnable;)Ljava/lang/Thread;
+Landroid/os/PowerManager;-><init>(Landroid/content/Context;Landroid/os/IPowerManager;Landroid/os/Handler;)V
+Landroid/content/res/AssetManager;->getResourceArray(I[I)I
+Landroid/content/res/AssetManager;->getResourceArraySize(I)I
+Landroid/app/WindowConfiguration;-><init>()V
+Landroid/view/SurfaceControl;->getPhysicalDisplayIds()[J
+Lcom/android/internal/os/BackgroundThread;->getHandler()Landroid/os/Handler;
+Landroid/net/Uri$StringUri;->buildUpon()Landroid/net/Uri$Builder;
+Lcom/android/internal/os/AtomicFile;->readFully()[B
+Lcom/android/internal/util/ArrayUtils;->indexOf([Ljava/lang/Object;Ljava/lang/Object;)I
+Landroid/content/res/ResourcesImpl;->loadXmlResourceParser(Ljava/lang/String;IILjava/lang/String;)Landroid/content/res/XmlResourceParser;
+Landroid/content/res/Resources;->loadXmlResourceParser(ILjava/lang/String;)Landroid/content/res/XmlResourceParser;
+Landroid/content/res/Resources;->getXml(I)Landroid/content/res/XmlResourceParser;
+Landroid/content/res/XmlBlock$Parser;->next()I
+Landroid/content/res/XmlBlock$Parser;->nextTag()I
+Landroid/content/res/XmlBlock$Parser;->nextText()Ljava/lang/String;
+Lcom/google/android/collect/Sets;->newArraySet()Landroid/util/ArraySet;
+Lcom/google/android/collect/Sets;->newArraySet([Ljava/lang/Object;)Landroid/util/ArraySet;
+Landroid/util/ArraySet;->contains(Ljava/lang/Object;)Z
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->getSensorTimerLocked(IZ)Lcom/android/internal/os/BatteryStatsImpl$DualTimer;
+Landroid/content/pm/PackageParser$SigningDetails;->hasCertificate(Landroid/content/pm/Signature;)Z
+Landroid/content/pm/PackageParser$SigningDetails;->hasCertificateInternal(Landroid/content/pm/Signature;I)Z
+Landroid/content/res/XmlBlock$Parser;->getAttributeValue(I)Ljava/lang/String;
+Landroid/content/res/XmlBlock$Parser;->getAttributeValue(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/os/BatteryStatsImpl;->detachIfNotNull(Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V
+Lcom/android/internal/os/BatteryStatsImpl;->detachIfNotNull([Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V
+Lcom/android/internal/os/BatteryStatsImpl;->detachIfNotNull([[Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V
+Landroid/util/Spline$MonotoneCubicSpline;-><init>([F[F)V
+Landroid/content/res/Configuration;->setTo(Landroid/content/res/Configuration;)V
+Landroid/content/res/Configuration;->setToDefaults()V
+Lcom/android/server/SystemConfig;->readSplitPermission(Lorg/xmlpull/v1/XmlPullParser;Ljava/io/File;)V
+Lcom/android/internal/os/RpmStats;->getSubsystem(Ljava/lang/String;)Lcom/android/internal/os/RpmStats$PowerStateSubsystem;
+Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->computeRealtime(JI)J
+Landroid/os/Parcel;->dataPosition()I
+Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->getCurrentDurationMsLocked(J)J
+Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->checkPrecondition(Lcom/android/internal/os/KernelCpuProcStringReader$ProcFileIterator;)Z
+Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->computeRunTimeLocked(J)J
+Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->computeCurrentCountLocked()I
+Lcom/android/internal/os/KernelMemoryBandwidthStats;->parseStats(Ljava/io/BufferedReader;)V
+Landroid/util/MapCollections;->getEntrySet()Ljava/util/Set;
+Landroid/util/MapCollections$EntrySet;->iterator()Ljava/util/Iterator;
+Lcom/android/internal/os/BatteryStatsImpl$Uid;->writeJobCompletionsToParcelLocked(Landroid/os/Parcel;)V
+Landroid/os/Parcel;->readBundle()Landroid/os/Bundle;
+Landroid/os/Parcel;->readBundle(Ljava/lang/ClassLoader;)Landroid/os/Bundle;
+Landroid/content/res/Resources;->getString(I)Ljava/lang/String;
+Landroid/content/res/Resources;->getString(I[Ljava/lang/Object;)Ljava/lang/String;
+Landroid/content/res/Resources;->getStringArray(I)[Ljava/lang/String;
+Landroid/os/ThreadLocalWorkSource;->setUid(I)J
+Landroid/content/pm/PackageParser;->parseClusterPackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parseClusterPackageLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$PackageLite;
+Landroid/content/pm/split/DefaultSplitAssetLoader;->getBaseAssetManager()Landroid/content/res/AssetManager;
+Landroid/content/pm/PackageParser;->parseBaseApk(Ljava/io/File;Landroid/content/res/AssetManager;I)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parseBaseApk(Ljava/lang/String;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parseBaseApkCommon(Landroid/content/pm/PackageParser$Package;Ljava/util/Set;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->cacheResult(Ljava/io/File;ILandroid/content/pm/PackageParser$Package;)V
+Landroid/content/pm/PackageParser;->parseMonolithicPackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser;->parseMonolithicPackageLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$PackageLite;
+Landroid/content/pm/PackageParser;->parseApkLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$ApkLite;
+Landroid/content/pm/PackageParser;->parseApkLite(Ljava/lang/String;Lorg/xmlpull/v1/XmlPullParser;Landroid/util/AttributeSet;Landroid/content/pm/PackageParser$SigningDetails;)Landroid/content/pm/PackageParser$ApkLite;
+Landroid/content/pm/PackageParser;->parseApkLiteInner(Ljava/io/File;Ljava/io/FileDescriptor;Ljava/lang/String;I)Landroid/content/pm/PackageParser$ApkLite;
+Landroid/content/pm/PackageParser;->toCacheEntry(Landroid/content/pm/PackageParser$Package;)[B
+Landroid/content/pm/PackageParser;->parseBaseApplication(Landroid/content/pm/PackageParser$Package;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Z
+Landroid/os/Parcel;->writeParcelable(Landroid/os/Parcelable;I)V
+Landroid/os/Parcel;->writeParcelableArray([Landroid/os/Parcelable;I)V
+Landroid/os/Parcel;->writeParcelableCreator(Landroid/os/Parcelable;)V
+Landroid/os/Parcel;->writeParcelableList(Ljava/util/List;I)V
+Landroid/content/pm/PackageParser$Package;->writeToParcel(Landroid/os/Parcel;I)V
+Landroid/content/res/Resources;->obtainAttributes(Landroid/util/AttributeSet;[I)Landroid/content/res/TypedArray;
+Landroid/content/res/Resources;->obtainAttributes(Landroid/content/res/Resources;Landroid/content/res/Resources$Theme;Landroid/util/AttributeSet;[I)Landroid/content/res/TypedArray;
+Landroid/content/pm/split/DefaultSplitAssetLoader;->close()V
+Landroid/content/res/AssetManager;->openXmlResourceParser(ILjava/lang/String;)Landroid/content/res/XmlResourceParser;
+Landroid/content/res/AssetManager;->close()V
+Landroid/content/res/AssetManager;->openXmlBlockAsset(ILjava/lang/String;)Landroid/content/res/XmlBlock;
+Landroid/content/pm/PackageParser;->generateAppDetailsHiddenActivity(Landroid/content/pm/PackageParser$Package;I[Ljava/lang/String;Z)Landroid/content/pm/PackageParser$Activity;
+Landroid/content/pm/split/DefaultSplitAssetLoader;->loadApkAssets(Ljava/lang/String;I)Landroid/content/res/ApkAssets;
+Landroid/content/pm/PackageParser$Activity;->writeToParcel(Landroid/os/Parcel;I)V
+Landroid/os/FileUtils;->trimFilename(Ljava/lang/StringBuilder;I)V
+Landroid/content/res/ApkAssets;->openXml(Ljava/lang/String;)Landroid/content/res/XmlResourceParser;
+Landroid/content/res/Configuration;->setLocales(Landroid/os/LocaleList;)V
+Landroid/content/pm/PackageParser;->buildTaskAffinityName(Ljava/lang/String;Ljava/lang/String;Ljava/lang/CharSequence;[Ljava/lang/String;)Ljava/lang/String;
+Landroid/content/res/AssetManager;->retrieveAttributes(Landroid/content/res/XmlBlock$Parser;[I[I[I)Z
+Landroid/content/pm/PackageParser;->buildCompoundName(Ljava/lang/String;Ljava/lang/CharSequence;Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/String;
+Landroid/content/pm/ActivityInfo;->writeToParcel(Landroid/os/Parcel;I)V
+Landroid/content/res/XmlBlock$Parser;->close()V
+Landroid/content/pm/PackageParser;->validateName(Ljava/lang/String;ZZ)Ljava/lang/String;
+Landroid/util/ArraySet;->equals(Ljava/lang/Object;)Z
+Landroid/content/pm/PackageItemInfo;->writeToParcel(Landroid/os/Parcel;I)V
+Landroid/content/pm/PackageParserCacheHelper$WriteHelper;->finishAndUninstall()V
+Landroid/content/res/TypedArray;->loadStringValueAt(I)Ljava/lang/CharSequence;
+Landroid/content/pm/ApplicationInfo;->writeToParcel(Landroid/os/Parcel;I)V
+Landroid/os/FileUtils;->isValidExtFilename(Ljava/lang/String;)Z
+Landroid/content/res/AssetManager;->findCookieForPath(Ljava/lang/String;)I
+Landroid/content/res/TypedArray;->getNonConfigurationString(II)Ljava/lang/String;
+Landroid/content/res/TypedArray;->peekValue(I)Landroid/util/TypedValue;
+Landroid/app/ActivityThread;->attach(ZJ)V
+Landroid/content/res/TypedArray;->getValueAt(ILandroid/util/TypedValue;)Z
+Landroid/content/res/XmlBlock$Parser;->getAttributeName(I)Ljava/lang/String;
+Landroid/content/res/XmlBlock$Parser;->getAttributeNameResource(I)I
+Landroid/content/pm/PackageParser$ApkLite;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;ZIIIILjava/util/List;Landroid/content/pm/PackageParser$SigningDetails;ZZZZZZZII)V
+Landroid/app/ResourcesManager;->createAssetManager(Landroid/content/res/ResourcesKey;)Landroid/content/res/AssetManager;
+Landroid/content/res/AssetManager$Builder;->build()Landroid/content/res/AssetManager;
+Landroid/os/FileUtils;->deleteContents(Ljava/io/File;)Z
+Landroid/os/FileUtils;->deleteContentsAndDir(Ljava/io/File;)Z
+Landroid/content/res/ResourcesImpl;->adjustLanguageTag(Ljava/lang/String;)Ljava/lang/String;
+Landroid/sysprop/DisplayProperties;->tryParseBoolean(Ljava/lang/String;)Ljava/lang/Boolean;
+Landroid/content/pm/PackageParserCacheHelper$WriteHelper;-><init>(Landroid/os/Parcel;)V
+Landroid/content/pm/PackageParser$Package;->getLongVersionCode()J
+Lcom/android/internal/util/function/pooled/OmniFunction;->run()V
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+Landroid/os/SystemProperties;->get(Ljava/lang/String;)Ljava/lang/String;
+Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Landroid/os/SystemProperties;->getInt(Ljava/lang/String;I)I
+Landroid/os/SystemProperties;->getLong(Ljava/lang/String;J)J
+Landroid/content/res/ThemedResourceCache;->onConfigurationChange(I)V
+Landroid/content/res/TypedArray;->recycle()V
+Landroid/content/res/Configuration;->fixUpLocaleList()V
+Landroid/content/res/XmlBlock;->newParser(I)Landroid/content/res/XmlResourceParser;
+Landroid/content/pm/ComponentInfo;->writeToParcel(Landroid/os/Parcel;I)V
+Landroid/content/res/ApkAssets;->getAssetPath()Ljava/lang/String;
+Landroid/util/MapCollections$MapIterator;->next()Ljava/lang/Object;
+Landroid/content/res/ResourcesImpl;->flushLayoutCache()V
+Landroid/os/FileUtils;->buildValidExtFilename(Ljava/lang/String;)Ljava/lang/String;
+Landroid/content/res/ApkAssets;->getStringFromPool(I)Ljava/lang/CharSequence;
+Landroid/content/pm/Signature;->equals(Ljava/lang/Object;)Z
+Landroid/content/pm/PackageUserState;->equals(Ljava/lang/Object;)Z
+Landroid/util/ArrayMap$1;->colGetEntry(II)Ljava/lang/Object;
+Lcom/android/internal/os/BackgroundThread;->ensureThreadLocked()V
+Landroid/app/ActivityThread;-><init>()V
+Landroid/app/ActivityThread;->getSystemContext()Landroid/app/ContextImpl;
+Landroid/app/ContextImpl;->createSystemContext(Landroid/app/ActivityThread;)Landroid/app/ContextImpl;
+Landroid/app/ContextImpl;-><init>(Landroid/app/ContextImpl;Landroid/app/ActivityThread;Landroid/app/LoadedApk;Ljava/lang/String;Landroid/os/IBinder;Landroid/os/UserHandle;ILjava/lang/ClassLoader;Ljava/lang/String;)V
+Landroid/app/ResourcesManager;->getDisplayMetrics()Landroid/util/DisplayMetrics;
+Landroid/app/ResourcesManager;->getDisplayMetrics(ILandroid/view/DisplayAdjustments;)Landroid/util/DisplayMetrics;
+Landroid/content/pm/PackageParser$Package;->setApplicationVolumeUuid(Ljava/lang/String;)V
+Landroid/content/pm/AndroidHidlUpdater;->updatePackage(Landroid/content/pm/PackageParser$Package;)V
+Landroid/content/res/ApkAssets;->close()V
+Landroid/content/res/XmlBlock$Parser;->getAttributeBooleanValue(IZ)Z
+Landroid/content/res/XmlBlock$Parser;->getAttributeBooleanValue(Ljava/lang/String;Ljava/lang/String;Z)Z
+Landroid/content/pm/PackageParser;->setMaxAspectRatio(Landroid/content/pm/PackageParser$Package;)V
+Landroid/content/pm/PackageParserCacheHelper$WriteHelper;->writeString(Landroid/os/Parcel;Ljava/lang/String;)V
+Landroid/os/Parcel;->writeTypedList(Ljava/util/List;)V
+Landroid/os/Parcel;->writeTypedList(Ljava/util/List;I)V
+Landroid/content/res/Configuration;->getLocales()Landroid/os/LocaleList;
+Landroid/view/DisplayEventReceiver;-><init>(Landroid/os/Looper;I)V
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->doInvoke()Ljava/lang/Object;
+Landroid/content/pm/PackageSharedLibraryUpdater;->prefixImplicitDependency(Landroid/content/pm/PackageParser$Package;Ljava/lang/String;Ljava/lang/String;)V
+Landroid/util/MapCollections$MapIterator;->getKey()Ljava/lang/Object;
+Landroid/util/MapCollections$ValuesCollection;->iterator()Ljava/util/Iterator;
+Lcom/android/internal/os/BatteryStatsImpl$SystemClocks;->elapsedRealtime()J
+Landroid/app/LoadedApk;->makeApplication(ZLandroid/app/Instrumentation;)Landroid/app/Application;
+Landroid/content/pm/IntentFilterVerificationInfo;->getIntFromXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;I)I
+Landroid/content/res/ResourcesImpl;->calcConfigChanges(Landroid/content/res/Configuration;)I
+Landroid/content/pm/PackageBackwardCompatibility$AndroidTestRunnerSplitUpdater;->updatePackage(Landroid/content/pm/PackageParser$Package;)V
+Landroid/util/SparseArray;->valueAt(I)Ljava/lang/Object;
+Landroid/util/ArraySet;->ensureCapacity(I)V
+Landroid/os/storage/StorageManager;->convert(Ljava/lang/String;)Ljava/util/UUID;
+Landroid/os/storage/StorageManager;->convert(Ljava/util/UUID;)Ljava/lang/String;
+Landroid/content/pm/PackageParser;->checkOverlayRequiredSystemProperty(Ljava/lang/String;Ljava/lang/String;)Z
+Landroid/content/res/ThemedResourceCache;->prune(I)Z
+Landroid/content/res/ThemedResourceCache;->pruneEntriesLocked(Landroid/util/LongSparseArray;I)Z
+Landroid/util/Pools$SynchronizedPool;->acquire()Ljava/lang/Object;
+Landroid/content/res/XmlBlock$Parser;->getAttributeCount()I
+Landroid/content/pm/PackageParser;->parseMetaData(Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;Landroid/os/Bundle;[Ljava/lang/String;)Landroid/os/Bundle;
+Landroid/content/res/Resources;->getDisplayMetrics()Landroid/util/DisplayMetrics;
+Landroid/text/TextUtils;->writeToParcel(Ljava/lang/CharSequence;Landroid/os/Parcel;I)V
+Landroid/view/DisplayAdjustments;->setCompatibilityInfo(Landroid/content/res/CompatibilityInfo;)V
+Landroid/content/res/CompatibilityInfo;->applyToDisplayMetrics(Landroid/util/DisplayMetrics;)V
+Landroid/content/res/TypedArray;->getString(I)Ljava/lang/String;
+Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->getUpdateVersion()I
+Landroid/os/ResultReceiver;->send(ILandroid/os/Bundle;)V
+Lcom/android/internal/os/ProcessCpuTracker;->getCpuTimeForPid(I)J
+Landroid/os/FileUtils;->contains(Ljava/io/File;Ljava/io/File;)Z
+Landroid/os/FileUtils;->contains(Ljava/lang/String;Ljava/lang/String;)Z
+Landroid/content/pm/PackageParser$SigningDetails;->checkCapability(Landroid/content/pm/PackageParser$SigningDetails;I)Z
+Landroid/util/MapCollections$MapIterator;->getValue()Ljava/lang/Object;
+Landroid/os/BinderProxy$ProxyMap;->get(J)Landroid/os/BinderProxy;
+Landroid/util/TimingsTraceLog;-><init>(Ljava/lang/String;J)V
+Landroid/os/PowerManager;->newWakeLock(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;
+Landroid/content/ComponentName;->hashCode()I
+Landroid/util/MapCollections$ArrayIterator;->hasNext()Z
+Landroid/app/IActivityTaskManager$Stub;-><init>()V
+Lcom/android/internal/os/ProcessCpuTracker;-><init>(Z)V
+Lcom/android/internal/util/RingBuffer;-><init>(Ljava/lang/Class;I)V
+Lcom/android/server/LocalServices;->getService(Ljava/lang/Class;)Ljava/lang/Object;
+Lcom/android/internal/util/XmlUtils;->readStringAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/os/BatteryStatsImpl;->setPowerProfileLocked(Lcom/android/internal/os/PowerProfile;)V
+Lcom/android/internal/os/BatteryStatsImpl;->readDailyStatsLocked()V
+Lcom/android/internal/widget/LockPatternUtils;-><init>(Landroid/content/Context;)V
+Landroid/text/SpannableStringBuilder;->replace(IILjava/lang/CharSequence;)Landroid/text/Editable;
+Landroid/text/SpannableStringBuilder;->replace(IILjava/lang/CharSequence;)Landroid/text/SpannableStringBuilder;
+Landroid/text/SpannableStringBuilder;->replace(IILjava/lang/CharSequence;II)Landroid/text/SpannableStringBuilder;
+Landroid/content/res/Resources;->newTheme()Landroid/content/res/Resources$Theme;
+Landroid/os/Parcel;->obtain()Landroid/os/Parcel;
+Landroid/os/Parcel;->obtain(J)Landroid/os/Parcel;
+Landroid/content/res/Configuration;->updateFrom(Landroid/content/res/Configuration;)I
+Landroid/app/ContextImpl;->createAppContext(Landroid/app/ActivityThread;Landroid/app/LoadedApk;)Landroid/app/ContextImpl;
+Landroid/app/ContextImpl;->createAppContext(Landroid/app/ActivityThread;Landroid/app/LoadedApk;Ljava/lang/String;)Landroid/app/ContextImpl;
+Landroid/util/SparseArray;->clear()V
+Landroid/util/ArrayMap;->remove(Ljava/lang/Object;)Ljava/lang/Object;
+Landroid/util/ArrayMap;->removeAt(I)Ljava/lang/Object;
+Landroid/os/Parcel;->writeBundle(Landroid/os/Bundle;)V
+Landroid/content/pm/PackageParser;->hasDomainURLs(Landroid/content/pm/PackageParser$Package;)Z
+Landroid/util/Pools$SynchronizedPool;->release(Ljava/lang/Object;)Z
+Landroid/os/Parcel;->setDataPosition(I)V
+Landroid/os/LocaleList;->getDefault()Landroid/os/LocaleList;
+Landroid/content/res/ConfigurationBoundResourceCache;->onConfigurationChange(I)V
+Landroid/util/DisplayMetrics;->setToDefaults()V
+Landroid/content/pm/PackageParser;->computeMinSdkVersion(ILjava/lang/String;I[Ljava/lang/String;[Ljava/lang/String;)I
+Lcom/android/internal/os/ProcessCpuTracker;->onMeasureProcessName(Ljava/lang/String;)I
+Lcom/android/server/SystemConfig$SharedLibraryEntry;-><init>(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V
+Landroid/util/MapCollections;->getKeySet()Ljava/util/Set;
+Landroid/content/ComponentName;->unflattenFromString(Ljava/lang/String;)Landroid/content/ComponentName;
+Landroid/util/Slog;->e(Ljava/lang/String;Ljava/lang/String;)I
+Landroid/util/Slog;->e(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I
+Landroid/os/SynchronousResultReceiver;->awaitResult(J)Landroid/os/SynchronousResultReceiver$Result;
+Landroid/os/SynchronousResultReceiver;->onReceiveResult(ILandroid/os/Bundle;)V
+Landroid/view/SurfaceControl;->getHdrCapabilities(Landroid/os/IBinder;)Landroid/view/Display$HdrCapabilities;
+Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->doRecycle()V
+Landroid/os/Handler;->postAtFrontOfQueue(Ljava/lang/Runnable;)Z
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f655c89..f4df6b7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -808,7 +808,9 @@
     /*package*/ ActivityInfo mActivityInfo;
     @UnsupportedAppUsage
     /*package*/ ActivityThread mMainThread;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.fragment.app.Fragment} and "
+                    + "{@code androidx.fragment.app.FragmentManager} instead")
     Activity mParent;
     @UnsupportedAppUsage
     boolean mCalled;
@@ -1547,7 +1549,9 @@
      * had previously been frozen by {@link #onSaveInstanceState}.
      *
      * <p>This method is called between {@link #onStart} and
-     * {@link #onPostCreate}.
+     * {@link #onPostCreate}. This method is called only when recreating
+     * an activity; the method isn't invoked if {@link #onStart} is called for
+     * any other reason.</p>
      *
      * @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
      *
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 69e7118..1fd7e52 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -127,17 +127,6 @@
     public abstract void setHasOverlayUi(int pid, boolean hasOverlayUi);
 
     /**
-     * Sets if the given pid is currently running a remote animation, which is taken a signal for
-     * determining oom adjustment and scheduling behavior.
-     *
-     * @param pid The pid we are setting overlay UI for.
-     * @param runningRemoteAnimation True if the process is running a remote animation, false
-     *                               otherwise.
-     * @see RemoteAnimationAdapter
-     */
-    public abstract void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation);
-
-    /**
      * Called after the network policy rules are updated by
      * {@link com.android.server.net.NetworkPolicyManagerService} for a specific {@param uid} and
      * {@param procStateSeq}.
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 415ec64..e891828 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -120,8 +120,10 @@
 
         mActivityTaskManager = ActivityTaskManager.getService();
         mSurfaceView = new SurfaceView(context);
+        // Since ActivityView#getAlpha has been overridden, we should use parent class's alpha
+        // as master to synchronize surface view's alpha value.
+        mSurfaceView.setAlpha(super.getAlpha());
         mSurfaceView.setUseAlpha();
-        mSurfaceView.setAlpha(0f);
         mSurfaceCallback = new SurfaceCallback();
         mSurfaceView.getHolder().addCallback(mSurfaceCallback);
         addView(mSurfaceView);
@@ -348,9 +350,20 @@
         mSurfaceView.layout(0 /* left */, 0 /* top */, r - l /* right */, b - t /* bottom */);
     }
 
+    /**
+     * Sets the alpha value when the content of {@link SurfaceView} needs to show or hide.
+     * <p>Note: The surface view may ignore the alpha value in some cases. Refer to
+     * {@link SurfaceView#setAlpha} for more details.
+     *
+     * @param alpha The opacity of the view.
+     */
     @Override
     public void setAlpha(float alpha) {
-        mSurfaceView.setAlpha(alpha);
+        super.setAlpha(alpha);
+
+        if (mSurfaceView != null) {
+            mSurfaceView.setAlpha(alpha);
+        }
     }
 
     @Override
diff --git a/core/java/android/app/DisabledWallpaperManager.java b/core/java/android/app/DisabledWallpaperManager.java
new file mode 100644
index 0000000..5185941
--- /dev/null
+++ b/core/java/android/app/DisabledWallpaperManager.java
@@ -0,0 +1,346 @@
+/*
+ * 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.app;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A no-op implementation of {@link WallpaperManager}.
+ */
+final class DisabledWallpaperManager extends WallpaperManager {
+
+    private static final String TAG = DisabledWallpaperManager.class.getSimpleName();
+
+    // Don't need to worry about synchronization
+    private static DisabledWallpaperManager sInstance;
+
+    // TODO(b/138939803): STOPSHIP changed to false and/or remove it
+    private static final boolean DEBUG = true;
+
+    @NonNull
+    static DisabledWallpaperManager getInstance() {
+        if (sInstance == null) {
+            sInstance = new DisabledWallpaperManager();
+        }
+        return sInstance;
+    }
+
+    private DisabledWallpaperManager() {
+        super(null, null, null);
+    }
+
+    @Override
+    public boolean isWallpaperSupported() {
+        return false;
+    }
+
+    @Override
+    public boolean isSetWallpaperAllowed() {
+        return false;
+    }
+
+    // TODO(b/138939803): STOPSHIP methods below should not be necessary,
+    // callers should check if isWallpaperSupported(), consider removing them to keep this class
+    // simpler
+
+    private static <T> T unsupported() {
+        if (DEBUG) Log.w(TAG, "unsupported method called; returning null", new Exception());
+        return null;
+    }
+
+    private static boolean unsupportedBoolean() {
+        if (DEBUG) Log.w(TAG, "unsupported method called; returning false", new Exception());
+        return false;
+    }
+
+    @Override
+    public Drawable getDrawable() {
+        return unsupported();
+    }
+
+    @Override
+    public Drawable getBuiltInDrawable() {
+        return unsupported();
+    }
+
+    @Override
+    public Drawable getBuiltInDrawable(int which) {
+        return unsupported();
+    }
+
+    @Override
+    public Drawable getBuiltInDrawable(int outWidth, int outHeight, boolean scaleToFit,
+            float horizontalAlignment, float verticalAlignment) {
+        return unsupported();
+    }
+
+    @Override
+    public Drawable getBuiltInDrawable(int outWidth, int outHeight, boolean scaleToFit,
+            float horizontalAlignment, float verticalAlignment, int which) {
+        return unsupported();
+    }
+
+    @Override
+    public Drawable peekDrawable() {
+        return unsupported();
+    }
+
+    @Override
+    public Drawable getFastDrawable() {
+        return unsupported();
+    }
+
+    @Override
+    public Drawable peekFastDrawable() {
+        return unsupported();
+    }
+
+    @Override
+    public Bitmap getBitmap() {
+        return unsupported();
+    }
+
+    @Override
+    public Bitmap getBitmap(boolean hardware) {
+        return unsupported();
+    }
+
+    @Override
+    public Bitmap getBitmapAsUser(int userId, boolean hardware) {
+        return unsupported();
+    }
+
+    @Override
+    public ParcelFileDescriptor getWallpaperFile(int which) {
+        return unsupported();
+    }
+
+    @Override
+    public void addOnColorsChangedListener(OnColorsChangedListener listener, Handler handler) {
+        unsupported();
+    }
+
+    @Override
+    public void addOnColorsChangedListener(OnColorsChangedListener listener, Handler handler,
+            int userId) {
+        unsupported();
+    }
+
+    @Override
+    public void removeOnColorsChangedListener(OnColorsChangedListener callback) {
+        unsupported();
+    }
+
+    @Override
+    public void removeOnColorsChangedListener(OnColorsChangedListener callback, int userId) {
+        unsupported();
+    }
+
+    @Override
+    public WallpaperColors getWallpaperColors(int which) {
+        return unsupported();
+    }
+
+    @Override
+    public WallpaperColors getWallpaperColors(int which, int userId) {
+        return unsupported();
+    }
+
+    @Override
+    public ParcelFileDescriptor getWallpaperFile(int which, int userId) {
+        return unsupported();
+    }
+
+    @Override
+    public void forgetLoadedWallpaper() {
+        unsupported();
+    }
+
+    @Override
+    public WallpaperInfo getWallpaperInfo() {
+        return unsupported();
+    }
+
+    @Override
+    public WallpaperInfo getWallpaperInfo(int userId) {
+        return unsupported();
+    }
+
+    @Override
+    public int getWallpaperId(int which) {
+        return unsupported();
+    }
+
+    @Override
+    public int getWallpaperIdForUser(int which, int userId) {
+        return unsupported();
+    }
+
+    @Override
+    public Intent getCropAndSetWallpaperIntent(Uri imageUri) {
+        return unsupported();
+    }
+
+    @Override
+    public void setResource(int resid) throws IOException {
+        unsupported();
+    }
+
+    @Override
+    public int setResource(int resid, int which) throws IOException {
+        return unsupported();
+    }
+
+    @Override
+    public void setBitmap(Bitmap bitmap) throws IOException {
+        unsupported();
+    }
+
+    @Override
+    public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
+            throws IOException {
+        return unsupported();
+    }
+
+    @Override
+    public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup, int which)
+            throws IOException {
+        return unsupported();
+    }
+
+    @Override
+    public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup, int which,
+            int userId) throws IOException {
+        return unsupported();
+    }
+
+    @Override
+    public void setStream(InputStream bitmapData) throws IOException {
+        unsupported();
+    }
+
+    @Override
+    public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
+            throws IOException {
+        return unsupported();
+    }
+
+    @Override
+    public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup,
+            int which) throws IOException {
+        return unsupported();
+    }
+
+    @Override
+    public boolean hasResourceWallpaper(int resid) {
+        return unsupportedBoolean();
+    }
+
+    @Override
+    public int getDesiredMinimumWidth() {
+        return unsupported();
+    }
+
+    @Override
+    public int getDesiredMinimumHeight() {
+        return unsupported();
+    }
+
+    @Override
+    public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
+        unsupported();
+    }
+
+    @Override
+    public void setDisplayPadding(Rect padding) {
+        unsupported();
+    }
+
+    @Override
+    public void setDisplayOffset(IBinder windowToken, int x, int y) {
+        unsupported();
+    }
+
+    @Override
+    public void clearWallpaper() {
+        unsupported();
+    }
+
+    @Override
+    public void clearWallpaper(int which, int userId) {
+        unsupported();
+    }
+
+    @Override
+    public boolean setWallpaperComponent(ComponentName name) {
+        return unsupportedBoolean();
+    }
+
+    @Override
+    public boolean setWallpaperComponent(ComponentName name, int userId) {
+        return unsupportedBoolean();
+    }
+
+    @Override
+    public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
+        unsupported();
+    }
+
+    @Override
+    public void setWallpaperOffsetSteps(float xStep, float yStep) {
+        unsupported();
+    }
+
+    @Override
+    public void sendWallpaperCommand(IBinder windowToken, String action, int x, int y, int z,
+            Bundle extras) {
+        unsupported();
+    }
+
+    @Override
+    public void clearWallpaperOffsets(IBinder windowToken) {
+        unsupported();
+    }
+
+    @Override
+    public void clear() throws IOException {
+        unsupported();
+    }
+
+    @Override
+    public void clear(int which) throws IOException {
+        unsupported();
+    }
+
+    @Override
+    public boolean isWallpaperBackupEligible(int which) {
+        return unsupportedBoolean();
+    }
+}
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 650147b..61867ea 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -185,4 +185,9 @@
      * @param newDisplayId id of the new display.
      */
     void onTaskDisplayChanged(int taskId, int newDisplayId);
+
+    /**
+     * Called when any additions or deletions to the recent tasks list have been made.
+     */
+    void onRecentTaskListUpdated();
 }
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 19575b2..87b064d 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.Window;
@@ -74,23 +75,33 @@
     /** Thread our activities are running in. */
     private final ActivityThread mActivityThread;
     /** The containing activity that owns the activities we create. */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.fragment.app.Fragment} and "
+                    + "{@code androidx.fragment.app.FragmentManager} instead")
     private final Activity mParent;
 
     /** The activity that is currently resumed. */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.fragment.app.Fragment} and "
+                    + "{@code androidx.fragment.app.FragmentManager} instead")
     private LocalActivityRecord mResumed;
     /** id -> record of all known activities. */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.fragment.app.Fragment} and "
+                    + "{@code androidx.fragment.app.FragmentManager} instead")
     private final Map<String, LocalActivityRecord> mActivities
             = new HashMap<String, LocalActivityRecord>();
     /** array of all known activities for easy iterating. */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.fragment.app.Fragment} and "
+                    + "{@code androidx.fragment.app.FragmentManager} instead")
     private final ArrayList<LocalActivityRecord> mActivityArray
             = new ArrayList<LocalActivityRecord>();
 
     /** True if only one activity can be resumed at a time */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.fragment.app.Fragment} and "
+                    + "{@code androidx.fragment.app.FragmentManager} instead")
     private boolean mSingleMode;
     
     /** Set to true once we find out the container is finishing. */
@@ -117,7 +128,9 @@
         mSingleMode = singleMode;
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.fragment.app.Fragment} and "
+                    + "{@code androidx.fragment.app.FragmentManager} instead")
     private void moveToState(LocalActivityRecord r, int desiredState) {
         if (r.curState == RESTORED || r.curState == DESTROYED) {
             // startActivity() has not yet been called, so nothing to do.
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 5034b53..c58972e 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -695,11 +695,22 @@
             @Override
             public WallpaperManager createService(ContextImpl ctx)
                     throws ServiceNotFoundException {
-                final IBinder b;
-                if (ctx.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
-                    b = ServiceManager.getServiceOrThrow(Context.WALLPAPER_SERVICE);
-                } else {
-                    b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
+                final IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
+                if (b == null) {
+                    // There are 2 reason service can be null:
+                    // 1.Device doesn't support it - that's fine
+                    // 2.App is running on instant mode - should fail
+                    final boolean enabled = Resources.getSystem()
+                            .getBoolean(com.android.internal.R.bool.config_enableWallpaperService);
+                    if (!enabled) {
+                        // Life moves on...
+                        return DisabledWallpaperManager.getInstance();
+                    }
+                    if (ctx.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
+                        // Instant app
+                        throw new ServiceNotFoundException(Context.WALLPAPER_SERVICE);
+                    }
+                    // Bad state - WallpaperManager methods will throw exception
                 }
                 IWallpaperManager service = IWallpaperManager.Stub.asInterface(b);
                 return new WallpaperManager(service, ctx.getOuterContext(),
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index b63feb5..e3a0e11 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -182,4 +182,8 @@
     @Override
     public void onTaskDisplayChanged(int taskId, int newDisplayId) throws RemoteException {
     }
+
+    @Override
+    public void onRecentTaskListUpdated() throws RemoteException {
+    }
 }
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index d305238..59ecf4a 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -510,7 +510,9 @@
 
     /*package*/ WallpaperManager(IWallpaperManager service, Context context, Handler handler) {
         mContext = context;
-        initGlobals(service, context.getMainLooper());
+        if (service != null) {
+            initGlobals(service, context.getMainLooper());
+        }
     }
 
     /**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5624ba5..49cfd41 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4981,6 +4981,42 @@
         return null;
     }
 
+
+    /**
+     * Called by a device or profile owner, or delegated certificate chooser (an app that has been
+     * delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to grant an application access
+     * to an already-installed (or generated) KeyChain key.
+     * This is useful (in combination with {@link #installKeyPair} or {@link #generateKeyPair}) to
+     * let an application call {@link android.security.KeyChain#getPrivateKey} without having to
+     * call {@link android.security.KeyChain#choosePrivateKeyAlias} first.
+     *
+     * The grantee app will receive the {@link android.security.KeyChain#ACTION_KEY_ACCESS_CHANGED}
+     * broadcast when access to a key is granted or revoked.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+     *        {@code null} if calling from a delegated certificate installer.
+     * @param alias The alias of the key to grant access to.
+     * @param packageName The name of the (already installed) package to grant access to.
+     * @param hasGrant Whether to grant access to the alias or revoke it.
+     * @return {@code true} if the grant was set successfully, {@code false} otherwise.
+     *
+     * @throws SecurityException if the caller is not a device owner, a profile  owner or
+     *         delegated certificate chooser.
+     * @throws IllegalArgumentException if {@code packageName} or {@code alias} are empty, or if
+     *         {@code packageName} is not a name of an installed package.
+     */
+    public boolean setKeyGrantForApp(@Nullable ComponentName admin, @NonNull String alias,
+            @NonNull String packageName, boolean hasGrant) {
+        throwIfParentInstance("addKeyGrant");
+        try {
+            return mService.setKeyGrantForApp(
+                    admin, mContext.getPackageName(), alias, packageName, hasGrant);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return false;
+    }
+
     /**
      * Returns {@code true} if the device supports attestation of device identifiers in addition
      * to key attestation.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 2b96419..5cdef6d 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -436,4 +436,6 @@
     boolean isUnattendedManagedKiosk();
 
     boolean startViewCalendarEventInManagedProfile(String packageName, long eventId, long start, long end, boolean allDay, int flags);
+
+    boolean setKeyGrantForApp(in ComponentName admin, String callerPackage, String alias, String packageName, boolean hasGrant);
 }
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index 36f5f96..5c0ddc1 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -85,6 +85,10 @@
      */
     @Override
     public void restoreEntity(BackupDataInputStream data) {
+        if (mWpm == null) {
+            Slog.w(TAG, "restoreEntity(): no wallpaper service");
+            return;
+        }
         final String key = data.getKey();
         if (isKeyInList(key, mKeys)) {
             if (key.equals(WALLPAPER_IMAGE_KEY)) {
diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java
index dadfe3d..ecc859d 100644
--- a/core/java/android/app/job/JobParameters.java
+++ b/core/java/android/app/job/JobParameters.java
@@ -50,6 +50,19 @@
     /** @hide */
     public static final int REASON_DEVICE_THERMAL = JobProtoEnums.STOP_REASON_DEVICE_THERMAL; // 5.
 
+    /**
+     * All the stop reason codes. This should be regarded as an immutable array at runtime.
+     * @hide
+     */
+    public static final int[] JOB_STOP_REASON_CODES = {
+            REASON_CANCELED,
+            REASON_CONSTRAINTS_NOT_SATISFIED,
+            REASON_PREEMPT,
+            REASON_TIMEOUT,
+            REASON_DEVICE_IDLE,
+            REASON_DEVICE_THERMAL,
+    };
+
     /** @hide */
     public static String getReasonName(int reason) {
         switch (reason) {
@@ -58,6 +71,7 @@
             case REASON_PREEMPT: return "preempt";
             case REASON_TIMEOUT: return "timeout";
             case REASON_DEVICE_IDLE: return "device_idle";
+            case REASON_DEVICE_THERMAL: return "thermal";
             default: return "unknown:" + reason;
         }
     }
diff --git a/core/java/android/app/job/JobSchedulerFrameworkInitializer.java b/core/java/android/app/job/JobSchedulerFrameworkInitializer.java
index cf2979c..c90b872 100644
--- a/core/java/android/app/job/JobSchedulerFrameworkInitializer.java
+++ b/core/java/android/app/job/JobSchedulerFrameworkInitializer.java
@@ -19,6 +19,7 @@
 import android.app.JobSchedulerImpl;
 import android.app.SystemServiceRegistry;
 import android.content.Context;
+import android.os.BatteryStats;
 
 /**
  * This class needs to be pre-loaded by zygote.  This is where the job scheduler service wrapper
@@ -31,5 +32,8 @@
         SystemServiceRegistry.registerStaticService(
                 Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
                 (b) -> new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b)));
+
+        BatteryStats.setJobStopReasons(JobParameters.JOB_STOP_REASON_CODES,
+                JobParameters::getReasonName);
     }
 }
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 3c79991..4ea3726 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -2112,6 +2112,10 @@
                 mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
                 setAuthorities(info.authority);
             }
+            if (Build.IS_DEBUGGABLE) {
+                setTransportLoggingEnabled(Log.isLoggable(getClass().getSimpleName(),
+                        Log.VERBOSE));
+            }
             ContentProvider.this.onCreate();
         }
     }
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index c201e4d..621f331 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -16,17 +16,22 @@
 
 package android.content;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
+import android.util.SparseArray;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Represents a single operation to be performed as part of a batch of operations.
@@ -45,20 +50,23 @@
     public final static int TYPE_DELETE = 3;
     /** @hide exposed for unit tests */
     public final static int TYPE_ASSERT = 4;
+    /** @hide exposed for unit tests */
+    public final static int TYPE_CALL = 5;
 
     @UnsupportedAppUsage
     private final int mType;
     @UnsupportedAppUsage
     private final Uri mUri;
+    private final String mMethod;
+    private final String mArg;
+    private final ArrayMap<String, Object> mValues;
+    private final ArrayMap<String, Object> mExtras;
     @UnsupportedAppUsage
     private final String mSelection;
-    private final String[] mSelectionArgs;
-    private final ContentValues mValues;
+    private final SparseArray<Object> mSelectionArgs;
     private final Integer mExpectedCount;
-    private final ContentValues mValuesBackReferences;
-    private final Map<Integer, Integer> mSelectionArgsBackReferences;
     private final boolean mYieldAllowed;
-    private final boolean mFailureAllowed;
+    private final boolean mExceptionAllowed;
 
     private final static String TAG = "ContentProviderOperation";
 
@@ -69,124 +77,130 @@
     private ContentProviderOperation(Builder builder) {
         mType = builder.mType;
         mUri = builder.mUri;
+        mMethod = builder.mMethod;
+        mArg = builder.mArg;
         mValues = builder.mValues;
+        mExtras = builder.mExtras;
         mSelection = builder.mSelection;
         mSelectionArgs = builder.mSelectionArgs;
         mExpectedCount = builder.mExpectedCount;
-        mSelectionArgsBackReferences = builder.mSelectionArgsBackReferences;
-        mValuesBackReferences = builder.mValuesBackReferences;
         mYieldAllowed = builder.mYieldAllowed;
-        mFailureAllowed = builder.mFailureAllowed;
+        mExceptionAllowed = builder.mExceptionAllowed;
     }
 
     private ContentProviderOperation(Parcel source) {
         mType = source.readInt();
         mUri = Uri.CREATOR.createFromParcel(source);
-        mValues = source.readInt() != 0 ? ContentValues.CREATOR.createFromParcel(source) : null;
-        mSelection = source.readInt() != 0 ? source.readString() : null;
-        mSelectionArgs = source.readInt() != 0 ? source.readStringArray() : null;
-        mExpectedCount = source.readInt() != 0 ? source.readInt() : null;
-        mValuesBackReferences = source.readInt() != 0
-                ? ContentValues.CREATOR.createFromParcel(source)
-                : null;
-        mSelectionArgsBackReferences = source.readInt() != 0
-                ? new HashMap<Integer, Integer>()
-                : null;
-        if (mSelectionArgsBackReferences != null) {
-            final int count = source.readInt();
-            for (int i = 0; i < count; i++) {
-                mSelectionArgsBackReferences.put(source.readInt(), source.readInt());
-            }
+        mMethod = source.readInt() != 0 ? source.readString() : null;
+        mArg = source.readInt() != 0 ? source.readString() : null;
+        final int valuesSize = source.readInt();
+        if (valuesSize != -1) {
+            mValues = new ArrayMap<>(valuesSize);
+            source.readArrayMap(mValues, null);
+        } else {
+            mValues = null;
         }
+        final int extrasSize = source.readInt();
+        if (extrasSize != -1) {
+            mExtras = new ArrayMap<>(extrasSize);
+            source.readArrayMap(mExtras, null);
+        } else {
+            mExtras = null;
+        }
+        mSelection = source.readInt() != 0 ? source.readString() : null;
+        mSelectionArgs = source.readSparseArray(null);
+        mExpectedCount = source.readInt() != 0 ? source.readInt() : null;
         mYieldAllowed = source.readInt() != 0;
-        mFailureAllowed = source.readInt() != 0;
+        mExceptionAllowed = source.readInt() != 0;
     }
 
     /** @hide */
     public ContentProviderOperation(ContentProviderOperation cpo, Uri withUri) {
         mType = cpo.mType;
         mUri = withUri;
+        mMethod = cpo.mMethod;
+        mArg = cpo.mArg;
         mValues = cpo.mValues;
+        mExtras = cpo.mExtras;
         mSelection = cpo.mSelection;
         mSelectionArgs = cpo.mSelectionArgs;
         mExpectedCount = cpo.mExpectedCount;
-        mSelectionArgsBackReferences = cpo.mSelectionArgsBackReferences;
-        mValuesBackReferences = cpo.mValuesBackReferences;
         mYieldAllowed = cpo.mYieldAllowed;
-        mFailureAllowed = cpo.mFailureAllowed;
+        mExceptionAllowed = cpo.mExceptionAllowed;
     }
 
+    @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mType);
         Uri.writeToParcel(dest, mUri);
-        if (mValues != null) {
+        if (mMethod != null) {
             dest.writeInt(1);
-            mValues.writeToParcel(dest, 0);
+            dest.writeString(mMethod);
         } else {
             dest.writeInt(0);
         }
+        if (mArg != null) {
+            dest.writeInt(1);
+            dest.writeString(mArg);
+        } else {
+            dest.writeInt(0);
+        }
+        if (mValues != null) {
+            dest.writeInt(mValues.size());
+            dest.writeArrayMap(mValues);
+        } else {
+            dest.writeInt(-1);
+        }
+        if (mExtras != null) {
+            dest.writeInt(mExtras.size());
+            dest.writeArrayMap(mExtras);
+        } else {
+            dest.writeInt(-1);
+        }
         if (mSelection != null) {
             dest.writeInt(1);
             dest.writeString(mSelection);
         } else {
             dest.writeInt(0);
         }
-        if (mSelectionArgs != null) {
-            dest.writeInt(1);
-            dest.writeStringArray(mSelectionArgs);
-        } else {
-            dest.writeInt(0);
-        }
+        dest.writeSparseArray(mSelectionArgs);
         if (mExpectedCount != null) {
             dest.writeInt(1);
             dest.writeInt(mExpectedCount);
         } else {
             dest.writeInt(0);
         }
-        if (mValuesBackReferences != null) {
-            dest.writeInt(1);
-            mValuesBackReferences.writeToParcel(dest, 0);
-        } else {
-            dest.writeInt(0);
-        }
-        if (mSelectionArgsBackReferences != null) {
-            dest.writeInt(1);
-            dest.writeInt(mSelectionArgsBackReferences.size());
-            for (Map.Entry<Integer, Integer> entry : mSelectionArgsBackReferences.entrySet()) {
-                dest.writeInt(entry.getKey());
-                dest.writeInt(entry.getValue());
-            }
-        } else {
-            dest.writeInt(0);
-        }
         dest.writeInt(mYieldAllowed ? 1 : 0);
-        dest.writeInt(mFailureAllowed ? 1 : 0);
+        dest.writeInt(mExceptionAllowed ? 1 : 0);
     }
 
     /**
-     * Create a {@link Builder} suitable for building an insert {@link ContentProviderOperation}.
-     * @param uri The {@link Uri} that is the target of the insert.
-     * @return a {@link Builder}
+     * Create a {@link Builder} suitable for building an operation that will
+     * invoke {@link ContentProvider#insert}.
+     *
+     * @param uri The {@link Uri} that is the target of the operation.
      */
-    public static Builder newInsert(Uri uri) {
+    public static @NonNull Builder newInsert(@NonNull Uri uri) {
         return new Builder(TYPE_INSERT, uri);
     }
 
     /**
-     * Create a {@link Builder} suitable for building an update {@link ContentProviderOperation}.
-     * @param uri The {@link Uri} that is the target of the update.
-     * @return a {@link Builder}
+     * Create a {@link Builder} suitable for building an operation that will
+     * invoke {@link ContentProvider#update}.
+     *
+     * @param uri The {@link Uri} that is the target of the operation.
      */
-    public static Builder newUpdate(Uri uri) {
+    public static @NonNull Builder newUpdate(@NonNull Uri uri) {
         return new Builder(TYPE_UPDATE, uri);
     }
 
     /**
-     * Create a {@link Builder} suitable for building a delete {@link ContentProviderOperation}.
-     * @param uri The {@link Uri} that is the target of the delete.
-     * @return a {@link Builder}
+     * Create a {@link Builder} suitable for building an operation that will
+     * invoke {@link ContentProvider#delete}.
+     *
+     * @param uri The {@link Uri} that is the target of the operation.
      */
-    public static Builder newDelete(Uri uri) {
+    public static @NonNull Builder newDelete(@NonNull Uri uri) {
         return new Builder(TYPE_DELETE, uri);
     }
 
@@ -195,14 +209,25 @@
      * {@link ContentProviderOperation} to assert a set of values as provided
      * through {@link Builder#withValues(ContentValues)}.
      */
-    public static Builder newAssertQuery(Uri uri) {
+    public static @NonNull Builder newAssertQuery(@NonNull Uri uri) {
         return new Builder(TYPE_ASSERT, uri);
     }
 
     /**
+     * Create a {@link Builder} suitable for building an operation that will
+     * invoke {@link ContentProvider#call}.
+     *
+     * @param uri The {@link Uri} that is the target of the operation.
+     */
+    public static @NonNull Builder newCall(@NonNull Uri uri, @Nullable String method,
+            @Nullable String arg) {
+        return new Builder(TYPE_CALL, uri, method, arg);
+    }
+
+    /**
      * Gets the Uri for the target of the operation.
      */
-    public Uri getUri() {
+    public @NonNull Uri getUri() {
         return mUri;
     }
 
@@ -216,9 +241,13 @@
         return mYieldAllowed;
     }
 
-    /** {@hide} */
-    public boolean isFailureAllowed() {
-        return mFailureAllowed;
+    /**
+     * Returns true if this operation allows subsequent operations to continue
+     * even if this operation throws an exception. When true, any encountered
+     * exception is returned via {@link ContentProviderResult#exception}.
+     */
+    public boolean isExceptionAllowed() {
+        return mExceptionAllowed;
     }
 
     /** @hide exposed for unit tests */
@@ -228,7 +257,8 @@
     }
 
     /**
-     * Returns true if the operation represents an insertion.
+     * Returns true if the operation represents a {@link ContentProvider#insert}
+     * operation.
      *
      * @see #newInsert
      */
@@ -237,7 +267,8 @@
     }
 
     /**
-     * Returns true if the operation represents a deletion.
+     * Returns true if the operation represents a {@link ContentProvider#delete}
+     * operation.
      *
      * @see #newDelete
      */
@@ -246,7 +277,8 @@
     }
 
     /**
-     * Returns true if the operation represents an update.
+     * Returns true if the operation represents a {@link ContentProvider#update}
+     * operation.
      *
      * @see #newUpdate
      */
@@ -264,6 +296,16 @@
     }
 
     /**
+     * Returns true if the operation represents a {@link ContentProvider#call}
+     * operation.
+     *
+     * @see #newCall
+     */
+    public boolean isCall() {
+        return mType == TYPE_CALL;
+    }
+
+    /**
      * Returns true if the operation represents an insertion, deletion, or update.
      *
      * @see #isInsert
@@ -297,13 +339,14 @@
      * @throws OperationApplicationException thrown if either the insert fails or
      * if the number of rows affected didn't match the expected count
      */
-    public ContentProviderResult apply(ContentProvider provider, ContentProviderResult[] backRefs,
-            int numBackRefs) throws OperationApplicationException {
-        if (mFailureAllowed) {
+    public @NonNull ContentProviderResult apply(@NonNull ContentProvider provider,
+            @NonNull ContentProviderResult[] backRefs, int numBackRefs)
+            throws OperationApplicationException {
+        if (mExceptionAllowed) {
             try {
                 return applyInternal(provider, backRefs, numBackRefs);
             } catch (Exception e) {
-                return new ContentProviderResult(e.getMessage());
+                return new ContentProviderResult(e);
             }
         } else {
             return applyInternal(provider, backRefs, numBackRefs);
@@ -313,9 +356,9 @@
     private ContentProviderResult applyInternal(ContentProvider provider,
             ContentProviderResult[] backRefs, int numBackRefs)
             throws OperationApplicationException {
-        ContentValues values = resolveValueBackReferences(backRefs, numBackRefs);
-        String[] selectionArgs =
-                resolveSelectionArgsBackReferences(backRefs, numBackRefs);
+        final ContentValues values = resolveValueBackReferences(backRefs, numBackRefs);
+        final Bundle extras = resolveExtrasBackReferences(backRefs, numBackRefs);
+        final String[] selectionArgs = resolveSelectionArgsBackReferences(backRefs, numBackRefs);
 
         if (mType == TYPE_INSERT) {
             final Uri newUri = provider.insert(mUri, values);
@@ -325,6 +368,9 @@
                 throw new OperationApplicationException(
                         "Insert into " + mUri + " returned no result");
             }
+        } else if (mType == TYPE_CALL) {
+            final Bundle res = provider.call(mUri.getAuthority(), mMethod, mArg, extras);
+            return new ContentProviderResult(res);
         }
 
         final int numRows;
@@ -376,124 +422,218 @@
     }
 
     /**
-     * The ContentValues back references are represented as a ContentValues object where the
-     * key refers to a column and the value is an index of the back reference whose
-     * valued should be associated with the column.
-     * <p>
-     * This is intended to be a private method but it is exposed for
-     * unit testing purposes
-     * @param backRefs an array of previous results
-     * @param numBackRefs the number of valid previous results in backRefs
-     * @return the ContentValues that should be used in this operation application after
-     * expansion of back references. This can be called if either mValues or mValuesBackReferences
-     * is null
+     * Return the values for this operation after resolving any requested
+     * back-references using the given results.
+     *
+     * @param backRefs the results to use when resolving any back-references
+     * @param numBackRefs the number of results which are valid
      */
-    public ContentValues resolveValueBackReferences(
-            ContentProviderResult[] backRefs, int numBackRefs) {
-        if (mValuesBackReferences == null) {
-            return mValues;
-        }
-        final ContentValues values;
-        if (mValues == null) {
-            values = new ContentValues();
-        } else {
-            values = new ContentValues(mValues);
-        }
-        for (Map.Entry<String, Object> entry : mValuesBackReferences.valueSet()) {
-            String key = entry.getKey();
-            Integer backRefIndex = mValuesBackReferences.getAsInteger(key);
-            if (backRefIndex == null) {
-                Log.e(TAG, this.toString());
-                throw new IllegalArgumentException("values backref " + key + " is not an integer");
+    public @Nullable ContentValues resolveValueBackReferences(
+            @NonNull ContentProviderResult[] backRefs, int numBackRefs) {
+        if (mValues != null) {
+            final ContentValues values = new ContentValues();
+            for (int i = 0; i < mValues.size(); i++) {
+                final Object value = mValues.valueAt(i);
+                final Object resolved;
+                if (value instanceof BackReference) {
+                    resolved = ((BackReference) value).resolve(backRefs, numBackRefs);
+                } else {
+                    resolved = value;
+                }
+                values.putObject(mValues.keyAt(i), resolved);
             }
-            values.put(key, backRefToValue(backRefs, numBackRefs, backRefIndex));
+            return values;
+        } else {
+            return null;
         }
-        return values;
     }
 
     /**
-     * The Selection Arguments back references are represented as a Map of Integer->Integer where
-     * the key is an index into the selection argument array (see {@link Builder#withSelection})
-     * and the value is the index of the previous result that should be used for that selection
-     * argument array slot.
-     * <p>
-     * This is intended to be a private method but it is exposed for
-     * unit testing purposes
-     * @param backRefs an array of previous results
-     * @param numBackRefs the number of valid previous results in backRefs
-     * @return the ContentValues that should be used in this operation application after
-     * expansion of back references. This can be called if either mValues or mValuesBackReferences
-     * is null
+     * Return the extras for this operation after resolving any requested
+     * back-references using the given results.
+     *
+     * @param backRefs the results to use when resolving any back-references
+     * @param numBackRefs the number of results which are valid
      */
-    public String[] resolveSelectionArgsBackReferences(
-            ContentProviderResult[] backRefs, int numBackRefs) {
-        if (mSelectionArgsBackReferences == null) {
-            return mSelectionArgs;
+    public @Nullable Bundle resolveExtrasBackReferences(
+            @NonNull ContentProviderResult[] backRefs, int numBackRefs) {
+        if (mExtras != null) {
+            final Bundle extras = new Bundle();
+            for (int i = 0; i < mExtras.size(); i++) {
+                final Object value = mExtras.valueAt(i);
+                final Object resolved;
+                if (value instanceof BackReference) {
+                    resolved = ((BackReference) value).resolve(backRefs, numBackRefs);
+                } else {
+                    resolved = value;
+                }
+                extras.putObject(mExtras.keyAt(i), resolved);
+            }
+            return extras;
+        } else {
+            return null;
         }
-        String[] newArgs = new String[mSelectionArgs.length];
-        System.arraycopy(mSelectionArgs, 0, newArgs, 0, mSelectionArgs.length);
-        for (Map.Entry<Integer, Integer> selectionArgBackRef
-                : mSelectionArgsBackReferences.entrySet()) {
-            final Integer selectionArgIndex = selectionArgBackRef.getKey();
-            final int backRefIndex = selectionArgBackRef.getValue();
-            newArgs[selectionArgIndex] =
-                    String.valueOf(backRefToValue(backRefs, numBackRefs, backRefIndex));
+    }
+
+    /**
+     * Return the selection arguments for this operation after resolving any
+     * requested back-references using the given results.
+     *
+     * @param backRefs the results to use when resolving any back-references
+     * @param numBackRefs the number of results which are valid
+     */
+    public @Nullable String[] resolveSelectionArgsBackReferences(
+            @NonNull ContentProviderResult[] backRefs, int numBackRefs) {
+        if (mSelectionArgs != null) {
+            int max = -1;
+            for (int i = 0; i < mSelectionArgs.size(); i++) {
+                max = Math.max(max, mSelectionArgs.keyAt(i));
+            }
+
+            final String[] selectionArgs = new String[max + 1];
+            for (int i = 0; i < mSelectionArgs.size(); i++) {
+                final Object value = mSelectionArgs.valueAt(i);
+                final Object resolved;
+                if (value instanceof BackReference) {
+                    resolved = ((BackReference) value).resolve(backRefs, numBackRefs);
+                } else {
+                    resolved = value;
+                }
+                selectionArgs[mSelectionArgs.keyAt(i)] = String.valueOf(resolved);
+            }
+            return selectionArgs;
+        } else {
+            return null;
         }
-        return newArgs;
+    }
+
+    /** {@hide} */
+    public static String typeToString(int type) {
+        switch (type) {
+            case TYPE_INSERT: return "insert";
+            case TYPE_UPDATE: return "update";
+            case TYPE_DELETE: return "delete";
+            case TYPE_ASSERT: return "assert";
+            case TYPE_CALL: return "call";
+            default: return Integer.toString(type);
+        }
     }
 
     @Override
     public String toString() {
-        return "mType: " + mType + ", mUri: " + mUri +
-                ", mSelection: " + mSelection +
-                ", mExpectedCount: " + mExpectedCount +
-                ", mYieldAllowed: " + mYieldAllowed +
-                ", mValues: " + mValues +
-                ", mValuesBackReferences: " + mValuesBackReferences +
-                ", mSelectionArgsBackReferences: " + mSelectionArgsBackReferences;
+        final StringBuilder sb = new StringBuilder("ContentProviderOperation(");
+        sb.append("type=" + typeToString(mType) + " ");
+        if (mUri != null) {
+            sb.append("uri=" + mUri + " ");
+        }
+        if (mValues != null) {
+            sb.append("values=" + mValues + " ");
+        }
+        if (mSelection != null) {
+            sb.append("selection=" + mSelection + " ");
+        }
+        if (mSelectionArgs != null) {
+            sb.append("selectionArgs=" + mSelectionArgs + " ");
+        }
+        if (mExpectedCount != null) {
+            sb.append("expectedCount=" + mExpectedCount + " ");
+        }
+        if (mYieldAllowed) {
+            sb.append("yieldAllowed ");
+        }
+        if (mExceptionAllowed) {
+            sb.append("exceptionAllowed ");
+        }
+        sb.deleteCharAt(sb.length() - 1);
+        sb.append(")");
+        return sb.toString();
     }
 
-    /**
-     * Return the string representation of the requested back reference.
-     * @param backRefs an array of results
-     * @param numBackRefs the number of items in the backRefs array that are valid
-     * @param backRefIndex which backRef to be used
-     * @throws ArrayIndexOutOfBoundsException thrown if the backRefIndex is larger than
-     * the numBackRefs
-     * @return the string representation of the requested back reference.
-     */
-    private long backRefToValue(ContentProviderResult[] backRefs, int numBackRefs,
-            Integer backRefIndex) {
-        if (backRefIndex >= numBackRefs) {
-            Log.e(TAG, this.toString());
-            throw new ArrayIndexOutOfBoundsException("asked for back ref " + backRefIndex
-                    + " but there are only " + numBackRefs + " back refs");
-        }
-        ContentProviderResult backRef = backRefs[backRefIndex];
-        long backRefValue;
-        if (backRef.uri != null) {
-            backRefValue = ContentUris.parseId(backRef.uri);
-        } else {
-            backRefValue = backRef.count;
-        }
-        return backRefValue;
-    }
-
+    @Override
     public int describeContents() {
         return 0;
     }
 
     public static final @android.annotation.NonNull Creator<ContentProviderOperation> CREATOR =
             new Creator<ContentProviderOperation>() {
+        @Override
         public ContentProviderOperation createFromParcel(Parcel source) {
             return new ContentProviderOperation(source);
         }
 
+        @Override
         public ContentProviderOperation[] newArray(int size) {
             return new ContentProviderOperation[size];
         }
     };
 
+    /** {@hide} */
+    public static class BackReference implements Parcelable {
+        private final int fromIndex;
+        private final String fromKey;
+
+        private BackReference(int fromIndex, String fromKey) {
+            this.fromIndex = fromIndex;
+            this.fromKey = fromKey;
+        }
+
+        public BackReference(Parcel src) {
+            this.fromIndex = src.readInt();
+            if (src.readInt() != 0) {
+                this.fromKey = src.readString();
+            } else {
+                this.fromKey = null;
+            }
+        }
+
+        public Object resolve(ContentProviderResult[] backRefs, int numBackRefs) {
+            if (fromIndex >= numBackRefs) {
+                Log.e(TAG, this.toString());
+                throw new ArrayIndexOutOfBoundsException("asked for back ref " + fromIndex
+                        + " but there are only " + numBackRefs + " back refs");
+            }
+            ContentProviderResult backRef = backRefs[fromIndex];
+            Object backRefValue;
+            if (backRef.extras != null) {
+                backRefValue = backRef.extras.get(fromKey);
+            } else if (backRef.uri != null) {
+                backRefValue = ContentUris.parseId(backRef.uri);
+            } else {
+                backRefValue = (long) backRef.count;
+            }
+            return backRefValue;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(fromIndex);
+            if (fromKey != null) {
+                dest.writeInt(1);
+                dest.writeString(fromKey);
+            } else {
+                dest.writeInt(0);
+            }
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final @android.annotation.NonNull Creator<BackReference> CREATOR =
+                new Creator<BackReference>() {
+            @Override
+            public BackReference createFromParcel(Parcel source) {
+                return new BackReference(source);
+            }
+
+            @Override
+            public BackReference[] newArray(int size) {
+                return new BackReference[size];
+            }
+        };
+    }
+
     /**
      * Used to add parameters to a {@link ContentProviderOperation}. The {@link Builder} is
      * first created by calling {@link ContentProviderOperation#newInsert(android.net.Uri)},
@@ -507,35 +647,36 @@
     public static class Builder {
         private final int mType;
         private final Uri mUri;
+        private final String mMethod;
+        private final String mArg;
+        private ArrayMap<String, Object> mValues;
+        private ArrayMap<String, Object> mExtras;
         private String mSelection;
-        private String[] mSelectionArgs;
-        private ContentValues mValues;
+        private SparseArray<Object> mSelectionArgs;
         private Integer mExpectedCount;
-        private ContentValues mValuesBackReferences;
-        private Map<Integer, Integer> mSelectionArgsBackReferences;
         private boolean mYieldAllowed;
-        private boolean mFailureAllowed;
+        private boolean mExceptionAllowed;
 
-        /** Create a {@link Builder} of a given type. The uri must not be null. */
         private Builder(int type, Uri uri) {
-            if (uri == null) {
-                throw new IllegalArgumentException("uri must not be null");
-            }
+            this(type, uri, null, null);
+        }
+
+        private Builder(int type, Uri uri, String method, String arg) {
             mType = type;
-            mUri = uri;
+            mUri = Objects.requireNonNull(uri);
+            mMethod = method;
+            mArg = arg;
         }
 
         /** Create a ContentProviderOperation from this {@link Builder}. */
-        public ContentProviderOperation build() {
+        public @NonNull ContentProviderOperation build() {
             if (mType == TYPE_UPDATE) {
-                if ((mValues == null || mValues.isEmpty())
-                      && (mValuesBackReferences == null || mValuesBackReferences.isEmpty())) {
+                if ((mValues == null || mValues.isEmpty())) {
                     throw new IllegalArgumentException("Empty values");
                 }
             }
             if (mType == TYPE_ASSERT) {
                 if ((mValues == null || mValues.isEmpty())
-                      && (mValuesBackReferences == null || mValuesBackReferences.isEmpty())
                         && (mExpectedCount == null)) {
                     throw new IllegalArgumentException("Empty values");
                 }
@@ -543,152 +684,259 @@
             return new ContentProviderOperation(this);
         }
 
-        /**
-         * Add a {@link ContentValues} of back references. The key is the name of the column
-         * and the value is an integer that is the index of the previous result whose
-         * value should be used for the column. The value is added as a {@link String}.
-         * A column value from the back references takes precedence over a value specified in
-         * {@link #withValues}.
-         * This can only be used with builders of type insert, update, or assert.
-         * @return this builder, to allow for chaining.
-         */
-        public Builder withValueBackReferences(ContentValues backReferences) {
-            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
-                throw new IllegalArgumentException(
-                        "only inserts, updates, and asserts can have value back-references");
-            }
-            mValuesBackReferences = backReferences;
-            return this;
-        }
-
-        /**
-         * Add a ContentValues back reference.
-         * A column value from the back references takes precedence over a value specified in
-         * {@link #withValues}.
-         * This can only be used with builders of type insert, update, or assert.
-         * @return this builder, to allow for chaining.
-         */
-        public Builder withValueBackReference(String key, int previousResult) {
-            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
-                throw new IllegalArgumentException(
-                        "only inserts, updates, and asserts can have value back-references");
-            }
-            if (mValuesBackReferences == null) {
-                mValuesBackReferences = new ContentValues();
-            }
-            mValuesBackReferences.put(key, previousResult);
-            return this;
-        }
-
-        /**
-         * Add a back references as a selection arg. Any value at that index of the selection arg
-         * that was specified by {@link #withSelection} will be overwritten.
-         * This can only be used with builders of type update, delete, or assert.
-         * @return this builder, to allow for chaining.
-         */
-        public Builder withSelectionBackReference(int selectionArgIndex, int previousResult) {
-            if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
-                throw new IllegalArgumentException("only updates, deletes, and asserts "
-                        + "can have selection back-references");
-            }
-            if (mSelectionArgsBackReferences == null) {
-                mSelectionArgsBackReferences = new HashMap<Integer, Integer>();
-            }
-            mSelectionArgsBackReferences.put(selectionArgIndex, previousResult);
-            return this;
-        }
-
-        /**
-         * The ContentValues to use. This may be null. These values may be overwritten by
-         * the corresponding value specified by {@link #withValueBackReference} or by
-         * future calls to {@link #withValues} or {@link #withValue}.
-         * This can only be used with builders of type insert, update, or assert.
-         * @return this builder, to allow for chaining.
-         */
-        public Builder withValues(ContentValues values) {
-            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
-                throw new IllegalArgumentException(
-                        "only inserts, updates, and asserts can have values");
-            }
+        private void setValue(@NonNull String key, @NonNull Object value) {
             if (mValues == null) {
-                mValues = new ContentValues();
+                mValues = new ArrayMap<>();
             }
-            mValues.putAll(values);
+            final boolean oldReference = mValues.get(key) instanceof BackReference;
+            final boolean newReference = value instanceof BackReference;
+            if (!oldReference || newReference) {
+                mValues.put(key, value);
+            }
+        }
+
+        private void setExtra(@NonNull String key, @NonNull Object value) {
+            if (mExtras == null) {
+                mExtras = new ArrayMap<>();
+            }
+            final boolean oldReference = mExtras.get(key) instanceof BackReference;
+            final boolean newReference = value instanceof BackReference;
+            if (!oldReference || newReference) {
+                mExtras.put(key, value);
+            }
+        }
+
+        private void setSelectionArg(int index, @NonNull Object value) {
+            if (mSelectionArgs == null) {
+                mSelectionArgs = new SparseArray<>();
+            }
+            final boolean oldReference = mSelectionArgs.get(index) instanceof BackReference;
+            final boolean newReference = value instanceof BackReference;
+            if (!oldReference || newReference) {
+                mSelectionArgs.put(index, value);
+            }
+        }
+
+        /**
+         * Configure the values to use for this operation. This method will
+         * replace any previously defined values for the contained keys, but it
+         * will not replace any back-reference requests.
+         * <p>
+         * Any value may be dynamically overwritten using the result of a
+         * previous operation by using methods such as
+         * {@link #withValueBackReference(String, int)}.
+         */
+        public @NonNull Builder withValues(@NonNull ContentValues values) {
+            assertValuesAllowed();
+            final ArrayMap<String, Object> rawValues = values.getValues();
+            for (int i = 0; i < rawValues.size(); i++) {
+                setValue(rawValues.keyAt(i), rawValues.valueAt(i));
+            }
             return this;
         }
 
         /**
-         * A value to insert or update. This value may be overwritten by
-         * the corresponding value specified by {@link #withValueBackReference}.
-         * This can only be used with builders of type insert, update, or assert.
-         * @param key the name of this value
-         * @param value the value itself. the type must be acceptable for insertion by
-         * {@link ContentValues#put}
-         * @return this builder, to allow for chaining.
+         * Configure the given value to use for this operation. This method will
+         * replace any previously defined value for this key.
+         *
+         * @param key the key indicating which value to configure
          */
-        public Builder withValue(String key, Object value) {
-            if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
-                throw new IllegalArgumentException("only inserts and updates can have values");
-            }
-            if (mValues == null) {
-                mValues = new ContentValues();
-            }
-            if (value == null) {
-                mValues.putNull(key);
-            } else if (value instanceof String) {
-                mValues.put(key, (String) value);
-            } else if (value instanceof Byte) {
-                mValues.put(key, (Byte) value);
-            } else if (value instanceof Short) {
-                mValues.put(key, (Short) value);
-            } else if (value instanceof Integer) {
-                mValues.put(key, (Integer) value);
-            } else if (value instanceof Long) {
-                mValues.put(key, (Long) value);
-            } else if (value instanceof Float) {
-                mValues.put(key, (Float) value);
-            } else if (value instanceof Double) {
-                mValues.put(key, (Double) value);
-            } else if (value instanceof Boolean) {
-                mValues.put(key, (Boolean) value);
-            } else if (value instanceof byte[]) {
-                mValues.put(key, (byte[]) value);
-            } else {
+        public @NonNull Builder withValue(@NonNull String key, @Nullable Object value) {
+            assertValuesAllowed();
+            if (!ContentValues.isSupportedValue(value)) {
                 throw new IllegalArgumentException("bad value type: " + value.getClass().getName());
             }
+            setValue(key, value);
             return this;
         }
 
         /**
-         * The selection and arguments to use. An occurrence of '?' in the selection will be
-         * replaced with the corresponding occurrence of the selection argument. Any of the
-         * selection arguments may be overwritten by a selection argument back reference as
-         * specified by {@link #withSelectionBackReference}.
-         * This can only be used with builders of type update, delete, or assert.
-         * @return this builder, to allow for chaining.
+         * Configure the given values to be dynamically overwritten using the
+         * result of a previous operation. This method will replace any
+         * previously defined values for these keys.
+         *
+         * @param backReferences set of values where the key indicates which
+         *            value to configure and the value the index indicating
+         *            which historical {@link ContentProviderResult} should
+         *            overwrite the value
          */
-        public Builder withSelection(String selection, String[] selectionArgs) {
-            if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
-                throw new IllegalArgumentException(
-                        "only updates, deletes, and asserts can have selections");
+        public @NonNull Builder withValueBackReferences(@NonNull ContentValues backReferences) {
+            assertValuesAllowed();
+            final ArrayMap<String, Object> rawValues = backReferences.getValues();
+            for (int i = 0; i < rawValues.size(); i++) {
+                setValue(rawValues.keyAt(i),
+                        new BackReference((int) rawValues.valueAt(i), null));
             }
+            return this;
+        }
+
+        /**
+         * Configure the given value to be dynamically overwritten using the
+         * result of a previous operation. This method will replace any
+         * previously defined value for this key.
+         *
+         * @param key the key indicating which value to configure
+         * @param fromIndex the index indicating which historical
+         *            {@link ContentProviderResult} should overwrite the value
+         */
+        public @NonNull Builder withValueBackReference(@NonNull String key, int fromIndex) {
+            assertValuesAllowed();
+            setValue(key, new BackReference(fromIndex, null));
+            return this;
+        }
+
+        /**
+         * Configure the given value to be dynamically overwritten using the
+         * result of a previous operation. This method will replace any
+         * previously defined value for this key.
+         *
+         * @param key the key indicating which value to configure
+         * @param fromIndex the index indicating which historical
+         *            {@link ContentProviderResult} should overwrite the value
+         * @param fromKey the key of indicating which
+         *            {@link ContentProviderResult#extras} value should
+         *            overwrite the value
+         */
+        public @NonNull Builder withValueBackReference(@NonNull String key, int fromIndex,
+                @NonNull String fromKey) {
+            assertValuesAllowed();
+            setValue(key, new BackReference(fromIndex, fromKey));
+            return this;
+        }
+
+        /**
+         * Configure the extras to use for this operation. This method will
+         * replace any previously defined values for the contained keys, but it
+         * will not replace any back-reference requests.
+         * <p>
+         * Any value may be dynamically overwritten using the result of a
+         * previous operation by using methods such as
+         * {@link #withExtraBackReference(String, int)}.
+         */
+        public @NonNull Builder withExtras(@NonNull Bundle extras) {
+            assertExtrasAllowed();
+            for (String key : extras.keySet()) {
+                setExtra(key, extras.get(key));
+            }
+            return this;
+        }
+
+        /**
+         * Configure the given extra to use for this operation. This method will
+         * replace any previously defined extras for this key.
+         *
+         * @param key the key indicating which extra to configure
+         */
+        public @NonNull Builder withExtra(@NonNull String key, @Nullable Object value) {
+            assertExtrasAllowed();
+            setExtra(key, value);
+            return this;
+        }
+
+        /**
+         * Configure the given extra to be dynamically overwritten using the
+         * result of a previous operation. This method will replace any
+         * previously defined extras for this key.
+         *
+         * @param key the key indicating which extra to configure
+         * @param fromIndex the index indicating which historical
+         *            {@link ContentProviderResult} should overwrite the extra
+         */
+        public @NonNull Builder withExtraBackReference(@NonNull String key, int fromIndex) {
+            assertExtrasAllowed();
+            setExtra(key, new BackReference(fromIndex, null));
+            return this;
+        }
+
+        /**
+         * Configure the given extra to be dynamically overwritten using the
+         * result of a previous operation. This method will replace any
+         * previously defined extras for this key.
+         *
+         * @param key the key indicating which extra to configure
+         * @param fromIndex the index indicating which historical
+         *            {@link ContentProviderResult} should overwrite the extra
+         * @param fromKey the key of indicating which
+         *            {@link ContentProviderResult#extras} value should
+         *            overwrite the extra
+         */
+        public @NonNull Builder withExtraBackReference(@NonNull String key, int fromIndex,
+                @NonNull String fromKey) {
+            assertExtrasAllowed();
+            setExtra(key, new BackReference(fromIndex, fromKey));
+            return this;
+        }
+
+        /**
+         * Configure the selection and selection arguments to use for this
+         * operation. This method will replace any previously defined selection
+         * and selection arguments, but it will not replace any back-reference
+         * requests.
+         * <p>
+         * An occurrence of {@code ?} in the selection will be replaced with the
+         * corresponding selection argument when the operation is executed.
+         * <p>
+         * Any selection argument may be dynamically overwritten using the
+         * result of a previous operation by using methods such as
+         * {@link #withSelectionBackReference(int, int)}.
+         */
+        public @NonNull Builder withSelection(@Nullable String selection,
+                @Nullable String[] selectionArgs) {
+            assertSelectionAllowed();
             mSelection = selection;
-            if (selectionArgs == null) {
-                mSelectionArgs = null;
-            } else {
-                mSelectionArgs = new String[selectionArgs.length];
-                System.arraycopy(selectionArgs, 0, mSelectionArgs, 0, selectionArgs.length);
+            if (selectionArgs != null) {
+                for (int i = 0; i < selectionArgs.length; i++) {
+                    setSelectionArg(i, selectionArgs[i]);
+                }
             }
             return this;
         }
 
         /**
+         * Configure the given selection argument to be dynamically overwritten
+         * using the result of a previous operation. This method will replace
+         * any previously defined selection argument at this index.
+         *
+         * @param index the index indicating which selection argument to
+         *            configure
+         * @param fromIndex the index indicating which historical
+         *            {@link ContentProviderResult} should overwrite the
+         *            selection argument
+         */
+        public @NonNull Builder withSelectionBackReference(int index, int fromIndex) {
+            assertSelectionAllowed();
+            setSelectionArg(index, new BackReference(fromIndex, null));
+            return this;
+        }
+
+        /**
+         * Configure the given selection argument to be dynamically overwritten
+         * using the result of a previous operation. This method will replace
+         * any previously defined selection argument at this index.
+         *
+         * @param index the index indicating which selection argument to
+         *            configure
+         * @param fromIndex the index indicating which historical
+         *            {@link ContentProviderResult} should overwrite the
+         *            selection argument
+         * @param fromKey the key of indicating which
+         *            {@link ContentProviderResult#extras} value should
+         *            overwrite the selection argument
+         */
+        public @NonNull Builder withSelectionBackReference(int index, int fromIndex,
+                @NonNull String fromKey) {
+            assertSelectionAllowed();
+            setSelectionArg(index, new BackReference(fromIndex, fromKey));
+            return this;
+        }
+
+        /**
          * If set then if the number of rows affected by this operation does not match
          * this count {@link OperationApplicationException} will be throw.
          * This can only be used with builders of type update, delete, or assert.
          * @return this builder, to allow for chaining.
          */
-        public Builder withExpectedCount(int count) {
+        public @NonNull Builder withExpectedCount(int count) {
             if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
                 throw new IllegalArgumentException(
                         "only updates, deletes, and asserts can have expected counts");
@@ -703,15 +951,59 @@
          * @return this builder, to allow for chaining.
          * @see android.database.sqlite.SQLiteDatabase#yieldIfContendedSafely()
          */
-        public Builder withYieldAllowed(boolean yieldAllowed) {
+        public @NonNull Builder withYieldAllowed(boolean yieldAllowed) {
             mYieldAllowed = yieldAllowed;
             return this;
         }
 
-        /** {@hide} */
-        public Builder withFailureAllowed(boolean failureAllowed) {
-            mFailureAllowed = failureAllowed;
+        /**
+         * If set to true, this operation allows subsequent operations to
+         * continue even if this operation throws an exception. When true, any
+         * encountered exception is returned via
+         * {@link ContentProviderResult#exception}.
+         */
+        public @NonNull Builder withExceptionAllowed(boolean exceptionAllowed) {
+            mExceptionAllowed = exceptionAllowed;
             return this;
         }
+
+        /** {@hide} */
+        public @NonNull Builder withFailureAllowed(boolean failureAllowed) {
+            return withExceptionAllowed(failureAllowed);
+        }
+
+        private void assertValuesAllowed() {
+            switch (mType) {
+                case TYPE_INSERT:
+                case TYPE_UPDATE:
+                case TYPE_ASSERT:
+                    break;
+                default:
+                    throw new IllegalArgumentException(
+                            "Values not supported for " + typeToString(mType));
+            }
+        }
+
+        private void assertSelectionAllowed() {
+            switch (mType) {
+                case TYPE_UPDATE:
+                case TYPE_DELETE:
+                case TYPE_ASSERT:
+                    break;
+                default:
+                    throw new IllegalArgumentException(
+                            "Selection not supported for " + typeToString(mType));
+            }
+        }
+
+        private void assertExtrasAllowed() {
+            switch (mType) {
+                case TYPE_CALL:
+                    break;
+                default:
+                    throw new IllegalArgumentException(
+                            "Extras not supported for " + typeToString(mType));
+            }
+        }
     }
 }
diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java
index b301011..11dda83 100644
--- a/core/java/android/content/ContentProviderResult.java
+++ b/core/java/android/content/ContentProviderResult.java
@@ -16,40 +16,50 @@
 
 package android.content;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.ParcelableException;
 
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
 
 /**
- * Contains the result of the application of a {@link ContentProviderOperation}. It is guaranteed
- * to have exactly one of {@link #uri} or {@link #count} set.
+ * Contains the result of the application of a {@link ContentProviderOperation}.
+ * <p>
+ * It is guaranteed to have exactly one of {@link #uri}, {@link #count},
+ * {@link #extras}, or {@link #exception} set.
  */
 public class ContentProviderResult implements Parcelable {
-    public final Uri uri;
-    public final Integer count;
-    /** {@hide} */
-    public final String failure;
+    public final @Nullable Uri uri;
+    public final @Nullable Integer count;
+    public final @Nullable Bundle extras;
+    public final @Nullable Exception exception;
 
-    public ContentProviderResult(Uri uri) {
-        this(Preconditions.checkNotNull(uri), null, null);
+    public ContentProviderResult(@NonNull Uri uri) {
+        this(Objects.requireNonNull(uri), null, null, null);
     }
 
     public ContentProviderResult(int count) {
-        this(null, count, null);
+        this(null, count, null, null);
+    }
+
+    public ContentProviderResult(@NonNull Bundle extras) {
+        this(null, null, Objects.requireNonNull(extras), null);
+    }
+
+    public ContentProviderResult(@NonNull Exception exception) {
+        this(null, null, null, exception);
     }
 
     /** {@hide} */
-    public ContentProviderResult(String failure) {
-        this(null, null, failure);
-    }
-
-    /** {@hide} */
-    public ContentProviderResult(Uri uri, Integer count, String failure) {
+    public ContentProviderResult(Uri uri, Integer count, Bundle extras, Exception exception) {
         this.uri = uri;
         this.count = count;
-        this.failure = failure;
+        this.extras = extras;
+        this.exception = exception;
     }
 
     public ContentProviderResult(Parcel source) {
@@ -64,9 +74,14 @@
             count = null;
         }
         if (source.readInt() != 0) {
-            failure = source.readString();
+            extras = source.readBundle();
         } else {
-            failure = null;
+            extras = null;
+        }
+        if (source.readInt() != 0) {
+            exception = (Exception) ParcelableException.readFromParcel(source);
+        } else {
+            exception = null;
         }
     }
 
@@ -74,7 +89,8 @@
     public ContentProviderResult(ContentProviderResult cpr, int userId) {
         uri = ContentProvider.maybeAddUserId(cpr.uri, userId);
         count = cpr.count;
-        failure = cpr.failure;
+        extras = cpr.extras;
+        exception = cpr.exception;
     }
 
     @Override
@@ -91,9 +107,15 @@
         } else {
             dest.writeInt(0);
         }
-        if (failure != null) {
+        if (extras != null) {
             dest.writeInt(1);
-            dest.writeString(failure);
+            dest.writeBundle(extras);
+        } else {
+            dest.writeInt(0);
+        }
+        if (exception != null) {
+            dest.writeInt(1);
+            ParcelableException.writeToParcel(dest, exception);
         } else {
             dest.writeInt(0);
         }
@@ -126,8 +148,11 @@
         if (count != null) {
             sb.append("count=" + count + " ");
         }
-        if (uri != null) {
-            sb.append("failure=" + failure + " ");
+        if (extras != null) {
+            sb.append("extras=" + extras + " ");
+        }
+        if (exception != null) {
+            sb.append("exception=" + exception + " ");
         }
         sb.deleteCharAt(sb.length() - 1);
         sb.append(")");
diff --git a/core/java/android/content/ContentValues.java b/core/java/android/content/ContentValues.java
index eafeed2..8223a0b 100644
--- a/core/java/android/content/ContentValues.java
+++ b/core/java/android/content/ContentValues.java
@@ -16,6 +16,8 @@
 
 package android.content;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -217,6 +219,33 @@
         mMap.put(key, null);
     }
 
+    /** {@hide} */
+    public void putObject(@Nullable String key, @Nullable Object value) {
+        if (value == null) {
+            putNull(key);
+        } else if (value instanceof String) {
+            put(key, (String) value);
+        } else if (value instanceof Byte) {
+            put(key, (Byte) value);
+        } else if (value instanceof Short) {
+            put(key, (Short) value);
+        } else if (value instanceof Integer) {
+            put(key, (Integer) value);
+        } else if (value instanceof Long) {
+            put(key, (Long) value);
+        } else if (value instanceof Float) {
+            put(key, (Float) value);
+        } else if (value instanceof Double) {
+            put(key, (Double) value);
+        } else if (value instanceof Boolean) {
+            put(key, (Boolean) value);
+        } else if (value instanceof byte[]) {
+            put(key, (byte[]) value);
+        } else {
+            throw new IllegalArgumentException("Unsupported type " + value.getClass());
+        }
+    }
+
     /**
      * Returns the number of values.
      *
@@ -556,4 +585,31 @@
         }
         return sb.toString();
     }
+
+    /** {@hide} */
+    public static boolean isSupportedValue(Object value) {
+        if (value == null) {
+            return true;
+        } else if (value instanceof String) {
+            return true;
+        } else if (value instanceof Byte) {
+            return true;
+        } else if (value instanceof Short) {
+            return true;
+        } else if (value instanceof Integer) {
+            return true;
+        } else if (value instanceof Long) {
+            return true;
+        } else if (value instanceof Float) {
+            return true;
+        } else if (value instanceof Double) {
+            return true;
+        } else if (value instanceof Boolean) {
+            return true;
+        } else if (value instanceof byte[]) {
+            return true;
+        } else {
+            return false;
+        }
+    }
 }
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 5ac13d8..a0170da 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -206,10 +206,16 @@
                     continue;
                 }
 
-                if (filterTags == null || Arrays.binarySearch(filterTags,
-                        CameraMetadataNative.getTag(keyName, vendorId)) >= 0) {
+
+                if (filterTags != null && Arrays.binarySearch(filterTags,
+                        CameraMetadataNative.getTag(keyName, vendorId)) < 0) {
+                    // ignore vendor keys not in filterTags
+                    continue;
+                }
+                if (instance == null || instance.getProtected(k) != null)  {
                     keyList.add(k);
                 }
+
             }
         }
 
diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java
index be2846f..aa5480a 100644
--- a/core/java/android/hardware/radio/TunerAdapter.java
+++ b/core/java/android/hardware/radio/TunerAdapter.java
@@ -271,6 +271,8 @@
             mCallback.setProgramListObserver(list, () -> {
                 try {
                     mTuner.stopProgramListUpdates();
+                } catch (IllegalStateException ex) {
+                    // it's fine to not stop updates if tuner is already closed
                 } catch (RemoteException ex) {
                     Log.e(TAG, "Couldn't stop program list updates", ex);
                 }
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 7f63f8f..9d9c683 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -563,6 +563,35 @@
         return mMap.keySet();
     }
 
+    /** {@hide} */
+    public void putObject(@Nullable String key, @Nullable Object value) {
+        if (value == null) {
+            putString(key, null);
+        } else if (value instanceof Boolean) {
+            putBoolean(key, (Boolean) value);
+        } else if (value instanceof Integer) {
+            putInt(key, (Integer) value);
+        } else if (value instanceof Long) {
+            putLong(key, (Long) value);
+        } else if (value instanceof Double) {
+            putDouble(key, (Double) value);
+        } else if (value instanceof String) {
+            putString(key, (String) value);
+        } else if (value instanceof boolean[]) {
+            putBooleanArray(key, (boolean[]) value);
+        } else if (value instanceof int[]) {
+            putIntArray(key, (int[]) value);
+        } else if (value instanceof long[]) {
+            putLongArray(key, (long[]) value);
+        } else if (value instanceof double[]) {
+            putDoubleArray(key, (double[]) value);
+        } else if (value instanceof String[]) {
+            putStringArray(key, (String[]) value);
+        } else {
+            throw new IllegalArgumentException("Unsupported type " + value.getClass());
+        }
+    }
+
     /**
      * Inserts a Boolean value into the mapping of this Bundle, replacing
      * any existing value for the given key.  Either key or value may be null.
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index a399e83..c5c0945 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -21,7 +21,6 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
-import android.app.job.JobParameters;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.server.ServerProtoEnums;
@@ -45,6 +44,7 @@
 import com.android.internal.location.gnssmetrics.GnssMetrics;
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
+import com.android.internal.util.Preconditions;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -56,6 +56,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 
 /**
  * A class providing access to battery usage statistics, including information on
@@ -407,6 +408,40 @@
     };
 
     /**
+     * "Job stop reason codes" from the job scheduler subsystem, which we can't refer to from this
+     * class, so we initialize it from the job scheduler side at runtime using
+     * {@link #setJobStopReasons}.
+     */
+    private static int[] sJobStopReasonCodes = {0};
+
+    /**
+     * A function that converts the "job stop reason codes" to their names.
+     *
+     * Similarly to {@link #sJobStopReasonCodes} it's initialized by the job scheduler subsystem
+     * using {@link #setJobStopReasons}.
+     */
+    private static Function<Integer, String> sJobStopReasonNameConverter = (x) -> "unknown";
+
+    /**
+     * Set by the job scheduler subsystem to "push" job stop reasons, and a function that returns
+     * the "name" of each code. We do it this way to remove a build time dependency from this
+     * class to the job scheduler framework code.
+     *
+     * Note the passed array will be used as-is, without copying. The caller must not change
+     * the array it passed to it.
+     *
+     * @hide
+     */
+    public static void setJobStopReasons(int[] reasonCodes,
+            Function<Integer, String> jobStopReasonNameConverter) {
+        Preconditions.checkArgument(reasonCodes.length > 0);
+        Preconditions.checkArgument(jobStopReasonNameConverter != null);
+
+        sJobStopReasonCodes = reasonCodes;
+        sJobStopReasonNameConverter = jobStopReasonNameConverter;
+    }
+
+    /**
      * State for keeping track of counting information.
      */
     public static abstract class Counter {
@@ -4260,17 +4295,18 @@
                 }
             }
 
+            final Object[] jobCompletionArgs = new Object[sJobStopReasonCodes.length + 1];
+
             final ArrayMap<String, SparseIntArray> completions = u.getJobCompletionStats();
             for (int ic=completions.size()-1; ic>=0; ic--) {
                 SparseIntArray types = completions.valueAt(ic);
                 if (types != null) {
-                    dumpLine(pw, uid, category, JOB_COMPLETION_DATA,
-                            "\"" + completions.keyAt(ic) + "\"",
-                            types.get(JobParameters.REASON_CANCELED, 0),
-                            types.get(JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED, 0),
-                            types.get(JobParameters.REASON_PREEMPT, 0),
-                            types.get(JobParameters.REASON_TIMEOUT, 0),
-                            types.get(JobParameters.REASON_DEVICE_IDLE, 0));
+                    jobCompletionArgs[0] = "\"" + completions.keyAt(ic) + "\"";
+                    for (int i = 0; i < sJobStopReasonCodes.length; i++) {
+                        jobCompletionArgs[i + 1] = types.get(sJobStopReasonCodes[i], 0);
+                    }
+
+                    dumpLine(pw, uid, category, JOB_COMPLETION_DATA, jobCompletionArgs);
                 }
             }
 
@@ -5887,7 +5923,7 @@
                     pw.print(":");
                     for (int it=0; it<types.size(); it++) {
                         pw.print(" ");
-                        pw.print(JobParameters.getReasonName(types.keyAt(it)));
+                        pw.print(sJobStopReasonNameConverter.apply(types.keyAt(it)));
                         pw.print("(");
                         pw.print(types.valueAt(it));
                         pw.print("x)");
@@ -7478,13 +7514,6 @@
 
             // Job completion (JOB_COMPLETION_DATA)
             final ArrayMap<String, SparseIntArray> completions = u.getJobCompletionStats();
-            final int[] reasons = new int[]{
-                JobParameters.REASON_CANCELED,
-                JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED,
-                JobParameters.REASON_PREEMPT,
-                JobParameters.REASON_TIMEOUT,
-                JobParameters.REASON_DEVICE_IDLE,
-            };
             for (int ic = 0; ic < completions.size(); ++ic) {
                 SparseIntArray types = completions.valueAt(ic);
                 if (types != null) {
@@ -7492,7 +7521,7 @@
 
                     proto.write(UidProto.JobCompletion.NAME, completions.keyAt(ic));
 
-                    for (int r : reasons) {
+                    for (int r : sJobStopReasonCodes) {
                         long rToken = proto.start(UidProto.JobCompletion.REASON_COUNT);
                         proto.write(UidProto.JobCompletion.ReasonCount.NAME, r);
                         proto.write(UidProto.JobCompletion.ReasonCount.COUNT, types.get(r, 0));
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 3cdebac..c5cbad3 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -235,22 +235,5 @@
                 Binder.restoreCallingIdentity(identity);
             }
         }
-
-        // Old methods; should go away
-        @Override
-        public void onProgressUpdated(int progress) throws RemoteException {
-            // TODO(b/111441001): remove from interface
-        }
-
-        @Override
-        public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
-            // TODO(b/111441001): remove from interface
-        }
-
-        @Override
-        public void onSectionComplete(String title, int status, int size, int durationMs)
-                throws RemoteException {
-            // TODO(b/111441001): remove from interface
-        }
     }
 }
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index b82e517..7e11840 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -435,6 +435,56 @@
         return bundle;
     }
 
+    /** {@hide} */
+    @Override
+    public void putObject(@Nullable String key, @Nullable Object value) {
+        if (value instanceof Byte) {
+            putByte(key, (Byte) value);
+        } else if (value instanceof Character) {
+            putChar(key, (Character) value);
+        } else if (value instanceof Short) {
+            putShort(key, (Short) value);
+        } else if (value instanceof Float) {
+            putFloat(key, (Float) value);
+        } else if (value instanceof CharSequence) {
+            putCharSequence(key, (CharSequence) value);
+        } else if (value instanceof Parcelable) {
+            putParcelable(key, (Parcelable) value);
+        } else if (value instanceof Size) {
+            putSize(key, (Size) value);
+        } else if (value instanceof SizeF) {
+            putSizeF(key, (SizeF) value);
+        } else if (value instanceof Parcelable[]) {
+            putParcelableArray(key, (Parcelable[]) value);
+        } else if (value instanceof ArrayList) {
+            putParcelableArrayList(key, (ArrayList) value);
+        } else if (value instanceof List) {
+            putParcelableList(key, (List) value);
+        } else if (value instanceof SparseArray) {
+            putSparseParcelableArray(key, (SparseArray) value);
+        } else if (value instanceof Serializable) {
+            putSerializable(key, (Serializable) value);
+        } else if (value instanceof byte[]) {
+            putByteArray(key, (byte[]) value);
+        } else if (value instanceof short[]) {
+            putShortArray(key, (short[]) value);
+        } else if (value instanceof char[]) {
+            putCharArray(key, (char[]) value);
+        } else if (value instanceof float[]) {
+            putFloatArray(key, (float[]) value);
+        } else if (value instanceof CharSequence[]) {
+            putCharSequenceArray(key, (CharSequence[]) value);
+        } else if (value instanceof Bundle) {
+            putBundle(key, (Bundle) value);
+        } else if (value instanceof Binder) {
+            putBinder(key, (Binder) value);
+        } else if (value instanceof IBinder) {
+            putIBinder(key, (IBinder) value);
+        } else {
+            super.putObject(key, value);
+        }
+    }
+
     /**
      * Inserts a byte value into the mapping of this Bundle, replacing
      * any existing value for the given key.
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 1f6c3cc..2e3b000 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -221,4 +221,7 @@
      */
     public abstract boolean isSettingRestrictedForUser(String setting, int userId, String value,
             int callingUid);
+
+    /** @return a specific user restriction that's in effect currently. */
+    public abstract boolean hasUserRestriction(String restriction, int userId);
 }
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index cdd0d45..eaf9929 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -738,6 +738,31 @@
     }
 
     /**
+     * Notify the Zygote processes that boot completed.
+     */
+    public void bootCompleted() {
+        // Notify both the 32-bit and 64-bit zygote.
+        if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+            bootCompleted(Build.SUPPORTED_32_BIT_ABIS[0]);
+        }
+        if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+            bootCompleted(Build.SUPPORTED_64_BIT_ABIS[0]);
+        }
+    }
+
+    private void bootCompleted(String abi) {
+        try {
+            synchronized (mLock) {
+                ZygoteState state = openZygoteSocketIfNeeded(abi);
+                state.mZygoteOutputWriter.write("1\n--boot-completed\n");
+                state.mZygoteOutputWriter.flush();
+            }
+        } catch (Exception ex) {
+            throw new RuntimeException("Failed to inform zygote of boot_completed", ex);
+        }
+    }
+
+    /**
      * Push hidden API blacklisting exemptions into the zygote process(es).
      *
      * <p>The list of exemptions will take affect for all new processes forked from the zygote after
diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java
index cec1945..e4f88c5 100644
--- a/core/java/android/os/image/DynamicSystemManager.java
+++ b/core/java/android/os/image/DynamicSystemManager.java
@@ -76,7 +76,7 @@
         @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
         public boolean commit() {
             try {
-                return mService.commit();
+                return mService.setEnable(true, true);
             } catch (RemoteException e) {
                 throw new RuntimeException(e.toString());
             }
@@ -188,9 +188,9 @@
      * @return {@code true} if the call succeeds. {@code false} if there is no installed image.
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
-    public boolean setEnable(boolean enable) {
+    public boolean setEnable(boolean enable, boolean oneShot) {
         try {
-            return mService.setEnable(enable);
+            return mService.setEnable(enable, oneShot);
         } catch (RemoteException e) {
             throw new RuntimeException(e.toString());
         }
diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl
index a34daca..2f4ab2d 100644
--- a/core/java/android/os/image/IDynamicSystemService.aidl
+++ b/core/java/android/os/image/IDynamicSystemService.aidl
@@ -72,9 +72,11 @@
     /**
      * Enable or disable DynamicSystem.
      *
+     * @param oneShot       If true, the GSI will boot once and then disable itself.
+     *
      * @return true if the call succeeds
      */
-    boolean setEnable(boolean enable);
+    boolean setEnable(boolean enable, boolean oneShot);
 
     /**
      * Write a chunk of the DynamicSystem system image
@@ -83,10 +85,4 @@
      */
     boolean write(in byte[] buf);
 
-    /**
-     * Finish write and make device to boot into the it after reboot.
-     *
-     * @return true if the call succeeds
-     */
-    boolean commit();
 }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 69c1295..5b9205d 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1987,11 +1987,31 @@
      */
     public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2;
 
+    /**
+     * Flag indicating that a disk space check should not take into account
+     * freeable cached space when determining allocatable space.
+     *
+     * Intended for use with {@link #getAllocatableBytes()}.
+     * @hide
+     */
+    public static final int FLAG_ALLOCATE_NON_CACHE_ONLY = 1 << 3;
+
+    /**
+     * Flag indicating that a disk space check should only return freeable
+     * cached space when determining allocatable space.
+     *
+     * Intended for use with {@link #getAllocatableBytes()}.
+     * @hide
+     */
+    public static final int FLAG_ALLOCATE_CACHE_ONLY = 1 << 4;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "FLAG_ALLOCATE_" }, value = {
             FLAG_ALLOCATE_AGGRESSIVE,
             FLAG_ALLOCATE_DEFY_ALL_RESERVED,
             FLAG_ALLOCATE_DEFY_HALF_RESERVED,
+            FLAG_ALLOCATE_NON_CACHE_ONLY,
+            FLAG_ALLOCATE_CACHE_ONLY,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface AllocateFlags {}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 81e1eb9..af3a16c 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -870,8 +870,8 @@
     protected interface ContactOptionsColumns {
         /**
          * The number of times a contact has been contacted.
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field is obsolete. For
-         * more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.</p>
          * <P>Type: INTEGER</P>
@@ -885,8 +885,8 @@
 
         /**
          * The last time a contact was contacted.
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field is obsolete. For
-         * more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.</p>
          * <P>Type: INTEGER</P>
@@ -1691,10 +1691,10 @@
          * TIMES_CONTACTED field is incremented by 1 and the LAST_TIME_CONTACTED
          * field is populated with the current system time.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this method is obsolete. For
-         * more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
-         * page.
+         * page.</p>
          *
          * @param resolver the ContentResolver to use
          * @param contactId the person who was contacted
@@ -1730,8 +1730,8 @@
          * Frequent contacts are no longer included in the result as of
          * Android version {@link android.os.Build.VERSION_CODES#Q}.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-         * results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          */
@@ -1745,8 +1745,8 @@
          * Android version {@link android.os.Build.VERSION_CODES#Q}.
          * This URI always returns an empty cursor.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-         * results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          */
@@ -1760,8 +1760,8 @@
          * various parts of the contact name. The filter argument should be passed
          * as an additional path segment after this URI.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-         * results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          */
@@ -4292,10 +4292,10 @@
          * Android version {@link android.os.Build.VERSION_CODES#Q}.
          * This column always contains 0.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field is obsolete.
-         * For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
-         * page.
+         * page.</p>
          */
         @Deprecated
         public static final String LAST_TIME_USED = "last_time_used";
@@ -4306,10 +4306,10 @@
          * Android version {@link android.os.Build.VERSION_CODES#Q}.
          * This column always contains 0.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field is obsolete.
-         * For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+         * this field is obsolete, regardless of Android version. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
-         * page.
+         * page.</p>
          */
         @Deprecated
         public static final String TIMES_USED = "times_used";
@@ -5259,8 +5259,8 @@
         /**
          * The content:// style URI for this table.
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-         * sorts results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          *
@@ -5277,8 +5277,8 @@
         /**
          * <p>URI used for the "enterprise caller-id".</p>
          *
-         * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-         * sorts results based on contacts frequency. For more information, see the
+         * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
+         * field doesn't sort results based on contacts frequency. For more information, see the
          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
          * page.
          *
@@ -6079,8 +6079,8 @@
              * to display names as well as phone numbers. The filter argument should be passed
              * as an additional path segment after this URI.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>This field deosn't sort results based on contacts
+             * frequency. For more information, see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -6092,8 +6092,9 @@
              * same columns. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
              * parameters, otherwise it will throw IllegalArgumentException.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-             * results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -6360,8 +6361,9 @@
              * as an additional path segment after this URI.
              * </p>
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer sorts
-             * results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.</p>
              *
@@ -6383,8 +6385,9 @@
              * same columns. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
              * parameters, otherwise it will throw IllegalArgumentException.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -7602,8 +7605,8 @@
              * <p>Similar to {@link Phone#CONTENT_FILTER_URI}, but allows users to filter callable
              * data.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>This field no longer sorts results based on
+             * contacts frequency. For more information, see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -7615,8 +7618,9 @@
              * callable data. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
              * parameters, otherwise it will throw IllegalArgumentException.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.</p>
              */
@@ -7646,8 +7650,9 @@
              * <p>The content:// style URI for these data items, which allows for a query parameter
              * to be appended onto the end to filter for data items matching the query.
              *
-             * <p class="caution"><b>Caution: </b>As of January 7, 2019, this field no longer
-             * sorts results based on contacts frequency. For more information, see the
+             * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+             * this field doesn't sort results based on contacts frequency. For more information,
+             * see the
              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
              * page.
              */
@@ -8298,15 +8303,14 @@
     }
 
     /**
-     * <p class="caution"><b>Caution: </b>As of January 7, 2019, this class is obsolete. For
-     * more information, see the
-     * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
-     * page.
-     * </p>
      * <p>
      * API allowing applications to send usage information for each {@link Data} row to the
      * Contacts Provider.  Applications can also clear all usage information.
      * </p>
+     * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
+     * this field is obsolete, regardless of Android version. For more information, see the
+     * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
+     * page.</p>
      * <p>
      * With the feedback, Contacts Provider may return more contextually appropriate results for
      * Data listing, typically supplied with
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index d0401e3..4f7c8c5 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -346,6 +346,20 @@
                 "system_gestures_excluded_by_pre_q_sticky_immersive";
 
         /**
+         * The minimum duration between gesture exclusion logging for a given window in
+         * milliseconds.
+         *
+         * Events that happen in-between will be silently dropped.
+         *
+         * A non-positive value disables logging.
+         *
+         * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER
+         * @hide
+         */
+        String KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS =
+                "system_gesture_exclusion_log_debounce_millis";
+
+        /**
          * Key for controlling which packages are explicitly blocked from running at refresh rates
          * higher than 90hz.
          *
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 2a590ce..2299aad 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -137,6 +137,8 @@
     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";
@@ -3562,6 +3564,17 @@
 
     /** @hide */
     @TestApi
+    public static void waitForIdle(Context context) {
+        final ContentResolver resolver = context.getContentResolver();
+        try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
+            client.call(WAIT_FOR_IDLE_CALL, null, null);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /** @hide */
+    @TestApi
     public static Uri scanFile(Context context, File file) {
         return scan(context, SCAN_FILE_CALL, file, false);
     }
diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java
index 70f434c..8331550 100644
--- a/core/java/android/service/autofill/FillContext.java
+++ b/core/java/android/service/autofill/FillContext.java
@@ -30,6 +30,8 @@
 import android.util.SparseIntArray;
 import android.view.autofill.AutofillId;
 
+import com.android.internal.util.DataClass;
+
 import java.util.LinkedList;
 
 /**
@@ -46,58 +48,36 @@
  * to {@link FillResponse.Builder#setClientState(Bundle)} to avoid interpreting
  * the UI state again while saving.
  */
+@DataClass(
+        genHiddenConstructor = true,
+        genAidl = false)
 public final class FillContext implements Parcelable {
+
+    /**
+     * The id of the {@link FillRequest fill request} this context
+     * corresponds to. This is useful to associate your custom client
+     * state with every request to avoid reinterpreting the UI when saving
+     * user data.
+     */
     private final int mRequestId;
+
+    /**
+     * The screen content.
+     */
     private final @NonNull AssistStructure mStructure;
+
+    /**
+     * The AutofillId of the view that triggered autofill.
+     */
     private final @NonNull AutofillId mFocusedId;
 
     /**
      * Lookup table AutofillId->ViewNode to speed up {@link #findViewNodesByAutofillIds}
      * This is purely a cache and can be deleted at any time
      */
-    @Nullable private ArrayMap<AutofillId, AssistStructure.ViewNode> mViewNodeLookupTable;
+    private transient @Nullable ArrayMap<AutofillId, AssistStructure.ViewNode> mViewNodeLookupTable;
 
 
-    /** @hide */
-    public FillContext(int requestId, @NonNull AssistStructure structure,
-            @NonNull AutofillId autofillId) {
-        mRequestId = requestId;
-        mStructure = structure;
-        mFocusedId = autofillId;
-    }
-
-    private FillContext(Parcel parcel) {
-        this(parcel.readInt(), parcel.readParcelable(null), parcel.readParcelable(null));
-    }
-
-    /**
-     * Gets the id of the {@link FillRequest fill request} this context
-     * corresponds to. This is useful to associate your custom client
-     * state with every request to avoid reinterpreting the UI when saving
-     * user data.
-     *
-     * @return The request id.
-     */
-    public int getRequestId() {
-        return mRequestId;
-    }
-
-    /**
-     * @return The screen content.
-     */
-    @NonNull
-    public AssistStructure getStructure() {
-        return mStructure;
-    }
-
-    /**
-     * @return the AutofillId of the view that triggered autofill.
-     */
-    @NonNull
-    public AutofillId getFocusedId() {
-        return mFocusedId;
-    }
-
     @Override
     public String toString() {
         if (!sDebug)  return super.toString();
@@ -105,18 +85,6 @@
         return "FillContext [reqId=" + mRequestId + ", focusedId=" + mFocusedId + "]";
     }
 
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeInt(mRequestId);
-        parcel.writeParcelable(mStructure, flags);
-        parcel.writeParcelable(mFocusedId, flags);
-    }
-
     /**
      * Finds {@link ViewNode ViewNodes} that have the requested ids.
      *
@@ -190,18 +158,119 @@
         return foundNodes;
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<FillContext> CREATOR =
-            new Parcelable.Creator<FillContext>() {
-        @Override
-        @NonNull
-        public FillContext createFromParcel(Parcel parcel) {
-            return new FillContext(parcel);
-        }
 
+
+    // Code below generated by codegen v1.0.0.
+    //
+    // DO NOT MODIFY!
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/autofill/FillContext.java
+    //
+    // CHECKSTYLE:OFF Generated code
+
+    /**
+     * Creates a new FillContext.
+     *
+     * @param requestId
+     *   The id of the {@link FillRequest fill request} this context
+     *   corresponds to. This is useful to associate your custom client
+     *   state with every request to avoid reinterpreting the UI when saving
+     *   user data.
+     * @param structure
+     *   The screen content.
+     * @param focusedId
+     *   The AutofillId of the view that triggered autofill.
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public FillContext(
+            int requestId,
+            @NonNull AssistStructure structure,
+            @NonNull AutofillId focusedId) {
+        this.mRequestId = requestId;
+        this.mStructure = structure;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mStructure);
+        this.mFocusedId = focusedId;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mFocusedId);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * The id of the {@link FillRequest fill request} this context
+     * corresponds to. This is useful to associate your custom client
+     * state with every request to avoid reinterpreting the UI when saving
+     * user data.
+     */
+    @DataClass.Generated.Member
+    public int getRequestId() {
+        return mRequestId;
+    }
+
+    /**
+     * The screen content.
+     */
+    @DataClass.Generated.Member
+    public @NonNull AssistStructure getStructure() {
+        return mStructure;
+    }
+
+    /**
+     * The AutofillId of the view that triggered autofill.
+     */
+    @DataClass.Generated.Member
+    public @NonNull AutofillId getFocusedId() {
+        return mFocusedId;
+    }
+
+    @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(mRequestId);
+        dest.writeTypedObject(mStructure, flags);
+        dest.writeTypedObject(mFocusedId, flags);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<FillContext> CREATOR
+            = new Parcelable.Creator<FillContext>() {
         @Override
-        @NonNull
         public FillContext[] newArray(int size) {
             return new FillContext[size];
         }
+
+        @Override
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        public FillContext createFromParcel(Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            int requestId = in.readInt();
+            AssistStructure structure = (AssistStructure) in.readTypedObject(AssistStructure.CREATOR);
+            AutofillId focusedId = (AutofillId) in.readTypedObject(AutofillId.CREATOR);
+            return new FillContext(
+                    requestId,
+                    structure,
+                    focusedId);
+        }
     };
+
+    @DataClass.Generated(
+            time = 1565152135263L,
+            codegenVersion = "1.0.0",
+            sourceFile = "frameworks/base/core/java/android/service/autofill/FillContext.java",
+            inputSignatures = "private final  int mRequestId\nprivate final @android.annotation.NonNull android.app.assist.AssistStructure mStructure\nprivate final @android.annotation.NonNull android.view.autofill.AutofillId mFocusedId\nprivate transient @android.annotation.Nullable android.util.ArrayMap<android.view.autofill.AutofillId,android.app.assist.AssistStructure.ViewNode> mViewNodeLookupTable\npublic @java.lang.Override java.lang.String toString()\npublic @android.annotation.NonNull android.app.assist.AssistStructure.ViewNode[] findViewNodesByAutofillIds(android.view.autofill.AutofillId[])\nclass FillContext extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genAidl=false)")
+    @Deprecated
+    private void __metadata() {}
+
 }
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 91f77ea..e53ebad 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -24,6 +24,7 @@
 import android.os.Parcelable;
 import android.view.View;
 
+import com.android.internal.util.DataClass;
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
@@ -39,6 +40,10 @@
  *
  * @see AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)
  */
+@DataClass(
+        genToString = true,
+        genHiddenConstructor = true,
+        genHiddenConstDefs = true)
 public final class FillRequest implements Parcelable {
 
     /**
@@ -63,54 +68,45 @@
      * is called. For example, standard {@link android.widget.TextView} views show an
      * {@code AUTOFILL} option in the overflow menu that triggers such request.
      */
-    public static final int FLAG_MANUAL_REQUEST = 0x1;
+    public static final @RequestFlags int FLAG_MANUAL_REQUEST = 0x1;
 
     /**
      * Indicates this request was made using
      * <a href="AutofillService.html#CompatibilityMode">compatibility mode</a>.
      */
-    public static final int FLAG_COMPATIBILITY_MODE_REQUEST = 0x2;
+    public static final @RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST = 0x2;
 
     /** @hide */
     public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
 
-    /** @hide */
-    @IntDef(flag = true, prefix = { "FLAG_" }, value = {
-            FLAG_MANUAL_REQUEST, FLAG_COMPATIBILITY_MODE_REQUEST
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    @interface RequestFlags{}
-
-    private final int mId;
-    private final @RequestFlags int mFlags;
-    private final @NonNull ArrayList<FillContext> mContexts;
-    private final @Nullable Bundle mClientState;
-
-    private FillRequest(@NonNull Parcel parcel) {
-        mId = parcel.readInt();
-        mContexts = new ArrayList<>();
-        parcel.readParcelableList(mContexts, null);
-
-        mClientState = parcel.readBundle();
-        mFlags = parcel.readInt();
-    }
-
-    /** @hide */
-    public FillRequest(int id, @NonNull ArrayList<FillContext> contexts,
-            @Nullable Bundle clientState, @RequestFlags int flags) {
-        mId = id;
-        mFlags = Preconditions.checkFlagsArgument(flags,
-                FLAG_MANUAL_REQUEST | FLAG_COMPATIBILITY_MODE_REQUEST);
-        mContexts = Preconditions.checkCollectionElementsNotNull(contexts, "contexts");
-        mClientState = clientState;
-    }
-
     /**
      * Gets the unique id of this request.
      */
-    public int getId() {
-        return mId;
-    }
+    private final int mId;
+
+    /**
+     * Gets the contexts associated with each previous fill request.
+     *
+     * <p><b>Note:</b> Starting on Android {@link android.os.Build.VERSION_CODES#Q}, it could also
+     * include contexts from requests whose {@link SaveInfo} had the
+     * {@link SaveInfo#FLAG_DELAY_SAVE} flag.
+     */
+    private final @NonNull List<FillContext> mFillContexts;
+
+    /**
+     * Gets the latest client state bundle set by the service in a
+     * {@link FillResponse.Builder#setClientState(Bundle) fill response}.
+     *
+     * <p><b>Note:</b> Prior to Android {@link android.os.Build.VERSION_CODES#P}, only client state
+     * bundles set by {@link FillResponse.Builder#setClientState(Bundle)} were considered. On
+     * Android {@link android.os.Build.VERSION_CODES#P} and higher, bundles set in the result of
+     * an authenticated request through the
+     * {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE} extra are
+     * also considered (and take precedence when set).
+     *
+     * @return The client state.
+     */
+    private final @Nullable Bundle mClientState;
 
     /**
      * Gets the flags associated with this request.
@@ -118,8 +114,105 @@
      * @return any combination of {@link #FLAG_MANUAL_REQUEST} and
      *         {@link #FLAG_COMPATIBILITY_MODE_REQUEST}.
      */
-    public @RequestFlags int getFlags() {
-        return mFlags;
+    private final @RequestFlags int mFlags;
+
+    private void onConstructed() {
+        Preconditions.checkCollectionElementsNotNull(mFillContexts, "contexts");
+    }
+
+
+
+    // Code below generated by codegen v1.0.0.
+    //
+    // DO NOT MODIFY!
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/autofill/FillRequest.java
+    //
+    // CHECKSTYLE:OFF Generated code
+
+    /** @hide */
+    @IntDef(flag = true, prefix = "FLAG_", value = {
+        FLAG_MANUAL_REQUEST,
+        FLAG_COMPATIBILITY_MODE_REQUEST
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface RequestFlags {}
+
+    /** @hide */
+    @DataClass.Generated.Member
+    public static String requestFlagsToString(@RequestFlags int value) {
+        return com.android.internal.util.BitUtils.flagsToString(
+                value, FillRequest::singleRequestFlagsToString);
+    }
+
+    @DataClass.Generated.Member
+    static String singleRequestFlagsToString(@RequestFlags int value) {
+        switch (value) {
+            case FLAG_MANUAL_REQUEST:
+                    return "FLAG_MANUAL_REQUEST";
+            case FLAG_COMPATIBILITY_MODE_REQUEST:
+                    return "FLAG_COMPATIBILITY_MODE_REQUEST";
+            default: return Integer.toHexString(value);
+        }
+    }
+
+    /**
+     * Creates a new FillRequest.
+     *
+     * @param id
+     *   Gets the unique id of this request.
+     * @param fillContexts
+     *   Gets the contexts associated with each previous fill request.
+     *
+     *   <p><b>Note:</b> Starting on Android {@link android.os.Build.VERSION_CODES#Q}, it could also
+     *   include contexts from requests whose {@link SaveInfo} had the
+     *   {@link SaveInfo#FLAG_DELAY_SAVE} flag.
+     * @param clientState
+     *   Gets the latest client state bundle set by the service in a
+     *   {@link FillResponse.Builder#setClientState(Bundle) fill response}.
+     *
+     *   <p><b>Note:</b> Prior to Android {@link android.os.Build.VERSION_CODES#P}, only client state
+     *   bundles set by {@link FillResponse.Builder#setClientState(Bundle)} were considered. On
+     *   Android {@link android.os.Build.VERSION_CODES#P} and higher, bundles set in the result of
+     *   an authenticated request through the
+     *   {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE} extra are
+     *   also considered (and take precedence when set).
+     * @param flags
+     *   Gets the flags associated with this request.
+     *
+     *   @return any combination of {@link #FLAG_MANUAL_REQUEST} and
+     *           {@link #FLAG_COMPATIBILITY_MODE_REQUEST}.
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public FillRequest(
+            int id,
+            @NonNull List<FillContext> fillContexts,
+            @Nullable Bundle clientState,
+            @RequestFlags int flags) {
+        this.mId = id;
+        this.mFillContexts = fillContexts;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mFillContexts);
+        this.mClientState = clientState;
+        this.mFlags = flags;
+
+        Preconditions.checkFlagsArgument(
+                mFlags,
+                FLAG_MANUAL_REQUEST
+                        | FLAG_COMPATIBILITY_MODE_REQUEST);
+
+        onConstructed();
+    }
+
+    /**
+     * Gets the unique id of this request.
+     */
+    @DataClass.Generated.Member
+    public int getId() {
+        return mId;
     }
 
     /**
@@ -129,13 +222,9 @@
      * include contexts from requests whose {@link SaveInfo} had the
      * {@link SaveInfo#FLAG_DELAY_SAVE} flag.
      */
+    @DataClass.Generated.Member
     public @NonNull List<FillContext> getFillContexts() {
-        return mContexts;
-    }
-
-    @Override
-    public String toString() {
-        return "FillRequest: [id=" + mId + ", flags=" + mFlags + ", ctxts= " + mContexts + "]";
+        return mFillContexts;
     }
 
     /**
@@ -151,33 +240,89 @@
      *
      * @return The client state.
      */
+    @DataClass.Generated.Member
     public @Nullable Bundle getClientState() {
         return mClientState;
     }
 
-    @Override
-    public int describeContents() {
-        return 0;
+    /**
+     * Gets the flags associated with this request.
+     *
+     * @return any combination of {@link #FLAG_MANUAL_REQUEST} and
+     *         {@link #FLAG_COMPATIBILITY_MODE_REQUEST}.
+     */
+    @DataClass.Generated.Member
+    public @RequestFlags int getFlags() {
+        return mFlags;
     }
 
     @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeInt(mId);
-        parcel.writeParcelableList(mContexts, flags);
-        parcel.writeBundle(mClientState);
-        parcel.writeInt(mFlags);
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "FillRequest { " +
+                "id = " + mId + ", " +
+                "fillContexts = " + mFillContexts + ", " +
+                "clientState = " + mClientState + ", " +
+                "flags = " + requestFlagsToString(mFlags) +
+        " }";
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<FillRequest> CREATOR =
-            new Parcelable.Creator<FillRequest>() {
-        @Override
-        public FillRequest createFromParcel(Parcel parcel) {
-            return new FillRequest(parcel);
-        }
+    @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) { ... }
 
+        byte flg = 0;
+        if (mClientState != null) flg |= 0x4;
+        dest.writeByte(flg);
+        dest.writeInt(mId);
+        dest.writeParcelableList(mFillContexts, flags);
+        if (mClientState != null) dest.writeBundle(mClientState);
+        dest.writeInt(mFlags);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<FillRequest> CREATOR
+            = new Parcelable.Creator<FillRequest>() {
         @Override
         public FillRequest[] newArray(int size) {
             return new FillRequest[size];
         }
+
+        @Override
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        public FillRequest createFromParcel(Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            byte flg = in.readByte();
+            int id = in.readInt();
+            List<FillContext> fillContexts = new ArrayList<>();
+            in.readParcelableList(fillContexts, FillContext.class.getClassLoader());
+            Bundle clientState = (flg & 0x4) == 0 ? null : in.readBundle();
+            int flags = in.readInt();
+            return new FillRequest(
+                    id,
+                    fillContexts,
+                    clientState,
+                    flags);
+        }
     };
+
+    @DataClass.Generated(
+            time = 1565152134349L,
+            codegenVersion = "1.0.0",
+            sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
+            inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final  int INVALID_REQUEST_ID\nprivate final  int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate  void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+    @Deprecated
+    private void __metadata() {}
+
 }
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 12d3228..da40254 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -293,6 +293,11 @@
                 Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e);
                 return;
             }
+            if (sbn == null) {
+                Log.w(TAG, "onNotificationEnqueuedWithChannel: "
+                        + "Error receiving StatusBarNotification");
+                return;
+            }
 
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = sbn;
@@ -311,6 +316,10 @@
                 Log.w(TAG, "onNotificationSnoozed: Error receiving StatusBarNotification", e);
                 return;
             }
+            if (sbn == null) {
+                Log.w(TAG, "onNotificationSnoozed: Error receiving StatusBarNotification");
+                return;
+            }
 
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = sbn;
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index b44c9d5..78e30ab 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1272,6 +1272,10 @@
                 Log.w(TAG, "onNotificationPosted: Error receiving StatusBarNotification", e);
                 return;
             }
+            if (sbn == null) {
+                Log.w(TAG, "onNotificationPosted: Error receiving StatusBarNotification");
+                return;
+            }
 
             try {
                 // convert icon metadata to legacy format for older clients
@@ -1313,6 +1317,10 @@
                 Log.w(TAG, "onNotificationRemoved: Error receiving StatusBarNotification", e);
                 return;
             }
+            if (sbn == null) {
+                Log.w(TAG, "onNotificationRemoved: Error receiving StatusBarNotification");
+                return;
+            }
             // protect subclass from concurrent modifications of (@link mNotificationKeys}.
             synchronized (mLock) {
                 applyUpdateLocked(update);
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 6aef5a5..b66764e 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -41,13 +41,14 @@
     public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
     public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
     public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
+    public static final String USE_BUGREPORT_API = "settings_use_bugreport_api";
 
     private static final Map<String, String> DEFAULT_FLAGS;
 
     static {
         DEFAULT_FLAGS = new HashMap<>();
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
-        DEFAULT_FLAGS.put("settings_call_bugreport_api", "false");
+        DEFAULT_FLAGS.put("settings_use_bugreport_api", "true");
         DEFAULT_FLAGS.put("settings_mobile_network_v2", "true");
         DEFAULT_FLAGS.put("settings_network_and_internet_v2", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
diff --git a/core/java/android/util/LruCache.java b/core/java/android/util/LruCache.java
index f04e7cb..3cbf727d 100644
--- a/core/java/android/util/LruCache.java
+++ b/core/java/android/util/LruCache.java
@@ -17,6 +17,7 @@
 package android.util;
 
 import android.annotation.UnsupportedAppUsage;
+
 import java.util.LinkedHashMap;
 import java.util.Map;
 
@@ -260,7 +261,7 @@
      * @param evicted true if the entry is being removed to make space, false
      *     if the removal was caused by a {@link #put} or {@link #remove}.
      * @param newValue the new value for {@code key}, if it exists. If non-null,
-     *     this removal was caused by a {@link #put}. Otherwise it was caused by
+     *     this removal was caused by a {@link #put} or a {@link #get}. Otherwise it was caused by
      *     an eviction or a {@link #remove}.
      */
     protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index dcdef3e..ea66656 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -220,7 +220,7 @@
         int SWAP_BUFFERS = 12;
         int FRAME_COMPLETED = 13;
 
-        int FRAME_STATS_COUNT = 16; // must always be last
+        int FRAME_STATS_COUNT = 17; // must always be last
     }
 
     /*
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index 6cda60c..724d96e 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.app.ActivityManager;
 import android.graphics.Rect;
 import android.view.RemoteAnimationTarget;
 import android.view.IRecentsAnimationController;
@@ -33,16 +34,16 @@
      * wallpaper not drawing in time, or the handler not finishing the animation within a predefined
      * amount of time.
      *
-     * @param deferredWithScreenshot If set to {@code true}, the contents of the task will be
-     *                               replaced with a screenshot, such that the runner's leash is
-     *                               still active. As soon as the runner doesn't need the leash
-     *                               anymore, it must call
-     *                               {@link IRecentsAnimationController#cleanupScreenshot).
+     * @param taskSnapshot If the snapshot is null, the animation will be cancelled and the leash
+     *                     will be inactive immediately. Otherwise, the contents of the task will be
+     *                     replaced with {@param taskSnapshot}, such that the runner's leash is
+     *                     still active. As soon as the runner doesn't need the leash anymore, it
+     *                     must call {@link IRecentsAnimationController#cleanupScreenshot).
      *
      * @see {@link RecentsAnimationController#cleanupScreenshot}
      */
     @UnsupportedAppUsage
-    void onAnimationCanceled(boolean deferredWithScreenshot) = 1;
+    void onAnimationCanceled(in @nullable ActivityManager.TaskSnapshot taskSnapshot) = 1;
 
     /**
      * Called when the system is ready for the handler to start animating all the visible tasks.
diff --git a/core/java/android/view/ISystemGestureExclusionListener.aidl b/core/java/android/view/ISystemGestureExclusionListener.aidl
index a032625..9c2f9a6 100644
--- a/core/java/android/view/ISystemGestureExclusionListener.aidl
+++ b/core/java/android/view/ISystemGestureExclusionListener.aidl
@@ -28,7 +28,14 @@
      * Called when the system gesture exclusion for the given display changed.
      * @param displayId the display whose system gesture exclusion changed
      * @param systemGestureExclusion a {@code Region} where the app would like priority over the
-     *                               system gestures, in display coordinates.
+     *                               system gestures, in display coordinates. Certain restrictions
+     *                               might be applied such that apps don't get all the exclusions
+     *                               they request.
+     * @param systemGestureExclusionUnrestricted a {@code Region} where the app would like priority
+     *                               over the system gestures, in display coordinates, without
+     *                               any restrictions applied. Null if no restrictions have been
+     *                               applied.
      */
-    void onSystemGestureExclusionChanged(int displayId, in Region systemGestureExclusion);
+    void onSystemGestureExclusionChanged(int displayId, in Region systemGestureExclusion,
+            in Region systemGestureExclusionUnrestricted);
 }
\ No newline at end of file
diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java
index bc2fe54..c686440 100644
--- a/core/java/android/view/RemoteAnimationAdapter.java
+++ b/core/java/android/view/RemoteAnimationAdapter.java
@@ -55,6 +55,7 @@
 
     /** @see #getCallingPid */
     private int mCallingPid;
+    private int mCallingUid;
 
     /**
      * @param runner The interface that gets notified when we actually need to start the animation.
@@ -103,10 +104,11 @@
     }
 
     /**
-     * To be called by system_server to keep track which pid is running this animation.
+     * To be called by system_server to keep track which pid and uid is running this animation.
      */
-    public void setCallingPid(int pid) {
+    public void setCallingPidUid(int pid, int uid) {
         mCallingPid = pid;
+        mCallingUid = uid;
     }
 
     /**
@@ -116,6 +118,13 @@
         return mCallingPid;
     }
 
+    /**
+     * @return The uid of the process running the animation.
+     */
+    public int getCallingUid() {
+        return mCallingUid;
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java
index 884cae4..da599ef 100644
--- a/core/java/android/view/RemoteAnimationDefinition.java
+++ b/core/java/android/view/RemoteAnimationDefinition.java
@@ -118,9 +118,9 @@
      * To be called by system_server to keep track which pid is running the remote animations inside
      * this definition.
      */
-    public void setCallingPid(int pid) {
+    public void setCallingPidUid(int pid, int uid) {
         for (int i = mTransitionAnimationMap.size() - 1; i >= 0; i--) {
-            mTransitionAnimationMap.valueAt(i).adapter.setCallingPid(pid);
+            mTransitionAnimationMap.valueAt(i).adapter.setCallingPidUid(pid, uid);
         }
     }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1779a80..6d4128b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13386,10 +13386,10 @@
 
         if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) {
             mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED;
-            if (mParent != null) {
+            if (mParent != null && mParent instanceof View) {
                 try {
                     mParent.notifySubtreeAccessibilityStateChanged(
-                            this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
+                            this, (View) mParent, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
                 } catch (AbstractMethodError e) {
                     Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
                             " does not fully implement ViewParent", e);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 82a5fa9..7ee8865 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5144,7 +5144,7 @@
         }
 
         if (child.getVisibility() != View.GONE) {
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            child.notifySubtreeAccessibilityStateChangedIfNeeded();
         }
 
         if (mTransientIndices != null) {
@@ -5432,7 +5432,7 @@
         dispatchViewRemoved(view);
 
         if (view.getVisibility() != View.GONE) {
-            notifySubtreeAccessibilityStateChangedIfNeeded();
+            view.notifySubtreeAccessibilityStateChangedIfNeeded();
         }
 
         int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
@@ -5740,7 +5740,7 @@
         }
         dispatchVisibilityAggregated(isAttachedToWindow() && getWindowVisibility() == VISIBLE
                 && isShown());
-        notifySubtreeAccessibilityStateChangedIfNeeded();
+        child.notifySubtreeAccessibilityStateChangedIfNeeded();
     }
 
     /**
@@ -6146,7 +6146,8 @@
         if (invalidate) {
             invalidateViewProperty(false, false);
         }
-        notifySubtreeAccessibilityStateChangedIfNeeded();
+        notifySubtreeAccessibilityStateChanged(
+                this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
     }
 
     @Override
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index c3e08fc..bbcba2e 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -91,6 +91,7 @@
     @UnsupportedAppUsage
     private float mDisabledAlpha;
 
+    private int mThumbExclusionMaxSize;
     private int mScaledTouchSlop;
     private float mTouchDownX;
     @UnsupportedAppUsage
@@ -171,6 +172,8 @@
         applyTickMarkTint();
 
         mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mThumbExclusionMaxSize = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.seekbar_thumb_exclusion_max_size);
     }
 
     /**
@@ -763,12 +766,30 @@
         }
         mGestureExclusionRects.clear();
         thumb.copyBounds(mThumbRect);
+        mThumbRect.offset(mPaddingLeft - mThumbOffset, mPaddingTop);
+        growRectTo(mThumbRect, Math.min(getHeight(), mThumbExclusionMaxSize));
         mGestureExclusionRects.add(mThumbRect);
         mGestureExclusionRects.addAll(mUserGestureExclusionRects);
         super.setSystemGestureExclusionRects(mGestureExclusionRects);
     }
 
     /**
+     * Grows {@code r} from its center such that each dimension is at least {@code minimumSize}.
+     */
+    private void growRectTo(Rect r, int minimumSize) {
+        int dy = (minimumSize - r.height()) / 2;
+        if (dy > 0) {
+            r.top -= dy;
+            r.bottom += dy;
+        }
+        int dx = (minimumSize - r.width()) / 2;
+        if (dx > 0) {
+            r.left -= dx;
+            r.right += dx;
+        }
+    }
+
+    /**
      * @hide
      */
     @Override
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index c55f7d6..5359e27 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -1106,7 +1106,8 @@
             checkSelectionChanged();
         }
 
-        notifySubtreeAccessibilityStateChangedIfNeeded();
+        notifySubtreeAccessibilityStateChanged(
+                this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
     }
 
     /**
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 90cb1c8..45e635ebe 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -59,13 +59,21 @@
     private static final int TABWIDGET_LOCATION_BOTTOM = 3;
     private TabWidget mTabWidget;
     private FrameLayout mTabContent;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                    + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                    + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                    + "\">TabLayout and ViewPager</a>")
     private List<TabSpec> mTabSpecs = new ArrayList<TabSpec>(2);
     /**
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                    + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                    + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                    + "\">TabLayout and ViewPager</a>")
     protected int mCurrentTab = -1;
     private View mCurrentView = null;
     /**
@@ -73,7 +81,11 @@
      * {@hide}
      */
     protected LocalActivityManager mLocalActivityManager = null;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                    + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                    + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                    + "\">TabLayout and ViewPager</a>")
     private OnTabChangeListener mOnTabChangeListener;
     private OnKeyListener mTabKeyListener;
 
@@ -514,9 +526,17 @@
 
         private final @NonNull String mTag;
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+                publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                        + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                        + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                        + "\">TabLayout and ViewPager</a>")
         private IndicatorStrategy mIndicatorStrategy;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+                publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                        + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                        + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                        + "\">TabLayout and ViewPager</a>")
         private ContentStrategy mContentStrategy;
 
         /**
@@ -779,7 +799,11 @@
             mIntent = intent;
         }
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+                publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                        + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                        + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                        + "\">TabLayout and ViewPager</a>")
         public View getContentView() {
             if (mLocalActivityManager == null) {
                 throw new IllegalStateException("Did you forget to call 'public void setup(LocalActivityManager activityGroup)'?");
@@ -809,7 +833,11 @@
             return mLaunchedView;
         }
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+                publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                        + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                        + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                        + "\">TabLayout and ViewPager</a>")
         public void tabClosed() {
             if (mLaunchedView != null) {
                 mLaunchedView.setVisibility(View.GONE);
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 434a799..bd0d039 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -65,7 +65,11 @@
     private OnTabSelectionChanged mSelectionChangedListener;
 
     // This value will be set to 0 as soon as the first tab is added to TabHost.
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                    + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                    + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                    + "\">TabLayout and ViewPager</a>")
     private int mSelectedTab = -1;
 
     @Nullable
@@ -74,7 +78,11 @@
     @Nullable
     private Drawable mRightStrip;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                    + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                    + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                    + "\">TabLayout and ViewPager</a>")
     private boolean mDrawBottomStrips = true;
     private boolean mStripMoved;
 
@@ -551,7 +559,11 @@
      * Provides a way for {@link TabHost} to be notified that the user clicked
      * on a tab indicator.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 137825207, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@code androidx.viewpager.widget.ViewPager} and "
+                    + "{@code com.google.android.material.tabs.TabLayout} instead.\n"
+                    + "See <a href=\"{@docRoot}guide/navigation/navigation-swipe-view"
+                    + "\">TabLayout and ViewPager</a>")
     void setTabSelectionListener(OnTabSelectionChanged listener) {
         mSelectionChangedListener = listener;
     }
diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index efcdb9a..f848309 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -195,7 +195,7 @@
         return applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp();
     }
 
-    private static boolean isDisclosureEnabled(Context context) {
+    public static boolean isDisclosureEnabled(Context context) {
         return Settings.Secure.getInt(context.getContentResolver(),
                 Settings.Secure.ASSIST_DISCLOSURE_ENABLED, 0) != 0;
     }
diff --git a/core/java/com/android/internal/colorextraction/ColorExtractor.java b/core/java/com/android/internal/colorextraction/ColorExtractor.java
index 3003ce8..f0da0d5 100644
--- a/core/java/com/android/internal/colorextraction/ColorExtractor.java
+++ b/core/java/com/android/internal/colorextraction/ColorExtractor.java
@@ -73,8 +73,10 @@
         }
 
         mOnColorsChangedListeners = new ArrayList<>();
-        wallpaperManager.addOnColorsChangedListener(this, null /* handler */);
-        initExtractColors(wallpaperManager, immediately);
+        if (wallpaperManager.isWallpaperSupported()) {
+            wallpaperManager.addOnColorsChangedListener(this, null /* handler */);
+            initExtractColors(wallpaperManager, immediately);
+        }
     }
 
     private void initExtractColors(WallpaperManager wallpaperManager, boolean immediately) {
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index ad1ff90..1d81c59 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -261,8 +261,21 @@
     public static boolean fitsOnInternal(Context context, SessionParams params) throws IOException {
         final StorageManager storage = context.getSystemService(StorageManager.class);
         final UUID target = storage.getUuidForPath(Environment.getDataDirectory());
-        return (params.sizeBytes <= storage.getAllocatableBytes(target,
-                translateAllocateFlags(params.installFlags)));
+        final int flags = translateAllocateFlags(params.installFlags);
+
+        final long allocateableBytes = storage.getAllocatableBytes(target,
+                flags | StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY);
+
+        // If we fit on internal storage without including freeable cache space, don't bother
+        // checking to determine how much space is taken up by the cache.
+        if (params.sizeBytes <= allocateableBytes) {
+            return true;
+        }
+
+        final long cacheClearable = storage.getAllocatableBytes(target,
+                flags | StorageManager.FLAG_ALLOCATE_CACHE_ONLY);
+
+        return params.sizeBytes <= allocateableBytes + cacheClearable;
     }
 
     public static boolean fitsOnExternal(Context context, SessionParams params) {
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 6d40266..abc4160 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -187,6 +187,11 @@
     boolean mPidQuery;
 
     /**
+     * Whether the current arguments constitute a notification that boot completed.
+     */
+    boolean mBootCompleted;
+
+    /**
      * Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time, or
      * when they change, via --set-api-blacklist-exemptions.
      */
@@ -361,6 +366,8 @@
                 mAbiListQuery = true;
             } else if (arg.equals("--get-pid")) {
                 mPidQuery = true;
+            } else if (arg.equals("--boot-completed")) {
+                mBootCompleted = true;
             } else if (arg.startsWith("--instruction-set=")) {
                 mInstructionSet = getAssignmentValue(arg);
             } else if (arg.startsWith("--app-data-dir=")) {
@@ -417,7 +424,11 @@
             }
         }
 
-        if (mAbiListQuery || mPidQuery) {
+        if (mBootCompleted) {
+            if (args.length - curArg > 0) {
+                throw new IllegalArgumentException("Unexpected arguments after --boot-completed");
+            }
+        } else if (mAbiListQuery || mPidQuery) {
             if (args.length - curArg > 0) {
                 throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
             }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 06a14f0..b3ec5f5 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -140,6 +140,11 @@
 
         ZygoteArguments parsedArgs = new ZygoteArguments(args);
 
+        if (parsedArgs.mBootCompleted) {
+            handleBootCompleted();
+            return null;
+        }
+
         if (parsedArgs.mAbiListQuery) {
             handleAbiListQuery();
             return null;
@@ -300,6 +305,10 @@
         }
     }
 
+    private void handleBootCompleted() {
+        VMRuntime.bootCompleted();
+    }
+
     /**
      * Preloads resources if the zygote is in lazily preload mode. Writes the result of the
      * preload operation; {@code 0} when a preload was initiated due to this request and {@code 1}
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index e3264a0..821022f 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -335,18 +335,12 @@
         }
 
         int totalLength = 0;
-        int maxLength = 0;
-        T[] maxLengthArray = arrays[0];
         for (T[] item : arrays) {
             if (item == null) {
                 continue;
             }
 
             totalLength += item.length;
-            if (item.length > maxLength) {
-                maxLengthArray = item;
-                maxLength = item.length;
-            }
         }
 
         // Optimization for entirely empty arrays.
diff --git a/core/java/com/android/internal/util/DataClass.java b/core/java/com/android/internal/util/DataClass.java
index 146f546..43539c7 100644
--- a/core/java/com/android/internal/util/DataClass.java
+++ b/core/java/com/android/internal/util/DataClass.java
@@ -65,11 +65,21 @@
     boolean genGetters() default true;
 
     /**
+     * {@link #genGetters} with @hide
+     */
+    boolean genHiddenGetters() default false;
+
+    /**
      * Generates setters for each field.
      */
     boolean genSetters() default false;
 
     /**
+     * {@link #genSetters} with @hide
+     */
+    boolean genHiddenSetters() default false;
+
+    /**
      * Generates a public constructor with each field initialized from a parameter and optionally
      * some user-defined state validation at the end.
      *
@@ -85,6 +95,11 @@
     boolean genConstructor() default true;
 
     /**
+     * {@link #genConstructor} with @hide
+     */
+    boolean genHiddenConstructor() default false;
+
+    /**
      * Generates a Builder for your class.
      *
      * Uses a package-private constructor under the hood, so same rules hold as for
@@ -93,6 +108,11 @@
     boolean genBuilder() default false;
 
     /**
+     * {@link #genBuilder} with @hide
+     */
+    boolean genHiddenBuilder() default false;
+
+    /**
      * Generates a structural {@link Object#equals} + {@link Object#hashCode}.
      *
      * You can customize individual fields' logic by declaring methods like:
@@ -126,6 +146,11 @@
     boolean genCopyConstructor() default false;
 
     /**
+     * {@link #genCopyConstructor} with @hide
+     */
+    boolean genHiddenCopyConstructor() default false;
+
+    /**
      * Generates constant annotations({@link IntDef}/{@link StringDef}) for any constant groups
      * with common prefix.
      * The annotation names are based on the common prefix.
@@ -146,6 +171,11 @@
      */
     boolean genConstDefs() default true;
 
+    /**
+     * {@link #genConstDefs} with @hide
+     */
+    boolean genHiddenConstDefs() default false;
+
 
     /**
      * Allows specifying custom parcelling logic based on reusable
@@ -177,11 +207,10 @@
 
     /**
      * @deprecated to be used by code generator exclusively
-     * @hide
      */
     @Deprecated
     @Retention(RetentionPolicy.SOURCE)
-    @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, ANNOTATION_TYPE, CONSTRUCTOR, TYPE})
+    @Target({METHOD})
     @interface Generated {
         long time();
         String codegenVersion();
@@ -190,7 +219,6 @@
 
         /**
          * @deprecated to be used by code generator exclusively
-         * @hide
          */
         @Deprecated
         @Retention(RetentionPolicy.SOURCE)
@@ -199,6 +227,22 @@
     }
 
     /**
+     * Opt out of generating {@link #genConstDefs IntDef/StringDef}s for annotated constant
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({FIELD})
+    @interface SuppressConstDefsGeneration {}
+
+    /**
+     * A class-level annotation to suppress methods' generation by name
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({TYPE})
+    @interface Suppress {
+        String[] value();
+    }
+
+    /**
      * Callback used by {@link #genForEachField}.
      *
      * @param <THIS> The enclosing data class instance.
diff --git a/core/java/com/android/internal/util/Parcelling.java b/core/java/com/android/internal/util/Parcelling.java
index 63530dc..390c596 100644
--- a/core/java/com/android/internal/util/Parcelling.java
+++ b/core/java/com/android/internal/util/Parcelling.java
@@ -24,6 +24,8 @@
 /**
  * Describes a 2-way parcelling contract of type {@code T} into/out of a {@link Parcel}
  *
+ * Implementations should be stateless.
+ *
  * @param <T> the type being [un]parcelled
  */
 public interface Parcelling<T> {
@@ -69,6 +71,7 @@
          * instance or reflectively creating one.
          */
         public static <P extends Parcelling<?>> P getOrCreate(Class<P> clazz) {
+            // No synchronization - creating an extra instance in a race case is ok
             P cached = get(clazz);
             if (cached != null) {
                 return cached;
diff --git a/core/java/com/android/internal/util/StatLogger.java b/core/java/com/android/internal/util/StatLogger.java
index 1dac136..ca6acd6 100644
--- a/core/java/com/android/internal/util/StatLogger.java
+++ b/core/java/com/android/internal/util/StatLogger.java
@@ -163,6 +163,9 @@
                 proto.write(Event.LABEL, mLabels[i]);
                 proto.write(Event.COUNT, mCountStats[i]);
                 proto.write(Event.TOTAL_DURATION_MICROS, mDurationStats[i]);
+                proto.write(Event.MAX_CALLS_PER_SECOND, mMaxCallsPerSecond[i]);
+                proto.write(Event.MAX_DURATION_PER_SECOND_MICROS, mMaxDurationPerSecond[i]);
+                proto.write(Event.MAX_DURATION_STATS_MICROS, mMaxDurationStats[i]);
 
                 proto.end(inner);
             }
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index 344d7ef..8799e3d 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -26,6 +26,8 @@
 import android.util.Base64;
 import android.util.Xml;
 
+import libcore.util.HexEncoding;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -396,16 +398,7 @@
         final int N = val.length;
         out.attribute(null, "num", Integer.toString(N));
 
-        StringBuilder sb = new StringBuilder(val.length*2);
-        for (int i=0; i<N; i++) {
-            int b = val[i];
-            int h = (b >> 4) & 0x0f;
-            sb.append((char)(h >= 10 ? ('a'+h-10) : ('0'+h)));
-            h = b & 0x0f;
-            sb.append((char)(h >= 10 ? ('a'+h-10) : ('0'+h)));
-        }
-
-        out.text(sb.toString());
+        out.text(HexEncoding.encodeToString(val).toLowerCase());
 
         out.endTag(null, "byte-array");
     }
@@ -1032,7 +1025,9 @@
                     "Not a number in num attribute in byte-array");
         }
 
-        byte[] array = new byte[num];
+        // 0 len byte array does not have a text in the XML tag. So, initialize to 0 len array.
+        // For all other array lens, HexEncoding.decode() below overrides the array.
+        byte[] array = new byte[0];
 
         int eventType = parser.getEventType();
         do {
@@ -1043,16 +1038,7 @@
                         throw new XmlPullParserException(
                                 "Invalid value found in byte-array: " + values);
                     }
-                    // This is ugly, but keeping it to mirror the logic in #writeByteArrayXml.
-                    for (int i = 0; i < num; i ++) {
-                        char nibbleHighChar = values.charAt(2 * i);
-                        char nibbleLowChar = values.charAt(2 * i + 1);
-                        int nibbleHigh = nibbleHighChar > 'a' ? (nibbleHighChar - 'a' + 10)
-                                : (nibbleHighChar - '0');
-                        int nibbleLow = nibbleLowChar > 'a' ? (nibbleLowChar - 'a' + 10)
-                                : (nibbleLowChar - '0');
-                        array[i] = (byte) ((nibbleHigh & 0x0F) << 4 | (nibbleLow & 0x0F));
-                    }
+                    array = HexEncoding.decode(values);
                 }
             } else if (eventType == parser.END_TAG) {
                 if (parser.getName().equals(endTag)) {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index dc45f78..32867a8 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -558,7 +558,7 @@
 
     /**
      * Returns the password history hash factor, needed to check new password against password
-     * history with {@link #checkPasswordHistory(String, byte[], int)}
+     * history with {@link #checkPasswordHistory(byte[], byte[], int)}
      */
     public byte[] getPasswordHistoryHashFactor(byte[] currentPassword, int userId) {
         try {
@@ -1242,23 +1242,6 @@
         return res;
     }
 
-    /**
-     * Transform a pattern byte array to base zero form.
-     * @param bytes pattern byte array.
-     * @return The pattern in base zero form.
-     */
-    public static byte[] patternByteArrayToBaseZero(byte[] bytes) {
-        if (bytes == null) {
-            return new byte[0];
-        }
-        final int patternSize = bytes.length;
-        byte[] res = new byte[patternSize];
-        for (int i = 0; i < patternSize; i++) {
-            res[i] = (byte) (bytes[i] - '1');
-        }
-        return res;
-    }
-
     /*
      * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
      * at least a second level of protection. First level is that the file
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index e7d240a..9bb4501 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -26,6 +26,8 @@
 import android.widget.ImageView;
 import android.widget.RemoteViews;
 
+import java.util.ArrayList;
+
 /**
  * A TextView that can float around an image on the end.
  *
@@ -42,6 +44,7 @@
     private View mMainColumn;
     private View mMediaContent;
     private int mImagePushIn;
+    private ArrayList<VisibilityChangeListener> mListeners;
 
     public MediaNotificationView(Context context) {
         this(context, null);
@@ -168,4 +171,50 @@
         mMainColumn = findViewById(com.android.internal.R.id.notification_main_column);
         mMediaContent = findViewById(com.android.internal.R.id.notification_media_content);
     }
+
+    @Override
+    public void onVisibilityAggregated(boolean isVisible) {
+        super.onVisibilityAggregated(isVisible);
+        if (mListeners != null) {
+            for (int i = 0; i < mListeners.size(); i++) {
+                mListeners.get(i).onAggregatedVisibilityChanged(isVisible);
+            }
+        }
+    }
+
+    /**
+     * Add a listener to receive updates on the visibility of this view
+     *
+     * @param listener The listener to add.
+     */
+    public void addVisibilityListener(VisibilityChangeListener listener) {
+        if (mListeners == null) {
+            mListeners = new ArrayList<>();
+        }
+        if (!mListeners.contains(listener)) {
+            mListeners.add(listener);
+        }
+    }
+
+    /**
+     * Remove the specified listener
+     *
+     * @param listener The listener to remove.
+     */
+    public void removeVisibilityListener(VisibilityChangeListener listener) {
+        if (mListeners != null) {
+            mListeners.remove(listener);
+        }
+    }
+
+    /**
+     * Interface for receiving updates when the view's visibility changes
+     */
+    public interface VisibilityChangeListener {
+        /**
+         * Method called when the visibility of this view has changed
+         * @param isVisible true if the view is now visible
+         */
+        void onAggregatedVisibilityChanged(boolean isVisible);
+    }
 }
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 9084f62..d48034b 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -53,6 +53,12 @@
     // to plot alongside the default one.  Useful for testing and comparison purposes.
     private static final String ALT_STRATEGY_PROPERY_KEY = "debug.velocitytracker.alt";
 
+    /**
+     * If set to a positive value between 1-255, shows an overlay with the approved (red) and
+     * rejected (blue) exclusions.
+     */
+    private static final String GESTURE_EXCLUSION_PROP = "debug.pointerlocation.showexclusion";
+
     public static class PointerState {
         // Trace of previous points.
         private float[] mTraceX = new float[32];
@@ -138,8 +144,10 @@
     private final PointerCoords mTempCoords = new PointerCoords();
 
     private final Region mSystemGestureExclusion = new Region();
+    private final Region mSystemGestureExclusionRejected = new Region();
     private final Path mSystemGestureExclusionPath = new Path();
     private final Paint mSystemGestureExclusionPaint;
+    private final Paint mSystemGestureExclusionRejectedPaint;
 
     private final VelocityTracker mVelocity;
     private final VelocityTracker mAltVelocity;
@@ -190,6 +198,10 @@
         mSystemGestureExclusionPaint.setARGB(25, 255, 0, 0);
         mSystemGestureExclusionPaint.setStyle(Paint.Style.FILL_AND_STROKE);
 
+        mSystemGestureExclusionRejectedPaint = new Paint();
+        mSystemGestureExclusionRejectedPaint.setARGB(25, 0, 0, 255);
+        mSystemGestureExclusionRejectedPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
         PointerState ps = new PointerState();
         mPointers.add(ps);
         mActivePointerId = 0;
@@ -263,6 +275,12 @@
             canvas.drawPath(mSystemGestureExclusionPath, mSystemGestureExclusionPaint);
         }
 
+        if (!mSystemGestureExclusionRejected.isEmpty()) {
+            mSystemGestureExclusionPath.reset();
+            mSystemGestureExclusionRejected.getBoundaryPath(mSystemGestureExclusionPath);
+            canvas.drawPath(mSystemGestureExclusionPath, mSystemGestureExclusionRejectedPaint);
+        }
+
         // Labels
         if (mActivePointerId >= 0) {
             final PointerState ps = mPointers.get(mActivePointerId);
@@ -754,6 +772,9 @@
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
+            final int alpha = systemGestureExclusionOpacity();
+            mSystemGestureExclusionPaint.setAlpha(alpha);
+            mSystemGestureExclusionRejectedPaint.setAlpha(alpha);
         } else {
             mSystemGestureExclusion.setEmpty();
         }
@@ -805,7 +826,12 @@
     }
 
     private static boolean shouldShowSystemGestureExclusion() {
-        return SystemProperties.getBoolean("debug.pointerlocation.showexclusion", false);
+        return systemGestureExclusionOpacity() > 0;
+    }
+
+    private static int systemGestureExclusionOpacity() {
+        int x = SystemProperties.getInt(GESTURE_EXCLUSION_PROP, 0);
+        return x >= 0 && x <= 255 ? x : 0;
     }
 
     // HACK
@@ -928,12 +954,19 @@
     private ISystemGestureExclusionListener mSystemGestureExclusionListener =
             new ISystemGestureExclusionListener.Stub() {
         @Override
-        public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion) {
+        public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion,
+                Region systemGestureExclusionUnrestricted) {
             Region exclusion = Region.obtain(systemGestureExclusion);
+            Region rejected = Region.obtain();
+            if (systemGestureExclusionUnrestricted != null) {
+                rejected.set(systemGestureExclusionUnrestricted);
+                rejected.op(exclusion, Region.Op.DIFFERENCE);
+            }
             Handler handler = getHandler();
             if (handler != null) {
                 handler.post(() -> {
                     mSystemGestureExclusion.set(exclusion);
+                    mSystemGestureExclusionRejected.set(rejected);
                     exclusion.recycle();
                     invalidate();
                 });
diff --git a/core/java/com/android/server/job/JobSchedulerInternal.java b/core/java/com/android/server/job/JobSchedulerInternal.java
index dbf3b98..eefb9fa 100644
--- a/core/java/com/android/server/job/JobSchedulerInternal.java
+++ b/core/java/com/android/server/job/JobSchedulerInternal.java
@@ -17,6 +17,7 @@
 package com.android.server.job;
 
 import android.app.job.JobInfo;
+import android.util.proto.ProtoOutputStream;
 
 import java.util.List;
 
@@ -89,5 +90,30 @@
                     + countSystemServerJobsSaved + "/"
                     + countSystemSyncManagerJobsSaved;
         }
+
+        /**
+         * Write the persist stats to the specified field.
+         */
+        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+            final long token = proto.start(fieldId);
+
+            final long flToken = proto.start(JobStorePersistStatsProto.FIRST_LOAD);
+            proto.write(JobStorePersistStatsProto.Stats.NUM_TOTAL_JOBS, countAllJobsLoaded);
+            proto.write(JobStorePersistStatsProto.Stats.NUM_SYSTEM_SERVER_JOBS,
+                    countSystemServerJobsLoaded);
+            proto.write(JobStorePersistStatsProto.Stats.NUM_SYSTEM_SYNC_MANAGER_JOBS,
+                    countSystemSyncManagerJobsLoaded);
+            proto.end(flToken);
+
+            final long lsToken = proto.start(JobStorePersistStatsProto.LAST_SAVE);
+            proto.write(JobStorePersistStatsProto.Stats.NUM_TOTAL_JOBS, countAllJobsSaved);
+            proto.write(JobStorePersistStatsProto.Stats.NUM_SYSTEM_SERVER_JOBS,
+                    countSystemServerJobsSaved);
+            proto.write(JobStorePersistStatsProto.Stats.NUM_SYSTEM_SYNC_MANAGER_JOBS,
+                    countSystemSyncManagerJobsSaved);
+            proto.end(lsToken);
+
+            proto.end(token);
+        }
     }
 }
diff --git a/core/jni/android_app_ActivityThread.cpp b/core/jni/android_app_ActivityThread.cpp
index 3a08148..5f83038 100644
--- a/core/jni/android_app_ActivityThread.cpp
+++ b/core/jni/android_app_ActivityThread.cpp
@@ -36,7 +36,6 @@
 android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
     int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
     android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
-    minikin::Layout::dumpMinikinStats(fd);
 }
 
 static void android_app_ActivityThread_initZygoteChildHeapProfiling(JNIEnv* env, jobject clazz) {
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 9450bc9..222a873 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -16,9 +16,6 @@
 
 #define LOG_TAG "OpenGLRenderer"
 #define ATRACE_TAG ATRACE_TAG_VIEW
-#ifdef __ANDROID__ // Layoutlib does not support EGL
-#include <EGL/egl.h>
-#endif
 #include "jni.h"
 #include "GraphicsJNI.h"
 #include <nativehelper/JNIHelp.h>
diff --git a/core/proto/android/server/alarmmanagerservice.proto b/core/proto/android/server/alarmmanagerservice.proto
index 490f729..b008fa9 100644
--- a/core/proto/android/server/alarmmanagerservice.proto
+++ b/core/proto/android/server/alarmmanagerservice.proto
@@ -20,7 +20,7 @@
 import "frameworks/base/core/proto/android/app/pendingintent.proto";
 import "frameworks/base/core/proto/android/internal/locallog.proto";
 import "frameworks/base/core/proto/android/os/worksource.proto";
-import "frameworks/base/core/proto/android/server/forceappstandbytracker.proto";
+import "frameworks/base/core/proto/android/server/appstatetracker.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
 
 package com.android.server;
@@ -38,8 +38,8 @@
     // Current settings
     optional ConstantsProto settings = 5;
 
-    // Dump from ForceAppStandbyTracker.
-    optional ForceAppStandbyTrackerProto force_app_standby_tracker = 6;
+    // Dump from AppStateTracker.
+    optional AppStateTrackerProto app_state_tracker = 6;
 
     optional bool is_interactive = 7;
     // Only valid if is_interactive is false.
diff --git a/core/proto/android/server/forceappstandbytracker.proto b/core/proto/android/server/appstatetracker.proto
similarity index 91%
rename from core/proto/android/server/forceappstandbytracker.proto
rename to core/proto/android/server/appstatetracker.proto
index 89424bc..51e8845 100644
--- a/core/proto/android/server/forceappstandbytracker.proto
+++ b/core/proto/android/server/appstatetracker.proto
@@ -23,12 +23,15 @@
 
 option java_multiple_files = true;
 
-// Dump from com.android.server.ForceAppStandbyTracker.
+// Dump from com.android.server.AppStateTracker.
 //
-// Next ID: 13
-message ForceAppStandbyTrackerProto {
+// Next ID: 14
+message AppStateTrackerProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
+    //  True if the forced app standby feature is enabled in settings.
+    optional bool forced_app_standby_feature_enabled = 13;
+
     // Whether all apps are forced standby or not.
     optional bool force_all_apps_standby = 1;
 
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 5d4be55..aac144c 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -28,8 +28,9 @@
 import "frameworks/base/core/proto/android/net/networkrequest.proto";
 import "frameworks/base/core/proto/android/os/bundle.proto";
 import "frameworks/base/core/proto/android/os/persistablebundle.proto";
-import "frameworks/base/core/proto/android/server/forceappstandbytracker.proto";
+import "frameworks/base/core/proto/android/server/appstatetracker.proto";
 import "frameworks/base/core/proto/android/server/job/enums.proto";
+import "frameworks/base/core/proto/android/server/statlogger.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
 
 // Next tag: 21
@@ -53,18 +54,22 @@
         optional JobStatusShortInfoProto info = 1;
         optional JobStatusDumpProto dump = 2;
 
+        optional bool is_job_ready_to_be_executed = 10;
         // A job is ready to be executed if:
-        // is_job_ready && is_user_started && !is_job_pending &&
+        // is_job_ready && are_users_started && !is_job_thermal_constrained && !is_job_pending &&
         // !is_job_currently_active && !is_uid_backing_up &&
-        // is_component_present.
+        // is_component_usable.
         optional bool is_job_ready = 3;
-        optional bool is_user_started = 4;
+        optional bool are_users_started = 4;
+        optional bool is_job_thermal_constrained = 11;
         optional bool is_job_pending = 5;
         optional bool is_job_currently_active = 6;
         optional bool is_uid_backing_up = 7;
-        optional bool is_component_present = 8;
+        optional bool is_component_usable = 8;
 
         reserved 9; // last_run_heartbeat
+
+        // Next tag: 12
     }
     repeated RegisteredJob registered_jobs = 3;
 
@@ -95,7 +100,7 @@
         optional JobStatusDumpProto dump = 2;
         optional sint32 evaluated_priority = 3;
         // How long this job has been pending.
-        optional int64 enqueued_duration_ms = 4;
+        optional int64 pending_duration_ms = 4;
     }
     repeated PendingJob pending_jobs = 9;
 
@@ -123,7 +128,7 @@
             optional sint32 evaluated_priority = 5;
 
             optional int64 time_since_made_active_ms = 6;
-            // How long this job has been pending.
+            // How long this job was pending before it became active.
             optional int64 pending_duration_ms = 7;
         }
         oneof job {
@@ -144,6 +149,8 @@
 
     // Dump from JobConcurrencyManager.
     optional JobConcurrencyManagerProto concurrency_manager = 20;
+
+    optional JobStorePersistStatsProto persist_stats = 21;
 }
 
 // A com.android.server.job.JobSchedulerService.Constants object.
@@ -347,7 +354,7 @@
     message BackgroundJobsController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-        optional com.android.server.ForceAppStandbyTrackerProto force_app_standby_tracker = 1;
+        optional com.android.server.AppStateTrackerProto app_state_tracker = 1;
 
         message TrackedJob {
             option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -386,7 +393,7 @@
     message ConnectivityController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-        optional bool is_connected = 1;
+        reserved 1; // is_connected
 
         message TrackedJob {
             option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -396,6 +403,12 @@
             optional .android.net.NetworkRequestProto required_network = 3;
         }
         repeated TrackedJob tracked_jobs = 2;
+
+        // List of the UIDs that ConnectivityController has requested that NetworkPolicyManager
+        // grant an exception to in the app standby chain.
+        repeated int32 requested_standby_exception_uids = 3;
+
+        repeated .android.net.NetworkProto available_networks = 4;
     }
     message ContentObserverController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -480,6 +493,31 @@
             optional int32 source_uid = 2;
         }
         repeated TrackedJob tracked_jobs = 2;
+
+        message IdlenessTracker {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+            message CarIdlenessTracker {
+                option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+                optional bool is_idle = 1;
+                optional bool is_garage_mode_on = 2;
+            }
+
+            message DeviceIdlenessTracker {
+                option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+                optional bool is_idle = 1;
+                optional bool is_screen_on = 2;
+                optional bool is_dock_idle = 3;
+            }
+
+            oneof active_tracker {
+                DeviceIdlenessTracker device_idleness_tracker = 1;
+                CarIdlenessTracker car_idleness_tracker = 2;
+            }
+        }
+        optional IdlenessTracker idleness_tracker = 3;
     }
     message QuotaController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -623,6 +661,17 @@
             optional AlarmListener in_quota_alarm_listener = 5;
         }
         repeated PackageStats package_stats = 5;
+
+        // Set of package names for each UID.
+        message UidPackageMapping {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+            optional int32 uid = 1;
+            repeated string package_names = 2;
+        }
+        repeated UidPackageMapping uid_to_package_cache = 7;
+
+        // Next tag: 8
     }
     message StorageController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -937,10 +986,15 @@
     optional sint64 time_until_earliest_runtime_ms = 19;
     // Can be negative if the latest runtime deadline has passed.
     optional sint64 time_until_latest_runtime_ms = 20;
+    // The original latest runtime value, in the elapsed realtime timebase. Valid only for periodic
+    // jobs.
+    optional uint64 original_latest_runtime_elapsed = 30;
 
     optional int32 num_failures = 21;
 
+    // Last time a job finished successfully for a periodic job, in currentTimeMillis time.
     optional int64 last_successful_run_time = 22;
+    // Last time a job finished unsuccessfully, in currentTimeMillis time.
     optional int64 last_failed_run_time = 23;
 
     optional int64 internal_flags = 24;
@@ -953,7 +1007,7 @@
     // was no attempt.
     optional int64 time_since_first_force_batch_attempt_ms = 29;
 
-    // Next tag: 30
+    // Next tag: 31
 }
 
 // Dump from com.android.server.job.JobConcurrencyManager.
@@ -962,9 +1016,9 @@
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
     // Whether the device is interactive (== screen on) now or not.
-    optional bool current_interactive = 1;
-    // Similar to current_interactive, screen on or not, but it takes into account the off timeout.
-    optional bool effective_interactive = 2;
+    optional bool current_interactive_state = 1;
+    // Similar to current_interactive_state, screen on or not, but it takes into account the off timeout.
+    optional bool effective_interactive_state = 2;
     // How many milliseconds have passed since the last screen on. (i.e. 1000 == 1 sec ago)
     optional int64 time_since_last_screen_on_ms = 3;
     // How many milliseconds have passed since the last screen off. (i.e. 1000 == 1 sec ago)
@@ -973,6 +1027,8 @@
     optional JobCountTrackerProto job_count_tracker = 5;
     // Current memory trim level.
     optional int32 memory_trim_level = 6;
+    // Performance stats.
+    optional StatLoggerProto stats = 7;
 }
 
 // Dump from com.android.server.job.JobConcurrencyManager.JobCountTracker.
@@ -997,4 +1053,23 @@
     optional int32 num_pending_fg_jobs = 6;
     // Number of pending background jobs.
     optional int32 num_pending_bg_jobs = 7;
+
+    optional int32 num_actual_max_fg_jobs = 8;
+    optional int32 num_actual_max_bg_jobs = 9;
+
+    optional int32 num_reserved_for_bg = 10;
+
+    optional int32 num_starting_fg_jobs = 11;
+    optional int32 num_starting_bg_jobs = 12;
+}
+
+message JobStorePersistStatsProto {
+    message Stats {
+        optional int32 num_total_jobs = 1;
+        optional int32 num_system_server_jobs = 2;
+        optional int32 num_system_sync_manager_jobs = 3;
+    }
+
+    optional Stats first_load = 1;
+    optional Stats last_save = 2;
 }
diff --git a/core/proto/android/server/statlogger.proto b/core/proto/android/server/statlogger.proto
index 8593da8..c995599 100644
--- a/core/proto/android/server/statlogger.proto
+++ b/core/proto/android/server/statlogger.proto
@@ -34,6 +34,9 @@
         optional string label = 2;
         optional int32 count = 3;
         optional int64 total_duration_micros = 4;
+        optional int32 max_calls_per_second = 5;
+        optional int64 max_duration_per_second_micros = 6;
+        optional int64 max_duration_stats_micros = 7;
     }
 
     repeated Event events = 1;
diff --git a/core/proto/android/service/graphicsstats.proto b/core/proto/android/service/graphicsstats.proto
index 11f0467..557075c 100644
--- a/core/proto/android/service/graphicsstats.proto
+++ b/core/proto/android/service/graphicsstats.proto
@@ -51,6 +51,9 @@
 
     // The frame time histogram for the package.
     repeated GraphicsStatsHistogramBucketProto histogram = 6;
+
+    // The gpu frame time histogram for the package
+    repeated GraphicsStatsHistogramBucketProto gpu_histogram = 7;
 }
 
 message GraphicsStatsJankSummaryProto {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4d6e7da..fa4e085 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3483,6 +3483,9 @@
     <!-- True if home app should be pinned via Pinner Service -->
     <bool name="config_pinnerHomeApp">false</bool>
 
+    <!-- True if assistant app should be pinned via Pinner Service -->
+    <bool name="config_pinnerAssistantApp">false</bool>
+
     <!-- List of files pinned by the Pinner Service with the apex boot image b/119800099 -->
     <string-array translatable="false" name="config_apexBootImagePinnerServiceFiles">
     </string-array>
@@ -4267,6 +4270,10 @@
     (default 2MB) -->
     <integer name="config_notificationStripRemoteViewSizeBytes">2000000</integer>
 
+    <!-- Contains a blacklist of apps that should not get pre-installed carrier app permission
+         grants, even if the UICC claims that the app should be privileged. See b/138150105 -->
+    <string-array name="config_restrictedPreinstalledCarrierApps" translatable="false"/>
+
     <!-- Sharesheet: define a max number of targets per application for new shortcuts-based direct share introduced in Q -->
     <integer name="config_maxShortcutTargetsPerApp">3</integer>
 
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6653879..609659b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -748,6 +748,8 @@
     <!-- Line spacing modifier for the message field of the harmful app dialog -->
     <item name="harmful_app_message_line_spacing_modifier" type="dimen">1.22</item>
 
+    <dimen name="seekbar_thumb_exclusion_max_size">48dp</dimen>
+
     <!-- chooser (sharesheet) spacing -->
     <dimen name="chooser_corner_radius">8dp</dimen>
     <dimen name="chooser_row_text_option_translate">25dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 036d959..2067735 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2927,6 +2927,7 @@
     <public type="attr" name="enforceStatusBarContrast" id="0x01010604" />
     <public type="attr" name="enforceNavigationBarContrast" id="0x01010605" />
     <public type="attr" name="identifier" id="0x01010606" />
+    <public type="attr" name="forceQueryable" id="0x01010608" />
 
     <!-- @hide @SystemApi -->
     <public type="drawable" name="ic_info" id="0x010800b4" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 34ea0a8..d1d7bf5 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -370,7 +370,7 @@
     <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. [CHAR LIMIT=TOAST] -->
     <string name="low_memory" product="watch">Watch storage is full. Delete some files to free space.</string>
     <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. [CHAR LIMIT=TOAST] -->
-    <string name="low_memory" product="tv">TV storage is full. Delete some files to free space.</string>
+    <string name="low_memory" product="tv">Android TV device storage is full. Delete some files to free space.</string>
     <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. [CHAR LIMIT=TOAST] -->
     <string name="low_memory" product="default">Phone storage is full. Delete some files to free space.</string>
 
@@ -430,7 +430,7 @@
     <!-- Title for the Phone Options dialog to lock the screen, turn off the phone etc. -->
     <string name="power_dialog" product="tablet">Tablet options</string>
     <!-- Title for the Phone Options dialog to lock the screen, turn off the phone etc. -->
-    <string name="power_dialog" product="tv">TV options</string>
+    <string name="power_dialog" product="tv">Android TV options</string>
     <!-- Title for the Phone Options dialog to lock the screen, turn off the phone etc. -->
     <string name="power_dialog" product="default">Phone options</string>
     <!-- Button to turn on silent mode, within the Phone Options dialog -->
@@ -468,7 +468,7 @@
     <string name="shutdown_confirm" product="tablet">Your tablet will shut down.</string>
     <!-- Shutdown Confirmation Dialog.  When the user chooses to power off the TV, there will
          be a confirmation dialog.  This is the message. -->
-    <string name="shutdown_confirm" product="tv">Your TV will shut down.</string>
+    <string name="shutdown_confirm" product="tv">Your Android TV device will shut down.</string>
     <!-- Shutdown Confirmation Dialog.  When the user chooses to power off the watch, there will
          be a confirmation dialog.  This is the message. -->
     <string name="shutdown_confirm" product="watch">Your watch will shut down.</string>
@@ -505,7 +505,7 @@
     <!-- Title of the Global Actions Dialog -->
     <string name="global_actions" product="tablet">Tablet options</string>
     <!-- Title of the Global Actions Dialog -->
-    <string name="global_actions" product="tv">TV options</string>
+    <string name="global_actions" product="tv">Android TV options</string>
     <!-- Title of the Global Actions Dialog -->
     <string name="global_actions" product="default">Phone options</string>
 
@@ -916,7 +916,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readSms" product="tablet">This app can read all SMS (text) messages stored on your tablet.</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_readSms" product="tv">This app can read all SMS (text) messages stored on your TV.</string>
+    <string name="permdesc_readSms" product="tv">This app can read all SMS (text) messages stored on your Android TV device.</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_readSms" product="default">This app can read all SMS (text) messages stored on your phone.</string>
 
@@ -979,7 +979,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_persistentActivity" product="tablet">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down the tablet.</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_persistentActivity" product="tv">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down the TV.</string>
+    <string name="permdesc_persistentActivity" product="tv">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down your Android TV device.</string>
     <string name="permdesc_persistentActivity" product="default">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down the phone.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1009,8 +1009,8 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_receiveBootCompleted" product="tv">Allows the app to
         have itself started as soon as the system has finished booting.
-        This can make it take longer to start the TV and allow the
-        app to slow down the overall tablet by always running.</string>
+        This can make it take longer to start your Android TV device and allow the
+        app to slow down the overall device by always running.</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_receiveBootCompleted" product="default">Allows the app to
         have itself started as soon as the system has finished booting.
@@ -1027,7 +1027,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_broadcastSticky" product="tv">Allows the app to
     send sticky broadcasts, which remain after the broadcast ends. Excessive use
-    may make the TV slow or unstable by causing it to use too much memory.
+    may make your Android TV device slow or unstable by causing it to use too much memory.
     </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_broadcastSticky" product="default">Allows the app to
@@ -1046,7 +1046,7 @@
       knowledge.</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_readContacts" product="tv">Allows the app to read
-      data about your contacts stored on your TV, including the frequency
+      data about your contacts stored on your Android TV device, including the frequency
       with which you\'ve called, emailed, or communicated in other ways with
       specific individuals. This permission allows apps to save your contact
       data, and malicious apps may share contact data without your
@@ -1069,7 +1069,7 @@
       data.</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_writeContacts" product="tv">Allows the app to
-      modify the data about your contacts stored on your TV, including the
+      modify the data about your contacts stored on your Android TV device, including the
       frequency with which you\'ve called, emailed, or communicated in other ways
       with specific contacts. This permission allows apps to delete contact
       data.</string>
@@ -1091,7 +1091,7 @@
     <string name="permdesc_writeCallLog" product="tablet">Allows the app to modify your tablet\'s call log, including data about incoming and outgoing calls.
         Malicious apps may use this to erase or modify your call log.</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_writeCallLog" product="tv">Allows the app to modify your TV\'s call log, including data about incoming and outgoing calls.
+    <string name="permdesc_writeCallLog" product="tv">Allows the app to modify your Android TV device\'s call log, including data about incoming and outgoing calls.
         Malicious apps may use this to erase or modify your call log.</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_writeCallLog" product="default">Allows the app to modify your phone\'s call log, including data about incoming and outgoing calls.
@@ -1109,7 +1109,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readCalendar" product="tablet">This app can read all calendar events stored on your tablet and share or save your calendar data.</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_readCalendar" product="tv">This app can read all calendar events stored on your TV and share or save your calendar data.</string>
+    <string name="permdesc_readCalendar" product="tv">This app can read all calendar events stored on your Android TV device and share or save your calendar data.</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_readCalendar" product="default">This app can read all calendar events stored on your phone and share or save your calendar data.</string>
 
@@ -1118,7 +1118,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeCalendar" product="tablet">This app can add, remove, or change calendar events on your tablet. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners.</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_writeCalendar" product="tv">This app can add, remove, or change calendar events on your TV. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners.</string>
+    <string name="permdesc_writeCalendar" product="tv">This app can add, remove, or change calendar events on your Android TV device. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners.</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_writeCalendar" product="default">This app can add, remove, or change calendar events on your phone. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners.</string>
 
@@ -1139,7 +1139,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessCoarseLocation" product="tablet">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when when the app is in the foreground. These location services must be turned on and available on your tablet for the app to be able to use them.</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_accessCoarseLocation" product="tv">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when when the app is in the foreground. These location services must be turned on and available on your TV for the app to be able to use them.</string>
+    <string name="permdesc_accessCoarseLocation" product="tv">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when when the app is in the foreground. These location services must be turned on and available on your Android TV device for the app to be able to use them.</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_accessCoarseLocation" product="default">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when the app is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them.</string>
 
@@ -1236,13 +1236,13 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_wakeLock" product="tablet">prevent tablet from sleeping</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_wakeLock" product="tv">prevent TV from sleeping</string>
+    <string name="permlab_wakeLock" product="tv">prevent your Android TV device from sleeping</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_wakeLock" product="default">prevent phone from sleeping</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_wakeLock" product="tablet">Allows the app to prevent the tablet from going to sleep.</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_wakeLock" product="tv">Allows the app to prevent the TV from going to sleep.</string>
+    <string name="permdesc_wakeLock" product="tv">Allows the app to prevent your Android TV device from going to sleep.</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_wakeLock" product="default">Allows the app to prevent the phone from going to sleep.</string>
 
@@ -1251,7 +1251,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_transmitIr" product="tablet">Allows the app to use the tablet\'s infrared transmitter.</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_transmitIr" product="tv">Allows the app to use the TV\'s infrared transmitter.</string>
+    <string name="permdesc_transmitIr" product="tv">Allows the app to use your Android TV device\'s infrared transmitter.</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_transmitIr" product="default">Allows the app to use the phone\'s infrared transmitter.</string>
 
@@ -1270,7 +1270,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setTimeZone" product="tablet">Allows the app to change the tablet\'s time zone.</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_setTimeZone" product="tv">Allows the app to change the TV\'s time zone.</string>
+    <string name="permdesc_setTimeZone" product="tv">Allows the app to change your Android TV device\'s time zone.</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_setTimeZone" product="default">Allows the app to change the phone\'s time zone.</string>
 
@@ -1282,7 +1282,7 @@
       created by applications you have installed.</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_getAccounts" product="tv">Allows the app to get
-      the list of accounts known by the TV.  This may include any accounts
+      the list of accounts known by your Android TV device.  This may include any accounts
       created by applications you have installed.</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_getAccounts" product="default">Allows the app to get
@@ -1337,7 +1337,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_changeWifiMulticastState" product="tv">Allows the app to receive
       packets sent to all devices on a Wi-Fi network using multicast addresses,
-      not just your TV.  It uses more power than the non-multicast mode.</string>
+      not just your Android TV device.  It uses more power than the non-multicast mode.</string>
     <string name="permdesc_changeWifiMulticastState" product="default">Allows the app to receive
       packets sent to all devices on a Wi-Fi network using multicast addresses,
       not just your phone.  It uses more power than the non-multicast mode.</string>
@@ -1350,7 +1350,7 @@
       devices.</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_bluetoothAdmin" product="tv">Allows the app to
-      configure the local Bluetooth TV, and to discover and pair with remote
+      configure Bluetooth on your Android TV device, and to discover and pair with remote
       devices.</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_bluetoothAdmin" product="default">Allows the app to configure
@@ -1365,7 +1365,7 @@
     <string name="permdesc_changeWimaxState" product="tablet">Allows the app to
       connect the tablet to and disconnect the tablet from WiMAX networks.</string>
     <string name="permdesc_changeWimaxState" product="tv">Allows the app to
-      connect the TV to and disconnect the TV from WiMAX networks.</string>
+      connect your Android TV device to and disconnect your Android TV device from WiMAX networks.</string>
     <string name="permdesc_changeWimaxState" product="default">Allows the app to
       connect the phone to and disconnect the phone from WiMAX networks.</string>
 
@@ -1377,7 +1377,7 @@
       connections with paired devices.</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_bluetooth" product="tv">Allows the app to view the
-      configuration of Bluetooth on the TV, and to make and accept
+      configuration of Bluetooth on your Android TV device, and to make and accept
       connections with paired devices.</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_bluetooth" product="default">Allows the app to view the
@@ -1753,8 +1753,8 @@
     typed when unlocking the screen, and lock the tablet or erase all the tablet\'s
     data if too many incorrect passwords are typed.</string>
     <!-- Description of policy access to watch user login attempts -->
-    <string name="policydesc_watchLogin" product="TV">Monitor the number of incorrect passwords
-    typed when unlocking the screen, and lock the TV or erase all the TV\'s
+    <string name="policydesc_watchLogin" product="tv">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock your Android TV device or erase all your Android TV device\'s
     data if too many incorrect passwords are typed.</string>
     <!-- Description of policy access to watch user login attempts -->
     <string name="policydesc_watchLogin" product="default">Monitor the number of incorrect passwords
@@ -1763,8 +1763,8 @@
     <string name="policydesc_watchLogin_secondaryUser" product="tablet">Monitor the number of incorrect passwords
     typed when unlocking the screen, and lock the tablet or erase all this user\'s data
     if too many incorrect passwords are typed.</string>
-    <string name="policydesc_watchLogin_secondaryUser" product="TV">Monitor the number of incorrect passwords
-    typed when unlocking the screen, and lock the TV or erase all this user\'s data
+    <string name="policydesc_watchLogin_secondaryUser" product="tv">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock your Android TV device or erase all this user\'s data
     if too many incorrect passwords are typed.</string>
     <string name="policydesc_watchLogin_secondaryUser" product="default">Monitor the number of incorrect passwords
     typed when unlocking the screen, and lock the phone or erase all this user\'s data
@@ -1782,7 +1782,7 @@
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData" product="tablet">Erase the tablet\'s data without warning by performing a factory data reset.</string>
     <!-- Description of policy access to wipe the user's data -->
-    <string name="policydesc_wipeData" product="tv">Erase the TV\'s data without warning by performing a factory data reset.</string>
+    <string name="policydesc_wipeData" product="tv">Erase your Android TV device\'s data without warning by performing a factory data reset.</string>
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData" product="default">Erase the phone\'s data without warning by performing a factory data reset.</string>
     <!-- Title of policy access to wipe secondary user's data -->
@@ -1790,7 +1790,7 @@
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData_secondaryUser" product="tablet">Erase this user\'s data on this tablet without warning.</string>
     <!-- Description of policy access to wipe the user's data -->
-    <string name="policydesc_wipeData_secondaryUser" product="tv">Erase this user\'s data on this TV without warning.</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv">Erase this user\'s data on this Android TV device without warning.</string>
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData_secondaryUser" product="default">Erase this user\'s data on this phone without warning.</string>
     <!-- Title of policy access to set global proxy -->
@@ -2103,7 +2103,7 @@
     <!-- Shown in the lock screen when there is no SIM card. -->
     <string name="lockscreen_missing_sim_message" product="tablet">No SIM card in tablet.</string>
     <!-- Shown in the lock screen when there is no SIM card. -->
-    <string name="lockscreen_missing_sim_message" product="tv">No SIM card in TV.</string>
+    <string name="lockscreen_missing_sim_message" product="tv">No SIM card in your Android TV device.</string>
     <!-- Shown in the lock screen when there is no SIM card. -->
     <string name="lockscreen_missing_sim_message" product="default">No SIM card in phone.</string>
     <!-- Shown in the lock screen to ask the user to insert a SIM card. -->
@@ -2188,7 +2188,7 @@
     <string name="lockscreen_failed_attempts_almost_glogin" product="tv">
         You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times.
        After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       you will be asked to unlock your TV using your Google signin.\n\n
+       you will be asked to unlock your Android TV device using your Google signin.\n\n
        Try again in <xliff:g id="number">%3$d</xliff:g> seconds.
     </string>
 
@@ -2212,9 +2212,9 @@
     <!-- For the unlock screen, informational message shown in dialog when user is almost at the limit
          where the device will be wiped. -->
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv">
-       You have incorrectly attempted to unlock the TV <xliff:g id="number">%1$d</xliff:g> times.
+       You have incorrectly attempted to unlock your Android TV device <xliff:g id="number">%1$d</xliff:g> times.
        After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       the TV will be reset to factory default and all user data will be lost.
+       your Android TV device will be reset to factory default and all user data will be lost.
     </string>
 
     <!-- For the unlock screen, informational message shown in dialog when user is almost at the limit
@@ -2235,8 +2235,8 @@
     <!-- For the unlock screen, informational message shown in dialog when user has exceeded the
         maximum attempts and the device will now be wiped -->
     <string name="lockscreen_failed_attempts_now_wiping" product="tv">
-       You have incorrectly attempted to unlock the TV <xliff:g id="number">%d</xliff:g> times.
-       The TV will now be reset to factory default.
+       You have incorrectly attempted to unlock your Android TV device <xliff:g id="number">%d</xliff:g> times.
+       Your Android TV device will now be reset to factory default.
     </string>
 
     <!-- For the unlock screen, informational message shown in dialog when user has exceeded the
@@ -2603,7 +2603,7 @@
     <!-- Description of an application permission, listed so the user can choose whether
         they want to allow the application to do this. -->
     <string name="permdesc_writeHistoryBookmarks" product="tv">Allows the
-        app to modify the Browser\'s history or bookmarks stored on your TV.
+        app to modify the Browser\'s history or bookmarks stored on your Android TV device.
         This may allow the app to erase or modify Browser data.  Note: this
         permission may note be enforced by third-party browsers or other
         applications with web browsing capabilities.</string>
@@ -3506,7 +3506,7 @@
     <string name="wifi_p2p_show_pin_message">PIN: </string>
 
     <string name="wifi_p2p_frequency_conflict_message" product="tablet">The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv">The TV will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tv">Your Android TV device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string>
     <string name="wifi_p2p_frequency_conflict_message" product="default">The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string>
 
     <!-- Name of the dialog that lets the user choose an accented character to insert -->
@@ -4404,9 +4404,9 @@
     </string>
     <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. -->
     <string name="kg_failed_attempts_almost_at_wipe" product="tv">
-       You have incorrectly attempted to unlock the TV <xliff:g id="number">%1$d</xliff:g> times.
+       You have incorrectly attempted to unlock your Android TV device <xliff:g id="number">%1$d</xliff:g> times.
        After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       the TV will be reset to factory default and all user data will be lost.
+       your Android TV device will be reset to factory default and all user data will be lost.
     </string>
     <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. -->
     <string name="kg_failed_attempts_almost_at_wipe" product="default">
@@ -4421,8 +4421,8 @@
     </string>
     <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped -->
     <string name="kg_failed_attempts_now_wiping" product="tv">
-       You have incorrectly attempted to unlock the TV <xliff:g id="number">%d</xliff:g> times.
-       The TV will now be reset to factory default.
+       You have incorrectly attempted to unlock your Android TV device <xliff:g id="number">%d</xliff:g> times.
+       Your Android TV device will now be reset to factory default.
     </string>
     <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped -->
     <string name="kg_failed_attempts_now_wiping" product="default">
@@ -4442,7 +4442,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tv">
        You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times.
        After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       you will be asked to unlock your TV using an email account.\n\n
+       you will be asked to unlock your Android TV device using an email account.\n\n
        Try again in <xliff:g id="number">%3$d</xliff:g> seconds.
     </string>
     <!-- Message shown in dialog when user is almost at the limit where they will be
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4094bf4..f7ae453 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3118,6 +3118,7 @@
   <java-symbol type="array" name="config_defaultPinnerServiceFiles" />
   <java-symbol type="bool" name="config_pinnerCameraApp" />
   <java-symbol type="bool" name="config_pinnerHomeApp" />
+  <java-symbol type="bool" name="config_pinnerAssistantApp" />
   <java-symbol type="array" name="config_apexBootImagePinnerServiceFiles" />
 
   <java-symbol type="string" name="config_doubleTouchGestureEnableFile" />
@@ -3825,6 +3826,7 @@
   <java-symbol type="color" name="chooser_gradient_highlight" />
   <java-symbol type="drawable" name="chooser_direct_share_label_placeholder" />
   <java-symbol type="dimen" name="chooser_direct_share_label_placeholder_max_width" />
+  <java-symbol type="dimen" name="seekbar_thumb_exclusion_max_size" />
   <java-symbol type="layout" name="chooser_az_label_row" />
   <java-symbol type="string" name="chooser_all_apps_button_label" />
   <java-symbol type="anim" name="resolver_launch_anim" />
@@ -3834,6 +3836,7 @@
 
   <java-symbol type="string" name="config_defaultSupervisionProfileOwnerComponent" />
   <java-symbol type="bool" name="config_inflateSignalStrength" />
+  <java-symbol type="array" name="config_restrictedPreinstalledCarrierApps" />
 
   <java-symbol type="drawable" name="android_logotype" />
   <java-symbol type="layout" name="platlogo_layout" />
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
index 6e65df1..3d9a1d9 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
@@ -250,6 +250,29 @@
         verify(mHalTunerSessionMock).stopProgramListUpdates();
     }
 
+    @Test
+    public void testNullAidlFilter() throws RemoteException {
+        openAidlClients(1);
+        mTunerSessions[0].startProgramListUpdates(null);
+        verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(any());
+
+        // Verify the AIDL client receives all types of updates (e.g. a new program, an update to
+        // that program, and a category).
+        updateHalProgramInfo(true, Arrays.asList(mAmFmInfo, mRdsInfo), null);
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], true, Arrays.asList(
+                mAmFmInfo, mRdsInfo), null);
+        updateHalProgramInfo(false, Arrays.asList(mModifiedAmFmInfo), null);
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], false,
+                Arrays.asList(mModifiedAmFmInfo), null);
+        updateHalProgramInfo(false, Arrays.asList(mDabEnsembleInfo), null);
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], false,
+                Arrays.asList(mDabEnsembleInfo), null);
+
+        // Verify closing the AIDL session also stops HAL updates.
+        mTunerSessions[0].close();
+        verify(mHalTunerSessionMock).stopProgramListUpdates();
+    }
+
     private void openAidlClients(int numClients) throws RemoteException {
         mAidlTunerCallbackMocks = new android.hardware.radio.ITunerCallback[numClients];
         mTunerSessions = new TunerSession[numClients];
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 833c734..1670d49 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -58,6 +58,8 @@
 
     resource_dirs: ["res"],
     resource_zips: [":FrameworksCoreTests_apks_as_resources"],
+
+    data: [":BstatsTestApp"],
 }
 
 // Rules to copy all the test apks to the intermediate raw resource directory
diff --git a/core/tests/coretests/BstatsTestApp/Android.bp b/core/tests/coretests/BstatsTestApp/Android.bp
index 424c71a..a89d728 100644
--- a/core/tests/coretests/BstatsTestApp/Android.bp
+++ b/core/tests/coretests/BstatsTestApp/Android.bp
@@ -15,10 +15,6 @@
 android_test_helper_app {
     name: "BstatsTestApp",
 
-    test_suites: [
-        "device-tests",
-    ],
-
     static_libs: ["coretests-aidl"],
 
     srcs: ["**/*.java"],
diff --git a/core/tests/coretests/src/android/content/ContentProviderOperationTest.java b/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
index b142761..b1ce33a 100644
--- a/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
+++ b/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
@@ -26,11 +26,6 @@
 
 import junit.framework.TestCase;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
@@ -39,11 +34,6 @@
     private final static Uri sTestUri1 = Uri.parse("content://authority/blah");
     private final static ContentValues sTestValues1;
 
-    private final static Class<ContentProviderOperation.Builder> CLASS_BUILDER =
-            ContentProviderOperation.Builder.class;
-    private final static Class<ContentProviderOperation> CLASS_OPERATION =
-            ContentProviderOperation.class;
-
     static {
         sTestValues1 = new ContentValues();
         sTestValues1.put("a", 1);
@@ -279,221 +269,6 @@
         assertEquals("a,103,101,b,102", TextUtils.join(",", s2));
     }
 
-    public void testParcelingOperation() throws NoSuchFieldException, IllegalAccessException,
-            NoSuchMethodException, InvocationTargetException, InstantiationException {
-        Parcel parcel = Parcel.obtain();
-        ContentProviderOperation op1;
-        ContentProviderOperation op2;
-
-        HashMap<Integer, Integer> selArgsBackRef = new HashMap<Integer, Integer>();
-        selArgsBackRef.put(1, 2);
-        selArgsBackRef.put(3, 4);
-
-        ContentValues values = new ContentValues();
-        values.put("v1", "val1");
-        values.put("v2", "43");
-
-        ContentValues valuesBackRef = new ContentValues();
-        values.put("v3", "val3");
-        values.put("v4", "44");
-
-        try {
-            ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(
-                    Uri.parse("content://goo/bar"));
-
-            builderSetExpectedCount(builder, 42);
-            builderSetSelection(builder, "selection");
-            builderSetSelectionArgs(builder, new String[]{"a", "b"});
-            builderSetSelectionArgsBackReferences(builder, selArgsBackRef);
-            builderSetValues(builder, values);
-            builderSetValuesBackReferences(builder, valuesBackRef);
-
-            op1 = newOperationFromBuilder(builder);
-            op1.writeToParcel(parcel, 0);
-            parcel.setDataPosition(0);
-            op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
-
-            assertEquals(ContentProviderOperation.TYPE_INSERT, operationGetType(op2));
-            assertEquals("content://goo/bar", operationGetUri(op2).toString());
-            assertEquals(Integer.valueOf(42), operationGetExpectedCount(op2));
-            assertEquals("selection", operationGetSelection(op2));
-            assertEquals(2, operationGetSelectionArgs(op2).length);
-            assertEquals("a", operationGetSelectionArgs(op2)[0]);
-            assertEquals("b", operationGetSelectionArgs(op2)[1]);
-            assertEquals(values, operationGetValues(op2));
-            assertEquals(valuesBackRef, operationGetValuesBackReferences(op2));
-            assertEquals(2, operationGetSelectionArgsBackReferences(op2).size());
-            assertEquals(Integer.valueOf(2), operationGetSelectionArgsBackReferences(op2).get(1));
-            assertEquals(Integer.valueOf(4), operationGetSelectionArgsBackReferences(op2).get(3));
-        } finally {
-            parcel.recycle();
-        }
-
-        try {
-            ContentProviderOperation.Builder builder = ContentProviderOperation.newUpdate(
-                    Uri.parse("content://goo/bar"));
-
-            builderSetSelectionArgsBackReferences(builder, selArgsBackRef);
-
-            op1 = newOperationFromBuilder(builder);
-            op1.writeToParcel(parcel, 0);
-            parcel.setDataPosition(0);
-            op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
-            assertEquals(ContentProviderOperation.TYPE_UPDATE, operationGetType(op2));
-            assertEquals("content://goo/bar", operationGetUri(op2).toString());
-            assertNull(operationGetExpectedCount(op2));
-            assertNull(operationGetSelection(op2));
-            assertNull(operationGetSelectionArgs(op2));
-            assertNull(operationGetValues(op2));
-            assertNull(operationGetValuesBackReferences(op2));
-            assertEquals(2, operationGetSelectionArgsBackReferences(op2).size());
-            assertEquals(Integer.valueOf(2), operationGetSelectionArgsBackReferences(op2).get(1));
-            assertEquals(Integer.valueOf(4), operationGetSelectionArgsBackReferences(op2).get(3));
-        } finally {
-            parcel.recycle();
-        }
-
-        try {
-            ContentProviderOperation.Builder builder = ContentProviderOperation.newDelete(
-                    Uri.parse("content://goo/bar"));
-
-            op1 = newOperationFromBuilder(builder);
-            op1.writeToParcel(parcel, 0);
-            parcel.setDataPosition(0);
-            op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
-            assertEquals(ContentProviderOperation.TYPE_DELETE, operationGetType(op2));
-            assertEquals("content://goo/bar", operationGetUri(op2).toString());
-            assertNull(operationGetExpectedCount(op2));
-            assertNull(operationGetSelection(op2));
-            assertNull(operationGetSelectionArgs(op2));
-            assertNull(operationGetValues(op2));
-            assertNull(operationGetValuesBackReferences(op2));
-            assertNull(operationGetSelectionArgsBackReferences(op2));
-        } finally {
-            parcel.recycle();
-        }
-    }
-
-    private static ContentProviderOperation newOperationFromBuilder(
-            ContentProviderOperation.Builder builder)
-            throws NoSuchMethodException, InstantiationException, IllegalAccessException,
-            InvocationTargetException {
-        final Constructor constructor = CLASS_OPERATION.getDeclaredConstructor(CLASS_BUILDER);
-        constructor.setAccessible(true);
-        return (ContentProviderOperation) constructor.newInstance(builder);
-    }
-
-    private void builderSetSelectionArgsBackReferences(
-            ContentProviderOperation.Builder builder, HashMap<Integer, Integer> selArgsBackRef)
-            throws NoSuchFieldException, IllegalAccessException {
-        Field field;
-        field = CLASS_BUILDER.getDeclaredField("mSelectionArgsBackReferences");
-        field.setAccessible(true);
-        field.set(builder, selArgsBackRef);
-    }
-
-    private void builderSetValuesBackReferences(
-            ContentProviderOperation.Builder builder, ContentValues valuesBackReferences)
-            throws NoSuchFieldException, IllegalAccessException {
-        Field field;
-        field = CLASS_BUILDER.getDeclaredField("mValuesBackReferences");
-        field.setAccessible(true);
-        field.set(builder, valuesBackReferences);
-    }
-
-    private void builderSetSelection(
-            ContentProviderOperation.Builder builder, String selection)
-            throws NoSuchFieldException, IllegalAccessException {
-        Field field;
-        field = CLASS_BUILDER.getDeclaredField("mSelection");
-        field.setAccessible(true);
-        field.set(builder, selection);
-    }
-
-    private void builderSetSelectionArgs(
-            ContentProviderOperation.Builder builder, String[] selArgs)
-            throws NoSuchFieldException, IllegalAccessException {
-        Field field;
-        field = CLASS_BUILDER.getDeclaredField("mSelectionArgs");
-        field.setAccessible(true);
-        field.set(builder, selArgs);
-    }
-
-    private void builderSetValues(
-            ContentProviderOperation.Builder builder, ContentValues values)
-            throws NoSuchFieldException, IllegalAccessException {
-        Field field;
-        field = CLASS_BUILDER.getDeclaredField("mValues");
-        field.setAccessible(true);
-        field.set(builder, values);
-    }
-
-    private void builderSetExpectedCount(
-            ContentProviderOperation.Builder builder, Integer expectedCount)
-            throws NoSuchFieldException, IllegalAccessException {
-        Field field;
-        field = CLASS_BUILDER.getDeclaredField("mExpectedCount");
-        field.setAccessible(true);
-        field.set(builder, expectedCount);
-    }
-
-    private int operationGetType(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mType");
-        field.setAccessible(true);
-        return field.getInt(operation);
-    }
-
-    private Uri operationGetUri(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mUri");
-        field.setAccessible(true);
-        return (Uri) field.get(operation);
-    }
-
-    private String operationGetSelection(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mSelection");
-        field.setAccessible(true);
-        return (String) field.get(operation);
-    }
-
-    private String[] operationGetSelectionArgs(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mSelectionArgs");
-        field.setAccessible(true);
-        return (String[]) field.get(operation);
-    }
-
-    private ContentValues operationGetValues(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mValues");
-        field.setAccessible(true);
-        return (ContentValues) field.get(operation);
-    }
-
-    private Integer operationGetExpectedCount(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mExpectedCount");
-        field.setAccessible(true);
-        return (Integer) field.get(operation);
-    }
-
-    private ContentValues operationGetValuesBackReferences(ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mValuesBackReferences");
-        field.setAccessible(true);
-        return (ContentValues) field.get(operation);
-    }
-
-    private Map<Integer, Integer> operationGetSelectionArgsBackReferences(
-            ContentProviderOperation operation)
-            throws NoSuchFieldException, IllegalAccessException {
-        final Field field = CLASS_OPERATION.getDeclaredField("mSelectionArgsBackReferences");
-        field.setAccessible(true);
-        return (Map<Integer, Integer>) field.get(operation);
-    }
-
     public void testParcelingResult() {
         Parcel parcel = Parcel.obtain();
         ContentProviderResult result1;
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 58c43ac2..eb61e9c 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -428,6 +428,18 @@
                 "com.android.frameworks.coretests.install_complete_package_info.test_permission",
                 packageName, PermissionInfo.PROTECTION_NORMAL, p.permissions.get(0));
 
+        // Hidden "app details" activity is added to every package.
+        boolean foundAppDetailsActivity = false;
+        for (int i = 0; i < p.activities.size(); i++) {
+            if (p.activities.get(i).className.equals(
+                    PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME)) {
+                foundAppDetailsActivity = true;
+                p.activities.remove(i);
+                break;
+            }
+        }
+        assertTrue("Did not find app details activity", foundAppDetailsActivity);
+
         assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", p);
 
         assertMetadata(p.mAppMetaData,
diff --git a/core/tests/coretests/src/android/os/ParcelNullabilityTest.java b/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
index a6b296d..b4e180c 100644
--- a/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
+++ b/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
@@ -327,8 +327,8 @@
         Parcel p = Parcel.obtain();
         p.writeParcelableList(null, 0);
 
-        List<Object> list = new ArrayList<>();
-        throughBytes(p).readParcelableList(null, null);
+        List<Parcelable> list = new ArrayList<>();
+        throughBytes(p).readParcelableList(list, null);
         assertTrue(list.isEmpty());
     }
 
diff --git a/core/tests/coretests/src/android/widget/AbsSeekBarTest.java b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
new file mode 100644
index 0000000..aec6096
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasSize;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.RectShape;
+import android.platform.test.annotations.Presubmit;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class AbsSeekBarTest {
+
+    private Context mContext;
+    private AbsSeekBar mBar;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        mBar = new SeekBar(mContext);
+    }
+
+    @Test
+    public void testExclusionForThumb_limitedTo48dp() {
+        mBar.setPadding(10, 10, 10, 10);
+        mBar.setThumb(newThumb(dpToPx(20)));
+        mBar.setMin(0);
+        mBar.setMax(100);
+        mBar.setProgress(50);
+        measureAndLayout(dpToPx(200), dpToPx(100));
+        List<Rect> exclusions = mBar.getSystemGestureExclusionRects();
+
+        assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size());
+        assertEquals("exclusion should be centered on thumb",
+                center(mBar), center(exclusions.get(0)));
+        assertEquals("exclusion should be 48dp high", dpToPx(48), exclusions.get(0).height());
+        assertEquals("exclusion should be 48dp wide", dpToPx(48), exclusions.get(0).width());
+    }
+
+    @Test
+    public void testExclusionForThumb_limitedToHeight() {
+        mBar.setPadding(10, 10, 10, 10);
+        mBar.setThumb(newThumb(dpToPx(20)));
+        mBar.setMin(0);
+        mBar.setMax(100);
+        mBar.setProgress(50);
+        measureAndLayout(dpToPx(200), dpToPx(32));
+        List<Rect> exclusions = mBar.getSystemGestureExclusionRects();
+
+        assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size());
+        assertEquals("exclusion should be centered on thumb",
+                center(mBar), center(exclusions.get(0)));
+        assertEquals("exclusion should be 32dp high", dpToPx(32), exclusions.get(0).height());
+        assertEquals("exclusion should be 32dp wide", dpToPx(32), exclusions.get(0).width());
+    }
+
+    @Test
+    public void testExclusionForThumb_passesThroughUserExclusions() {
+        mBar.setSystemGestureExclusionRects(Arrays.asList(new Rect(1, 2, 3, 4)));
+
+        mBar.setPadding(10, 10, 10, 10);
+        mBar.setThumb(newThumb(dpToPx(20)));
+        mBar.setMin(0);
+        mBar.setMax(100);
+        mBar.setProgress(50);
+        measureAndLayout(dpToPx(200), dpToPx(32));
+
+        assertThat(mBar.getSystemGestureExclusionRects(), hasItem(new Rect(1, 2, 3, 4)));
+        assertThat(mBar.getSystemGestureExclusionRects(), hasSize(2));
+
+        mBar.setSystemGestureExclusionRects(Arrays.asList(new Rect(3, 4, 5, 6)));
+        assertThat(mBar.getSystemGestureExclusionRects(), hasItem(new Rect(3, 4, 5, 6)));
+        assertThat(mBar.getSystemGestureExclusionRects(), hasSize(2));
+    }
+
+    private Point center(Rect rect) {
+        return new Point(rect.centerX(), rect.centerY());
+    }
+
+    private Point center(View view) {
+        return center(new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
+    }
+
+    private ShapeDrawable newThumb(int size) {
+        final ShapeDrawable thumb = new ShapeDrawable(new RectShape());
+        thumb.setIntrinsicWidth(size);
+        thumb.setIntrinsicHeight(size);
+        return thumb;
+    }
+
+    private void measureAndLayout(int wPx, int hPx) {
+        mBar.measure(makeMeasureSpec(wPx, EXACTLY), makeMeasureSpec(hPx, EXACTLY));
+        mBar.layout(0, 0, wPx, hPx);
+    }
+
+    private int dpToPx(int dp) {
+        return (int) (mContext.getResources().getDisplayMetrics().density * dp);
+    }
+}
diff --git a/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
index 2596ece..27f3596 100644
--- a/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
@@ -16,13 +16,22 @@
 
 package com.android.internal.util;
 
+import static org.junit.Assert.assertArrayEquals;
+
+import android.util.Xml;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
+
 import junit.framework.TestCase;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
 public class XmlUtilsTest extends TestCase {
 
     // https://code.google.com/p/android/issues/detail?id=63717
@@ -38,4 +47,23 @@
         assertEquals("nullValue", deserialized.get(null));
         assertEquals("fooValue", deserialized.get("foo"));
     }
+
+    public void testreadWriteXmlByteArrayValue() throws Exception {
+        byte[] testByteArray = {0x1 , 0xa, 0xb, 0x9, 0x34, (byte) 0xaa, (byte) 0xba, (byte) 0x99};
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
+        XmlSerializer serializer = new FastXmlSerializer();
+        serializer.setOutput(baos, StandardCharsets.UTF_8.name());
+        serializer.startDocument(null, true);
+        XmlUtils.writeValueXml(testByteArray,  "testByteArray", serializer);
+        serializer.endDocument();
+
+        InputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        XmlPullParser pullParser = Xml.newPullParser();
+        pullParser.setInput(bais, StandardCharsets.UTF_8.name());
+        String[] name = new String[1];
+        byte[] testByteArrayDeserialized = (byte[]) XmlUtils.readValueXml(pullParser, name);
+        assertEquals("testByteArray", name[0]);
+        assertArrayEquals(testByteArray, testByteArrayDeserialized);
+    }
 }
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index 5af0da8..5ad93f4 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -21,7 +21,6 @@
 import android.content.res.AssetManager;
 import android.graphics.fonts.FontVariationAxis;
 import android.text.TextUtils;
-import android.util.Log;
 
 import dalvik.annotation.optimization.CriticalNative;
 
@@ -145,7 +144,6 @@
             }
             return nAddFont(mBuilderPtr, fontBuffer, ttcIndex, weight, italic);
         } catch (IOException e) {
-            Log.e(TAG, "Error mapping font file " + path);
             return false;
         }
     }
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 4a9cf14..95a8417 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -105,7 +105,6 @@
             final long fontSize = fileChannel.size();
             return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
         } catch (IOException e) {
-            Log.e(TAG, "Error mapping font file " + fullPath);
             return null;
         }
     }
diff --git a/keystore/java/android/security/AttestedKeyPair.java b/keystore/java/android/security/AttestedKeyPair.java
index c6bff5c..2debfee 100644
--- a/keystore/java/android/security/AttestedKeyPair.java
+++ b/keystore/java/android/security/AttestedKeyPair.java
@@ -16,6 +16,9 @@
 
 package android.security;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
 import java.security.KeyPair;
 import java.security.cert.Certificate;
 import java.util.ArrayList;
@@ -36,9 +39,12 @@
     private final Certificate[] mAttestationRecord;
 
     /**
-     * @hide Only created by the platform, no need to expose as public API.
+     * Public constructor for creating a new instance (useful for testing).
+     *
+     * @param keyPair the key pair associated with the attestation record.
+     * @param attestationRecord attestation record for the provided key pair.
      */
-    public AttestedKeyPair(KeyPair keyPair, Certificate[] attestationRecord) {
+    public AttestedKeyPair(@Nullable KeyPair keyPair, @Nullable Certificate[] attestationRecord) {
         mKeyPair = keyPair;
         mAttestationRecord = attestationRecord;
     }
@@ -47,7 +53,7 @@
      * Returns the generated key pair associated with the attestation record
      * in this instance.
      */
-    public KeyPair getKeyPair() {
+    public @Nullable KeyPair getKeyPair() {
         return mKeyPair;
     }
 
@@ -66,7 +72,7 @@
      * and  <a href="https://developer.android.com/training/articles/security-key-attestation.html">
      * Key Attestation</a> for the format of the attestation record inside the certificate.
      */
-    public List<Certificate> getAttestationRecord() {
+    public @NonNull List<Certificate> getAttestationRecord() {
         if (mAttestationRecord == null) {
             return new ArrayList();
         }
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index 0a9d965..a0d3ff9 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -18,7 +18,6 @@
 
 #include "Properties.h"
 
-#include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 #include <ui/GraphicTypes.h>
 
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
index 71cc9a8..0698775 100644
--- a/libs/hwui/FrameInfo.cpp
+++ b/libs/hwui/FrameInfo.cpp
@@ -37,13 +37,14 @@
         "FrameCompleted",
         "DequeueBufferDuration",
         "QueueBufferDuration",
+        "GpuCompleted",
 };
 
 static_assert((sizeof(FrameInfoNames) / sizeof(FrameInfoNames[0])) ==
                       static_cast<int>(FrameInfoIndex::NumIndexes),
               "size mismatch: FrameInfoNames doesn't match the enum!");
 
-static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 16,
+static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 17,
               "Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
 
 void FrameInfo::importUiThreadInfo(int64_t* info) {
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index b75192f..51674fb 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -51,6 +51,8 @@
     DequeueBufferDuration,
     QueueBufferDuration,
 
+    GpuCompleted,
+
     // Must be the last value!
     // Also must be kept in sync with FrameMetrics.java#FRAME_STATS_COUNT
     NumIndexes
@@ -143,6 +145,13 @@
         return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted);
     }
 
+    inline int64_t gpuDrawTime() const {
+        // GPU start time is approximated to the moment before swapBuffer is invoked.
+        // We could add an EGLSyncKHR fence at the beginning of the frame, but that is an overhead.
+        int64_t endTime = get(FrameInfoIndex::GpuCompleted);
+        return endTime > 0 ? endTime - get(FrameInfoIndex::SwapBuffers) : -1;
+    }
+
     inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; }
 
     inline int64_t get(FrameInfoIndex index) const {
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 53c5ad8..eae3584 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -232,5 +232,13 @@
                                                     : FrameInfoIndex::IntendedVsync;
 }
 
+void JankTracker::finishGpuDraw(const FrameInfo& frame) {
+    int64_t totalGPUDrawTime = frame.gpuDrawTime();
+    if (totalGPUDrawTime >= 0) {
+        mData->reportGPUFrame(totalGPUDrawTime);
+        (*mGlobalData)->reportGPUFrame(totalGPUDrawTime);
+    }
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index 110211e..08059268 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -58,6 +58,7 @@
 
     FrameInfo* startFrame() { return &mFrames.next(); }
     void finishFrame(const FrameInfo& frame);
+    void finishGpuDraw(const FrameInfo& frame);
 
     void dumpStats(int fd) { dumpData(fd, &mDescription, mData.get()); }
     void dumpFrames(int fd);
diff --git a/libs/hwui/ProfileData.cpp b/libs/hwui/ProfileData.cpp
index c7f9232..7921662 100644
--- a/libs/hwui/ProfileData.cpp
+++ b/libs/hwui/ProfileData.cpp
@@ -98,6 +98,10 @@
     if (mStatStartTime > other.mStatStartTime || mStatStartTime == 0) {
         mStatStartTime = other.mStatStartTime;
     }
+    for (size_t i = 0; i < other.mGPUFrameCounts.size(); i++) {
+        mGPUFrameCounts[i] >>= divider;
+        mGPUFrameCounts[i] += other.mGPUFrameCounts[i];
+    }
 }
 
 void ProfileData::dump(int fd) const {
@@ -117,6 +121,14 @@
     histogramForEach([fd](HistogramEntry entry) {
         dprintf(fd, " %ums=%u", entry.renderTimeMs, entry.frameCount);
     });
+    dprintf(fd, "\n50th gpu percentile: %ums", findGPUPercentile(50));
+    dprintf(fd, "\n90th gpu percentile: %ums", findGPUPercentile(90));
+    dprintf(fd, "\n95th gpu percentile: %ums", findGPUPercentile(95));
+    dprintf(fd, "\n99th gpu percentile: %ums", findGPUPercentile(99));
+    dprintf(fd, "\nGPU HISTOGRAM:");
+    histogramGPUForEach([fd](HistogramEntry entry) {
+        dprintf(fd, " %ums=%u", entry.renderTimeMs, entry.frameCount);
+    });
 }
 
 uint32_t ProfileData::findPercentile(int percentile) const {
@@ -140,6 +152,7 @@
 void ProfileData::reset() {
     mJankTypeCounts.fill(0);
     mFrameCounts.fill(0);
+    mGPUFrameCounts.fill(0);
     mSlowFrameCounts.fill(0);
     mTotalFrameCount = 0;
     mJankFrameCount = 0;
@@ -167,5 +180,40 @@
     }
 }
 
+uint32_t ProfileData::findGPUPercentile(int percentile) const {
+    uint32_t totalGPUFrameCount = 0;  // this is usually mTotalFrameCount - 3.
+    for (int i = mGPUFrameCounts.size() - 1; i >= 0; i--) {
+        totalGPUFrameCount += mGPUFrameCounts[i];
+    }
+    int pos = percentile * totalGPUFrameCount / 100;
+    int remaining = totalGPUFrameCount - pos;
+    for (int i = mGPUFrameCounts.size() - 1; i >= 0; i--) {
+        remaining -= mGPUFrameCounts[i];
+        if (remaining <= 0) {
+            return GPUFrameTimeForFrameCountIndex(i);
+        }
+    }
+    return 0;
+}
+
+uint32_t ProfileData::GPUFrameTimeForFrameCountIndex(uint32_t index) {
+    return index != 25 ? index + 1 : 4950;
+}
+
+void ProfileData::reportGPUFrame(int64_t duration) {
+    uint32_t index = static_cast<uint32_t>(ns2ms(duration));
+    if (index > 25) {
+        index = 25;
+    }
+
+    mGPUFrameCounts[index]++;
+}
+
+void ProfileData::histogramGPUForEach(const std::function<void(HistogramEntry)>& callback) const {
+    for (size_t i = 0; i < mGPUFrameCounts.size(); i++) {
+        callback(HistogramEntry{GPUFrameTimeForFrameCountIndex(i), mGPUFrameCounts[i]});
+    }
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
\ No newline at end of file
diff --git a/libs/hwui/ProfileData.h b/libs/hwui/ProfileData.h
index 564920b..ccbffc6 100644
--- a/libs/hwui/ProfileData.h
+++ b/libs/hwui/ProfileData.h
@@ -54,8 +54,10 @@
     void mergeWith(const ProfileData& other);
     void dump(int fd) const;
     uint32_t findPercentile(int percentile) const;
+    uint32_t findGPUPercentile(int percentile) const;
 
     void reportFrame(int64_t duration);
+    void reportGPUFrame(int64_t duration);
     void reportJank() { mJankFrameCount++; }
     void reportJankType(JankType type) { mJankTypeCounts[static_cast<int>(type)]++; }
 
@@ -69,15 +71,21 @@
         uint32_t frameCount;
     };
     void histogramForEach(const std::function<void(HistogramEntry)>& callback) const;
+    void histogramGPUForEach(const std::function<void(HistogramEntry)>& callback) const;
 
     constexpr static int HistogramSize() {
         return std::tuple_size<decltype(ProfileData::mFrameCounts)>::value +
                std::tuple_size<decltype(ProfileData::mSlowFrameCounts)>::value;
     }
 
+    constexpr static int GPUHistogramSize() {
+        return std::tuple_size<decltype(ProfileData::mGPUFrameCounts)>::value;
+    }
+
     // Visible for testing
     static uint32_t frameTimeForFrameCountIndex(uint32_t index);
     static uint32_t frameTimeForSlowFrameCountIndex(uint32_t index);
+    static uint32_t GPUFrameTimeForFrameCountIndex(uint32_t index);
 
 private:
     // Open our guts up to unit tests
@@ -88,6 +96,9 @@
     std::array<uint32_t, 57> mFrameCounts;
     // Holds a histogram of frame times in 50ms increments from 150ms to 5s
     std::array<uint16_t, 97> mSlowFrameCounts;
+    // Holds a histogram of GPU draw times in 1ms increments. Frames longer than 25ms are placed in
+    // last bucket.
+    std::array<uint32_t, 26> mGPUFrameCounts;
 
     uint32_t mTotalFrameCount;
     uint32_t mJankFrameCount;
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index f91d178..61403aa 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -16,19 +16,24 @@
 
 #include "VectorDrawable.h"
 
+#include <math.h>
+#include <string.h>
 #include <utils/Log.h>
-#include "hwui/Paint.h"
+
 #include "PathParser.h"
 #include "SkColorFilter.h"
 #include "SkImageInfo.h"
 #include "SkShader.h"
+#include "hwui/Paint.h"
+
+#ifdef __ANDROID__
+#include "renderthread/RenderThread.h"
+#endif
+
 #include "utils/Macros.h"
 #include "utils/TraceUtils.h"
 #include "utils/VectorDrawableUtils.h"
 
-#include <math.h>
-#include <string.h>
-
 namespace android {
 namespace uirenderer {
 namespace VectorDrawable {
@@ -472,7 +477,7 @@
                           mStagingProperties.getBounds().bottom(), &paint);
 }
 
-void Tree::getPaintFor(SkPaint* outPaint, const TreeProperties &prop) const {
+void Tree::getPaintFor(SkPaint* outPaint, const TreeProperties& prop) const {
     // HWUI always draws VD with bilinear filtering.
     outPaint->setFilterQuality(kLow_SkFilterQuality);
     if (prop.getColorFilter() != nullptr) {
@@ -492,7 +497,7 @@
 }
 
 void Tree::updateCache(sp<skiapipeline::VectorDrawableAtlas>& atlas, GrContext* context) {
-#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
+#ifdef __ANDROID__  // Layoutlib does not support hardware acceleration
     SkRect dst;
     sk_sp<SkSurface> surface = mCache.getSurface(&dst);
     bool canReuseSurface = surface && dst.width() >= mProperties.getScaledWidth() &&
@@ -533,7 +538,7 @@
 
 sk_sp<SkSurface> Tree::Cache::getSurface(SkRect* bounds) {
     sk_sp<SkSurface> surface;
-#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
+#ifdef __ANDROID__  // Layoutlib does not support hardware acceleration
     sp<skiapipeline::VectorDrawableAtlas> atlas = mAtlas.promote();
     if (atlas.get() && mAtlasKey != INVALID_ATLAS_KEY) {
         auto atlasEntry = atlas->getEntry(mAtlasKey);
@@ -547,13 +552,28 @@
 }
 
 void Tree::Cache::clear() {
-#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
-    sp<skiapipeline::VectorDrawableAtlas> lockAtlas = mAtlas.promote();
-    if (lockAtlas.get()) {
-        lockAtlas->releaseEntry(mAtlasKey);
+#ifdef __ANDROID__  // Layoutlib does not support hardware acceleration
+    if (mAtlasKey != INVALID_ATLAS_KEY) {
+        if (renderthread::RenderThread::isCurrent()) {
+            sp<skiapipeline::VectorDrawableAtlas> lockAtlas = mAtlas.promote();
+            if (lockAtlas.get()) {
+                lockAtlas->releaseEntry(mAtlasKey);
+            }
+        } else {
+            // VectorDrawableAtlas can be accessed only on RenderThread.
+            // Use by-copy capture of the current Cache variables, because "this" may not be valid
+            // by the time the lambda is evaluated on RenderThread.
+            renderthread::RenderThread::getInstance().queue().post(
+                    [atlas = mAtlas, atlasKey = mAtlasKey]() {
+                        sp<skiapipeline::VectorDrawableAtlas> lockAtlas = atlas.promote();
+                        if (lockAtlas.get()) {
+                            lockAtlas->releaseEntry(atlasKey);
+                        }
+                    });
+        }
+        mAtlasKey = INVALID_ATLAS_KEY;
     }
     mAtlas = nullptr;
-    mAtlasKey = INVALID_ATLAS_KEY;
 #endif
 }
 
diff --git a/libs/hwui/protos/graphicsstats.proto b/libs/hwui/protos/graphicsstats.proto
index 1226d44..0cd5c62 100644
--- a/libs/hwui/protos/graphicsstats.proto
+++ b/libs/hwui/protos/graphicsstats.proto
@@ -46,6 +46,9 @@
 
     // The frame time histogram for the package
     repeated GraphicsStatsHistogramBucketProto histogram = 6;
+
+    // The gpu frame time histogram for the package
+    repeated GraphicsStatsHistogramBucketProto gpu_histogram = 7;
 }
 
 message GraphicsStatsJankSummaryProto {
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 1b638c1..5469a68 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -28,7 +28,6 @@
 #include <SkExecutor.h>
 #include <SkGraphics.h>
 #include <SkMathPriv.h>
-#include <gui/Surface.h>
 #include <math.h>
 #include <set>
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index d19351b..88a0c6e 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -147,6 +147,7 @@
         mNativeSurface = new ReliableSurface{std::move(surface)};
         // TODO: Fix error handling & re-shorten timeout
         mNativeSurface->setDequeueTimeout(4000_ms);
+        mNativeSurface->enableFrameTimestamps(true);
     } else {
         mNativeSurface = nullptr;
     }
@@ -294,6 +295,7 @@
     // just keep using the previous frame's structure instead
     if (!wasSkipped(mCurrentFrameInfo)) {
         mCurrentFrameInfo = mJankTracker.startFrame();
+        mLast4FrameInfos.next().first = mCurrentFrameInfo;
     }
     mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo);
     mCurrentFrameInfo->set(FrameInfoIndex::SyncQueued) = syncQueued;
@@ -445,7 +447,7 @@
                                       mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes,
                                       &(profiler()));
 
-    int64_t frameCompleteNr = mFrameCompleteCallbacks.size() ? getFrameNumber() : -1;
+    int64_t frameCompleteNr = getFrameNumber();
 
     waitOnFences();
 
@@ -500,11 +502,13 @@
         }
         mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = swap.dequeueDuration;
         mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = swap.queueDuration;
+        mLast4FrameInfos[-1].second = frameCompleteNr;
         mHaveNewSurface = false;
         mFrameNumber = -1;
     } else {
         mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = 0;
         mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = 0;
+        mLast4FrameInfos[-1].second = -1;
     }
 
     // TODO: Use a fence for real completion?
@@ -537,6 +541,19 @@
         mFrameMetricsReporter->reportFrameMetrics(mCurrentFrameInfo->data());
     }
 
+    if (mLast4FrameInfos.size() == mLast4FrameInfos.capacity()) {
+        // By looking 4 frames back, we guarantee all SF stats are available. There are at
+        // most 3 buffers in BufferQueue. Surface object keeps stats for the last 8 frames.
+        FrameInfo* forthBehind = mLast4FrameInfos.front().first;
+        int64_t composedFrameId = mLast4FrameInfos.front().second;
+        nsecs_t acquireTime = -1;
+        mNativeSurface->getFrameTimestamps(composedFrameId, nullptr, &acquireTime, nullptr, nullptr,
+            nullptr, nullptr, nullptr, nullptr, nullptr);
+        // Ignore default -1, NATIVE_WINDOW_TIMESTAMP_INVALID and NATIVE_WINDOW_TIMESTAMP_PENDING
+        forthBehind->set(FrameInfoIndex::GpuCompleted) = acquireTime > 0 ? acquireTime : -1;
+        mJankTracker.finishGpuDraw(*forthBehind);
+    }
+
     GpuMemoryTracker::onFrameCompleted();
 }
 
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index f9b9310..8a76d6b 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -29,6 +29,7 @@
 #include "RenderNode.h"
 #include "renderthread/RenderTask.h"
 #include "renderthread/RenderThread.h"
+#include "utils/RingBuffer.h"
 
 #include <SkBitmap.h>
 #include <SkRect.h>
@@ -41,6 +42,7 @@
 #include <future>
 #include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
 namespace android {
@@ -260,6 +262,7 @@
     std::vector<sp<RenderNode>> mRenderNodes;
 
     FrameInfo* mCurrentFrameInfo = nullptr;
+    RingBuffer<std::pair<FrameInfo*, int64_t>, 4> mLast4FrameInfos;
     std::string mName;
     JankTracker mJankTracker;
     FrameInfoVisualizer mProfiler;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index da27c1f..1202164 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -29,7 +29,6 @@
 #include <EGL/eglext.h>
 #include <GLES/gl.h>
 
-#include <gui/Surface.h>
 #include <system/window.h>
 #include <string>
 #include <vector>
diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h
index 41fc35e..7f1a078 100644
--- a/libs/hwui/renderthread/ReliableSurface.h
+++ b/libs/hwui/renderthread/ReliableSurface.h
@@ -49,6 +49,21 @@
         return ret;
     }
 
+    status_t getFrameTimestamps(uint64_t frameNumber,
+            nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
+            nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
+            nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
+            nsecs_t* outDisplayPresentTime, nsecs_t* outDequeueReadyTime,
+            nsecs_t* outReleaseTime) {
+        return mSurface->getFrameTimestamps(frameNumber, outRequestedPresentTime, outAcquireTime,
+            outLatchTime, outFirstRefreshStartTime, outLastRefreshStartTime,
+            outGlCompositionDoneTime, outDisplayPresentTime, outDequeueReadyTime, outReleaseTime);
+    }
+
+    void enableFrameTimestamps(bool enable) {
+        return mSurface->enableFrameTimestamps(enable);
+    }
+
 private:
     const sp<Surface> mSurface;
 
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index df7eeb3..5aa1af3 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -53,6 +53,10 @@
 class VkFunctorDrawHandler;
 }
 
+namespace VectorDrawable {
+class Tree;
+}
+
 namespace renderthread {
 
 class CanvasContext;
@@ -138,6 +142,7 @@
     friend class android::uirenderer::TestUtils;
     friend class android::uirenderer::WebViewFunctor;
     friend class android::uirenderer::skiapipeline::VkFunctorDrawHandler;
+    friend class android::uirenderer::VectorDrawable::Tree;
 
     RenderThread();
     virtual ~RenderThread();
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 280f7d3..5100165 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -17,7 +17,8 @@
 #include "VulkanManager.h"
 
 #include <android/sync.h>
-#include <gui/Surface.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
 
 #include "Properties.h"
 #include "RenderThread.h"
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index 8a16b20..8b5912b 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -40,6 +40,7 @@
 static_assert(sizeof(sCurrentFileVersion) == sHeaderSize, "Header size is wrong");
 
 constexpr int sHistogramSize = ProfileData::HistogramSize();
+constexpr int sGPUHistogramSize = ProfileData::GPUHistogramSize();
 
 static bool mergeProfileDataIntoProto(protos::GraphicsStatsProto* proto,
                                       const std::string& package, int64_t versionCode,
@@ -211,6 +212,37 @@
         bucket->set_frame_count(bucket->frame_count() + entry.frameCount);
         index++;
     });
+    if (hitMergeError) return false;
+    // fill in GPU frame time histogram
+    creatingHistogram = false;
+    if (proto->gpu_histogram_size() == 0) {
+        proto->mutable_gpu_histogram()->Reserve(sGPUHistogramSize);
+        creatingHistogram = true;
+    } else if (proto->gpu_histogram_size() != sGPUHistogramSize) {
+        ALOGE("GPU histogram size mismatch, proto is %d expected %d", proto->gpu_histogram_size(),
+              sGPUHistogramSize);
+        return false;
+    }
+    index = 0;
+    data->histogramGPUForEach([&](ProfileData::HistogramEntry entry) {
+        if (hitMergeError) return;
+
+        protos::GraphicsStatsHistogramBucketProto* bucket;
+        if (creatingHistogram) {
+            bucket = proto->add_gpu_histogram();
+            bucket->set_render_millis(entry.renderTimeMs);
+        } else {
+            bucket = proto->mutable_gpu_histogram(index);
+            if (bucket->render_millis() != static_cast<int32_t>(entry.renderTimeMs)) {
+                ALOGW("GPU frame time mistmatch %d vs. %u", bucket->render_millis(),
+                      entry.renderTimeMs);
+                hitMergeError = true;
+                return;
+            }
+        }
+        bucket->set_frame_count(bucket->frame_count() + entry.frameCount);
+        index++;
+    });
     return !hitMergeError;
 }
 
@@ -226,6 +258,22 @@
     return 0;
 }
 
+static int32_t findGPUPercentile(protos::GraphicsStatsProto* proto, int percentile) {
+    uint32_t totalGPUFrameCount = 0;  // this is usually  proto->summary().total_frames() - 3.
+    for (auto it = proto->gpu_histogram().rbegin(); it != proto->gpu_histogram().rend(); ++it) {
+        totalGPUFrameCount += it->frame_count();
+    }
+    int32_t pos = percentile * totalGPUFrameCount / 100;
+    int32_t remaining = totalGPUFrameCount - pos;
+    for (auto it = proto->gpu_histogram().rbegin(); it != proto->gpu_histogram().rend(); ++it) {
+        remaining -= it->frame_count();
+        if (remaining <= 0) {
+            return it->render_millis();
+        }
+    }
+    return 0;
+}
+
 void dumpAsTextToFd(protos::GraphicsStatsProto* proto, int fd) {
     // This isn't a full validation, just enough that we can deref at will
     if (proto->package_name().empty() || !proto->has_summary()) {
@@ -255,6 +303,14 @@
     for (const auto& it : proto->histogram()) {
         dprintf(fd, " %dms=%d", it.render_millis(), it.frame_count());
     }
+    dprintf(fd, "\n50th gpu percentile: %dms", findGPUPercentile(proto, 50));
+    dprintf(fd, "\n90th gpu percentile: %dms", findGPUPercentile(proto, 90));
+    dprintf(fd, "\n95th gpu percentile: %dms", findGPUPercentile(proto, 95));
+    dprintf(fd, "\n99th gpu percentile: %dms", findGPUPercentile(proto, 99));
+    dprintf(fd, "\nGPU HISTOGRAM:");
+    for (const auto& it : proto->gpu_histogram()) {
+        dprintf(fd, " %dms=%d", it.render_millis(), it.frame_count());
+    }
     dprintf(fd, "\n");
 }
 
diff --git a/media/OWNERS b/media/OWNERS
index a33a990..8bd037a 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -10,6 +10,7 @@
 jaewan@google.com
 jmtrivi@google.com
 jsharkey@android.com
+klhyun@google.com
 lajos@google.com
 marcone@google.com
 sungsoo@google.com
diff --git a/media/java/android/media/AudioPortEventHandler.java b/media/java/android/media/AudioPortEventHandler.java
index f9a4b1e..6d9d626 100644
--- a/media/java/android/media/AudioPortEventHandler.java
+++ b/media/java/android/media/AudioPortEventHandler.java
@@ -19,10 +19,12 @@
 import android.annotation.UnsupportedAppUsage;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.os.Looper;
 import android.os.Message;
-import java.util.ArrayList;
+
+import com.android.internal.annotations.GuardedBy;
+
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 
 /**
  * The AudioPortEventHandler handles AudioManager.OnAudioPortUpdateListener callbacks
@@ -33,6 +35,9 @@
 class AudioPortEventHandler {
     private Handler mHandler;
     private HandlerThread mHandlerThread;
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
     private final ArrayList<AudioManager.OnAudioPortUpdateListener> mListeners =
             new ArrayList<AudioManager.OnAudioPortUpdateListener>();
 
@@ -53,7 +58,7 @@
     private long mJniCallback;
 
     void init() {
-        synchronized (this) {
+        synchronized (mLock) {
             if (mHandler != null) {
                 return;
             }
@@ -66,7 +71,7 @@
                     @Override
                     public void handleMessage(Message msg) {
                         ArrayList<AudioManager.OnAudioPortUpdateListener> listeners;
-                        synchronized (this) {
+                        synchronized (mLock) {
                             if (msg.what == AUDIOPORT_EVENT_NEW_LISTENER) {
                                 listeners = new ArrayList<AudioManager.OnAudioPortUpdateListener>();
                                 if (mListeners.contains(msg.obj)) {
@@ -152,7 +157,7 @@
     private native void native_finalize();
 
     void registerListener(AudioManager.OnAudioPortUpdateListener l) {
-        synchronized (this) {
+        synchronized (mLock) {
             mListeners.add(l);
         }
         if (mHandler != null) {
@@ -162,7 +167,7 @@
     }
 
     void unregisterListener(AudioManager.OnAudioPortUpdateListener l) {
-        synchronized (this) {
+        synchronized (mLock) {
             mListeners.remove(l);
         }
     }
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 7ae6a02..148ffaf 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -527,7 +527,7 @@
     // Names for the data formats for debugging purpose.
     private static final String[] IFD_FORMAT_NAMES = new String[] {
             "", "BYTE", "STRING", "USHORT", "ULONG", "URATIONAL", "SBYTE", "UNDEFINED", "SSHORT",
-            "SLONG", "SRATIONAL", "SINGLE", "DOUBLE"
+            "SLONG", "SRATIONAL", "SINGLE", "DOUBLE", "IFD"
     };
     // Sizes of the components of each IFD value format
     private static final int[] IFD_FORMAT_BYTES_PER_FORMAT = new int[] {
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index a69b105..f4dffa2 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -16,12 +16,10 @@
 
 package android.media;
 
-import android.annotation.MainThread;
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -30,9 +28,11 @@
 import com.android.internal.annotations.GuardedBy;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Executor;
 
 
@@ -43,7 +43,6 @@
 public class MediaRouter2 {
     private static final String TAG = "MediaRouter";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
     private static final Object sLock = new Object();
 
     @GuardedBy("sLock")
@@ -51,134 +50,160 @@
 
     private Context mContext;
     private final IMediaRouterService mMediaRouterService;
-    private List<CallbackRecord> mCallbackRecords = new ArrayList<>();
-    final String mPackageName;
 
-    IMediaRouter2Client mClient;
+    private CopyOnWriteArrayList<CallbackRecord> mCallbackRecords = new CopyOnWriteArrayList<>();
+    @GuardedBy("sLock")
+    private List<String> mControlCategories = Collections.emptyList();
+    @GuardedBy("sLock")
+    private Client mClient;
+
+    private final String mPackageName;
 
     /**
      * Gets an instance of the media router associated with the context.
      */
     public static MediaRouter2 getInstance(@NonNull Context context) {
+        Objects.requireNonNull(context, "context must not be null");
         synchronized (sLock) {
             if (sInstance == null) {
-                sInstance = new MediaRouter2(context);
+                sInstance = new MediaRouter2(context.getApplicationContext());
             }
             return sInstance;
         }
     }
 
-    private MediaRouter2(Context context) {
-        mContext = Objects.requireNonNull(context, "context must not be null");
+    private MediaRouter2(Context appContext) {
+        mContext = appContext;
         mMediaRouterService = IMediaRouterService.Stub.asInterface(
                 ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
         mPackageName = mContext.getPackageName();
+        //TODO: read control categories from the manifest
     }
 
     /**
-     * Registers a callback to discover routes that match the selector and to receive events
-     * when they change.
+     * Registers a callback to discover routes and to receive events when they change.
      */
-    @MainThread
-    public void addCallback(@NonNull List<String> controlCategories, @NonNull Executor executor,
+    public void registerCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull Callback callback) {
-        addCallback(controlCategories, executor, callback, 0);
+        registerCallback(executor, callback, 0);
     }
 
     /**
-     * Registers a callback to discover routes that match the selector and to receive events
-     * when they change.
+     * Registers a callback to discover routes and to receive events when they change.
      * <p>
-     * If you add the same callback twice or more, the previous arguments will be overwritten
+     * If you register the same callback twice or more, the previous arguments will be overwritten
      * with the new arguments.
      * </p>
      */
-    @MainThread
-    public void addCallback(@NonNull List<String> controlCategories, @NonNull Executor executor,
+    public void registerCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull Callback callback, int flags) {
-        checkMainThread();
-
-        Objects.requireNonNull(controlCategories, "control categories must not be null");
         Objects.requireNonNull(executor, "executor must not be null");
         Objects.requireNonNull(callback, "callback must not be null");
 
-        if (mCallbackRecords.size() == 0) {
-            Client client = new Client();
-            try {
-                mMediaRouterService.registerClient2AsUser(client, mPackageName,
-                        UserHandle.myUserId());
-                //TODO: We should merge control categories of callbacks.
-                mMediaRouterService.setControlCategories(client, controlCategories);
-                mClient = client;
-            } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to register media router.", ex);
+        // This is required to prevent adding the same callback twice.
+        synchronized (mCallbackRecords) {
+            if (mCallbackRecords.size() == 0) {
+                synchronized (sLock) {
+                    Client client = new Client();
+                    try {
+                        mMediaRouterService.registerClient2AsUser(client, mPackageName,
+                                UserHandle.myUserId());
+                        //TODO: We should merge control categories of callbacks.
+                        mMediaRouterService.setControlCategories(client, mControlCategories);
+                        mClient = client;
+                    } catch (RemoteException ex) {
+                        Log.e(TAG, "Unable to register media router.", ex);
+                    }
+                }
             }
+
+            final int index = findCallbackRecordIndexLocked(callback);
+            CallbackRecord record;
+            if (index < 0) {
+                record = new CallbackRecord(callback);
+                mCallbackRecords.add(record);
+            } else {
+                record = mCallbackRecords.get(index);
+            }
+            record.mExecutor = executor;
+            record.mFlags = flags;
         }
 
-        final int index = findCallbackRecordIndex(callback);
-        CallbackRecord record;
-        if (index < 0) {
-            record = new CallbackRecord(callback);
-            mCallbackRecords.add(record);
-        } else {
-            record = mCallbackRecords.get(index);
-        }
-        record.mExecutor = executor;
-        record.mControlCategories = controlCategories;
-        record.mFlags = flags;
-
-        //TODO: Check if we need an update.
+        //TODO: Update discovery request here.
     }
 
     /**
-     * Removes the given callback. The callback will no longer receive events.
+     * Unregisters the given callback. The callback will no longer receive events.
      * If the callback has not been added or been removed already, it is ignored.
-     * @param callback the callback to remove.
-     * @see #addCallback
+     *
+     * @param callback the callback to unregister
+     * @see #registerCallback
      */
-    @MainThread
-    public void removeCallback(@NonNull Callback callback) {
-        checkMainThread();
-
+    public void unregisterCallback(@NonNull Callback callback) {
         Objects.requireNonNull(callback, "callback must not be null");
 
-        final int index = findCallbackRecordIndex(callback);
-        if (index < 0) {
-            Log.w(TAG, "Ignoring to remove unknown callback. " + callback);
-            return;
-        }
-        mCallbackRecords.remove(index);
-        if (mCallbackRecords.size() == 0 && mClient != null) {
-            try {
-                mMediaRouterService.unregisterClient2(mClient);
-            } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to unregister media router.", ex);
+        synchronized (mCallbackRecords) {
+            final int index = findCallbackRecordIndexLocked(callback);
+            if (index < 0) {
+                Log.w(TAG, "Ignoring to remove unknown callback. " + callback);
+                return;
             }
-            mClient = null;
+            mCallbackRecords.remove(index);
+            synchronized (sLock) {
+                if (mCallbackRecords.size() == 0 && mClient != null) {
+                    try {
+                        mMediaRouterService.unregisterClient2(mClient);
+                    } catch (RemoteException ex) {
+                        Log.e(TAG, "Unable to unregister media router.", ex);
+                    }
+                    mClient = null;
+                }
+            }
         }
     }
 
-    private int findCallbackRecordIndex(Callback callback) {
-        final int count = mCallbackRecords.size();
-        for (int i = 0; i < count; i++) {
-            CallbackRecord callbackRecord = mCallbackRecords.get(i);
-            if (callbackRecord.mCallback == callback) {
-                return i;
+    //TODO(b/139033746): Rename "Control Category" when it's finalized.
+    /**
+     * Sets the control categories of the application.
+     * Routes that support at least one of the given control categories only exists and are handled
+     * by the media router.
+     */
+    public void setControlCategories(@NonNull Collection<String> controlCategories) {
+        Objects.requireNonNull(controlCategories, "control categories must not be null");
+
+        Client client;
+        List<String> newControlCategories;
+        synchronized (sLock) {
+            mControlCategories = new ArrayList<>(controlCategories);
+            newControlCategories = mControlCategories;
+            client = mClient;
+        }
+        if (client != null) {
+            try {
+                mMediaRouterService.setControlCategories(client, newControlCategories);
+            } catch (RemoteException ex) {
+                Log.e(TAG, "Unable to set control categories.", ex);
             }
         }
-        return -1;
     }
 
+
     /**
      * Selects the specified route.
      *
-     * @param route The route to select.
+     * @param route the route to select
      */
     //TODO: add a parameter for category (e.g. mirroring/casting)
-    public void selectRoute(@Nullable MediaRoute2Info route) {
-        if (mClient != null) {
+    public void selectRoute(@NonNull MediaRoute2Info route) {
+        Objects.requireNonNull(route, "route must not be null");
+
+        Client client;
+        synchronized (sLock) {
+            client = mClient;
+        }
+        if (client != null) {
             try {
-                mMediaRouterService.selectRoute2(mClient, route);
+                mMediaRouterService.selectRoute2(client, route);
             } catch (RemoteException ex) {
                 Log.e(TAG, "Unable to select route.", ex);
             }
@@ -187,6 +212,7 @@
 
     /**
      * Sends a media control request to be performed asynchronously by the route's destination.
+     *
      * @param route the route that will receive the control request
      * @param request the media control request
      */
@@ -196,20 +222,29 @@
         Objects.requireNonNull(route, "route must not be null");
         Objects.requireNonNull(request, "request must not be null");
 
-        if (mClient != null) {
+        Client client;
+        synchronized (sLock) {
+            client = mClient;
+        }
+        if (client != null) {
             try {
-                mMediaRouterService.sendControlRequest(mClient, route, request);
+                mMediaRouterService.sendControlRequest(client, route, request);
             } catch (RemoteException ex) {
                 Log.e(TAG, "Unable to send control request.", ex);
             }
         }
     }
 
-    void checkMainThread() {
-        Looper looper = Looper.myLooper();
-        if (looper == null || looper != Looper.getMainLooper()) {
-            throw new IllegalStateException("the method must be called on the main thread");
+    @GuardedBy("mCallbackRecords")
+    private int findCallbackRecordIndexLocked(Callback callback) {
+        final int count = mCallbackRecords.size();
+        for (int i = 0; i < count; i++) {
+            CallbackRecord callbackRecord = mCallbackRecords.get(i);
+            if (callbackRecord.mCallback == callback) {
+                return i;
+            }
         }
+        return -1;
     }
 
     /**
@@ -232,15 +267,13 @@
         public void onRouteRemoved(MediaRoute2Info routeInfo) {}
     }
 
-    final class CallbackRecord {
+    static final class CallbackRecord {
         public final Callback mCallback;
         public Executor mExecutor;
-        public List<String> mControlCategories;
         public int mFlags;
 
         CallbackRecord(@NonNull Callback callback) {
-            mCallback = Objects.requireNonNull(callback, "callback must not be null");
-            mControlCategories = Collections.emptyList();
+            mCallback = callback;
         }
     }
 
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 85105e0..6c53f7d 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -56,11 +56,10 @@
     final String mPackageName;
 
     private Context mContext;
+    @GuardedBy("sLock")
     private Client mClient;
     private final IMediaRouterService mMediaRouterService;
     final Handler mHandler;
-
-    @GuardedBy("sLock")
     final List<CallbackRecord> mCallbacks = new CopyOnWriteArrayList<>();
 
     @SuppressWarnings("WeakerAccess") /* synthetic access */
@@ -73,6 +72,7 @@
 
     /**
      * Gets an instance of media router manager that controls media route of other applications.
+     *
      * @return The media router manager instance for the context.
      */
     public static MediaRouter2Manager getInstance(@NonNull Context context) {
@@ -96,28 +96,29 @@
     /**
      * Registers a callback to listen route info.
      *
-     * @param executor The executor that runs the callback.
-     * @param callback The callback to add.
+     * @param executor the executor that runs the callback
+     * @param callback the callback to add
      */
-    public void addCallback(@NonNull @CallbackExecutor Executor executor,
+    public void registerCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull Callback callback) {
-
         Objects.requireNonNull(executor, "executor must not be null");
         Objects.requireNonNull(callback, "callback must not be null");
 
-        synchronized (sLock) {
-            if (findCallbackRecordIndex(callback) >= 0) {
+        synchronized (mCallbacks) {
+            if (findCallbackRecordIndexLocked(callback) >= 0) {
                 Log.w(TAG, "Ignoring to add the same callback twice.");
                 return;
             }
-            if (mCallbacks.size() == 0) {
-                Client client = new Client();
-                try {
-                    mMediaRouterService.registerManagerAsUser(client, mPackageName,
-                            UserHandle.myUserId());
-                    mClient = client;
-                } catch (RemoteException ex) {
-                    Log.e(TAG, "Unable to register media router manager.", ex);
+            synchronized (sLock) {
+                if (mCallbacks.size() == 0) {
+                    Client client = new Client();
+                    try {
+                        mMediaRouterService.registerManagerAsUser(client, mPackageName,
+                                UserHandle.myUserId());
+                        mClient = client;
+                    } catch (RemoteException ex) {
+                        Log.e(TAG, "Unable to register media router manager.", ex);
+                    }
                 }
             }
             CallbackRecord record = new CallbackRecord(executor, callback);
@@ -127,34 +128,35 @@
     }
 
     /**
-     * Removes the specified callback.
+     * Unregisters the specified callback.
      *
-     * @param callback The callback to remove.
+     * @param callback the callback to unregister
      */
-    public void removeCallback(@NonNull Callback callback) {
-        if (callback == null) {
-            throw new IllegalArgumentException("callback must not be null");
-        }
+    public void unregisterCallback(@NonNull Callback callback) {
+        Objects.requireNonNull(callback, "callback must not be null");
 
-        synchronized (sLock) {
-            final int index = findCallbackRecordIndex(callback);
+        synchronized (mCallbacks) {
+            final int index = findCallbackRecordIndexLocked(callback);
             if (index < 0) {
                 Log.w(TAG, "Ignore removing unknown callback. " + callback);
                 return;
             }
             mCallbacks.remove(index);
-            if (mCallbacks.size() == 0 && mClient != null) {
-                try {
-                    mMediaRouterService.unregisterManager(mClient);
-                } catch (RemoteException ex) {
-                    Log.e(TAG, "Unable to unregister media router manager", ex);
+            synchronized (sLock) {
+                if (mCallbacks.size() == 0 && mClient != null) {
+                    try {
+                        mMediaRouterService.unregisterManager(mClient);
+                    } catch (RemoteException ex) {
+                        Log.e(TAG, "Unable to unregister media router manager", ex);
+                    }
+                    mClient = null;
                 }
-                mClient = null;
             }
         }
     }
 
-    private int findCallbackRecordIndex(Callback callback) {
+    @GuardedBy("mCallbacks")
+    private int findCallbackRecordIndexLocked(Callback callback) {
         final int count = mCallbacks.size();
         for (int i = 0; i < count; i++) {
             if (mCallbacks.get(i).mCallback == callback) {
@@ -173,6 +175,8 @@
      */
     @NonNull
     public List<MediaRoute2Info> getAvailableRoutes(@NonNull String packageName) {
+        Objects.requireNonNull(packageName, "packageName must not be null");
+
         List<String> controlCategories = mControlCategoryMap.get(packageName);
         if (controlCategories == null) {
             return Collections.emptyList();
@@ -193,9 +197,16 @@
      * @param route the route to be selected
      */
     public void selectRoute(@NonNull String packageName, @NonNull MediaRoute2Info route) {
-        if (mClient != null) {
+        Objects.requireNonNull(packageName, "packageName must not be null");
+        Objects.requireNonNull(route, "route must not be null");
+
+        Client client;
+        synchronized (sLock) {
+            client = mClient;
+        }
+        if (client != null) {
             try {
-                mMediaRouterService.selectClientRoute2(mClient, packageName, route);
+                mMediaRouterService.selectClientRoute2(client, packageName, route);
             } catch (RemoteException ex) {
                 Log.e(TAG, "Unable to select media route", ex);
             }
@@ -208,9 +219,13 @@
      * @param packageName the package name of the application that should stop routing
      */
     public void unselectRoute(@NonNull String packageName) {
-        if (mClient != null) {
+        Client client;
+        synchronized (sLock) {
+            client = mClient;
+        }
+        if (client != null) {
             try {
-                mMediaRouterService.selectClientRoute2(mClient, packageName, null);
+                mMediaRouterService.selectClientRoute2(client, packageName, null);
             } catch (RemoteException ex) {
                 Log.e(TAG, "Unable to select media route", ex);
             }
@@ -227,10 +242,6 @@
         return -1;
     }
 
-    MediaRoute2ProviderInfo getProvider(int index) {
-        return mProviders.get(index);
-    }
-
     void updateProvider(@NonNull MediaRoute2ProviderInfo provider) {
         if (provider == null || !provider.isValid()) {
             Log.w(TAG, "Ignoring invalid provider : " + provider);
@@ -241,7 +252,7 @@
 
         final int index = findProviderIndex(provider);
         if (index >= 0) {
-            final MediaRoute2ProviderInfo prevProvider = getProvider(index);
+            final MediaRoute2ProviderInfo prevProvider = mProviders.get(index);
             final Set<String> updatedRouteIds = new HashSet<>();
             for (MediaRoute2Info routeInfo : routes) {
                 final MediaRoute2Info prevRoute = prevProvider.getRoute(routeInfo.getId());
@@ -374,11 +385,9 @@
         }
 
         void notifyRoutes() {
-            for (MediaRoute2ProviderInfo provider : mProviders) {
-                for (MediaRoute2Info routeInfo : provider.getRoutes()) {
-                    mExecutor.execute(
-                            () -> mCallback.onRouteAdded(routeInfo));
-                }
+            for (MediaRoute2Info routeInfo : mRoutes) {
+                mExecutor.execute(
+                        () -> mCallback.onRouteAdded(routeInfo));
             }
         }
     }
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 1f2283c..6fd3342 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -16,6 +16,7 @@
 
 package android.media.session;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -31,6 +32,7 @@
 import android.media.Session2Token;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -50,6 +52,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 
 /**
  * Provides support for interacting with {@link MediaSession media sessions}
@@ -86,7 +89,7 @@
     @GuardedBy("mLock")
     private final CallbackStub mCbStub = new CallbackStub();
     @GuardedBy("mLock")
-    private final Map<Callback, Handler> mCallbacks = new HashMap<>();
+    private final Map<Callback, Executor> mCallbacks = new HashMap<>();
     @GuardedBy("mLock")
     private MediaSession.Token mCurMediaButtonSession;
     @GuardedBy("mLock")
@@ -765,13 +768,16 @@
      */
     // TODO: Remove this method once Bluetooth app stop calling it.
     public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
+        if (handler == null) {
+            handler = new Handler();
+        }
         synchronized (mLock) {
             if (mLegacyCallback != null) {
                 unregisterCallback(mLegacyCallback);
             }
             mLegacyCallback = callback;
             if (callback != null) {
-                registerCallback(callback, handler);
+                registerCallback(new HandlerExecutor(handler), callback);
             }
         }
     }
@@ -779,27 +785,29 @@
     /**
      * Register a {@link Callback}.
      *
+     * @param executor The executor on which the callback should be invoked
      * @param callback A {@link Callback}.
-     * @param handler The handler on which the callback should be invoked, or {@code null}
-     *            if the callback should be invoked on the calling thread's looper.
      * @hide
      */
     @SystemApi
     @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
-    public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) {
+    public void registerCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull Callback callback) {
+        if (executor == null) {
+            throw new NullPointerException("executor shouldn't be null");
+        }
         if (callback == null) {
             throw new NullPointerException("callback shouldn't be null");
         }
         synchronized (mLock) {
             try {
-                if (handler == null) {
-                    handler = new Handler();
-                }
-                mCallbacks.put(callback, handler);
+                mCallbacks.put(callback, executor);
                 if (mCurMediaButtonSession != null) {
-                    handler.post(() -> callback.onAddressedPlayerChanged(mCurMediaButtonSession));
+                    executor.execute(
+                            () -> callback.onAddressedPlayerChanged(mCurMediaButtonSession));
                 } else if (mCurMediaButtonReceiver != null) {
-                    handler.post(() -> callback.onAddressedPlayerChanged(mCurMediaButtonReceiver));
+                    executor.execute(
+                            () -> callback.onAddressedPlayerChanged(mCurMediaButtonReceiver));
                 }
 
                 if (mCallbacks.size() == 1) {
@@ -1147,8 +1155,8 @@
         public void onMediaKeyEventDispatchedToMediaSession(KeyEvent event,
                 MediaSession.Token sessionToken) {
             synchronized (mLock) {
-                for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) {
-                    e.getValue().post(
+                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
+                    e.getValue().execute(
                             () -> e.getKey().onMediaKeyEventDispatched(event, sessionToken));
                 }
             }
@@ -1158,8 +1166,8 @@
         public void onMediaKeyEventDispatchedToMediaButtonReceiver(KeyEvent event,
                 ComponentName mediaButtonReceiver) {
             synchronized (mLock) {
-                for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) {
-                    e.getValue().post(
+                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
+                    e.getValue().execute(
                             () -> e.getKey().onMediaKeyEventDispatched(event, mediaButtonReceiver));
                 }
             }
@@ -1170,8 +1178,8 @@
             synchronized (mLock) {
                 mCurMediaButtonSession = sessionToken;
                 mCurMediaButtonReceiver = null;
-                for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) {
-                    e.getValue().post(() -> e.getKey().onAddressedPlayerChanged(sessionToken));
+                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
+                    e.getValue().execute(() -> e.getKey().onAddressedPlayerChanged(sessionToken));
                 }
             }
         }
@@ -1182,8 +1190,8 @@
             synchronized (mLock) {
                 mCurMediaButtonSession = null;
                 mCurMediaButtonReceiver = mediaButtonReceiver;
-                for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) {
-                    e.getValue().post(() -> e.getKey().onAddressedPlayerChanged(
+                for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) {
+                    e.getValue().execute(() -> e.getKey().onAddressedPlayerChanged(
                             mediaButtonReceiver));
                 }
             }
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 6d8b966..4a9da62 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -26,6 +26,7 @@
 
 #include <gui/IProducerListener.h>
 #include <gui/Surface.h>
+#include <ui/PublicFormat.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_hardware_HardwareBuffer.h>
@@ -126,7 +127,7 @@
             Condition mCondition;
             std::deque<wp<Surface>> mQueue;
 
-            static const nsecs_t kWaitDuration = 20000000; // 20 ms
+            static const nsecs_t kWaitDuration = 500000000; // 500 ms
         };
         sp<DetachThread> mThread;
 
@@ -401,8 +402,28 @@
             return 0;
         }
     } else {
+        // Set consumer buffer format to user specified format
+        PublicFormat publicFormat = static_cast<PublicFormat>(userFormat);
+        int nativeFormat = mapPublicFormatToHalFormat(publicFormat);
+        android_dataspace nativeDataspace = mapPublicFormatToHalDataspace(publicFormat);
+        res = native_window_set_buffers_format(anw.get(), nativeFormat);
+        if (res != OK) {
+            ALOGE("%s: Unable to configure consumer native buffer format to %#x",
+                    __FUNCTION__, nativeFormat);
+            jniThrowRuntimeException(env, "Failed to set Surface format");
+            return 0;
+        }
+
+        res = native_window_set_buffers_data_space(anw.get(), nativeDataspace);
+        if (res != OK) {
+            ALOGE("%s: Unable to configure consumer dataspace %#x",
+                    __FUNCTION__, nativeDataspace);
+            jniThrowRuntimeException(env, "Failed to set Surface dataspace");
+            return 0;
+        }
         surfaceFormat = userFormat;
     }
+
     ctx->setBufferFormat(surfaceFormat);
     env->SetIntField(thiz,
             gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(surfaceFormat));
diff --git a/media/native/midi/amidi.cpp b/media/native/midi/amidi.cpp
index 357bb5e5..46f2815 100644
--- a/media/native/midi/amidi.cpp
+++ b/media/native/midi/amidi.cpp
@@ -142,7 +142,7 @@
     return AMEDIA_OK;
 }
 
-media_status_t AMidiDevice_fromJava(JNIEnv *env, jobject j_midiDeviceObj,
+media_status_t AMIDI_API AMidiDevice_fromJava(JNIEnv *env, jobject j_midiDeviceObj,
         AMidiDevice** devicePtrPtr)
 {
     if (j_midiDeviceObj == nullptr) {
@@ -188,7 +188,7 @@
     return AMEDIA_OK;
 }
 
-media_status_t AMidiDevice_release(const AMidiDevice *device)
+media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *device)
 {
     if (device == nullptr || device->midiDeviceObj == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
@@ -217,21 +217,21 @@
     return AMEDIA_OK;
 }
 
-int32_t AMidiDevice_getType(const AMidiDevice *device) {
+int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device) {
     if (device == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
     return device->deviceInfo.type;
 }
 
-ssize_t AMidiDevice_getNumInputPorts(const AMidiDevice *device) {
+ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device) {
     if (device == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
     return device->deviceInfo.inputPortCount;
 }
 
-ssize_t AMidiDevice_getNumOutputPorts(const AMidiDevice *device) {
+ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device) {
     if (device == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
@@ -291,7 +291,7 @@
 /*
  * Output (receiving) API
  */
-media_status_t AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
+media_status_t AMIDI_API AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
         AMidiOutputPort **outOutputPortPtr) {
     return AMIDI_openPort(device, portNumber, PORTTYPE_OUTPUT, (AMIDI_Port**)outOutputPortPtr);
 }
@@ -350,7 +350,7 @@
     AMIDI_Port *mPort;
 };
 
-ssize_t AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
+ssize_t AMIDI_API AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
          uint8_t *buffer, size_t maxBytes, size_t* numBytesReceivedPtr, int64_t *timestampPtr) {
 
     if (outputPort == nullptr || buffer == nullptr) {
@@ -361,19 +361,19 @@
            numBytesReceivedPtr, timestampPtr);
 }
 
-void AMidiOutputPort_close(const AMidiOutputPort *outputPort) {
+void AMIDI_API AMidiOutputPort_close(const AMidiOutputPort *outputPort) {
     AMIDI_closePort((AMIDI_Port*)outputPort);
 }
 
 /*
  * Input (sending) API
  */
-media_status_t AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
+media_status_t AMIDI_API AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
         AMidiInputPort **outInputPortPtr) {
     return AMIDI_openPort(device, portNumber, PORTTYPE_INPUT, (AMIDI_Port**)outInputPortPtr);
 }
 
-void AMidiInputPort_close(const AMidiInputPort *inputPort) {
+void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort) {
     AMIDI_closePort((AMIDI_Port*)inputPort);
 }
 
@@ -386,12 +386,12 @@
     return numBytes + AMIDI_PACKET_OVERHEAD;
 }
 
-ssize_t AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
+ssize_t AMIDI_API AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
                             size_t numBytes) {
     return AMidiInputPort_sendWithTimestamp(inputPort, buffer, numBytes, 0);
 }
 
-ssize_t AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
+ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
         const uint8_t *data, size_t numBytes, int64_t timestamp) {
     if (inputPort == nullptr || data == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
@@ -423,7 +423,7 @@
     return numSent;
 }
 
-media_status_t AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) {
+media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) {
     if (inputPort == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
diff --git a/media/native/midi/include/amidi/AMidi.h b/media/native/midi/include/amidi/AMidi.h
index 76dec0f..0f930b5 100644
--- a/media/native/midi/include/amidi/AMidi.h
+++ b/media/native/midi/include/amidi/AMidi.h
@@ -37,6 +37,8 @@
 extern "C" {
 #endif
 
+#define AMIDI_API __attribute__((visibility("default")))
+
 typedef struct AMidiDevice AMidiDevice;
 typedef struct AMidiInputPort AMidiInputPort;
 typedef struct AMidiOutputPort AMidiOutputPort;
@@ -78,7 +80,7 @@
  *    is null or already connected to a native AMidiDevice
   *  @see AMEDIA_ERROR_UNKNOWN - an unknown error occurred.
  */
-media_status_t AMidiDevice_fromJava(
+media_status_t AMIDI_API AMidiDevice_fromJava(
         JNIEnv *env, jobject midiDeviceObj, AMidiDevice **outDevicePtrPtr) __INTRODUCED_IN(29);
 
 /**
@@ -93,7 +95,7 @@
  *  @see AMEDIA_ERROR_INVALID_OBJECT - the JNI interface initialization to the associated java MidiDevice failed.
  *  @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
  */
-media_status_t AMidiDevice_release(const AMidiDevice *midiDevice) __INTRODUCED_IN(29);
+media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *midiDevice) __INTRODUCED_IN(29);
 
 /**
  * Gets the MIDI device type.
@@ -108,7 +110,7 @@
  *  @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
  *  @see AMEDIA_ERROR_UNKNOWN - Unknown error.
  */
-int32_t AMidiDevice_getType(const AMidiDevice *device) __INTRODUCED_IN(29);
+int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device) __INTRODUCED_IN(29);
 
 /**
  * Gets the number of input (sending) ports available on the specified MIDI device.
@@ -120,7 +122,7 @@
  *  @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
  *  @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
  */
-ssize_t AMidiDevice_getNumInputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
+ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
 
 /**
  * Gets the number of output (receiving) ports available on the specified MIDI device.
@@ -132,7 +134,7 @@
  *  @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
  *  @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
  */
-ssize_t AMidiDevice_getNumOutputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
+ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
 
 /*
  * API for receiving data from the Output port of a device.
@@ -150,7 +152,7 @@
  * @return AMEDIA_OK, or a negative error code:
  *  @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
  */
-media_status_t AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
+media_status_t AMIDI_API AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
                              AMidiOutputPort **outOutputPortPtr) __INTRODUCED_IN(29);
 
 /**
@@ -158,7 +160,7 @@
  *
  * @param outputPort    The native API port identifier of the port.
  */
-void AMidiOutputPort_close(const AMidiOutputPort *outputPort) __INTRODUCED_IN(29);
+void AMIDI_API AMidiOutputPort_close(const AMidiOutputPort *outputPort) __INTRODUCED_IN(29);
 
 /**
  * Receives the next pending MIDI message. To retrieve all pending messages, the client should
@@ -178,7 +180,7 @@
  * @return the number of messages received (either 0 or 1), or a negative error code:
  *  @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
  */
-ssize_t AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
+ssize_t AMIDI_API AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
          uint8_t *buffer, size_t maxBytes, size_t* numBytesReceivedPtr, int64_t *outTimestampPtr) __INTRODUCED_IN(29);
 
 /*
@@ -197,7 +199,7 @@
  * @return AMEDIA_OK, or a negative error code:
  *  @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
  */
-media_status_t AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
+media_status_t AMIDI_API AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
                             AMidiInputPort **outInputPortPtr) __INTRODUCED_IN(29);
 
 /**
@@ -210,7 +212,7 @@
  * @return The number of bytes sent, which could be less than specified or a negative error code:
  * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL, the specified buffer was NULL.
  */
-ssize_t AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
+ssize_t AMIDI_API AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
                    size_t numBytes) __INTRODUCED_IN(29);
 
 /**
@@ -224,7 +226,7 @@
  * @return The number of bytes sent, which could be less than specified or a negative error code:
  * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL, the specified buffer was NULL.
  */
-ssize_t AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
+ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
         const uint8_t *buffer, size_t numBytes, int64_t timestamp) __INTRODUCED_IN(29);
 
 /**
@@ -238,14 +240,14 @@
  * @see AMEDIA_ERROR_UNSUPPORTED - The FLUSH command couldn't
  * be sent.
  */
-media_status_t AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
+media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
 
 /**
  * Closes the input port.
  *
  * @param inputPort Identifies the input (sending) port to close.
  */
-void AMidiInputPort_close(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
+void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
 
 #endif /* __ANDROID_API__ >= 29 */
 
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index 4282a5bc..946fb5e 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -44,8 +44,7 @@
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
 @RunWith(AndroidJUnit4.class)
@@ -92,9 +91,8 @@
         mContext = InstrumentationRegistry.getTargetContext();
         mManager = MediaRouter2Manager.getInstance(mContext);
         mRouter = MediaRouter2.getInstance(mContext);
-        mExecutor = new ThreadPoolExecutor(
-            1, 20, 3, TimeUnit.SECONDS,
-            new SynchronousQueue<Runnable>());
+        //TODO: If we need to support thread pool executors, change this to thread pool executor.
+        mExecutor = Executors.newSingleThreadExecutor();
         mPackageName = mContext.getPackageName();
     }
 
@@ -116,36 +114,34 @@
     public void testRouteAdded() {
         MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
 
-        mManager.addCallback(mExecutor, mockCallback);
+        mManager.registerCallback(mExecutor, mockCallback);
 
         verify(mockCallback, timeout(TIMEOUT_MS)).onRouteAdded(argThat(
                 (MediaRoute2Info info) ->
                         info.getId().equals(ROUTE_ID1) && info.getName().equals(ROUTE_NAME1)));
-        mManager.removeCallback(mockCallback);
+        mManager.unregisterCallback(mockCallback);
     }
 
     //TODO: Recover this test when media router 2 is finalized.
     public void testRouteRemoved() {
         MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
-        mManager.addCallback(mExecutor, mockCallback);
+        mManager.registerCallback(mExecutor, mockCallback);
 
         MediaRouter2.Callback mockRouterCallback = mock(MediaRouter2.Callback.class);
 
         //TODO: Figure out a more proper way to test.
         // (Control requests shouldn't be used in this way.)
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(
-                (Runnable) () -> {
-                    mRouter.addCallback(CONTROL_CATEGORIES_ALL, mExecutor, mockRouterCallback);
-                    mRouter.sendControlRequest(
-                            new MediaRoute2Info.Builder(ROUTE_ID2, ROUTE_NAME2).build(),
-                            new Intent(ACTION_REMOVE_ROUTE));
-                    mRouter.removeCallback(mockRouterCallback);
-                }
-        );
+        mRouter.setControlCategories(CONTROL_CATEGORIES_ALL);
+        mRouter.registerCallback(mExecutor, mockRouterCallback);
+        mRouter.sendControlRequest(
+                new MediaRoute2Info.Builder(ROUTE_ID2, ROUTE_NAME2).build(),
+                new Intent(ACTION_REMOVE_ROUTE));
+        mRouter.unregisterCallback(mockRouterCallback);
+
         verify(mockCallback, timeout(TIMEOUT_MS)).onRouteRemoved(argThat(
                 (MediaRoute2Info info) ->
                         info.getId().equals(ROUTE_ID2) && info.getName().equals(ROUTE_NAME2)));
-        mManager.removeCallback(mockCallback);
+        mManager.unregisterCallback(mockCallback);
     }
 
     /**
@@ -154,17 +150,14 @@
     @Test
     public void testControlCategory() throws Exception {
         MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
-        mManager.addCallback(mExecutor, mockCallback);
+        mManager.registerCallback(mExecutor, mockCallback);
 
         MediaRouter2.Callback mockRouterCallback = mock(MediaRouter2.Callback.class);
 
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(
-                () -> {
-                    mRouter.addCallback(CONTROL_CATEGORIES_SPECIAL,
-                            mExecutor, mockRouterCallback);
-                    mRouter.removeCallback(mockRouterCallback);
-                }
-        );
+        mRouter.setControlCategories(CONTROL_CATEGORIES_SPECIAL);
+        mRouter.registerCallback(mExecutor, mockRouterCallback);
+        mRouter.unregisterCallback(mockRouterCallback);
+
         verify(mockCallback, timeout(TIMEOUT_MS))
                 .onRouteListChanged(argThat(routes -> routes.size() > 0));
 
@@ -174,7 +167,7 @@
         Assert.assertEquals(1, routes.size());
         Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
 
-        mManager.removeCallback(mockCallback);
+        mManager.unregisterCallback(mockCallback);
     }
 
     @Test
@@ -182,11 +175,7 @@
         CountDownLatch latch = new CountDownLatch(1);
 
         MediaRouter2.Callback mockRouterCallback = mock(MediaRouter2.Callback.class);
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(
-                () -> {
-                    mRouter.addCallback(CONTROL_CATEGORIES_ALL, mExecutor, mockRouterCallback);
-                }
-        );
+        mRouter.registerCallback(mExecutor, mockRouterCallback);
 
         MediaRouter2Manager.Callback managerCallback = new MediaRouter2Manager.Callback() {
             MediaRoute2Info mSelectedRoute = null;
@@ -210,11 +199,11 @@
             }
         };
 
-        mManager.addCallback(mExecutor, managerCallback);
+        mManager.registerCallback(mExecutor, managerCallback);
 
         Assert.assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
-        mManager.removeCallback(managerCallback);
+        mManager.unregisterCallback(managerCallback);
     }
 
     /**
@@ -225,12 +214,10 @@
         MediaRouter2Manager.Callback managerCallback = mock(MediaRouter2Manager.Callback.class);
         MediaRouter2.Callback routerCallback = mock(MediaRouter2.Callback.class);
 
-        mManager.addCallback(mExecutor, managerCallback);
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(
-                () -> {
-                    mRouter.addCallback(CONTROL_CATEGORIES_ALL, mExecutor, routerCallback);
-                }
-        );
+        mManager.registerCallback(mExecutor, managerCallback);
+        mRouter.setControlCategories(CONTROL_CATEGORIES_ALL);
+        mRouter.registerCallback(mExecutor, routerCallback);
+
         verify(managerCallback, timeout(TIMEOUT_MS))
                 .onRouteListChanged(argThat(routes -> routes.size() > 0));
 
@@ -253,12 +240,8 @@
                 .onRouteChanged(argThat(routeInfo -> TextUtils.equals(ROUTE_ID2, routeInfo.getId())
                         && TextUtils.equals(routeInfo.getClientPackageName(), null)));
 
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(
-                () -> {
-                    mRouter.removeCallback(routerCallback);
-                }
-        );
-        mManager.removeCallback(managerCallback);
+        mRouter.unregisterCallback(routerCallback);
+        mManager.unregisterCallback(managerCallback);
     }
 
     Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
diff --git a/packages/CompanionDeviceManager/OWNERS b/packages/CompanionDeviceManager/OWNERS
new file mode 100644
index 0000000..da723b3
--- /dev/null
+++ b/packages/CompanionDeviceManager/OWNERS
@@ -0,0 +1 @@
+eugenesusla@google.com
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index d0ca04b..d11b5c5 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -24,6 +24,7 @@
 import static com.android.internal.util.CollectionUtils.size;
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
+import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PendingIntent;
@@ -115,7 +116,8 @@
             }
             mFindCallback = findCallback;
             mServiceCallback = serviceCallback;
-            DeviceDiscoveryService.this.startDiscovery(request);
+            Handler.getMain().sendMessage(obtainMessage(
+                    DeviceDiscoveryService::startDiscovery, DeviceDiscoveryService.this, request));
         }
     };
 
@@ -145,6 +147,7 @@
         sInstance = this;
     }
 
+    @MainThread
     private void startDiscovery(AssociationRequest request) {
         if (!request.equals(mRequest)) {
             mRequest = request;
@@ -211,12 +214,13 @@
         return !isEmpty(mediumSpecificFilters) || isEmpty(mFilters);
     }
 
+    @MainThread
     private void reset() {
         if (DEBUG) Log.i(LOG_TAG, "reset()");
         stopScan();
         mDevicesFound.clear();
         mSelectedDevice = null;
-        notifyDataSetChanged();
+        mDevicesAdapter.notifyDataSetChanged();
     }
 
     @Override
@@ -260,16 +264,17 @@
 
         if (DEBUG) Log.i(LOG_TAG, "Found device " + device);
 
+        Handler.getMain().sendMessage(obtainMessage(
+                DeviceDiscoveryService::onDeviceFoundMainThread, this, device));
+    }
+
+    @MainThread
+    void onDeviceFoundMainThread(@NonNull DeviceFilterPair device) {
         if (mDevicesFound.isEmpty()) {
             onReadyToShowUI();
         }
         mDevicesFound.add(device);
-        notifyDataSetChanged();
-    }
-
-    private void notifyDataSetChanged() {
-        Handler.getMain().sendMessage(obtainMessage(
-                DevicesAdapter::notifyDataSetChanged, mDevicesAdapter));
+        mDevicesAdapter.notifyDataSetChanged();
     }
 
     //TODO also, on timeout -> call onFailure
@@ -286,9 +291,15 @@
     }
 
     private void onDeviceLost(@Nullable DeviceFilterPair device) {
-        mDevicesFound.remove(device);
-        notifyDataSetChanged();
         if (DEBUG) Log.i(LOG_TAG, "Lost device " + device.getDisplayName());
+        Handler.getMain().sendMessage(obtainMessage(
+                DeviceDiscoveryService::onDeviceLostMainThread, this, device));
+    }
+
+    @MainThread
+    void onDeviceLostMainThread(@Nullable DeviceFilterPair device) {
+        mDevicesFound.remove(device);
+        mDevicesAdapter.notifyDataSetChanged();
     }
 
     void onDeviceSelected(String callingPackage, String deviceAddress) {
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index e731b45..142078e 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -291,7 +291,7 @@
         if (mInstallTask != null && mInstallTask.getResult() == RESULT_OK) {
             enabled = mInstallTask.commit();
         } else if (isDynamicSystemInstalled()) {
-            enabled = mDynSystem.setEnable(true);
+            enabled = mDynSystem.setEnable(true, true);
         } else {
             Log.e(TAG, "Trying to reboot to AOT while there is no complete installation");
             return;
diff --git a/packages/MtpDocumentsProvider/Android.bp b/packages/MtpDocumentsProvider/Android.bp
deleted file mode 100644
index 3dafa26..0000000
--- a/packages/MtpDocumentsProvider/Android.bp
+++ /dev/null
@@ -1,11 +0,0 @@
-android_app {
-    name: "MtpDocumentsProvider",
-
-    srcs: ["src/**/*.java"],
-    platform_apis: true,
-    certificate: "media",
-    privileged: true,
-    optimize: {
-        proguard_flags_files: ["proguard.flags"],
-    },
-}
diff --git a/packages/MtpDocumentsProvider/AndroidManifest.xml b/packages/MtpDocumentsProvider/AndroidManifest.xml
deleted file mode 100644
index c0a59b3..0000000
--- a/packages/MtpDocumentsProvider/AndroidManifest.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.mtp"
-          android:sharedUserId="android.media">
-    <uses-feature android:name="android.hardware.usb.host" />
-    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
-    <uses-permission android:name="android.permission.MANAGE_USB" />
-    <application android:label="@string/app_label">
-        <provider
-            android:name=".MtpDocumentsProvider"
-            android:authorities="com.android.mtp.documents"
-            android:grantUriPermissions="true"
-            android:exported="true"
-            android:permission="android.permission.MANAGE_DOCUMENTS">
-            <intent-filter>
-                <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
-            </intent-filter>
-        </provider>
-
-        <service android:name=".MtpDocumentsService" />
-
-        <activity android:name=".ReceiverActivity"
-                  android:label="@string/downloads_app_label"
-                  android:icon="@mipmap/ic_launcher_download"
-                  android:theme="@android:style/Theme.NoDisplay"
-                  android:excludeFromRecents="true">
-            <intent-filter>
-                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
-            </intent-filter>
-            <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
-                       android:resource="@xml/device_filter" />
-        </activity>
-
-        <receiver android:name=".UsbIntentReceiver" android:exported="true">
-            <intent-filter>
-                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
-                <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
-            </intent-filter>
-            <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
-                       android:resource="@xml/device_filter" />
-        </receiver>
-    </application>
-</manifest>
diff --git a/packages/MtpDocumentsProvider/MOVED b/packages/MtpDocumentsProvider/MOVED
new file mode 100644
index 0000000..6c8a519
--- /dev/null
+++ b/packages/MtpDocumentsProvider/MOVED
@@ -0,0 +1 @@
+../../../../packages/services/Mtp
diff --git a/packages/MtpDocumentsProvider/perf_tests/Android.mk b/packages/MtpDocumentsProvider/perf_tests/Android.mk
deleted file mode 100644
index d2f1c7a..0000000
--- a/packages/MtpDocumentsProvider/perf_tests/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
-LOCAL_PACKAGE_NAME := MtpDocumentsProviderPerfTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider
-LOCAL_CERTIFICATE := media
-LOCAL_COMPATIBILITY_SUITE += device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/packages/MtpDocumentsProvider/perf_tests/AndroidManifest.xml b/packages/MtpDocumentsProvider/perf_tests/AndroidManifest.xml
deleted file mode 100644
index 4367652..0000000
--- a/packages/MtpDocumentsProvider/perf_tests/AndroidManifest.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.mtp.perftests"
-    android:sharedUserId="android.media">
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.mtp"
-        android:label="Performance tests for MtpDocumentsProvider." />
-</manifest>
diff --git a/packages/MtpDocumentsProvider/perf_tests/AndroidTest.xml b/packages/MtpDocumentsProvider/perf_tests/AndroidTest.xml
deleted file mode 100644
index 8b7292b..0000000
--- a/packages/MtpDocumentsProvider/perf_tests/AndroidTest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<configuration description="Runs MtpDocumentsProviderPerfTests metric instrumentation.">
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="apct-metric-instrumentation" />
-    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
-        <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="MtpDocumentsProviderPerfTests.apk" />
-    </target_preparer>
-
-    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="com.android.mtp.perftests" />
-    </test>
-</configuration>
diff --git a/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java b/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java
deleted file mode 100644
index 58b9c67..0000000
--- a/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
-import android.os.ProxyFileDescriptorCallback;
-import android.os.storage.StorageManager;
-import android.system.ErrnoException;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.io.IOException;
-
-@RunWith(JUnit4.class)
-public class AppFusePerfTest {
-    final static int SIZE = 10 * 1024 * 1024;  // 10MB
-
-    @Test
-    @LargeTest
-    public void testReadWriteFile() throws IOException {
-        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        final StorageManager storageManager = context.getSystemService(StorageManager.class);
-
-        final byte[] bytes = new byte[SIZE];
-        final int SAMPLES = 100;
-        final double[] readTime = new double[SAMPLES];
-        final double[] writeTime = new double[SAMPLES];
-
-        for (int i = 0; i < SAMPLES; i++) {
-            final ParcelFileDescriptor fd = storageManager.openProxyFileDescriptor(
-                    ParcelFileDescriptor.MODE_READ_ONLY, new TestCallback());
-            try (final ParcelFileDescriptor.AutoCloseInputStream stream =
-                    new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
-                final long startTime = System.nanoTime();
-                stream.read(bytes);
-                readTime[i] = (System.nanoTime() - startTime) / 1000.0 / 1000.0;
-            }
-        }
-
-        for (int i = 0; i < SAMPLES; i++) {
-            final ParcelFileDescriptor fd = storageManager.openProxyFileDescriptor(
-                    ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE,
-                    new TestCallback());
-            try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
-                    new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
-                final long startTime = System.nanoTime();
-                stream.write(bytes);
-                writeTime[i] = (System.nanoTime() - startTime) / 1000.0 / 1000.0;
-            }
-        }
-
-        double readAverage = 0;
-        double writeAverage = 0;
-        double readSquaredAverage = 0;
-        double writeSquaredAverage = 0;
-        for (int i = 0; i < SAMPLES; i++) {
-            readAverage += readTime[i];
-            writeAverage += writeTime[i];
-            readSquaredAverage += readTime[i] * readTime[i];
-            writeSquaredAverage += writeTime[i] * writeTime[i];
-        }
-
-        readAverage /= SAMPLES;
-        writeAverage /= SAMPLES;
-        readSquaredAverage /= SAMPLES;
-        writeSquaredAverage /= SAMPLES;
-
-        final Bundle results = new Bundle();
-        results.putDouble("readAverage", readAverage);
-        results.putDouble("readStandardDeviation",
-                Math.sqrt(readSquaredAverage - readAverage * readAverage));
-        results.putDouble("writeAverage", writeAverage);
-        results.putDouble("writeStandardDeviation",
-                Math.sqrt(writeSquaredAverage - writeAverage * writeAverage));
-        InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, results);
-    }
-
-    private static class TestCallback extends ProxyFileDescriptorCallback {
-        @Override
-        public long onGetSize() throws ErrnoException {
-            return SIZE;
-        }
-
-        @Override
-        public int onRead(long offset, int size, byte[] data) throws ErrnoException {
-            return size;
-        }
-
-        @Override
-        public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
-            return size;
-        }
-
-        @Override
-        public void onFsync() throws ErrnoException {}
-
-        @Override
-        public void onRelease() {}
-    }
-}
diff --git a/packages/MtpDocumentsProvider/proguard.flags b/packages/MtpDocumentsProvider/proguard.flags
deleted file mode 100644
index e660121..0000000
--- a/packages/MtpDocumentsProvider/proguard.flags
+++ /dev/null
@@ -1,4 +0,0 @@
-# Keeps methods that are invoked by JNI.
--keepclassmembers class * {
-  @com.android.mtp.annotations.UsedByNative *;
-}
diff --git a/packages/MtpDocumentsProvider/res/drawable-hdpi/ic_root_mtp.png b/packages/MtpDocumentsProvider/res/drawable-hdpi/ic_root_mtp.png
deleted file mode 100644
index 7691433..0000000
--- a/packages/MtpDocumentsProvider/res/drawable-hdpi/ic_root_mtp.png
+++ /dev/null
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/drawable-mdpi/ic_root_mtp.png b/packages/MtpDocumentsProvider/res/drawable-mdpi/ic_root_mtp.png
deleted file mode 100644
index 1cf7b3a..0000000
--- a/packages/MtpDocumentsProvider/res/drawable-mdpi/ic_root_mtp.png
+++ /dev/null
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/drawable-xhdpi/ic_root_mtp.png b/packages/MtpDocumentsProvider/res/drawable-xhdpi/ic_root_mtp.png
deleted file mode 100644
index 27e3542..0000000
--- a/packages/MtpDocumentsProvider/res/drawable-xhdpi/ic_root_mtp.png
+++ /dev/null
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/drawable-xxhdpi/ic_root_mtp.png b/packages/MtpDocumentsProvider/res/drawable-xxhdpi/ic_root_mtp.png
deleted file mode 100644
index 3df2578b..0000000
--- a/packages/MtpDocumentsProvider/res/drawable-xxhdpi/ic_root_mtp.png
+++ /dev/null
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/drawable-xxxhdpi/ic_root_mtp.png b/packages/MtpDocumentsProvider/res/drawable-xxxhdpi/ic_root_mtp.png
deleted file mode 100644
index fd2b795..0000000
--- a/packages/MtpDocumentsProvider/res/drawable-xxxhdpi/ic_root_mtp.png
+++ /dev/null
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/mipmap-hdpi/ic_launcher_download.png b/packages/MtpDocumentsProvider/res/mipmap-hdpi/ic_launcher_download.png
deleted file mode 100644
index f958bbd..0000000
--- a/packages/MtpDocumentsProvider/res/mipmap-hdpi/ic_launcher_download.png
+++ /dev/null
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/mipmap-mdpi/ic_launcher_download.png b/packages/MtpDocumentsProvider/res/mipmap-mdpi/ic_launcher_download.png
deleted file mode 100644
index f2e9376..0000000
--- a/packages/MtpDocumentsProvider/res/mipmap-mdpi/ic_launcher_download.png
+++ /dev/null
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/mipmap-xhdpi/ic_launcher_download.png b/packages/MtpDocumentsProvider/res/mipmap-xhdpi/ic_launcher_download.png
deleted file mode 100644
index 4dc5336..0000000
--- a/packages/MtpDocumentsProvider/res/mipmap-xhdpi/ic_launcher_download.png
+++ /dev/null
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/mipmap-xxhdpi/ic_launcher_download.png b/packages/MtpDocumentsProvider/res/mipmap-xxhdpi/ic_launcher_download.png
deleted file mode 100644
index 8716290..0000000
--- a/packages/MtpDocumentsProvider/res/mipmap-xxhdpi/ic_launcher_download.png
+++ /dev/null
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/mipmap-xxxhdpi/ic_launcher_download.png b/packages/MtpDocumentsProvider/res/mipmap-xxxhdpi/ic_launcher_download.png
deleted file mode 100644
index f5be219..0000000
--- a/packages/MtpDocumentsProvider/res/mipmap-xxxhdpi/ic_launcher_download.png
+++ /dev/null
Binary files differ
diff --git a/packages/MtpDocumentsProvider/res/values-af/strings.xml b/packages/MtpDocumentsProvider/res/values-af/strings.xml
deleted file mode 100644
index c2c8761..0000000
--- a/packages/MtpDocumentsProvider/res/values-af/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP-gasheer"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Aflaaie"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Toegang tot lêers word tans van <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> af verkry"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Die ander toestel is besig. Jy kan nie lêers oordra voordat dit beskikbaar is nie."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Geen lêers is gevind nie. Die ander toestel is dalk gesluit. Indien wel, ontsluit dit en probeer weer."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-am/strings.xml b/packages/MtpDocumentsProvider/res/values-am/strings.xml
deleted file mode 100644
index 7b721c8..0000000
--- a/packages/MtpDocumentsProvider/res/values-am/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"የMTP አስተናጋጅ"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"የወረዱ"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"ፋይሎችን ከ<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> በመድረስ ላይ"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"ሌላኛው መሣሪያ ሥራ በዝቶበታል። እስከሚገኝ ድረስ ፋይሎችን ማስተላለፍ አይችሉም።"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"ምንም ፋይሎች አልተገኙም። ሌላኛው መሣሪያ ተቆልፎ ሊሆን ይችላል። ተቆልፎ ከሆነ ይክፈቱት እና እንደገና ይሞክሩ።"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ar/strings.xml b/packages/MtpDocumentsProvider/res/values-ar/strings.xml
deleted file mode 100644
index 284a860..0000000
--- a/packages/MtpDocumentsProvider/res/values-ar/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"‏مضيف بروتوكول نقل الوسائط (MTP)"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"التنزيلات"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"جارٍ الوصول إلى الملفات من <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"الجهاز الآخر مشغول، ولا يمكنك نقل الملفات إلا بعد أن يصبح متاحًا."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"لم يتم العثور على ملفات، وربما يكون الجهاز الآخر في وضع القفل. إذا كان الأمر كذلك، فعليك إلغاء قفله وإعادة المحاولة."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-as/strings.xml b/packages/MtpDocumentsProvider/res/values-as/strings.xml
deleted file mode 100644
index c8bdbd6..0000000
--- a/packages/MtpDocumentsProvider/res/values-as/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"এমটিপি হ\'ষ্ট"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"ডাউনল\'ডসমূহ"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>ৰ পৰা ফাইলসমূহ চোৱা হৈছে"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"আনটো ডিভাইচ ব্যস্ত হৈ আছে। সেইটো উপলব্ধ নোহোৱালৈকে আপুনি ফাইলসমূহ স্থানান্তৰ কৰিব নোৱাৰে।"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"কোনো ফাইল পোৱা নগ\'ল। আনটো ডিভাইচ লক হৈ থাকিব পাৰে। যদি লক হৈ আছে, তেন্তে আনলক কৰি আকৌ চেষ্টা কৰক।"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-az/strings.xml b/packages/MtpDocumentsProvider/res/values-az/strings.xml
deleted file mode 100644
index e8ed124..0000000
--- a/packages/MtpDocumentsProvider/res/values-az/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Endirmələr"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Fayllara <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> cihazından daxil olunur"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Digər cihaz məşğuldur. Əlçatan olmayana kimi fayl köçürə bilməzsiniz."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Fayl tapılmadı. Digər cihaz kilidlənmiş ola bilər. Elədirsə, kiliddən çıxarın və yenidən cəhd edin."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-b+sr+Latn/strings.xml b/packages/MtpDocumentsProvider/res/values-b+sr+Latn/strings.xml
deleted file mode 100644
index bc900996..0000000
--- a/packages/MtpDocumentsProvider/res/values-b+sr+Latn/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Preuzimanja"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Pristup datotekama sa uređaja <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Drugi uređaj je zauzet. Datoteke možete da prenesete tek kad on postane dostupan."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Nije pronađena nijedna datoteka. Drugi uređaj je možda zaključan. Ako jeste, otključajte ga i pokušajte ponovo."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-be/strings.xml b/packages/MtpDocumentsProvider/res/values-be/strings.xml
deleted file mode 100644
index f6263ac..0000000
--- a/packages/MtpDocumentsProvider/res/values-be/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Вузел MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Спампоўкі"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Доступ да файлаў з <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Іншая прылада занята. Вы не можаце перадаць файлы, пакуль яна не стане даступнай."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Файлы не знойдзены. Іншая прылада можа быць заблакіравана. Калі гэта так, разблакіруйце яе і паўтарыце спробу."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-bg/strings.xml b/packages/MtpDocumentsProvider/res/values-bg/strings.xml
deleted file mode 100644
index 52d3119..0000000
--- a/packages/MtpDocumentsProvider/res/values-bg/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP хост"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Изтегляния"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> на <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"От <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> се осъществява достъп до файловете"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Другото устройство е заето. Не можете да прехвърляте файлове, докато то не се освободи."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Няма намерени файлове. Другото устройство може да е заключено. Ако е така, отключете го и опитайте отново."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-bn/strings.xml b/packages/MtpDocumentsProvider/res/values-bn/strings.xml
deleted file mode 100644
index 7fad89e..0000000
--- a/packages/MtpDocumentsProvider/res/values-bn/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP হোস্ট"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"ডাউনলোডগুলি"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> থেকে ফাইলগুলিকে অ্যাক্সেস করা হচ্ছে"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"অন্য ডিভাইসটি ব্যস্ত আছে৷ এটি উপলব্ধ না হওয়া পর্যন্ত আপনি ফাইলগুলিকে স্থানান্তর করতে পারবেন না৷"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"কোনো ফাইল পাওয়া যায়নি৷ অন্য ডিভাইসটি লক থাকতে পারে৷ যদি তাই হয়, তাহলে এটিকে আনলক করে আবার চেষ্টা করুন৷"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-bs/strings.xml b/packages/MtpDocumentsProvider/res/values-bs/strings.xml
deleted file mode 100644
index 18c2363..0000000
--- a/packages/MtpDocumentsProvider/res/values-bs/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Preuzimanja"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Pristupanje fajlovima iz uređaja <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Drugi uređaj je zauzet. Nećete moći prenositi fajlove dok ne bude dostupan."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Fajlovi nisu pronađeni. Moguće je da je drugi uređaj zaključan. Ako jeste, otključajte ga i pokušajte ponovo."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ca/strings.xml b/packages/MtpDocumentsProvider/res/values-ca/strings.xml
deleted file mode 100644
index b2aa599..0000000
--- a/packages/MtpDocumentsProvider/res/values-ca/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Amfitrió MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Baixades"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> de <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"S\'està accedint als fitxers del dispositiu <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"L\'altre dispositiu està ocupat. No pots transferir fitxers fins que estigui disponible."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"No s\'han trobat fitxers. És possible que l\'altre dispositiu estigui bloquejat. Si és així, desbloqueja\'l i torna-ho a provar."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-cs/strings.xml b/packages/MtpDocumentsProvider/res/values-cs/strings.xml
deleted file mode 100644
index 2156e8c..0000000
--- a/packages/MtpDocumentsProvider/res/values-cs/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Hostitel MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Stahování"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> – <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Používání souborů ze zařízení <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Druhé zařízení je zaneprázdněné. Dokud nebude dostupné, soubory nelze přenést."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Nebyly nalezeny žádné soubory. Druhé zařízení je možná uzamčené. Pokud ano, odemkněte jej a zkuste to znovu."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-da/strings.xml b/packages/MtpDocumentsProvider/res/values-da/strings.xml
deleted file mode 100644
index b82c5e8..0000000
--- a/packages/MtpDocumentsProvider/res/values-da/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP-host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Adgang til filer fra <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Den anden enhed er optaget. Du kan ikke overføre filer, før den er tilgængelig."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Der blev ikke fundet nogen filer. Den anden enhed er muligvis låst. Hvis dette er tilfældet, skal du låse den op og prøve igen."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-de/strings.xml b/packages/MtpDocumentsProvider/res/values-de/strings.xml
deleted file mode 100644
index 9a71c76..0000000
--- a/packages/MtpDocumentsProvider/res/values-de/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP-Host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> von <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Zugriff auf Dateien von <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Das andere Gerät ist nicht verfügbar. Du kannst die Dateien übertragen, sobald das Gerät wieder verfügbar ist."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Keine Dateien gefunden. Das andere Gerät ist möglicherweise gesperrt. Entsperre es in diesem Fall und versuche es noch einmal."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-el/strings.xml b/packages/MtpDocumentsProvider/res/values-el/strings.xml
deleted file mode 100644
index 562d295..0000000
--- a/packages/MtpDocumentsProvider/res/values-el/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Κεντρικός υπολογιστής MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Λήψεις"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Πρόσβαση στα αρχεία από τη συσκευή <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Η άλλη συσκευή είναι απασχολημένη. Δεν μπορείτε να μεταφέρετε αρχεία μέχρι να γίνει διαθέσιμη."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Δεν βρέθηκαν αρχεία. Η άλλη συσκευή ενδέχεται να είναι κλειδωμένη. Εάν ισχύει αυτό, ξεκλειδώστε την και δοκιμάστε ξανά."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-en-rAU/strings.xml b/packages/MtpDocumentsProvider/res/values-en-rAU/strings.xml
deleted file mode 100644
index 5f2167e..0000000
--- a/packages/MtpDocumentsProvider/res/values-en-rAU/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Accessing files from <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"The other device is busy. You can\'t transfer files until it\'s available."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"No files found. The other device may be locked. If so, unlock it and try again."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-en-rCA/strings.xml b/packages/MtpDocumentsProvider/res/values-en-rCA/strings.xml
deleted file mode 100644
index 5f2167e..0000000
--- a/packages/MtpDocumentsProvider/res/values-en-rCA/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Accessing files from <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"The other device is busy. You can\'t transfer files until it\'s available."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"No files found. The other device may be locked. If so, unlock it and try again."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-en-rGB/strings.xml b/packages/MtpDocumentsProvider/res/values-en-rGB/strings.xml
deleted file mode 100644
index 5f2167e..0000000
--- a/packages/MtpDocumentsProvider/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Accessing files from <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"The other device is busy. You can\'t transfer files until it\'s available."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"No files found. The other device may be locked. If so, unlock it and try again."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-en-rIN/strings.xml b/packages/MtpDocumentsProvider/res/values-en-rIN/strings.xml
deleted file mode 100644
index 5f2167e..0000000
--- a/packages/MtpDocumentsProvider/res/values-en-rIN/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Accessing files from <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"The other device is busy. You can\'t transfer files until it\'s available."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"No files found. The other device may be locked. If so, unlock it and try again."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-en-rXC/strings.xml b/packages/MtpDocumentsProvider/res/values-en-rXC/strings.xml
deleted file mode 100644
index e968a55..0000000
--- a/packages/MtpDocumentsProvider/res/values-en-rXC/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‎‎‏‎‎MTP Host‎‏‎‎‏‎"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‎‏‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎Downloads‎‏‎‎‏‎"</string>
-    <string name="root_name" msgid="5819495383921089536">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎‏‎‏‏‏‎‎‎‎‎‎‎‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎<xliff:g id="STORAGE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‎‏‎‎‏‏‏‎‎‎‎Accessing files from ‎‏‎‎‏‏‎<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎The other device is busy. You can\'t transfer files until it\'s available.‎‏‎‎‏‎"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‎‎‏‏‎‏‎‎‏‏‎‎‎‏‎‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎‏‏‎No files found. The other device may be locked. If so, unlock it and try again.‎‏‎‎‏‎"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-es-rUS/strings.xml b/packages/MtpDocumentsProvider/res/values-es-rUS/strings.xml
deleted file mode 100644
index 740d224..0000000
--- a/packages/MtpDocumentsProvider/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Host MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Descargas"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Accediendo a los archivos de <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"El otro dispositivo está ocupado. No podrás transferir archivos hasta que esté disponible."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"No se encontraron archivos. Es posible que el otro dispositivo esté bloqueado. Si es así, desbloquéalo y vuelve a intentarlo."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-es/strings.xml b/packages/MtpDocumentsProvider/res/values-es/strings.xml
deleted file mode 100644
index d80a75a..0000000
--- a/packages/MtpDocumentsProvider/res/values-es/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Host de MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Descargas"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> de <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Accediendo a los archivos desde <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"El otro dispositivo está ocupado. No se pueden transferir archivos hasta que esté disponible."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"No se ha encontrado ningún archivo. Es posible que el otro dispositivo esté bloqueado. Si es así, desbloquéalo y vuelve a intentarlo."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-et/strings.xml b/packages/MtpDocumentsProvider/res/values-et/strings.xml
deleted file mode 100644
index 7568777..0000000
--- a/packages/MtpDocumentsProvider/res/values-et/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Allalaadimised"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>, <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Juurdepääsemine failidele seadmest <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Teine seade on hõivatud. Te ei saa faile üle viia enne, kui see seade on saadaval."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Faile ei leitud. Teine seade võib olla lukustatud. Kui see on nii, avage see ja proovige uuesti."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-eu/strings.xml b/packages/MtpDocumentsProvider/res/values-eu/strings.xml
deleted file mode 100644
index dc9d463..0000000
--- a/packages/MtpDocumentsProvider/res/values-eu/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP ostalaria"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Deskargak"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> gailuko fitxategiak atzitzen"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Beste gailua lanpetuta dago. Erabilgarri egon arte ezingo duzu transferitu fitxategirik."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Ez da aurkitu fitxategirik. Baliteke beste gailua blokeatuta egotea. Hala bada, desblokea ezazu eta saiatu berriro."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-fa/strings.xml b/packages/MtpDocumentsProvider/res/values-fa/strings.xml
deleted file mode 100644
index 9ac58c7..0000000
--- a/packages/MtpDocumentsProvider/res/values-fa/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"‏میزبان MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"بارگیری‌ها"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"دسترسی به فایل‌ها از <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"دستگاه دیگر مشغول است. تا زمانی که این دستگاه دردسترس قرار نگیرد نمی‌توانید فایل‌ها را منتقل کنید."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"فایلی پیدا نشد. دستگاه دیگر ممکن است قفل باشد. اگر این‌طور است، قفل آن را باز کنید و دوباره تلاش کنید."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-fi/strings.xml b/packages/MtpDocumentsProvider/res/values-fi/strings.xml
deleted file mode 100644
index 0a61d08..0000000
--- a/packages/MtpDocumentsProvider/res/values-fi/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP-isäntä"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Lataukset"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Käytetään laitteen <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> tiedostoja"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Toinen laite on varattu. Et voi siirtää tiedostoja, ennen kuin se on käytettävissä."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Tiedostoja ei löytynyt. Toinen laite voi olla lukittu. Jos näin on, avaa se ja yritä uudelleen."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-fr-rCA/strings.xml b/packages/MtpDocumentsProvider/res/values-fr-rCA/strings.xml
deleted file mode 100644
index 281760e..0000000
--- a/packages/MtpDocumentsProvider/res/values-fr-rCA/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Hôte MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Téléchargements"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Accès aux fichiers à partir de l\'appareil <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"L\'autre appareil est occupé. Vous devez attendre qu\'il soit disponible pour transférer des fichiers."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Aucun fichier trouvé. L\'autre appareil est peut-être verrouillé. Si c\'est le cas, déverrouillez-le, puis réessayez."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-fr/strings.xml b/packages/MtpDocumentsProvider/res/values-fr/strings.xml
deleted file mode 100644
index 96c713b..0000000
--- a/packages/MtpDocumentsProvider/res/values-fr/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Hôte MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Téléchargements"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> – <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Accès aux fichiers depuis le <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>…"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"L\'autre appareil est occupé. Vous devez attendre qu\'il soit disponible pour transférer des fichiers."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Aucun fichier trouvé. L\'autre appareil est peut-être verrouillé. Si tel est le cas, déverrouillez-le, puis réessayez."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-gl/strings.xml b/packages/MtpDocumentsProvider/res/values-gl/strings.xml
deleted file mode 100644
index 7e61c7c..0000000
--- a/packages/MtpDocumentsProvider/res/values-gl/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Host MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Descargas"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> de <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Accedendo aos ficheiros do dispositivo <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"O outro dispositivo está ocupado. Non podes transferir ficheiros ata que estea dispoñible."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Non se atopou ningún ficheiro. Se o outro dispositivo está bloqueado, desbloquéao e téntao de novo."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-gu/strings.xml b/packages/MtpDocumentsProvider/res/values-gu/strings.xml
deleted file mode 100644
index 468bd9d..0000000
--- a/packages/MtpDocumentsProvider/res/values-gu/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP હોસ્ટ"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"ડાઉનલોડ્સ"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> ની ફાઇલોને ઍક્સેસ કરી રહ્યાં છે"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"અન્ય ઉપકરણ વ્યસ્ત છે. તે ઉપલબ્ધ ન થાય ત્યાં સુધી તમે ફાઇલોને ટ્રાન્સફર કરી શકતાં નથી."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"કોઈ ફાઇલો મળી નહીં. અન્ય ઉપકરણ લૉક કરેલ હોઈ શકે છે. જો આમ હોય, તો તેને અનલૉક કરો અને ફરી પ્રયાસ કરો."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-hi/strings.xml b/packages/MtpDocumentsProvider/res/values-hi/strings.xml
deleted file mode 100644
index e469fc0..0000000
--- a/packages/MtpDocumentsProvider/res/values-hi/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP होस्ट"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"डाउनलोड"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> से फ़ाइलें ऐक्सेस कर रहा है"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"दूसरा डिवाइस व्यस्त है. आप उसके उपलब्ध हो जाने तक फ़ाइलें ट्रांसफ़र नहीं कर सकते."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"कोई फ़ाइल नहीं मिली. हो सकता है कि दूसरा डिवाइस लॉक हो. अगर ऐसा है, तो उसे अनलॉक करें और दोबारा कोशिश करें."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-hr/strings.xml b/packages/MtpDocumentsProvider/res/values-hr/strings.xml
deleted file mode 100644
index 63fc5c7..0000000
--- a/packages/MtpDocumentsProvider/res/values-hr/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Preuzimanja"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g><xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Pristupanje datotekama s uređaja <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Drugi je uređaj zauzet. Datoteke ćete moći prenijeti kada postane dostupan."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Datoteke nisu pronađene. Drugi je uređaj možda zaključan. U tom ga slučaju otključajte i pokušajte ponovo."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-hu/strings.xml b/packages/MtpDocumentsProvider/res/values-hu/strings.xml
deleted file mode 100644
index e5b822c..0000000
--- a/packages/MtpDocumentsProvider/res/values-hu/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Letöltések"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Hozzáférés a fájlokhoz a következő eszközről: <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"A másik eszköz elfoglalt. Nem vihetők át fájlok addig, amíg rendelkezésre nem áll."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Nem található fájl. Lehet, hogy a másik eszköz zárolva van. Ha igen, oldja fel, és próbálkozzon újra."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-hy/strings.xml b/packages/MtpDocumentsProvider/res/values-hy/strings.xml
deleted file mode 100644
index 3a6bfb5..0000000
--- a/packages/MtpDocumentsProvider/res/values-hy/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP խնամորդ"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Ներբեռնումներ"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Մուտք է գործում ֆայլեր <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> սարքից"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Մյուս սարքը զբաղված է: Ֆայլերը կարող եք փոխանցել միայն երբ այն հասանելի է:"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Ֆայլեր չեն գտնվել: Հնարավոր է, որ մյուս սարքը կողպված է: Եթե դա այդպես է, ապակողպեք այն և փորձեք նորից:"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-in/strings.xml b/packages/MtpDocumentsProvider/res/values-in/strings.xml
deleted file mode 100644
index 6f65337..0000000
--- a/packages/MtpDocumentsProvider/res/values-in/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Host MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Download"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Mengakses file dari <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Perangkat lainnya sedang sibuk. Anda dapat mentransfer file jika telah tersedia."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"File tidak ditemukan. Perangkat lainnya mungkin terkunci. Jika begitu, buka kuncinya dan coba lagi."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-is/strings.xml b/packages/MtpDocumentsProvider/res/values-is/strings.xml
deleted file mode 100644
index 9388f7e..0000000
--- a/packages/MtpDocumentsProvider/res/values-is/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP-hýsill"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Niðurhal"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Fær aðgang að skrám frá <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Hitt tækið er upptekið. Þú getur ekki fært skrár fyrr en það er tiltækt."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Engar skrár fundust. Hitt tækið gæti verið læst. Ef svo er skaltu opna það og reyna aftur."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-it/strings.xml b/packages/MtpDocumentsProvider/res/values-it/strings.xml
deleted file mode 100644
index a41699f..0000000
--- a/packages/MtpDocumentsProvider/res/values-it/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Host MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Download"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> di <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Accesso ai file da <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"L\'altro dispositivo è occupato. I file non possono essere trasferiti fino a quando non sarà disponibile."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Nessun file trovato. L\'altro dispositivo potrebbe essere bloccato. In questo caso, sbloccalo e riprova."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-iw/strings.xml b/packages/MtpDocumentsProvider/res/values-iw/strings.xml
deleted file mode 100644
index 62dfe7d..0000000
--- a/packages/MtpDocumentsProvider/res/values-iw/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"‏מארח פרוטוקול העברת מדיה (MTP)"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"הורדות"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"גישה לקבצים מ-<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"המכשיר השני לא פנוי. ניתן יהיה להעביר קבצים רק לאחר שהוא יהיה זמין."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"לא נמצאו קבצים. ייתכן שהמכשיר השני נעול. אם כן, פתח אותו ונסה שוב."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ja/strings.xml b/packages/MtpDocumentsProvider/res/values-ja/strings.xml
deleted file mode 100644
index 72ab33d..0000000
--- a/packages/MtpDocumentsProvider/res/values-ja/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP ホスト"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"ダウンロード"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> からファイルにアクセスしています"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"接続先のデバイスは使用中のため、利用できるようになるまでファイルを転送できません。"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"ファイルが見つかりません。接続先のデバイスがロックされている可能性があります。その場合は、ロックを解除してからもう一度お試しください。"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ka/strings.xml b/packages/MtpDocumentsProvider/res/values-ka/strings.xml
deleted file mode 100644
index 33812df..0000000
--- a/packages/MtpDocumentsProvider/res/values-ka/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP ჰოსტი"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"ჩამოტვირთვები"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"მიმდინარეობს <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>-ზე არსებულ ფაილებზე წვდომა"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"სხვა მოწყობილობა დაკავებულია. ფაილების გადატანა ვერ მოხერხდება, სანამ ის ხელმისაწვდომი არ გახდება."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"ფაილები ვერ მოიძებნა. მეორე მოწყობილობა შეიძლება დაბლოკილი იყოს. ამ შემთხვევაში, განბლოკეთ ის და ცადეთ ხელახლა."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-kk/strings.xml b/packages/MtpDocumentsProvider/res/values-kk/strings.xml
deleted file mode 100644
index a6dea5b..0000000
--- a/packages/MtpDocumentsProvider/res/values-kk/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP хосты"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Жүктеп алынғандар"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Файлдарға <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> құрылғысынан кіру"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Екінші құрылғы бос емес. Ол босамайынша, файлдар тасымалданбайды."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Ешқандай файл табылмады. Екінші құрылғы құлыптаулы болуы мүмкін. Құлыптаулы болса, құлпын ашып, қайталап көріңіз."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-km/strings.xml b/packages/MtpDocumentsProvider/res/values-km/strings.xml
deleted file mode 100644
index baffa95..0000000
--- a/packages/MtpDocumentsProvider/res/values-km/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"ម៉ាស៊ីន MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"ដោយឡូត"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"កំពុងចូលដំណើរការពី <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"ឧបករណ៍ផ្សេងទៀតកំពុងជាប់រវល់។ អ្នកមិនផ្ទេរឯកសារបានទេ រហូតទាល់តែវាអាចប្រើបាន។"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"រកមិនឃើញឯកសារទេ។ ឧបករណ៍ផ្សេងទៀតប្រហែលជាត្រូវបានចាក់សោ។ ប្រសិនបើវាត្រូវបានចាក់សោមែន សូមដោះសោ ហើយព្យាយាមម្តងទៀត។"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-kn/strings.xml b/packages/MtpDocumentsProvider/res/values-kn/strings.xml
deleted file mode 100644
index 3f16c14..0000000
--- a/packages/MtpDocumentsProvider/res/values-kn/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP ಹೋಸ್ಟ್"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"ಡೌನ್‌ಲೋಡ್‌ಗಳು"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> ನಿಂದ ಫೈಲ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲಾಗುತ್ತಿದೆ"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"ಬೇರೆಯ ಸಾಧನವು ಕಾರ್ಯನಿರತವಾಗಿದೆ. ಇದು ಲಭ್ಯವಾಗುವವರೆಗೆ ಫೈಲ್‌ಗಳನ್ನು ನಿಮಗೆ ವರ್ಗಾಯಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"ಯಾವುದೇ ಫೈಲ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ. ಬೇರೆಯ ಸಾಧನವು ಲಾಕ್ ಆಗಿರಬಹುದು. ಹಾಗಾದಲ್ಲಿ, ಇದನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ ಹಾಗೂ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ko/strings.xml b/packages/MtpDocumentsProvider/res/values-ko/strings.xml
deleted file mode 100644
index bbe2fe6..0000000
--- a/packages/MtpDocumentsProvider/res/values-ko/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP 호스트"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"다운로드"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>에서 파일에 액세스 중"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"다른 기기가 사용 중입니다. 다른 기기를 사용할 수 있을 때까지 파일을 전송할 수 없습니다."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"파일이 없습니다. 다른 기기가 잠겨 있을 수 있습니다. 기기의 잠금을 해제하고 다시 시도하세요."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ky/strings.xml b/packages/MtpDocumentsProvider/res/values-ky/strings.xml
deleted file mode 100644
index e60a494..0000000
--- a/packages/MtpDocumentsProvider/res/values-ky/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP хосту"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Жүктөлүп алынган нерселер"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> түзмөгүндөгү файлдар колдонулууда"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Берки түзмөк бош эмес. Ал бошомоюнча файлдарды өткөрө албайсыз."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Бир дагы файл табылган жок. Берки түзмөк кулпуланып турат окшойт. Кулпусун ачып, кайра аракет кылып көрүңүз."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-lo/strings.xml b/packages/MtpDocumentsProvider/res/values-lo/strings.xml
deleted file mode 100644
index bcc0ee6..0000000
--- a/packages/MtpDocumentsProvider/res/values-lo/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"ໂຮສ MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"ການດາວໂຫລດ"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"ກຳລັງເຂົ້າເຖິງໄຟລ໌ຈາກ <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"ອຸປະກອນອື່ນບໍ່ຫວ່າງເທື່ອ. ທ່ານບໍ່ສາມາດໂອນຍ້າຍໄຟລ໌ໄດ້ຈົນກວ່າມັນຈະຫວ່າງ."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"ບໍ່ພົບໄຟລ໌. ອຸປະກອນອີກເຄື່ອງອາດຖືກລັອກໄວ້ຢູ່. ຫາກມັນຖືກລັອກໄວ້, ໃຫ້ປົດລັອກມັນກ່ອນແລ້ວລອງໃໝ່ອີກຄັ້ງ."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-lt/strings.xml b/packages/MtpDocumentsProvider/res/values-lt/strings.xml
deleted file mode 100644
index 8bff3a8..0000000
--- a/packages/MtpDocumentsProvider/res/values-lt/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MPP priegloba"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Atsisiuntimai"</string>
-    <string name="root_name" msgid="5819495383921089536">"„<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>“ <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Pasiekiami failai iš „<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>“"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Kitas įrenginys yra užsiėmęs. Failus galėsite perkelti tik tada, kai jis bus pasiekiamas."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Nerasta failų. Gali būti, kad kitas įrenginys yra užrakintas. Jei taip yra, atrakinkite jį ir bandykite dar kartą."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-lv/strings.xml b/packages/MtpDocumentsProvider/res/values-lv/strings.xml
deleted file mode 100644
index 5e96338..0000000
--- a/packages/MtpDocumentsProvider/res/values-lv/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP saimniekdators"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Lejupielādes"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Piekļuve failiem no: <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Otra ierīce ir aizņemta. Varēsiet pārsūtīt failus tikai tad, kad tā būs pieejama."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Neviens fails netika atrasts. Iespējams, otra ierīce ir bloķēta. Ja tā ir, atbloķējiet ierīci un mēģiniet vēlreiz."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-mk/strings.xml b/packages/MtpDocumentsProvider/res/values-mk/strings.xml
deleted file mode 100644
index 6028b71..0000000
--- a/packages/MtpDocumentsProvider/res/values-mk/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP-хост"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Преземања"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Се пристапува до датотеки од <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Другиот уред е зафатен. Не може да се пренесуваат датотеки сѐ додека не стане достапен."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Не се најдени датотеки. Другиот уред можеби е заклучен. Ако е така, отклучете го и обидете се повторно."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ml/strings.xml b/packages/MtpDocumentsProvider/res/values-ml/strings.xml
deleted file mode 100644
index 49eb847..0000000
--- a/packages/MtpDocumentsProvider/res/values-ml/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP ഹോസ്റ്റ്"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"ഡൗണ്‍ലോഡുകൾ"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> ഉപകരണത്തിൽ നിന്ന് ഫയലുകൾ ആക്സസ്സ് ചെയ്യുന്നു"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"രണ്ടാമത്തെ ഉപകരണം തിരക്കിലാണ്. അത് ലഭ്യമാകുന്നത് വരെ നിങ്ങൾക്ക് ഫയലുകൾ കൈമാറാൻ കഴിയില്ല."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"ഫയലുകളൊന്നും കണ്ടെത്തിയില്ല. രണ്ടാമത്തെ ഉപകരണം ലോക്കുചെയ്ത നിലയിലായിരിക്കാം. ആണെങ്കിൽ, അൺലോക്കുചെയ്ത് വീണ്ടും ശ്രമിക്കുക."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-mn/strings.xml b/packages/MtpDocumentsProvider/res/values-mn/strings.xml
deleted file mode 100644
index 43b8204..0000000
--- a/packages/MtpDocumentsProvider/res/values-mn/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP Хост"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Таталт"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>-с файлд хандаж байна"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Нөгөө төхөөрөмж завгүй байна. Үүнийг боломжтой болох хүртэл файл шилжүүлэх боломжгүй."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Файл олдсонгүй. Нөгөө төхөөрөмж түгжигдсэн байж болзошгүй. Ингэсэн тохиолдолд түгжээг нь тайлаад, дахин оролдоно уу."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-mr/strings.xml b/packages/MtpDocumentsProvider/res/values-mr/strings.xml
deleted file mode 100644
index 983112c..0000000
--- a/packages/MtpDocumentsProvider/res/values-mr/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP होस्ट"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"डाउनलोड"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> मधून फायलींंमध्ये प्रवेश करत आहे"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"दुसरे डिव्हाइस व्यस्त आहे. ते उपलब्‍ध होईपर्यंत तुम्ही फायली ट्रान्सफर करू शकत नाही."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"कोणत्याही फायली आढळल्या नाहीत. दुसरे डिव्हाइस कदाचित बंद असू शकते. तसे असल्यास, ते अनलॉक करा आणि पुन्हा प्रयत्न करा."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ms/strings.xml b/packages/MtpDocumentsProvider/res/values-ms/strings.xml
deleted file mode 100644
index febec1d..0000000
--- a/packages/MtpDocumentsProvider/res/values-ms/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Hos MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Muat turun"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Mengakses fail daripada <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Peranti lain sedang sibuk. Anda tidak boleh memindahkan fail sehingga peranti itu tersedia."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Tiada fail ditemui. Peranti lain itu mungkin dikunci. Jika benar, sila buka kuncinya dan cuba lagi."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-my/strings.xml b/packages/MtpDocumentsProvider/res/values-my/strings.xml
deleted file mode 100644
index 8b509fb..0000000
--- a/packages/MtpDocumentsProvider/res/values-my/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP လက်ခံစက်"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"ဒေါင်းလုဒ်များ"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> မှ ဖိုင်များကို အသုံးပြုနေသည်"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"တခြားစက်ပစ္စည်းသည် မအားသေးပါ။ ၎င်းအဆင်သင့် မဖြစ်သေးသ၍ ဖိုင်များကို လွှဲပြောင်း၍ရမည် မဟုတ်ပါ။"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"မည်သည့်ဖိုင်မျှ မတွေ့ပါ။ ၎င်းစက်ပစ္စည်းကို လော့ခ်ချထားပုံရပါသည်။ သို့ဖြစ်လျှင် ၎င်းကိုလော့ခ်ဖြုတ်ပြီး ထပ်လုပ်ကြည့်ပါ။"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-nb/strings.xml b/packages/MtpDocumentsProvider/res/values-nb/strings.xml
deleted file mode 100644
index 40fabed..0000000
--- a/packages/MtpDocumentsProvider/res/values-nb/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP-vert"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Nedlastinger"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> på <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Bruker filer på <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Den andre enheten er opptatt. Du kan ikke overføre filer før den er tilgjengelig."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Ingen filer ble funnet. Den andre enheten kan være låst. I så fall må du låse den opp og prøve igjen."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ne/strings.xml b/packages/MtpDocumentsProvider/res/values-ne/strings.xml
deleted file mode 100644
index 53c0954..0000000
--- a/packages/MtpDocumentsProvider/res/values-ne/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP होस्ट"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"डाउनलोडहरू"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> बाट फाइलहरूमाथि पहुँच राख्दै"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"अर्को यन्त्र व्यस्त छ। त्यो यन्त्र उपलब्ध नभएसम्म तपाईं फाइल स्थानान्तरण गर्न सक्नुहुन्न।"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"कुनै फाइल भेट्टिएन। अर्को यन्त्र लक गरिएको हुन सक्छ। यदि त्यसो हो भने त्यसलाई अनलक गरेर फेरि प्रयास गर्नुहोस्।"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-nl/strings.xml b/packages/MtpDocumentsProvider/res/values-nl/strings.xml
deleted file mode 100644
index b1a01b2..0000000
--- a/packages/MtpDocumentsProvider/res/values-nl/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP-host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Bestanden openen op <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Het andere apparaat wordt gebruikt. Je moet wachten tot het beschikbaar is om bestanden te kunnen overzetten."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Geen bestanden gevonden. Het kan zijn dat het andere apparaat is vergrendeld. Als dat het geval is, ontgrendel je het en probeer je het opnieuw."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-or/strings.xml b/packages/MtpDocumentsProvider/res/values-or/strings.xml
deleted file mode 100644
index 79de689..0000000
--- a/packages/MtpDocumentsProvider/res/values-or/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP ହୋଷ୍ଟ"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"ଡାଉନଲୋଡ୍‌"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>ରୁ ଫାଇଲ୍‍ ଆକ୍ସେସ୍‍ କରାଯାଉଛି"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"ଅନ୍ୟ ଡିଭାଇସଟି ବ୍ୟସ୍ତ ଅଛି। ଏହା ଉପଲବ୍ଧ ନହେବା ପର୍ଯ୍ୟନ୍ତ ଆପଣ ଫାଇଲ୍‍ ଟ୍ରାନ୍ସଫର୍‍ କରିପାରିବେ ନାହିଁ।"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"କୌଣସି ଫାଇଲ୍‍ ମିଳିଲା ନାହିଁ। ଅନ୍ୟ ଡିଭାଇସଟି ଲକ୍‍ ହୋଇଯାଇଥାଇପାରେ। ଯଦି ଏପରି ହୋଇଥାଏ, ଏହାକୁ ଅନଲକ୍‍ କରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-pa/strings.xml b/packages/MtpDocumentsProvider/res/values-pa/strings.xml
deleted file mode 100644
index 7e3b892..0000000
--- a/packages/MtpDocumentsProvider/res/values-pa/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP ਹੋਸਟ"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"ਡਾਊਨਲੋਡ"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> ਦੀਆਂ ਫ਼ਾਈਲਾਂ \'ਤੇ ਪਹੁੰਚ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"ਦੂਜਾ ਡੀਵਾਈਸ ਰੁਝੇਵੇਂ ਵਿੱਚ ਹੈ। ਉਸਦੇ ਉਪਲਬਧ ਹੋਣ ਤੱਕ ਤੁਸੀਂ ਫ਼ਾਈਲਾਂ ਦਾ ਤਬਾਦਲਾ ਨਹੀਂ ਕਰ ਸਕਦੇ।"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"ਕੋਈ ਫ਼ਾਈਲਾਂ ਨਹੀਂ ਮਿਲੀਆਂ। ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਦੂਜਾ ਡੀਵਾਈਸ ਲਾਕ ਹੋਵੇ। ਜੇਕਰ ਇੰਝ ਹੈ, ਤਾਂ ਉਸਨੂੰ ਅਣਲਾਕ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-pl/strings.xml b/packages/MtpDocumentsProvider/res/values-pl/strings.xml
deleted file mode 100644
index 69fa0f4..0000000
--- a/packages/MtpDocumentsProvider/res/values-pl/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Host MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Pobrane"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> – <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Uzyskuję dostęp do plików na urządzeniu <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Drugie urządzenie jest zajęte. Dopóki nie będzie dostępne, nie możesz przesłać plików."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Nie znaleziono plików. Drugie urządzenie może być zablokowane. Jeśli tak jest, odblokuj je i spróbuj ponownie."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-pt-rBR/strings.xml b/packages/MtpDocumentsProvider/res/values-pt-rBR/strings.xml
deleted file mode 100644
index 03a1426..0000000
--- a/packages/MtpDocumentsProvider/res/values-pt-rBR/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Host do MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> do <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Acessando arquivos do <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"O outro dispositivo está ocupado. Não é possível transferir arquivos até que ele esteja disponível."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Nenhum arquivo encontrado. É possível que o outro dispositivo esteja bloqueado. Se for o caso, desbloqueie-o e tente novamente."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-pt-rPT/strings.xml b/packages/MtpDocumentsProvider/res/values-pt-rPT/strings.xml
deleted file mode 100644
index 05d32d4..0000000
--- a/packages/MtpDocumentsProvider/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Anfitrião MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Transferências"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Aceder a ficheiros do <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"O outro dispositivo está ocupado. Não pode transferir os ficheiros enquanto não estiver disponível."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Nenhum ficheiro encontrado. O outro dispositivo pode estar bloqueado. Se assim for, desbloqueie e tente novamente."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-pt/strings.xml b/packages/MtpDocumentsProvider/res/values-pt/strings.xml
deleted file mode 100644
index 03a1426..0000000
--- a/packages/MtpDocumentsProvider/res/values-pt/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Host do MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Downloads"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> do <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Acessando arquivos do <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"O outro dispositivo está ocupado. Não é possível transferir arquivos até que ele esteja disponível."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Nenhum arquivo encontrado. É possível que o outro dispositivo esteja bloqueado. Se for o caso, desbloqueie-o e tente novamente."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ro/strings.xml b/packages/MtpDocumentsProvider/res/values-ro/strings.xml
deleted file mode 100644
index 21ebc57..0000000
--- a/packages/MtpDocumentsProvider/res/values-ro/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Gazdă MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Descărcări"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Se accesează fișierele de pe <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Celălalt dispozitiv este ocupat. Nu puteți să transferați fișiere înainte să fie disponibil."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Nu s-au găsit fișiere. Este posibil ca celălalt dispozitiv să fie blocat. În acest caz, deblocați-l și încercați din nou."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ru/strings.xml b/packages/MtpDocumentsProvider/res/values-ru/strings.xml
deleted file mode 100644
index 717f12f..0000000
--- a/packages/MtpDocumentsProvider/res/values-ru/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP-хост"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Загрузки"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Доступ к файлам на устройстве <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>…"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Другое устройство занято. Вы сможете передать файлы, когда оно будет доступно."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Файлы не найдены. Если другое устройство заблокировано, разблокируйте его и повторите попытку."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-si/strings.xml b/packages/MtpDocumentsProvider/res/values-si/strings.xml
deleted file mode 100644
index 7a096b0..0000000
--- a/packages/MtpDocumentsProvider/res/values-si/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP සංග්‍රාහක"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"බාගැනීම්"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> වෙතින් ගොනු වෙත පිවිසීම"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"අනෙක් උපාංගය කාර්ය බහුලය. එය ලබා ගත හැකි වන තෙක් ඔබට ගොනු මාරු කළ නොහැකිය."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"ගොනු හමු නොවීය. අනෙක් උපාංගය අගුලු දමා තිබිය හැකිය. එසේ නම්, එය අගුලු හැර නැවත උත්සාහ කරන්න."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-sk/strings.xml b/packages/MtpDocumentsProvider/res/values-sk/strings.xml
deleted file mode 100644
index 365e1b7..0000000
--- a/packages/MtpDocumentsProvider/res/values-sk/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Hostiteľ MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Stiahnuté súbory"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Prístup k súborom zo zariadenia <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Druhé zariadenie je zaneprázdnené. Súbory bude možné preniesť, keď bude k dispozícii."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Nenašli sa žiadne súbory. Druhé zariadenie môže byť uzamknuté. Ak je to tak, odomknite ho a skúste to znova."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-sl/strings.xml b/packages/MtpDocumentsProvider/res/values-sl/strings.xml
deleted file mode 100644
index 60945d6..0000000
--- a/packages/MtpDocumentsProvider/res/values-sl/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Gostitelj MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Prenosi"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Dostopanje do datotek iz naprave <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Druga naprava ni na voljo. Dokler ne bo na voljo, ne bo mogoče prenašati datotek."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Ni datotek. Druga naprava je morda zaklenjena. Če je zaklenjena, jo odklenite in poskusite znova."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-sq/strings.xml b/packages/MtpDocumentsProvider/res/values-sq/strings.xml
deleted file mode 100644
index d92f29f..0000000
--- a/packages/MtpDocumentsProvider/res/values-sq/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Pritësi i protokollit MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Shkarkimet"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Po qaset te skedarët nga <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Pajisja tjetër është e zënë. Nuk mund të transferosh skedarë deri sa të jetë në dispozicion."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Nuk u gjet asnjë skedar. Pajisja tjetër mund të jetë e kyçur. Nëse po, shkyçe dhe provo përsëri."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-sr/strings.xml b/packages/MtpDocumentsProvider/res/values-sr/strings.xml
deleted file mode 100644
index d91c5c4..0000000
--- a/packages/MtpDocumentsProvider/res/values-sr/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP хост"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Преузимања"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Приступ датотекама са уређаја <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Други уређај је заузет. Датотеке можете да пренесете тек кад он постане доступан."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Није пронађена ниједна датотека. Други уређај је можда закључан. Ако јесте, откључајте га и покушајте поново."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-sv/strings.xml b/packages/MtpDocumentsProvider/res/values-sv/strings.xml
deleted file mode 100644
index 26818eb..0000000
--- a/packages/MtpDocumentsProvider/res/values-sv/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP-värd"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Nedladdningar"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Åtkomst till filer från <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Den andra enheten är upptagen. Du kan inte överföra filer förrän den är tillgänglig."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Inga filer hittades. Den andra enheten kan vara låst. Om den är det låser du upp den och försöker igen."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-sw/strings.xml b/packages/MtpDocumentsProvider/res/values-sw/strings.xml
deleted file mode 100644
index de3ed54..0000000
--- a/packages/MtpDocumentsProvider/res/values-sw/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Seva pangishi ya MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Vipakuliwa"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Inafikia faili kwenye <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Kifaa hicho kingine kinatumika. Huwezi kuhamisha faili hadi kipatikane."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Hakuna faili zilizopatikana. Huenda kifaa hicho kingine kimefungwa. Ikiwa kimefungwa, kifungue na ujaribu tena."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ta/strings.xml b/packages/MtpDocumentsProvider/res/values-ta/strings.xml
deleted file mode 100644
index c6e6e620..0000000
--- a/packages/MtpDocumentsProvider/res/values-ta/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP ஹோஸ்ட்"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"இறக்கங்கள்"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> இலிருந்து கோப்புகளை அணுகுகிறது"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"பிற சாதனம் பணிமிகுதியில் உள்ளதால், அந்தப் பணி முடியும் வரை கோப்புகளை இடமாற்ற முடியாது."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"கோப்புகள் இல்லை. பிற சாதனம் பூட்டப்பட்டிருக்கக்கூடும் என்பதால் முதலில் அதைத் திறந்து, மீண்டும் முயலவும்."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-te/strings.xml b/packages/MtpDocumentsProvider/res/values-te/strings.xml
deleted file mode 100644
index b3436bf..0000000
--- a/packages/MtpDocumentsProvider/res/values-te/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP హోస్ట్"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"డౌన్‌లోడ్‌లు"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> నుండి ఫైల్‌లను యాక్సెస్ చేస్తోంది"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"ఇతర పరికరం బిజీగా ఉంది. అది అందుబాటులోకి వచ్చే వరకు మీరు ఫైల్‌లను బదిలీ చేయలేరు."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"ఫైల్‍లు ఏవీ కనుగొనబడలేదు. ఇతర పరికరం లాక్ చేయబడి ఉండవచ్చు. అలా జరిగి ఉంటే, దాన్ని అన్‌లాక్ చేసి, ఆపై మళ్లీ ప్రయత్నించండి."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-th/strings.xml b/packages/MtpDocumentsProvider/res/values-th/strings.xml
deleted file mode 100644
index d2b62fe..0000000
--- a/packages/MtpDocumentsProvider/res/values-th/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"โฮสต์ MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"ดาวน์โหลด"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"กำลังเข้าถึงไฟล์จาก <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"อุปกรณ์อีกเครื่องหนึ่งไม่ว่าง คุณไม่สามารถโอนไฟล์จนกว่าอุปกรณ์จะสามารถใช้ได้"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"ไม่พบไฟล์ อุปกรณ์อีกเครื่องหนึ่งอาจล็อกอยู่ หากเป็นเช่นนั้น ให้ปลดล็อกและลองอีกครั้ง"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-tl/strings.xml b/packages/MtpDocumentsProvider/res/values-tl/strings.xml
deleted file mode 100644
index 68b2eba..0000000
--- a/packages/MtpDocumentsProvider/res/values-tl/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Host ng MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Mga Download"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Nag-a-access ng mga file mula sa <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Abala ang kabilang device. Hindi ka makakapaglipat ng mga file hanggang sa maging available ito."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Walang natagpuang mga file. Maaaring naka-lock ang kabilang device. Kung gayon, i-unlock ito at subukang muli."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-tr/strings.xml b/packages/MtpDocumentsProvider/res/values-tr/strings.xml
deleted file mode 100644
index 14250ef..0000000
--- a/packages/MtpDocumentsProvider/res/values-tr/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP Ana Makinesi"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"İndirilenler"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> cihazdaki dosyalara erişiliyor"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Diğer cihaz meşgul. Cihaz kullanılabilir duruma gelene kadar dosyaları aktaramazsınız."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Hiçbir dosya bulunamadı. Diğer cihaz kilitli olabilir. Kilitliyse, kilidini açıp tekrar deneyin."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-uk/strings.xml b/packages/MtpDocumentsProvider/res/values-uk/strings.xml
deleted file mode 100644
index 8589f8c..0000000
--- a/packages/MtpDocumentsProvider/res/values-uk/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Хост MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Завантаження"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Відкриваються файли з пристрою <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Інший пристрій зайнятий. Щоб передавати файли, він має бути доступним."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Не вдалося знайти файли. Можливо, інший пристрій заблоковано. У такому разі розблокуйте його та повторіть спробу."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-ur/strings.xml b/packages/MtpDocumentsProvider/res/values-ur/strings.xml
deleted file mode 100644
index 17578ae..0000000
--- a/packages/MtpDocumentsProvider/res/values-ur/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"‏MTP میزبان"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"ڈاؤن لوڈز"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> سے فائلوں کی رسائی ہو رہی ہے"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"دوسرا آلہ مصروف ہے۔ اس کے دستیاب ہونے تک آپ فائلیں منتقل نہیں کر سکتے۔"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"کوئی فائلیں نہیں ملیں۔ ہو سکتا ہے دوسرا آلہ مقفل ہو۔ اگر ایسا ہے تو اسے غیر مقفل کریں اور دوبارہ کوشش کریں۔"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-uz/strings.xml b/packages/MtpDocumentsProvider/res/values-uz/strings.xml
deleted file mode 100644
index c511172..0000000
--- a/packages/MtpDocumentsProvider/res/values-uz/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP Host"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Yuklanmalar"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g><xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> qurilmasidan fayllar o‘qilmoqda"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Ulangan qurilma band. U bo‘shamaguncha fayllarni o‘tkazib bo‘lmaydi."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Hech qanday fayl topilmadi. Ulangan qurilma qulflangan bo‘lishi mumkin. Agar shunday bo‘lsa, uni qulfdan chiqaring va qayta urinib ko‘ring."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-vi/strings.xml b/packages/MtpDocumentsProvider/res/values-vi/strings.xml
deleted file mode 100644
index 0eb6310..0000000
--- a/packages/MtpDocumentsProvider/res/values-vi/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Máy chủ MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Tải xuống"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Đang truy cập tệp từ <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Thiết bị khác đang bận. Bạn không thể chuyển tệp cho đến khi thiết bị rảnh."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Không tìm thấy tệp. Thiết bị khác có thể đã bị khóa. Nếu như vậy, hãy mở khóa thiết bị rồi thử lại."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-zh-rCN/strings.xml b/packages/MtpDocumentsProvider/res/values-zh-rCN/strings.xml
deleted file mode 100644
index 7f1f394..0000000
--- a/packages/MtpDocumentsProvider/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"MTP 主机"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"下载"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"正在访问 <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> 的文件"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"另一台设备正忙。您必须等到该设备可用时才能传输文件。"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"未找到任何文件。另一台设备可能处于锁定状态;如果是这样,请解锁该设备并重试。"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-zh-rHK/strings.xml b/packages/MtpDocumentsProvider/res/values-zh-rHK/strings.xml
deleted file mode 100644
index be8c548..0000000
--- a/packages/MtpDocumentsProvider/res/values-zh-rHK/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"媒體傳輸協定主機"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"下載"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> 的「<xliff:g id="STORAGE_NAME">%2$s</xliff:g>」"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"正在從 <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> 存取檔案"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"另一部裝置目前處於忙碌狀態,要等到該裝置可用時才能轉移檔案。"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"找不到檔案。如果另一部裝置處於鎖定狀態,請解鎖該裝置,然後再試一次。"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-zh-rTW/strings.xml b/packages/MtpDocumentsProvider/res/values-zh-rTW/strings.xml
deleted file mode 100644
index 2fe3c06..0000000
--- a/packages/MtpDocumentsProvider/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"媒體傳輸通訊協定主機"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"下載"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"正在從 <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> 存取檔案"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"另一個裝置忙碌中。必須等到該裝置可用時才能轉移檔案。"</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"找不到任何檔案。如果另一個裝置處於鎖定狀態,請將該裝置解鎖後再試一次。"</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-zu/strings.xml b/packages/MtpDocumentsProvider/res/values-zu/strings.xml
deleted file mode 100644
index f3f7206..0000000
--- a/packages/MtpDocumentsProvider/res/values-zu/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="6271216747302322594">"Ukusingatha kwe-MTP"</string>
-    <string name="downloads_app_label" msgid="7120690641874849726">"Okulandiwe"</string>
-    <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Ifinyelela kumafayela kusukela ku-<xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="error_busy_device" msgid="3997316850357386589">"Enye idivayisi imatasatasa. Awukwazi ukudlulisela amafayela ize itholakale."</string>
-    <string name="error_locked_device" msgid="7557872102188356147">"Awekho amafayela atholiwe. Enye idivayisi kungenzeka ikhiyiwe. Uma kunjalo, yivule uphinde uzame futhi."</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/values/strings.xml b/packages/MtpDocumentsProvider/res/values/strings.xml
deleted file mode 100644
index b94aba0..0000000
--- a/packages/MtpDocumentsProvider/res/values/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- App title of MtpDocumentsProvider [CHAR LIMIT=32] -->
-    <string name="app_label">MTP Host</string>
-    <!-- App title of DocumentsUI [CHAR LIMIT=32] -->
-    <string name="downloads_app_label">Downloads</string>
-    <!-- Name of MTP root shown in UI. Please align the two strings (device
-         model and storage name) in proper order in the language.
-         [CHAR LIMIT=32] -->
-    <string name="root_name"><xliff:g id="device_model" example="Nexus 9">%1$s</xliff:g> <xliff:g id="storage_name" example="Internal Storage">%2$s</xliff:g></string>
-    <!-- Title of notification showing Files app is accessing files in a MTP device. [CHAR LIMIT=60]-->
-    <string name="accessing_notification_title">Accessing files from <xliff:g id="device_model" example="Nexus 9">%1$s</xliff:g></string>
-    <!-- Error message shown in Files app when the connected MTP device is busy. [CHAR LIMIT=150]-->
-    <string name="error_busy_device">The other device is busy. You can\'t transfer files until it\'s available.</string>
-    <!-- Error message shown in Files app when the connected MTP device may be locked. [CHAR LIMIT=150]-->
-    <string name="error_locked_device">No files found. The other device may be locked. If so, unlock it and try again.</string>
-</resources>
diff --git a/packages/MtpDocumentsProvider/res/xml/device_filter.xml b/packages/MtpDocumentsProvider/res/xml/device_filter.xml
deleted file mode 100644
index 7afa2b1..0000000
--- a/packages/MtpDocumentsProvider/res/xml/device_filter.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <!-- filter for MTP/PTP devices -->
-    <usb-device class="255" subclass="255" protocol="0" />
-    <usb-device class="6" subclass="1" protocol="1" />
-</resources>
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/BusyDeviceException.java b/packages/MtpDocumentsProvider/src/com/android/mtp/BusyDeviceException.java
deleted file mode 100644
index 83488cd..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/BusyDeviceException.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import java.io.IOException;
-
-/**
- * Exception thrown when the device is busy and the requested operation cannon be completed.
- */
-class BusyDeviceException extends IOException {
-    BusyDeviceException() {
-        super("The MTP device is busy.");
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
deleted file mode 100644
index 6ed4ea1..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.annotation.Nullable;
-import android.annotation.WorkerThread;
-import android.content.ContentResolver;
-import android.database.Cursor;
-import android.mtp.MtpConstants;
-import android.mtp.MtpObjectInfo;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Process;
-import android.provider.DocumentsContract;
-import android.util.Log;
-
-import com.android.internal.util.Preconditions;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.LinkedList;
-
-/**
- * Loader for MTP document.
- * At the first request, the loader returns only first NUM_INITIAL_ENTRIES. Then it launches
- * background thread to load the rest documents and caches its result for next requests.
- * TODO: Rename this class to ObjectInfoLoader
- */
-class DocumentLoader implements AutoCloseable {
-    static final int NUM_INITIAL_ENTRIES = 10;
-    static final int NUM_LOADING_ENTRIES = 20;
-    static final int NOTIFY_PERIOD_MS = 500;
-
-    private final MtpDeviceRecord mDevice;
-    private final MtpManager mMtpManager;
-    private final ContentResolver mResolver;
-    private final MtpDatabase mDatabase;
-    private final TaskList mTaskList = new TaskList();
-    private Thread mBackgroundThread;
-
-    DocumentLoader(MtpDeviceRecord device, MtpManager mtpManager, ContentResolver resolver,
-                   MtpDatabase database) {
-        mDevice = device;
-        mMtpManager = mtpManager;
-        mResolver = resolver;
-        mDatabase = database;
-    }
-
-    /**
-     * Queries the child documents of given parent.
-     * It loads the first NUM_INITIAL_ENTRIES of object info, then launches the background thread
-     * to load the rest.
-     */
-    synchronized Cursor queryChildDocuments(String[] columnNames, Identifier parent)
-            throws IOException {
-        assert parent.mDeviceId == mDevice.deviceId;
-
-        LoaderTask task = mTaskList.findTask(parent);
-        if (task == null) {
-            if (parent.mDocumentId == null) {
-                throw new FileNotFoundException("Parent not found.");
-            }
-            // TODO: Handle nit race around here.
-            // 1. getObjectHandles.
-            // 2. putNewDocument.
-            // 3. startAddingChildDocuemnts.
-            // 4. stopAddingChildDocuments - It removes the new document added at the step 2,
-            //     because it is not updated between start/stopAddingChildDocuments.
-            task = new LoaderTask(mMtpManager, mDatabase, mDevice.operationsSupported, parent);
-            task.loadObjectHandles();
-            task.loadObjectInfoList(NUM_INITIAL_ENTRIES);
-        } else {
-            // Once remove the existing task in order to add it to the head of the list.
-            mTaskList.remove(task);
-        }
-
-        mTaskList.addFirst(task);
-        if (task.getState() == LoaderTask.STATE_LOADING) {
-            resume();
-        }
-        return task.createCursor(mResolver, columnNames);
-    }
-
-    /**
-     * Resumes a background thread.
-     */
-    synchronized void resume() {
-        if (mBackgroundThread == null) {
-            mBackgroundThread = new BackgroundLoaderThread();
-            mBackgroundThread.start();
-        }
-    }
-
-    /**
-     * Obtains next task to be run in background thread, or release the reference to background
-     * thread.
-     *
-     * Worker thread that receives null task needs to exit.
-     */
-    @WorkerThread
-    synchronized @Nullable LoaderTask getNextTaskOrReleaseBackgroundThread() {
-        Preconditions.checkState(mBackgroundThread != null);
-
-        for (final LoaderTask task : mTaskList) {
-            if (task.getState() == LoaderTask.STATE_LOADING) {
-                return task;
-            }
-        }
-
-        final Identifier identifier = mDatabase.getUnmappedDocumentsParent(mDevice.deviceId);
-        if (identifier != null) {
-            final LoaderTask existingTask = mTaskList.findTask(identifier);
-            if (existingTask != null) {
-                Preconditions.checkState(existingTask.getState() != LoaderTask.STATE_LOADING);
-                mTaskList.remove(existingTask);
-            }
-            final LoaderTask newTask = new LoaderTask(
-                    mMtpManager, mDatabase, mDevice.operationsSupported, identifier);
-            newTask.loadObjectHandles();
-            mTaskList.addFirst(newTask);
-            return newTask;
-        }
-
-        mBackgroundThread = null;
-        return null;
-    }
-
-    /**
-     * Terminates background thread.
-     */
-    @Override
-    public void close() throws InterruptedException {
-        final Thread thread;
-        synchronized (this) {
-            mTaskList.clear();
-            thread = mBackgroundThread;
-        }
-        if (thread != null) {
-            thread.interrupt();
-            thread.join();
-        }
-    }
-
-    synchronized void clearCompletedTasks() {
-        mTaskList.clearCompletedTasks();
-    }
-
-    /**
-     * Cancels the task for |parentIdentifier|.
-     *
-     * Task is removed from the cached list and it will create new task when |parentIdentifier|'s
-     * children are queried next.
-     */
-    void cancelTask(Identifier parentIdentifier) {
-        final LoaderTask task;
-        synchronized (this) {
-            task = mTaskList.findTask(parentIdentifier);
-        }
-        if (task != null) {
-            task.cancel();
-            mTaskList.remove(task);
-        }
-    }
-
-    /**
-     * Background thread to fetch object info.
-     */
-    private class BackgroundLoaderThread extends Thread {
-        /**
-         * Finds task that needs to be processed, then loads NUM_LOADING_ENTRIES of object info and
-         * store them to the database. If it does not find a task, exits the thread.
-         */
-        @Override
-        public void run() {
-            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-            while (!Thread.interrupted()) {
-                final LoaderTask task = getNextTaskOrReleaseBackgroundThread();
-                if (task == null) {
-                    return;
-                }
-                task.loadObjectInfoList(NUM_LOADING_ENTRIES);
-                final boolean shouldNotify =
-                        task.getState() != LoaderTask.STATE_CANCELLED &&
-                        (task.mLastNotified.getTime() <
-                         new Date().getTime() - NOTIFY_PERIOD_MS ||
-                         task.getState() != LoaderTask.STATE_LOADING);
-                if (shouldNotify) {
-                    task.notify(mResolver);
-                }
-            }
-        }
-    }
-
-    /**
-     * Task list that has helper methods to search/clear tasks.
-     */
-    private static class TaskList extends LinkedList<LoaderTask> {
-        LoaderTask findTask(Identifier parent) {
-            for (int i = 0; i < size(); i++) {
-                if (get(i).mIdentifier.equals(parent))
-                    return get(i);
-            }
-            return null;
-        }
-
-        void clearCompletedTasks() {
-            int i = 0;
-            while (i < size()) {
-                if (get(i).getState() == LoaderTask.STATE_COMPLETED) {
-                    remove(i);
-                } else {
-                    i++;
-                }
-            }
-        }
-    }
-
-    /**
-     * Loader task.
-     * Each task is responsible for fetching child documents for the given parent document.
-     */
-    private static class LoaderTask {
-        static final int STATE_START = 0;
-        static final int STATE_LOADING = 1;
-        static final int STATE_COMPLETED = 2;
-        static final int STATE_ERROR = 3;
-        static final int STATE_CANCELLED = 4;
-
-        final MtpManager mManager;
-        final MtpDatabase mDatabase;
-        final int[] mOperationsSupported;
-        final Identifier mIdentifier;
-        int[] mObjectHandles;
-        int mState;
-        Date mLastNotified;
-        int mPosition;
-        IOException mError;
-
-        LoaderTask(MtpManager manager, MtpDatabase database, int[] operationsSupported,
-                Identifier identifier) {
-            assert operationsSupported != null;
-            assert identifier.mDocumentType != MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE;
-            mManager = manager;
-            mDatabase = database;
-            mOperationsSupported = operationsSupported;
-            mIdentifier = identifier;
-            mObjectHandles = null;
-            mState = STATE_START;
-            mPosition = 0;
-            mLastNotified = new Date();
-        }
-
-        synchronized void loadObjectHandles() {
-            assert mState == STATE_START;
-            mPosition = 0;
-            int parentHandle = mIdentifier.mObjectHandle;
-            // Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
-            // getObjectHandles if we would like to obtain children under the root.
-            if (mIdentifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE) {
-                parentHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
-            }
-            try {
-                mObjectHandles = mManager.getObjectHandles(
-                        mIdentifier.mDeviceId, mIdentifier.mStorageId, parentHandle);
-                mState = STATE_LOADING;
-            } catch (IOException error) {
-                mError = error;
-                mState = STATE_ERROR;
-            }
-        }
-
-        /**
-         * Returns a cursor that traverses the child document of the parent document handled by the
-         * task.
-         * The returned task may have a EXTRA_LOADING flag.
-         */
-        synchronized Cursor createCursor(ContentResolver resolver, String[] columnNames)
-                throws IOException {
-            final Bundle extras = new Bundle();
-            switch (getState()) {
-                case STATE_LOADING:
-                    extras.putBoolean(DocumentsContract.EXTRA_LOADING, true);
-                    break;
-                case STATE_ERROR:
-                    throw mError;
-            }
-            final Cursor cursor =
-                    mDatabase.queryChildDocuments(columnNames, mIdentifier.mDocumentId);
-            cursor.setExtras(extras);
-            cursor.setNotificationUri(resolver, createUri());
-            return cursor;
-        }
-
-        /**
-         * Stores object information into database.
-         */
-        void loadObjectInfoList(int count) {
-            synchronized (this) {
-                if (mState != STATE_LOADING) {
-                    return;
-                }
-                if (mPosition == 0) {
-                    try{
-                        mDatabase.getMapper().startAddingDocuments(mIdentifier.mDocumentId);
-                    } catch (FileNotFoundException error) {
-                        mError = error;
-                        mState = STATE_ERROR;
-                        return;
-                    }
-                }
-            }
-            final ArrayList<MtpObjectInfo> infoList = new ArrayList<>();
-            for (int chunkEnd = mPosition + count;
-                    mPosition < mObjectHandles.length && mPosition < chunkEnd;
-                    mPosition++) {
-                try {
-                    infoList.add(mManager.getObjectInfo(
-                            mIdentifier.mDeviceId, mObjectHandles[mPosition]));
-                } catch (IOException error) {
-                    Log.e(MtpDocumentsProvider.TAG, "Failed to load object info", error);
-                }
-            }
-            final long[] objectSizeList = new long[infoList.size()];
-            for (int i = 0; i < infoList.size(); i++) {
-                final MtpObjectInfo info = infoList.get(i);
-                // Compressed size is 32-bit unsigned integer but getCompressedSize returns the
-                // value in Java int (signed 32-bit integer). Use getCompressedSizeLong instead
-                // to get the value in Java long.
-                if (info.getCompressedSizeLong() != 0xffffffffl) {
-                    objectSizeList[i] = info.getCompressedSizeLong();
-                    continue;
-                }
-
-                if (!MtpDeviceRecord.isSupported(
-                        mOperationsSupported,
-                        MtpConstants.OPERATION_GET_OBJECT_PROP_DESC) ||
-                        !MtpDeviceRecord.isSupported(
-                                mOperationsSupported,
-                                MtpConstants.OPERATION_GET_OBJECT_PROP_VALUE)) {
-                    objectSizeList[i] = -1;
-                    continue;
-                }
-
-                // Object size is more than 4GB.
-                try {
-                    objectSizeList[i] = mManager.getObjectSizeLong(
-                            mIdentifier.mDeviceId,
-                            info.getObjectHandle(),
-                            info.getFormat());
-                } catch (IOException error) {
-                    Log.e(MtpDocumentsProvider.TAG, "Failed to get object size property.", error);
-                    objectSizeList[i] = -1;
-                }
-            }
-            synchronized (this) {
-                // Check if the task is cancelled or not.
-                if (mState != STATE_LOADING) {
-                    return;
-                }
-                try {
-                    mDatabase.getMapper().putChildDocuments(
-                            mIdentifier.mDeviceId,
-                            mIdentifier.mDocumentId,
-                            mOperationsSupported,
-                            infoList.toArray(new MtpObjectInfo[infoList.size()]),
-                            objectSizeList);
-                } catch (FileNotFoundException error) {
-                    // Looks like the parent document information is removed.
-                    // Adding documents has already cancelled in Mapper so we don't need to invoke
-                    // stopAddingDocuments.
-                    mError = error;
-                    mState = STATE_ERROR;
-                    return;
-                }
-                if (mPosition >= mObjectHandles.length) {
-                    try{
-                        mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
-                        mState = STATE_COMPLETED;
-                    } catch (FileNotFoundException error) {
-                        mError = error;
-                        mState = STATE_ERROR;
-                        return;
-                    }
-                }
-            }
-        }
-
-        /**
-         * Cancels the task.
-         */
-        synchronized void cancel() {
-            mDatabase.getMapper().cancelAddingDocuments(mIdentifier.mDocumentId);
-            mState = STATE_CANCELLED;
-        }
-
-        /**
-         * Returns a state of the task.
-         */
-        int getState() {
-            return mState;
-        }
-
-        /**
-         * Notifies a change of child list of the document.
-         */
-        void notify(ContentResolver resolver) {
-            resolver.notifyChange(createUri(), null, false);
-            mLastNotified = new Date();
-        }
-
-        private Uri createUri() {
-            return DocumentsContract.buildChildDocumentsUri(
-                    MtpDocumentsProvider.AUTHORITY, mIdentifier.mDocumentId);
-        }
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java
deleted file mode 100644
index 124d207..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import java.util.Objects;
-import static com.android.mtp.MtpDatabaseConstants.DocumentType;
-
-/**
- * Static utilities for ID.
- */
-class Identifier {
-    final int mDeviceId;
-    final int mStorageId;
-    final int mObjectHandle;
-    final String mDocumentId;
-    final @DocumentType int mDocumentType;
-
-    Identifier(int deviceId, int storageId, int objectHandle, String documentId,
-            @DocumentType int documentType) {
-        mDeviceId = deviceId;
-        mStorageId = storageId;
-        mObjectHandle = objectHandle;
-        mDocumentId = documentId;
-        mDocumentType = documentType;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof Identifier))
-            return false;
-        final Identifier other = (Identifier) obj;
-        return mDeviceId == other.mDeviceId && mStorageId == other.mStorageId &&
-                mObjectHandle == other.mObjectHandle && mDocumentId.equals(other.mDocumentId);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mDeviceId, mStorageId, mObjectHandle, mDocumentId);
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder builder = new StringBuilder();
-        builder.append("Identifier { ");
-
-        builder.append("mDeviceId: ");
-        builder.append(mDeviceId);
-        builder.append(", ");
-
-        builder.append("mStorageId: ");
-        builder.append(mStorageId);
-        builder.append(", ");
-
-        builder.append("mObjectHandle: ");
-        builder.append(mObjectHandle);
-        builder.append(", ");
-
-        builder.append("mDocumentId: ");
-        builder.append(mDocumentId);
-        builder.append(", ");
-
-        builder.append("mDocumentType: ");
-        builder.append(mDocumentType);
-        builder.append(" }");
-        return builder.toString();
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
deleted file mode 100644
index 63f18f3..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.annotation.Nullable;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.database.sqlite.SQLiteDatabase;
-import android.mtp.MtpObjectInfo;
-import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract.Root;
-import android.util.ArraySet;
-import android.util.Log;
-
-import com.android.internal.util.Preconditions;
-
-import java.io.FileNotFoundException;
-import java.util.Set;
-
-import static com.android.mtp.MtpDatabaseConstants.*;
-import static com.android.mtp.MtpDatabase.strings;
-
-/**
- * Mapping operations for MtpDatabase.
- * Also see the comments of {@link MtpDatabase}.
- */
-class Mapper {
-    private static final String[] EMPTY_ARGS = new String[0];
-    private final MtpDatabase mDatabase;
-
-    /**
-     * IDs which currently Mapper operates mapping for.
-     */
-    private final Set<String> mInMappingIds = new ArraySet<>();
-
-    Mapper(MtpDatabase database) {
-        mDatabase = database;
-    }
-
-    /**
-     * Puts device information to database.
-     *
-     * @return If device is added to the database.
-     * @throws FileNotFoundException
-     */
-    synchronized boolean putDeviceDocument(MtpDeviceRecord device) throws FileNotFoundException {
-        final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
-        database.beginTransaction();
-        try {
-            final ContentValues[] valuesList = new ContentValues[1];
-            final ContentValues[] extraValuesList = new ContentValues[1];
-            valuesList[0] = new ContentValues();
-            extraValuesList[0] = new ContentValues();
-            MtpDatabase.getDeviceDocumentValues(valuesList[0], extraValuesList[0], device);
-            final boolean changed = putDocuments(
-                    null,
-                    valuesList,
-                    extraValuesList,
-                    COLUMN_PARENT_DOCUMENT_ID + " IS NULL",
-                    EMPTY_ARGS,
-                    strings(COLUMN_DEVICE_ID, COLUMN_MAPPING_KEY));
-            database.setTransactionSuccessful();
-            return changed;
-        } finally {
-            database.endTransaction();
-        }
-    }
-
-    /**
-     * Puts root information to database.
-     *
-     * @param parentDocumentId Document ID of device document.
-     * @param roots List of root information.
-     * @return If roots are added or removed from the database.
-     * @throws FileNotFoundException
-     */
-    synchronized boolean putStorageDocuments(
-            String parentDocumentId, int[] operationsSupported, MtpRoot[] roots)
-            throws FileNotFoundException {
-        final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
-        database.beginTransaction();
-        try {
-            final ContentValues[] valuesList = new ContentValues[roots.length];
-            final ContentValues[] extraValuesList = new ContentValues[roots.length];
-            for (int i = 0; i < roots.length; i++) {
-                valuesList[i] = new ContentValues();
-                extraValuesList[i] = new ContentValues();
-                MtpDatabase.getStorageDocumentValues(
-                        valuesList[i],
-                        extraValuesList[i],
-                        parentDocumentId,
-                        operationsSupported,
-                        roots[i]);
-            }
-            final boolean changed = putDocuments(
-                    parentDocumentId,
-                    valuesList,
-                    extraValuesList,
-                    COLUMN_PARENT_DOCUMENT_ID + " = ?",
-                    strings(parentDocumentId),
-                    strings(COLUMN_STORAGE_ID, Document.COLUMN_DISPLAY_NAME));
-
-            database.setTransactionSuccessful();
-            return changed;
-        } finally {
-            database.endTransaction();
-        }
-    }
-
-    /**
-     * Puts document information to database.
-     *
-     * @param deviceId Device ID
-     * @param parentId Parent document ID.
-     * @param documents List of document information.
-     * @param documentSizes 64-bit size of documents. MtpObjectInfo#getComporessedSize will be
-     *     ignored because it does not contain 4GB> object size. Can be -1 if the size is unknown.
-     * @throws FileNotFoundException
-     */
-    synchronized void putChildDocuments(
-            int deviceId, String parentId,
-            int[] operationsSupported,
-            MtpObjectInfo[] documents,
-            long[] documentSizes)
-            throws FileNotFoundException {
-        assert documents.length == documentSizes.length;
-        final ContentValues[] valuesList = new ContentValues[documents.length];
-        for (int i = 0; i < documents.length; i++) {
-            valuesList[i] = new ContentValues();
-            MtpDatabase.getObjectDocumentValues(
-                    valuesList[i],
-                    deviceId,
-                    parentId,
-                    operationsSupported,
-                    documents[i],
-                    documentSizes[i]);
-        }
-        putDocuments(
-                parentId,
-                valuesList,
-                null,
-                COLUMN_PARENT_DOCUMENT_ID + " = ?",
-                strings(parentId),
-                strings(COLUMN_OBJECT_HANDLE, Document.COLUMN_DISPLAY_NAME));
-    }
-
-    void clearMapping() {
-        final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
-        database.beginTransaction();
-        try {
-            mInMappingIds.clear();
-            // Disconnect all device rows.
-            try {
-                startAddingDocuments(null);
-                stopAddingDocuments(null);
-            } catch (FileNotFoundException exception) {
-                Log.e(MtpDocumentsProvider.TAG, "Unexpected FileNotFoundException.", exception);
-                throw new RuntimeException(exception);
-            }
-            database.setTransactionSuccessful();
-        } finally {
-            database.endTransaction();
-        }
-    }
-
-    /**
-     * Starts adding new documents.
-     * It changes the direct child documents of the given document from VALID to INVALIDATED.
-     * Note that it keeps DISCONNECTED documents as they are.
-     *
-     * @param parentDocumentId Parent document ID or NULL for root documents.
-     * @throws FileNotFoundException
-     */
-    void startAddingDocuments(@Nullable String parentDocumentId) throws FileNotFoundException {
-        final String selection;
-        final String[] args;
-        if (parentDocumentId != null) {
-            selection = COLUMN_PARENT_DOCUMENT_ID + " = ?";
-            args = strings(parentDocumentId);
-        } else {
-            selection = COLUMN_PARENT_DOCUMENT_ID + " IS NULL";
-            args = EMPTY_ARGS;
-        }
-
-        final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
-        database.beginTransaction();
-        try {
-            getParentOrHaltMapping(parentDocumentId);
-            Preconditions.checkState(!mInMappingIds.contains(parentDocumentId));
-
-            // Set all valid documents as invalidated.
-            final ContentValues values = new ContentValues();
-            values.put(COLUMN_ROW_STATE, ROW_STATE_INVALIDATED);
-            database.update(
-                    TABLE_DOCUMENTS,
-                    values,
-                    selection + " AND " + COLUMN_ROW_STATE + " = ?",
-                    DatabaseUtils.appendSelectionArgs(args, strings(ROW_STATE_VALID)));
-
-            database.setTransactionSuccessful();
-            mInMappingIds.add(parentDocumentId);
-        } finally {
-            database.endTransaction();
-        }
-    }
-
-    /**
-     * Puts the documents into the database.
-     * If the mapping mode is not heuristic, it just adds the rows to the database or updates the
-     * existing rows with the new values. If the mapping mode is heuristic, it adds some new rows as
-     * 'pending' state when that rows may be corresponding to existing 'invalidated' rows. Then
-     * {@link #stopAddingDocuments(String)} turns the pending rows into 'valid'
-     * rows. If the methods adds rows to database, it updates valueList with correct document ID.
-     *
-     * @param parentId Parent document ID.
-     * @param valuesList Values for documents to be stored in the database.
-     * @param rootExtraValuesList Values for root extra to be stored in the database.
-     * @param selection SQL where closure to select rows that shares the same parent.
-     * @param args Argument for selection SQL.
-     * @return Whether the database content is changed.
-     * @throws FileNotFoundException When parentId is not registered in the database.
-     */
-    private boolean putDocuments(
-            String parentId,
-            ContentValues[] valuesList,
-            @Nullable ContentValues[] rootExtraValuesList,
-            String selection,
-            String[] args,
-            String[] mappingKeys) throws FileNotFoundException {
-        final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
-        boolean changed = false;
-        database.beginTransaction();
-        try {
-            getParentOrHaltMapping(parentId);
-            Preconditions.checkState(mInMappingIds.contains(parentId));
-            final ContentValues oldRowSnapshot = new ContentValues();
-            final ContentValues newRowSnapshot = new ContentValues();
-            for (int i = 0; i < valuesList.length; i++) {
-                final ContentValues values = valuesList[i];
-                final ContentValues rootExtraValues;
-                if (rootExtraValuesList != null) {
-                    rootExtraValues = rootExtraValuesList[i];
-                } else {
-                    rootExtraValues = null;
-                }
-                try (final Cursor candidateCursor =
-                        queryCandidate(selection, args, mappingKeys, values)) {
-                    final long rowId;
-                    if (candidateCursor == null) {
-                        rowId = database.insert(TABLE_DOCUMENTS, null, values);
-                        changed = true;
-                    } else {
-                        candidateCursor.moveToNext();
-                        rowId = candidateCursor.getLong(0);
-                        if (!changed) {
-                            mDatabase.writeRowSnapshot(String.valueOf(rowId), oldRowSnapshot);
-                        }
-                        database.update(
-                                TABLE_DOCUMENTS,
-                                values,
-                                SELECTION_DOCUMENT_ID,
-                                strings(rowId));
-                    }
-                    // Document ID is a primary integer key of the table. So the returned row
-                    // IDs should be same with the document ID.
-                    values.put(Document.COLUMN_DOCUMENT_ID, rowId);
-                    if (rootExtraValues != null) {
-                        rootExtraValues.put(Root.COLUMN_ROOT_ID, rowId);
-                        database.replace(TABLE_ROOT_EXTRA, null, rootExtraValues);
-                    }
-
-                    if (!changed) {
-                        mDatabase.writeRowSnapshot(String.valueOf(rowId), newRowSnapshot);
-                        // Put row state as string because SQLite returns snapshot values as string.
-                        oldRowSnapshot.put(COLUMN_ROW_STATE, String.valueOf(ROW_STATE_VALID));
-                        if (!oldRowSnapshot.equals(newRowSnapshot)) {
-                            changed = true;
-                        }
-                    }
-                }
-            }
-
-            database.setTransactionSuccessful();
-            return changed;
-        } finally {
-            database.endTransaction();
-        }
-    }
-
-    /**
-     * Stops adding documents.
-     * It handles 'invalidated' and 'disconnected' documents which we don't put corresponding
-     * documents so far.
-     * If the type adding document is 'device' or 'storage', the document may appear again
-     * afterward. The method marks such documents as 'disconnected'. If the type of adding document
-     * is 'object', it seems the documents are really removed from the remote MTP device. So the
-     * method deletes the metadata from the database.
-     *
-     * @param parentId Parent document ID or null for root documents.
-     * @return Whether the methods changes file metadata in database.
-     * @throws FileNotFoundException
-     */
-    boolean stopAddingDocuments(@Nullable String parentId) throws FileNotFoundException {
-        final String selection;
-        final String[] args;
-        if (parentId != null) {
-            selection = COLUMN_PARENT_DOCUMENT_ID + " = ?";
-            args = strings(parentId);
-        } else {
-            selection = COLUMN_PARENT_DOCUMENT_ID + " IS NULL";
-            args = EMPTY_ARGS;
-        }
-
-        final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
-        database.beginTransaction();
-        try {
-            final Identifier parentIdentifier = getParentOrHaltMapping(parentId);
-            Preconditions.checkState(mInMappingIds.contains(parentId));
-            mInMappingIds.remove(parentId);
-
-            boolean changed = false;
-            // Delete/disconnect all invalidated/disconnected rows that cannot be mapped.
-            // If parentIdentifier is null, added documents are devices.
-            // if parentIdentifier is DOCUMENT_TYPE_DEVICE, added documents are storages.
-            final boolean keepUnmatchedDocument =
-                    parentIdentifier == null ||
-                    parentIdentifier.mDocumentType == DOCUMENT_TYPE_DEVICE;
-            if (keepUnmatchedDocument) {
-                if (mDatabase.disconnectDocumentsRecursively(
-                        COLUMN_ROW_STATE + " = ? AND " + selection,
-                        DatabaseUtils.appendSelectionArgs(strings(ROW_STATE_INVALIDATED), args))) {
-                    changed = true;
-                }
-            } else {
-                if (mDatabase.deleteDocumentsAndRootsRecursively(
-                        COLUMN_ROW_STATE + " IN (?, ?) AND " + selection,
-                        DatabaseUtils.appendSelectionArgs(
-                                strings(ROW_STATE_INVALIDATED, ROW_STATE_DISCONNECTED), args))) {
-                    changed = true;
-                }
-            }
-
-            database.setTransactionSuccessful();
-            return changed;
-        } finally {
-            database.endTransaction();
-        }
-    }
-
-    /**
-     * Cancels adding documents.
-     * @param parentId
-     */
-    void cancelAddingDocuments(@Nullable String parentId) {
-        final String selection;
-        final String[] args;
-        if (parentId != null) {
-            selection = COLUMN_PARENT_DOCUMENT_ID + " = ?";
-            args = strings(parentId);
-        } else {
-            selection = COLUMN_PARENT_DOCUMENT_ID + " IS NULL";
-            args = EMPTY_ARGS;
-        }
-
-        final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
-        database.beginTransaction();
-        try {
-            if (!mInMappingIds.contains(parentId)) {
-                return;
-            }
-            mInMappingIds.remove(parentId);
-            final ContentValues values = new ContentValues();
-            values.put(COLUMN_ROW_STATE, ROW_STATE_VALID);
-            mDatabase.getSQLiteDatabase().update(
-                    TABLE_DOCUMENTS,
-                    values,
-                    selection + " AND " + COLUMN_ROW_STATE + " = ?",
-                    DatabaseUtils.appendSelectionArgs(args, strings(ROW_STATE_INVALIDATED)));
-            database.setTransactionSuccessful();
-        } finally {
-            database.endTransaction();
-        }
-    }
-
-    /**
-     * Queries candidate for each mappingKey, and returns the first cursor that includes a
-     * candidate.
-     *
-     * @param selection Pre-selection for candidate.
-     * @param args Arguments for selection.
-     * @param mappingKeys List of mapping key columns.
-     * @param values Values of document that Mapper tries to map.
-     * @return Cursor for mapping candidate or null when Mapper does not find any candidate.
-     */
-    private @Nullable Cursor queryCandidate(
-            String selection, String[] args, String[] mappingKeys, ContentValues values) {
-        for (final String mappingKey : mappingKeys) {
-            final Cursor candidateCursor = queryCandidate(selection, args, mappingKey, values);
-            if (candidateCursor.getCount() == 0) {
-                candidateCursor.close();
-                continue;
-            }
-            return candidateCursor;
-        }
-        return null;
-    }
-
-    /**
-     * Looks for mapping candidate with given mappingKey.
-     *
-     * @param selection Pre-selection for candidate.
-     * @param args Arguments for selection.
-     * @param mappingKey Column name of mapping key.
-     * @param values Values of document that Mapper tries to map.
-     * @return Cursor for mapping candidate.
-     */
-    private Cursor queryCandidate(
-            String selection, String[] args, String mappingKey, ContentValues values) {
-        final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
-        return database.query(
-                TABLE_DOCUMENTS,
-                strings(Document.COLUMN_DOCUMENT_ID),
-                selection + " AND " +
-                COLUMN_ROW_STATE + " IN (?, ?) AND " +
-                mappingKey + " = ?",
-                DatabaseUtils.appendSelectionArgs(
-                        args,
-                        strings(ROW_STATE_INVALIDATED,
-                                ROW_STATE_DISCONNECTED,
-                                values.getAsString(mappingKey))),
-                null,
-                null,
-                null,
-                "1");
-    }
-
-    /**
-     * Returns the parent identifier from parent document ID if the parent ID is found in the
-     * database. Otherwise it halts mapping and throws FileNotFoundException.
-     *
-     * @param parentId Parent document ID
-     * @return Parent identifier
-     * @throws FileNotFoundException
-     */
-    private @Nullable Identifier getParentOrHaltMapping(
-            @Nullable String parentId) throws FileNotFoundException {
-        if (parentId == null) {
-            return null;
-        }
-        try {
-            return mDatabase.createIdentifier(parentId);
-        } catch (FileNotFoundException error) {
-            mInMappingIds.remove(parentId);
-            throw error;
-        }
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
deleted file mode 100644
index 59c205a..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ /dev/null
@@ -1,921 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import static com.android.mtp.MtpDatabaseConstants.*;
-
-import android.annotation.Nullable;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.database.MatrixCursor;
-import android.database.MatrixCursor.RowBuilder;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteQueryBuilder;
-import android.media.MediaFile;
-import android.mtp.MtpConstants;
-import android.mtp.MtpObjectInfo;
-import android.net.Uri;
-import android.provider.DocumentsContract;
-import android.provider.MetadataReader;
-import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract.Root;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
-
-import java.io.FileNotFoundException;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Database for MTP objects.
- * The object handle which is identifier for object in MTP protocol is not stable over sessions.
- * When we resume the process, we need to remap our document ID with MTP's object handle.
- *
- * If the remote MTP device is backed by typical file system, the file name
- * is unique among files in a directory. However, MTP protocol itself does
- * not guarantee the uniqueness of name so we cannot use fullpath as ID.
- *
- * Instead of fullpath, we use artificial ID generated by MtpDatabase itself. The database object
- * remembers the map of document ID and object handle, and remaps new object handle with document ID
- * by comparing the directory structure and object name.
- *
- * To start putting documents into the database, the client needs to call
- * {@link Mapper#startAddingDocuments(String)} with the parent document ID. Also it
- * needs to call {@link Mapper#stopAddingDocuments(String)} after putting all child
- * documents to the database. (All explanations are same for root documents)
- *
- * database.getMapper().startAddingDocuments();
- * database.getMapper().putChildDocuments();
- * database.getMapper().stopAddingDocuments();
- *
- * To update the existing documents, the client code can repeat to call the three methods again.
- * The newly added rows update corresponding existing rows that have same MTP identifier like
- * objectHandle.
- *
- * The client can call putChildDocuments multiple times to add documents by chunk, but it needs to
- * put all documents under the parent before calling stopAddingChildDocuments. Otherwise missing
- * documents are regarded as deleted, and will be removed from the database.
- *
- * If the client calls clearMtpIdentifier(), it clears MTP identifier in the database. In this case,
- * the database tries to find corresponding rows by using document's name instead of MTP identifier
- * at the next update cycle.
- *
- * TODO: Improve performance by SQL optimization.
- */
-class MtpDatabase {
-    private final SQLiteDatabase mDatabase;
-    private final Mapper mMapper;
-
-    SQLiteDatabase getSQLiteDatabase() {
-        return mDatabase;
-    }
-
-    MtpDatabase(Context context, int flags) {
-        final OpenHelper helper = new OpenHelper(context, flags);
-        mDatabase = helper.getWritableDatabase();
-        mMapper = new Mapper(this);
-    }
-
-    void close() {
-        mDatabase.close();
-    }
-
-    /**
-     * Returns operations for mapping.
-     * @return Mapping operations.
-     */
-    Mapper getMapper() {
-        return mMapper;
-    }
-
-    /**
-     * Queries roots information.
-     * @param columnNames Column names defined in {@link android.provider.DocumentsContract.Root}.
-     * @return Database cursor.
-     */
-    Cursor queryRoots(Resources resources, String[] columnNames) {
-        final String selection =
-                COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + " = ?";
-        final Cursor deviceCursor = mDatabase.query(
-                TABLE_DOCUMENTS,
-                strings(COLUMN_DEVICE_ID),
-                selection,
-                strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_DEVICE),
-                COLUMN_DEVICE_ID,
-                null,
-                null,
-                null);
-
-        try {
-            final SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
-            builder.setTables(JOIN_ROOTS);
-            builder.setProjectionMap(COLUMN_MAP_ROOTS);
-            final MatrixCursor result = new MatrixCursor(columnNames);
-            final ContentValues values = new ContentValues();
-
-            while (deviceCursor.moveToNext()) {
-                final int deviceId = deviceCursor.getInt(0);
-                final Cursor storageCursor = builder.query(
-                        mDatabase,
-                        columnNames,
-                        selection + " AND " + COLUMN_DEVICE_ID + " = ?",
-                        strings(ROW_STATE_VALID,
-                                ROW_STATE_INVALIDATED,
-                                DOCUMENT_TYPE_STORAGE,
-                                deviceId),
-                        null,
-                        null,
-                        null);
-                try {
-                    values.clear();
-                    try (final Cursor deviceRoot = builder.query(
-                            mDatabase,
-                            columnNames,
-                            selection + " AND " + COLUMN_DEVICE_ID + " = ?",
-                            strings(ROW_STATE_VALID,
-                                    ROW_STATE_INVALIDATED,
-                                    DOCUMENT_TYPE_DEVICE,
-                                    deviceId),
-                            null,
-                            null,
-                            null)) {
-                        deviceRoot.moveToNext();
-                        DatabaseUtils.cursorRowToContentValues(deviceRoot, values);
-                    }
-
-                    if (storageCursor.getCount() != 0) {
-                        long capacityBytes = 0;
-                        long availableBytes = 0;
-                        final int capacityIndex =
-                                storageCursor.getColumnIndex(Root.COLUMN_CAPACITY_BYTES);
-                        final int availableIndex =
-                                storageCursor.getColumnIndex(Root.COLUMN_AVAILABLE_BYTES);
-                        while (storageCursor.moveToNext()) {
-                            // If requested columnNames does not include COLUMN_XXX_BYTES, we
-                            // don't calculate corresponding values.
-                            if (capacityIndex != -1) {
-                                capacityBytes += storageCursor.getLong(capacityIndex);
-                            }
-                            if (availableIndex != -1) {
-                                availableBytes += storageCursor.getLong(availableIndex);
-                            }
-                        }
-                        values.put(Root.COLUMN_CAPACITY_BYTES, capacityBytes);
-                        values.put(Root.COLUMN_AVAILABLE_BYTES, availableBytes);
-                    } else {
-                        values.putNull(Root.COLUMN_CAPACITY_BYTES);
-                        values.putNull(Root.COLUMN_AVAILABLE_BYTES);
-                    }
-                    if (storageCursor.getCount() == 1 && values.containsKey(Root.COLUMN_TITLE)) {
-                        storageCursor.moveToFirst();
-                        // Add storage name to device name if we have only 1 storage.
-                        values.put(
-                                Root.COLUMN_TITLE,
-                                resources.getString(
-                                        R.string.root_name,
-                                        values.getAsString(Root.COLUMN_TITLE),
-                                        storageCursor.getString(
-                                                storageCursor.getColumnIndex(Root.COLUMN_TITLE))));
-                    }
-                } finally {
-                    storageCursor.close();
-                }
-
-                putValuesToCursor(values, result);
-            }
-
-            return result;
-        } finally {
-            deviceCursor.close();
-        }
-    }
-
-    /**
-     * Queries root documents information.
-     * @param columnNames Column names defined in
-     *     {@link android.provider.DocumentsContract.Document}.
-     * @return Database cursor.
-     */
-    @VisibleForTesting
-    Cursor queryRootDocuments(String[] columnNames) {
-        return mDatabase.query(
-                TABLE_DOCUMENTS,
-                columnNames,
-                COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + " = ?",
-                strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_STORAGE),
-                null,
-                null,
-                null);
-    }
-
-    /**
-     * Queries documents information.
-     * @param columnNames Column names defined in
-     *     {@link android.provider.DocumentsContract.Document}.
-     * @return Database cursor.
-     */
-    Cursor queryChildDocuments(String[] columnNames, String parentDocumentId) {
-        return mDatabase.query(
-                TABLE_DOCUMENTS,
-                columnNames,
-                COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_PARENT_DOCUMENT_ID + " = ?",
-                strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, parentDocumentId),
-                null,
-                null,
-                null);
-    }
-
-    /**
-     * Returns document IDs of storages under the given device document.
-     *
-     * @param documentId Document ID that points a device.
-     * @return Storage document IDs.
-     * @throws FileNotFoundException The given document ID is not registered in database.
-     */
-    String[] getStorageDocumentIds(String documentId)
-            throws FileNotFoundException {
-        Preconditions.checkArgument(createIdentifier(documentId).mDocumentType ==
-                DOCUMENT_TYPE_DEVICE);
-        // Check if the parent document is device that has single storage.
-        try (final Cursor cursor = mDatabase.query(
-                TABLE_DOCUMENTS,
-                strings(Document.COLUMN_DOCUMENT_ID),
-                COLUMN_ROW_STATE + " IN (?, ?) AND " +
-                COLUMN_PARENT_DOCUMENT_ID + " = ? AND " +
-                COLUMN_DOCUMENT_TYPE + " = ?",
-                strings(ROW_STATE_VALID,
-                        ROW_STATE_INVALIDATED,
-                        documentId,
-                        DOCUMENT_TYPE_STORAGE),
-                null,
-                null,
-                null)) {
-            final String[] ids = new String[cursor.getCount()];
-            for (int i = 0; cursor.moveToNext(); i++) {
-                ids[i] = cursor.getString(0);
-            }
-            return ids;
-        }
-    }
-
-    /**
-     * Queries a single document.
-     * @param documentId
-     * @param projection
-     * @return Database cursor.
-     */
-    Cursor queryDocument(String documentId, String[] projection) {
-        return mDatabase.query(
-                TABLE_DOCUMENTS,
-                projection,
-                SELECTION_DOCUMENT_ID,
-                strings(documentId),
-                null,
-                null,
-                null,
-                "1");
-    }
-
-    @Nullable String getDocumentIdForDevice(int deviceId) {
-        final Cursor cursor = mDatabase.query(
-                TABLE_DOCUMENTS,
-                strings(Document.COLUMN_DOCUMENT_ID),
-                COLUMN_DOCUMENT_TYPE + " = ? AND " + COLUMN_DEVICE_ID + " = ?",
-                strings(DOCUMENT_TYPE_DEVICE, deviceId),
-                null,
-                null,
-                null,
-                "1");
-        try {
-            if (cursor.moveToNext()) {
-                return cursor.getString(0);
-            } else {
-                return null;
-            }
-        } finally {
-            cursor.close();
-        }
-    }
-
-    /**
-     * Obtains parent identifier.
-     * @param documentId
-     * @return parent identifier.
-     * @throws FileNotFoundException
-     */
-    Identifier getParentIdentifier(String documentId) throws FileNotFoundException {
-        final Cursor cursor = mDatabase.query(
-                TABLE_DOCUMENTS,
-                strings(COLUMN_PARENT_DOCUMENT_ID),
-                SELECTION_DOCUMENT_ID,
-                strings(documentId),
-                null,
-                null,
-                null,
-                "1");
-        try {
-            if (cursor.moveToNext()) {
-                return createIdentifier(cursor.getString(0));
-            } else {
-                throw new FileNotFoundException("Cannot find a row having ID = " + documentId);
-            }
-        } finally {
-            cursor.close();
-        }
-    }
-
-    String getDeviceDocumentId(int deviceId) throws FileNotFoundException {
-        try (final Cursor cursor = mDatabase.query(
-                TABLE_DOCUMENTS,
-                strings(Document.COLUMN_DOCUMENT_ID),
-                COLUMN_DEVICE_ID + " = ? AND " + COLUMN_DOCUMENT_TYPE + " = ? AND " +
-                COLUMN_ROW_STATE + " != ?",
-                strings(deviceId, DOCUMENT_TYPE_DEVICE, ROW_STATE_DISCONNECTED),
-                null,
-                null,
-                null,
-                "1")) {
-            if (cursor.getCount() > 0) {
-                cursor.moveToNext();
-                return cursor.getString(0);
-            } else {
-                throw new FileNotFoundException("The device ID not found: " + deviceId);
-            }
-        }
-    }
-
-    /**
-     * Adds new document under the parent.
-     * The method does not affect invalidated and pending documents because we know the document is
-     * newly added and never mapped with existing ones.
-     * @param parentDocumentId
-     * @param info
-     * @param size Object size. info#getCompressedSize() will be ignored because it does not contain
-     *     object size more than 4GB.
-     * @return Document ID of added document.
-     */
-    String putNewDocument(
-            int deviceId, String parentDocumentId, int[] operationsSupported, MtpObjectInfo info,
-            long size) {
-        final ContentValues values = new ContentValues();
-        getObjectDocumentValues(
-                values, deviceId, parentDocumentId, operationsSupported, info, size);
-        mDatabase.beginTransaction();
-        try {
-            final long id = mDatabase.insert(TABLE_DOCUMENTS, null, values);
-            mDatabase.setTransactionSuccessful();
-            return Long.toString(id);
-        } finally {
-            mDatabase.endTransaction();
-        }
-    }
-
-    /**
-     * Deletes document and its children.
-     * @param documentId
-     */
-    void deleteDocument(String documentId) {
-        deleteDocumentsAndRootsRecursively(SELECTION_DOCUMENT_ID, strings(documentId));
-    }
-
-    /**
-     * Gets identifier from document ID.
-     * @param documentId Document ID.
-     * @return Identifier.
-     * @throws FileNotFoundException
-     */
-    Identifier createIdentifier(String documentId) throws FileNotFoundException {
-        // Currently documentId is old format.
-        final Cursor cursor = mDatabase.query(
-                TABLE_DOCUMENTS,
-                strings(COLUMN_DEVICE_ID,
-                        COLUMN_STORAGE_ID,
-                        COLUMN_OBJECT_HANDLE,
-                        COLUMN_DOCUMENT_TYPE),
-                SELECTION_DOCUMENT_ID + " AND " + COLUMN_ROW_STATE + " IN (?, ?)",
-                strings(documentId, ROW_STATE_VALID, ROW_STATE_INVALIDATED),
-                null,
-                null,
-                null,
-                "1");
-        try {
-            if (cursor.getCount() == 0) {
-                throw new FileNotFoundException("ID \"" + documentId + "\" is not found.");
-            } else {
-                cursor.moveToNext();
-                return new Identifier(
-                        cursor.getInt(0),
-                        cursor.getInt(1),
-                        cursor.getInt(2),
-                        documentId,
-                        cursor.getInt(3));
-            }
-        } finally {
-            cursor.close();
-        }
-    }
-
-    /**
-     * Deletes a document, and its root information if the document is a root document.
-     * @param selection Query to select documents.
-     * @param args Arguments for selection.
-     * @return Whether the method deletes rows.
-     */
-    boolean deleteDocumentsAndRootsRecursively(String selection, String[] args) {
-        mDatabase.beginTransaction();
-        try {
-            boolean changed = false;
-            final Cursor cursor = mDatabase.query(
-                    TABLE_DOCUMENTS,
-                    strings(Document.COLUMN_DOCUMENT_ID),
-                    selection,
-                    args,
-                    null,
-                    null,
-                    null);
-            try {
-                while (cursor.moveToNext()) {
-                    if (deleteDocumentsAndRootsRecursively(
-                            COLUMN_PARENT_DOCUMENT_ID + " = ?",
-                            strings(cursor.getString(0)))) {
-                        changed = true;
-                    }
-                }
-            } finally {
-                cursor.close();
-            }
-            if (deleteDocumentsAndRoots(selection, args)) {
-                changed = true;
-            }
-            mDatabase.setTransactionSuccessful();
-            return changed;
-        } finally {
-            mDatabase.endTransaction();
-        }
-    }
-
-    /**
-     * Marks the documents and their child as disconnected documents.
-     * @param selection
-     * @param args
-     * @return True if at least one row is updated.
-     */
-    boolean disconnectDocumentsRecursively(String selection, String[] args) {
-        mDatabase.beginTransaction();
-        try {
-            boolean changed = false;
-            try (final Cursor cursor = mDatabase.query(
-                    TABLE_DOCUMENTS,
-                    strings(Document.COLUMN_DOCUMENT_ID),
-                    selection,
-                    args,
-                    null,
-                    null,
-                    null)) {
-                while (cursor.moveToNext()) {
-                    if (disconnectDocumentsRecursively(
-                            COLUMN_PARENT_DOCUMENT_ID + " = ?",
-                            strings(cursor.getString(0)))) {
-                        changed = true;
-                    }
-                }
-            }
-            if (disconnectDocuments(selection, args)) {
-                changed = true;
-            }
-            mDatabase.setTransactionSuccessful();
-            return changed;
-        } finally {
-            mDatabase.endTransaction();
-        }
-    }
-
-    boolean deleteDocumentsAndRoots(String selection, String[] args) {
-        mDatabase.beginTransaction();
-        try {
-            int deleted = 0;
-            deleted += mDatabase.delete(
-                    TABLE_ROOT_EXTRA,
-                    Root.COLUMN_ROOT_ID + " IN (" + SQLiteQueryBuilder.buildQueryString(
-                            false,
-                            TABLE_DOCUMENTS,
-                            new String[] { Document.COLUMN_DOCUMENT_ID },
-                            selection,
-                            null,
-                            null,
-                            null,
-                            null) + ")",
-                    args);
-            deleted += mDatabase.delete(TABLE_DOCUMENTS, selection, args);
-            mDatabase.setTransactionSuccessful();
-            // TODO Remove mappingState.
-            return deleted != 0;
-        } finally {
-            mDatabase.endTransaction();
-        }
-    }
-
-    boolean disconnectDocuments(String selection, String[] args) {
-        mDatabase.beginTransaction();
-        try {
-            final ContentValues values = new ContentValues();
-            values.put(COLUMN_ROW_STATE, ROW_STATE_DISCONNECTED);
-            values.putNull(COLUMN_DEVICE_ID);
-            values.putNull(COLUMN_STORAGE_ID);
-            values.putNull(COLUMN_OBJECT_HANDLE);
-            final boolean updated = mDatabase.update(TABLE_DOCUMENTS, values, selection, args) != 0;
-            mDatabase.setTransactionSuccessful();
-            return updated;
-        } finally {
-            mDatabase.endTransaction();
-        }
-    }
-
-    int getRowState(String documentId) throws FileNotFoundException {
-        try (final Cursor cursor = mDatabase.query(
-                TABLE_DOCUMENTS,
-                strings(COLUMN_ROW_STATE),
-                SELECTION_DOCUMENT_ID,
-                strings(documentId),
-                null,
-                null,
-                null)) {
-            if (cursor.getCount() == 0) {
-                throw new FileNotFoundException();
-            }
-            cursor.moveToNext();
-            return cursor.getInt(0);
-        }
-    }
-
-    void writeRowSnapshot(String documentId, ContentValues values) throws FileNotFoundException {
-        try (final Cursor cursor = mDatabase.query(
-                JOIN_ROOTS,
-                strings("*"),
-                SELECTION_DOCUMENT_ID,
-                strings(documentId),
-                null,
-                null,
-                null,
-                "1")) {
-            if (cursor.getCount() == 0) {
-                throw new FileNotFoundException();
-            }
-            cursor.moveToNext();
-            values.clear();
-            DatabaseUtils.cursorRowToContentValues(cursor, values);
-        }
-    }
-
-    void updateObject(String documentId, int deviceId, String parentId, int[] operationsSupported,
-                      MtpObjectInfo info, Long size) {
-        final ContentValues values = new ContentValues();
-        getObjectDocumentValues(values, deviceId, parentId, operationsSupported, info, size);
-
-        mDatabase.beginTransaction();
-        try {
-            mDatabase.update(
-                    TABLE_DOCUMENTS,
-                    values,
-                    Document.COLUMN_DOCUMENT_ID + " = ?",
-                    strings(documentId));
-            mDatabase.setTransactionSuccessful();
-        } finally {
-            mDatabase.endTransaction();
-        }
-    }
-
-    /**
-     * Obtains a document that has already mapped but has unmapped children.
-     * @param deviceId Device to find documents.
-     * @return Identifier of found document or null.
-     */
-    @Nullable Identifier getUnmappedDocumentsParent(int deviceId) {
-        final String fromClosure =
-                TABLE_DOCUMENTS + " AS child INNER JOIN " +
-                TABLE_DOCUMENTS + " AS parent ON " +
-                "child." + COLUMN_PARENT_DOCUMENT_ID + " = " +
-                "parent." + Document.COLUMN_DOCUMENT_ID;
-        final String whereClosure =
-                "parent." + COLUMN_DEVICE_ID + " = ? AND " +
-                "parent." + COLUMN_ROW_STATE + " IN (?, ?) AND " +
-                "parent." + COLUMN_DOCUMENT_TYPE + " != ? AND " +
-                "child." + COLUMN_ROW_STATE + " = ?";
-        try (final Cursor cursor = mDatabase.query(
-                fromClosure,
-                strings("parent." + COLUMN_DEVICE_ID,
-                        "parent." + COLUMN_STORAGE_ID,
-                        "parent." + COLUMN_OBJECT_HANDLE,
-                        "parent." + Document.COLUMN_DOCUMENT_ID,
-                        "parent." + COLUMN_DOCUMENT_TYPE),
-                whereClosure,
-                strings(deviceId, ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_DEVICE,
-                        ROW_STATE_DISCONNECTED),
-                null,
-                null,
-                null,
-                "1")) {
-            if (cursor.getCount() == 0) {
-                return null;
-            }
-            cursor.moveToNext();
-            return new Identifier(
-                    cursor.getInt(0),
-                    cursor.getInt(1),
-                    cursor.getInt(2),
-                    cursor.getString(3),
-                    cursor.getInt(4));
-        }
-    }
-
-    /**
-     * Removes metadata except for data used by outgoingPersistedUriPermissions.
-     */
-    void cleanDatabase(Uri[] outgoingPersistedUris) {
-        mDatabase.beginTransaction();
-        try {
-            final Set<String> ids = new HashSet<>();
-            for (final Uri uri : outgoingPersistedUris) {
-                String documentId = DocumentsContract.getDocumentId(uri);
-                while (documentId != null) {
-                    if (ids.contains(documentId)) {
-                        break;
-                    }
-                    ids.add(documentId);
-                    try (final Cursor cursor = mDatabase.query(
-                            TABLE_DOCUMENTS,
-                            strings(COLUMN_PARENT_DOCUMENT_ID),
-                            SELECTION_DOCUMENT_ID,
-                            strings(documentId),
-                            null,
-                            null,
-                            null)) {
-                        documentId = cursor.moveToNext() ? cursor.getString(0) : null;
-                    }
-                }
-            }
-            deleteDocumentsAndRoots(
-                    Document.COLUMN_DOCUMENT_ID + " NOT IN " + getIdList(ids), null);
-            mDatabase.setTransactionSuccessful();
-        } finally {
-            mDatabase.endTransaction();
-        }
-    }
-
-    int getLastBootCount() {
-        try (final Cursor cursor = mDatabase.query(
-                TABLE_LAST_BOOT_COUNT, strings(COLUMN_VALUE), null, null, null, null, null)) {
-            if (cursor.moveToNext()) {
-                return cursor.getInt(0);
-            } else {
-                return 0;
-            }
-        }
-    }
-
-    void setLastBootCount(int value) {
-        Preconditions.checkArgumentNonnegative(value, "Boot count must not be negative.");
-        mDatabase.beginTransaction();
-        try {
-            final ContentValues values = new ContentValues();
-            values.put(COLUMN_VALUE, value);
-            mDatabase.delete(TABLE_LAST_BOOT_COUNT, null, null);
-            mDatabase.insert(TABLE_LAST_BOOT_COUNT, null, values);
-            mDatabase.setTransactionSuccessful();
-        } finally {
-            mDatabase.endTransaction();
-        }
-    }
-
-    private static class OpenHelper extends SQLiteOpenHelper {
-        public OpenHelper(Context context, int flags) {
-            super(context,
-                  flags == FLAG_DATABASE_IN_MEMORY ? null : DATABASE_NAME,
-                  null,
-                  DATABASE_VERSION);
-        }
-
-        @Override
-        public void onCreate(SQLiteDatabase db) {
-            db.execSQL(QUERY_CREATE_DOCUMENTS);
-            db.execSQL(QUERY_CREATE_ROOT_EXTRA);
-            db.execSQL(QUERY_CREATE_LAST_BOOT_COUNT);
-        }
-
-        @Override
-        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-            db.execSQL("DROP TABLE IF EXISTS " + TABLE_DOCUMENTS);
-            db.execSQL("DROP TABLE IF EXISTS " + TABLE_ROOT_EXTRA);
-            db.execSQL("DROP TABLE IF EXISTS " + TABLE_LAST_BOOT_COUNT);
-            onCreate(db);
-        }
-    }
-
-    @VisibleForTesting
-    static void deleteDatabase(Context context) {
-        context.deleteDatabase(DATABASE_NAME);
-    }
-
-    static void getDeviceDocumentValues(
-            ContentValues values,
-            ContentValues extraValues,
-            MtpDeviceRecord device) {
-        values.clear();
-        values.put(COLUMN_DEVICE_ID, device.deviceId);
-        values.putNull(COLUMN_STORAGE_ID);
-        values.putNull(COLUMN_OBJECT_HANDLE);
-        values.putNull(COLUMN_PARENT_DOCUMENT_ID);
-        values.put(COLUMN_ROW_STATE, ROW_STATE_VALID);
-        values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_DEVICE);
-        values.put(COLUMN_MAPPING_KEY, device.deviceKey);
-        values.put(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
-        values.put(Document.COLUMN_DISPLAY_NAME, device.name);
-        values.putNull(Document.COLUMN_SUMMARY);
-        values.putNull(Document.COLUMN_LAST_MODIFIED);
-        values.put(Document.COLUMN_ICON, R.drawable.ic_root_mtp);
-        values.put(Document.COLUMN_FLAGS, getDocumentFlags(
-                device.operationsSupported,
-                Document.MIME_TYPE_DIR,
-                0,
-                MtpConstants.PROTECTION_STATUS_NONE,
-                // Storages are placed under device so we cannot create a document just under
-                // device.
-                DOCUMENT_TYPE_DEVICE) & ~Document.FLAG_DIR_SUPPORTS_CREATE);
-        values.putNull(Document.COLUMN_SIZE);
-
-        extraValues.clear();
-        extraValues.put(Root.COLUMN_FLAGS, getRootFlags(device.operationsSupported));
-        extraValues.putNull(Root.COLUMN_AVAILABLE_BYTES);
-        extraValues.putNull(Root.COLUMN_CAPACITY_BYTES);
-        extraValues.put(Root.COLUMN_MIME_TYPES, "");
-    }
-
-    /**
-     * Gets {@link ContentValues} for the given root.
-     * @param values {@link ContentValues} that receives values.
-     * @param extraValues {@link ContentValues} that receives extra values for roots.
-     * @param parentDocumentId Parent document ID.
-     * @param operationsSupported Array of Operation code supported by the device.
-     * @param root Root to be converted {@link ContentValues}.
-     */
-    static void getStorageDocumentValues(
-            ContentValues values,
-            ContentValues extraValues,
-            String parentDocumentId,
-            int[] operationsSupported,
-            MtpRoot root) {
-        values.clear();
-        values.put(COLUMN_DEVICE_ID, root.mDeviceId);
-        values.put(COLUMN_STORAGE_ID, root.mStorageId);
-        values.putNull(COLUMN_OBJECT_HANDLE);
-        values.put(COLUMN_PARENT_DOCUMENT_ID, parentDocumentId);
-        values.put(COLUMN_ROW_STATE, ROW_STATE_VALID);
-        values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_STORAGE);
-        values.put(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
-        values.put(Document.COLUMN_DISPLAY_NAME, root.mDescription);
-        values.putNull(Document.COLUMN_SUMMARY);
-        values.putNull(Document.COLUMN_LAST_MODIFIED);
-        values.put(Document.COLUMN_ICON, R.drawable.ic_root_mtp);
-        values.put(Document.COLUMN_FLAGS, getDocumentFlags(
-                operationsSupported,
-                Document.MIME_TYPE_DIR,
-                0,
-                MtpConstants.PROTECTION_STATUS_NONE,
-                DOCUMENT_TYPE_STORAGE));
-        values.put(Document.COLUMN_SIZE, root.mMaxCapacity - root.mFreeSpace);
-
-        extraValues.put(Root.COLUMN_FLAGS, getRootFlags(operationsSupported));
-        extraValues.put(Root.COLUMN_AVAILABLE_BYTES, root.mFreeSpace);
-        extraValues.put(Root.COLUMN_CAPACITY_BYTES, root.mMaxCapacity);
-        extraValues.put(Root.COLUMN_MIME_TYPES, "");
-    }
-
-    /**
-     * Gets {@link ContentValues} for the given MTP object.
-     * @param values {@link ContentValues} that receives values.
-     * @param deviceId Device ID of the object.
-     * @param parentId Parent document ID of the object.
-     * @param info MTP object info. getCompressedSize will be ignored.
-     * @param size 64-bit size of documents. Negative value is regarded as unknown size.
-     */
-    static void getObjectDocumentValues(
-            ContentValues values, int deviceId, String parentId,
-            int[] operationsSupported, MtpObjectInfo info, long size) {
-        values.clear();
-        final String mimeType = getMimeType(info);
-        values.put(COLUMN_DEVICE_ID, deviceId);
-        values.put(COLUMN_STORAGE_ID, info.getStorageId());
-        values.put(COLUMN_OBJECT_HANDLE, info.getObjectHandle());
-        values.put(COLUMN_PARENT_DOCUMENT_ID, parentId);
-        values.put(COLUMN_ROW_STATE, ROW_STATE_VALID);
-        values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_OBJECT);
-        values.put(Document.COLUMN_MIME_TYPE, mimeType);
-        values.put(Document.COLUMN_DISPLAY_NAME, info.getName());
-        values.putNull(Document.COLUMN_SUMMARY);
-        values.put(
-                Document.COLUMN_LAST_MODIFIED,
-                info.getDateModified() != 0 ? info.getDateModified() : null);
-        values.putNull(Document.COLUMN_ICON);
-        values.put(Document.COLUMN_FLAGS, getDocumentFlags(
-                operationsSupported, mimeType, info.getThumbCompressedSizeLong(),
-                info.getProtectionStatus(), DOCUMENT_TYPE_OBJECT));
-        if (size >= 0) {
-            values.put(Document.COLUMN_SIZE, size);
-        } else {
-            values.putNull(Document.COLUMN_SIZE);
-        }
-    }
-
-    private static String getMimeType(MtpObjectInfo info) {
-        if (info.getFormat() == MtpConstants.FORMAT_ASSOCIATION) {
-            return DocumentsContract.Document.MIME_TYPE_DIR;
-        }
-
-        return MediaFile.getMimeType(info.getName(), info.getFormat());
-    }
-
-    private static int getRootFlags(int[] operationsSupported) {
-        int rootFlag = Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_LOCAL_ONLY;
-        if (MtpDeviceRecord.isWritingSupported(operationsSupported)) {
-            rootFlag |= Root.FLAG_SUPPORTS_CREATE;
-        }
-        return rootFlag;
-    }
-
-    private static int getDocumentFlags(
-            @Nullable int[] operationsSupported, String mimeType, long thumbnailSize,
-            int protectionState, @DocumentType int documentType) {
-        int flag = 0;
-        if (!mimeType.equals(Document.MIME_TYPE_DIR) &&
-                MtpDeviceRecord.isWritingSupported(operationsSupported) &&
-                protectionState == MtpConstants.PROTECTION_STATUS_NONE) {
-            flag |= Document.FLAG_SUPPORTS_WRITE;
-        }
-        if (MtpDeviceRecord.isSupported(
-                operationsSupported, MtpConstants.OPERATION_DELETE_OBJECT) &&
-                (protectionState == MtpConstants.PROTECTION_STATUS_NONE ||
-                 protectionState == MtpConstants.PROTECTION_STATUS_NON_TRANSFERABLE_DATA) &&
-                documentType == DOCUMENT_TYPE_OBJECT) {
-            flag |= Document.FLAG_SUPPORTS_DELETE;
-        }
-        if (mimeType.equals(Document.MIME_TYPE_DIR) &&
-                MtpDeviceRecord.isWritingSupported(operationsSupported) &&
-                protectionState == MtpConstants.PROTECTION_STATUS_NONE) {
-            flag |= Document.FLAG_DIR_SUPPORTS_CREATE;
-        }
-        if (MetadataReader.isSupportedMimeType(mimeType)) {
-            flag |= Document.FLAG_SUPPORTS_METADATA;
-        }
-        if (thumbnailSize > 0) {
-            flag |= Document.FLAG_SUPPORTS_THUMBNAIL;
-        }
-        return flag;
-    }
-
-    static String[] strings(Object... args) {
-        final String[] results = new String[args.length];
-        for (int i = 0; i < args.length; i++) {
-            results[i] = Objects.toString(args[i]);
-        }
-        return results;
-    }
-
-    static void putValuesToCursor(ContentValues values, MatrixCursor cursor) {
-        final RowBuilder row = cursor.newRow();
-        for (final String name : cursor.getColumnNames()) {
-            row.add(values.get(name));
-        }
-    }
-
-    private static String getIdList(Set<String> ids) {
-        String result = "(";
-        for (final String id : ids) {
-            if (result.length() > 1) {
-                result += ",";
-            }
-            result += id;
-        }
-        result += ")";
-        return result;
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
deleted file mode 100644
index 6d98e34..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.annotation.IntDef;
-import android.database.sqlite.SQLiteQueryBuilder;
-import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract.Root;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Class containing MtpDatabase constants.
- */
-class MtpDatabaseConstants {
-    static final int DATABASE_VERSION = 5;
-    static final String DATABASE_NAME = "database";
-
-    static final int FLAG_DATABASE_IN_MEMORY = 1;
-    static final int FLAG_DATABASE_IN_FILE = 0;
-
-    /**
-     * Table representing documents including root documents.
-     */
-    static final String TABLE_DOCUMENTS = "Documents";
-
-    /**
-     * Table containing additional information only available for root documents.
-     * The table uses same primary keys with corresponding documents.
-     */
-    static final String TABLE_ROOT_EXTRA = "RootExtra";
-
-    /**
-     * Table containing last boot count.
-     */
-    static final String TABLE_LAST_BOOT_COUNT = "LastBootCount";
-
-    /**
-     * 'FROM' closure of joining TABLE_DOCUMENTS and TABLE_ROOT_EXTRA.
-     */
-    static final String JOIN_ROOTS = createJoinFromClosure(
-            TABLE_DOCUMENTS,
-            TABLE_ROOT_EXTRA,
-            Document.COLUMN_DOCUMENT_ID,
-            Root.COLUMN_ROOT_ID);
-
-    static final String COLUMN_DEVICE_ID = "device_id";
-    static final String COLUMN_STORAGE_ID = "storage_id";
-    static final String COLUMN_OBJECT_HANDLE = "object_handle";
-    static final String COLUMN_PARENT_DOCUMENT_ID = "parent_document_id";
-    static final String COLUMN_DOCUMENT_TYPE = "document_type";
-    static final String COLUMN_ROW_STATE = "row_state";
-    static final String COLUMN_MAPPING_KEY = "mapping_key";
-
-    /**
-     * Value for TABLE_LAST_BOOT_COUNT.
-     * Type: INTEGER
-     */
-    static final String COLUMN_VALUE = "value";
-
-    /**
-     * The state represents that the row has a valid object handle.
-     */
-    static final int ROW_STATE_VALID = 0;
-
-    /**
-     * The state represents that the rows added at the previous cycle and need to be updated with
-     * fresh values.
-     * The row may not have valid object handle. External application can still fetch the documents.
-     * If the external application tries to fetch object handle, the provider resolves pending
-     * documents with invalidated documents ahead.
-     */
-    static final int ROW_STATE_INVALIDATED = 1;
-
-    /**
-     * The documents are of device/storage that are disconnected now. The documents are invisible
-     * but their document ID will be reuse when the device/storage is connected again.
-     */
-    static final int ROW_STATE_DISCONNECTED = 2;
-
-    @IntDef(value = { DOCUMENT_TYPE_DEVICE, DOCUMENT_TYPE_STORAGE, DOCUMENT_TYPE_OBJECT })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface DocumentType {}
-
-    /**
-     * Document that represents a MTP device.
-     */
-    static final int DOCUMENT_TYPE_DEVICE = 0;
-
-    /**
-     * Document that represents a MTP storage.
-     */
-    static final int DOCUMENT_TYPE_STORAGE = 1;
-
-    /**
-     * Document that represents a MTP object.
-     */
-    static final int DOCUMENT_TYPE_OBJECT = 2;
-
-    static final String SELECTION_DOCUMENT_ID = Document.COLUMN_DOCUMENT_ID + " = ?";
-    static final String SELECTION_ROOT_ID = Root.COLUMN_ROOT_ID + " = ?";
-
-    static final String QUERY_CREATE_DOCUMENTS =
-            "CREATE TABLE " + TABLE_DOCUMENTS + " (" +
-            Document.COLUMN_DOCUMENT_ID +
-                " INTEGER PRIMARY KEY AUTOINCREMENT," +
-            COLUMN_DEVICE_ID + " INTEGER," +
-            COLUMN_STORAGE_ID + " INTEGER," +
-            COLUMN_OBJECT_HANDLE + " INTEGER," +
-            COLUMN_PARENT_DOCUMENT_ID + " INTEGER," +
-            COLUMN_ROW_STATE + " INTEGER NOT NULL," +
-            COLUMN_DOCUMENT_TYPE + " INTEGER NOT NULL," +
-            COLUMN_MAPPING_KEY + " STRING," +
-            Document.COLUMN_MIME_TYPE + " TEXT NOT NULL," +
-            Document.COLUMN_DISPLAY_NAME + " TEXT NOT NULL," +
-            Document.COLUMN_SUMMARY + " TEXT," +
-            Document.COLUMN_LAST_MODIFIED + " INTEGER," +
-            Document.COLUMN_ICON + " INTEGER," +
-            Document.COLUMN_FLAGS + " INTEGER NOT NULL," +
-            Document.COLUMN_SIZE + " INTEGER);";
-
-    static final String QUERY_CREATE_ROOT_EXTRA =
-            "CREATE TABLE " + TABLE_ROOT_EXTRA + " (" +
-            Root.COLUMN_ROOT_ID + " INTEGER PRIMARY KEY," +
-            Root.COLUMN_FLAGS + " INTEGER NOT NULL," +
-            Root.COLUMN_AVAILABLE_BYTES + " INTEGER," +
-            Root.COLUMN_CAPACITY_BYTES + " INTEGER," +
-            Root.COLUMN_MIME_TYPES + " TEXT NOT NULL);";
-
-    static final String QUERY_CREATE_LAST_BOOT_COUNT =
-            "CREATE TABLE " + TABLE_LAST_BOOT_COUNT + " (value INTEGER NOT NULL);";
-
-    /**
-     * Map for columns names to provide DocumentContract.Root compatible columns.
-     * @see SQLiteQueryBuilder#setProjectionMap(Map)
-     */
-    static final Map<String, String> COLUMN_MAP_ROOTS;
-    static {
-        COLUMN_MAP_ROOTS = new HashMap<>();
-        COLUMN_MAP_ROOTS.put(Root.COLUMN_ROOT_ID, TABLE_ROOT_EXTRA + "." + Root.COLUMN_ROOT_ID);
-        COLUMN_MAP_ROOTS.put(Root.COLUMN_FLAGS, TABLE_ROOT_EXTRA + "." + Root.COLUMN_FLAGS);
-        COLUMN_MAP_ROOTS.put(
-                Root.COLUMN_ICON,
-                TABLE_DOCUMENTS + "." + Document.COLUMN_ICON + " AS " + Root.COLUMN_ICON);
-        COLUMN_MAP_ROOTS.put(
-                Root.COLUMN_TITLE,
-                TABLE_DOCUMENTS + "." + Document.COLUMN_DISPLAY_NAME + " AS " + Root.COLUMN_TITLE);
-        COLUMN_MAP_ROOTS.put(
-                Root.COLUMN_SUMMARY,
-                TABLE_DOCUMENTS + "." + Document.COLUMN_SUMMARY + " AS " + Root.COLUMN_SUMMARY);
-        COLUMN_MAP_ROOTS.put(
-                Root.COLUMN_DOCUMENT_ID,
-                TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID +
-                " AS " + Root.COLUMN_DOCUMENT_ID);
-        COLUMN_MAP_ROOTS.put(
-                Root.COLUMN_AVAILABLE_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_AVAILABLE_BYTES);
-        COLUMN_MAP_ROOTS.put(
-                Root.COLUMN_CAPACITY_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_CAPACITY_BYTES);
-        COLUMN_MAP_ROOTS.put(
-                Root.COLUMN_MIME_TYPES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_MIME_TYPES);
-        COLUMN_MAP_ROOTS.put(COLUMN_DEVICE_ID, COLUMN_DEVICE_ID);
-    }
-
-    private static String createJoinFromClosure(
-            String table1, String table2, String column1, String column2) {
-        return table1 + " LEFT JOIN " + table2 +
-                " ON " + table1 + "." + column1 + " = " + table2 + "." + column2;
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
deleted file mode 100644
index c52b81d..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.annotation.Nullable;
-import android.mtp.MtpConstants;
-
-class MtpDeviceRecord {
-    public final int deviceId;
-    public final String name;
-    public final @Nullable String deviceKey;
-    public final boolean opened;
-    public final MtpRoot[] roots;
-    public final @Nullable int[] operationsSupported;
-    public final @Nullable int[] eventsSupported;
-
-    MtpDeviceRecord(int deviceId, String name, @Nullable String deviceKey, boolean opened,
-                    MtpRoot[] roots, @Nullable int[] operationsSupported,
-                    @Nullable int[] eventsSupported) {
-        this.deviceId = deviceId;
-        this.name = name;
-        this.opened = opened;
-        this.roots = roots;
-        this.deviceKey = deviceKey;
-        this.operationsSupported = operationsSupported;
-        this.eventsSupported = eventsSupported;
-    }
-
-    /**
-     * Helper method to check operations/events are supported by the device or not.
-     */
-    static boolean isSupported(@Nullable int[] supportedList, int code) {
-        if (supportedList == null) {
-            return false;
-        }
-        for (int i = 0; i < supportedList.length; i++) {
-            if (supportedList[i] == code) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    static boolean isPartialReadSupported(@Nullable int[] supportedList, long fileSize) {
-        if (isSupported(supportedList, MtpConstants.OPERATION_GET_PARTIAL_OBJECT_64)) {
-            return true;
-        }
-        if (0 <= fileSize &&
-                fileSize <= 0xffffffffL &&
-                isSupported(supportedList, MtpConstants.OPERATION_GET_PARTIAL_OBJECT)) {
-            return true;
-        }
-        return false;
-    }
-
-    static boolean isWritingSupported(@Nullable int[] supportedList) {
-        return isSupported(supportedList, MtpConstants.OPERATION_SEND_OBJECT_INFO) &&
-                isSupported(supportedList, MtpConstants.OPERATION_SEND_OBJECT);
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
deleted file mode 100644
index 8c8116b..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ /dev/null
@@ -1,856 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.UriPermission;
-import android.content.res.AssetFileDescriptor;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.database.MatrixCursor;
-import android.database.sqlite.SQLiteDiskIOException;
-import android.graphics.Point;
-import android.media.MediaFile;
-import android.mtp.MtpConstants;
-import android.mtp.MtpObjectInfo;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.FileUtils;
-import android.os.ParcelFileDescriptor;
-import android.os.ProxyFileDescriptorCallback;
-import android.os.storage.StorageManager;
-import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract.Path;
-import android.provider.DocumentsContract.Root;
-import android.provider.DocumentsProvider;
-import android.provider.MetadataReader;
-import android.provider.Settings;
-import android.system.ErrnoException;
-import android.system.OsConstants;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-
-import libcore.io.IoUtils;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeoutException;
-
-/**
- * DocumentsProvider for MTP devices.
- */
-public class MtpDocumentsProvider extends DocumentsProvider {
-    static final String AUTHORITY = "com.android.mtp.documents";
-    static final String TAG = "MtpDocumentsProvider";
-    static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
-            Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON,
-            Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID,
-            Root.COLUMN_AVAILABLE_BYTES,
-    };
-    static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
-            Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE,
-            Document.COLUMN_DISPLAY_NAME, Document.COLUMN_LAST_MODIFIED,
-            Document.COLUMN_FLAGS, Document.COLUMN_SIZE,
-    };
-
-    static final boolean DEBUG = false;
-
-    private final Object mDeviceListLock = new Object();
-
-    private static MtpDocumentsProvider sSingleton;
-
-    private MtpManager mMtpManager;
-    private ContentResolver mResolver;
-    @GuardedBy("mDeviceListLock")
-    private Map<Integer, DeviceToolkit> mDeviceToolkits;
-    private RootScanner mRootScanner;
-    private Resources mResources;
-    private MtpDatabase mDatabase;
-    private ServiceIntentSender mIntentSender;
-    private Context mContext;
-    private StorageManager mStorageManager;
-
-    /**
-     * Provides singleton instance to MtpDocumentsService.
-     */
-    static MtpDocumentsProvider getInstance() {
-        return sSingleton;
-    }
-
-    @Override
-    public boolean onCreate() {
-        sSingleton = this;
-        mContext = getContext();
-        mResources = getContext().getResources();
-        mMtpManager = new MtpManager(getContext());
-        mResolver = getContext().getContentResolver();
-        mDeviceToolkits = new HashMap<>();
-        mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_FILE);
-        mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase);
-        mIntentSender = new ServiceIntentSender(getContext());
-        mStorageManager = getContext().getSystemService(StorageManager.class);
-
-        // Check boot count and cleans database if it's first time to launch MtpDocumentsProvider
-        // after booting.
-        try {
-            final int bootCount = Settings.Global.getInt(mResolver, Settings.Global.BOOT_COUNT, -1);
-            final int lastBootCount = mDatabase.getLastBootCount();
-            if (bootCount != -1 && bootCount != lastBootCount) {
-                mDatabase.setLastBootCount(bootCount);
-                final List<UriPermission> permissions =
-                        mResolver.getOutgoingPersistedUriPermissions();
-                final Uri[] uris = new Uri[permissions.size()];
-                for (int i = 0; i < permissions.size(); i++) {
-                    uris[i] = permissions.get(i).getUri();
-                }
-                mDatabase.cleanDatabase(uris);
-            }
-        } catch (SQLiteDiskIOException error) {
-            // It can happen due to disk shortage.
-            Log.e(TAG, "Failed to clean database.", error);
-            return false;
-        }
-
-        resume();
-        return true;
-    }
-
-    @VisibleForTesting
-    boolean onCreateForTesting(
-            Context context,
-            Resources resources,
-            MtpManager mtpManager,
-            ContentResolver resolver,
-            MtpDatabase database,
-            StorageManager storageManager,
-            ServiceIntentSender intentSender) {
-        mContext = context;
-        mResources = resources;
-        mMtpManager = mtpManager;
-        mResolver = resolver;
-        mDeviceToolkits = new HashMap<>();
-        mDatabase = database;
-        mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase);
-        mIntentSender = intentSender;
-        mStorageManager = storageManager;
-
-        resume();
-        return true;
-    }
-
-    @Override
-    public Cursor queryRoots(String[] projection) throws FileNotFoundException {
-        if (projection == null) {
-            projection = MtpDocumentsProvider.DEFAULT_ROOT_PROJECTION;
-        }
-        final Cursor cursor = mDatabase.queryRoots(mResources, projection);
-        cursor.setNotificationUri(
-                mResolver, DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY));
-        return cursor;
-    }
-
-    @Override
-    public Cursor queryDocument(String documentId, String[] projection)
-            throws FileNotFoundException {
-        if (projection == null) {
-            projection = MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION;
-        }
-        final Cursor cursor = mDatabase.queryDocument(documentId, projection);
-        final int cursorCount = cursor.getCount();
-        if (cursorCount == 0) {
-            cursor.close();
-            throw new FileNotFoundException();
-        } else if (cursorCount != 1) {
-            cursor.close();
-            Log.wtf(TAG, "Unexpected cursor size: " + cursorCount);
-            return null;
-        }
-
-        final Identifier identifier = mDatabase.createIdentifier(documentId);
-        if (identifier.mDocumentType != MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE) {
-            return cursor;
-        }
-        final String[] storageDocIds = mDatabase.getStorageDocumentIds(documentId);
-        if (storageDocIds.length != 1) {
-            return mDatabase.queryDocument(documentId, projection);
-        }
-
-        // If the documentId specifies a device having exact one storage, we repalce some device
-        // attributes with the storage attributes.
-        try {
-            final String storageName;
-            final int storageFlags;
-            try (final Cursor storageCursor = mDatabase.queryDocument(
-                    storageDocIds[0],
-                    MtpDatabase.strings(Document.COLUMN_DISPLAY_NAME, Document.COLUMN_FLAGS))) {
-                if (!storageCursor.moveToNext()) {
-                    throw new FileNotFoundException();
-                }
-                storageName = storageCursor.getString(0);
-                storageFlags = storageCursor.getInt(1);
-            }
-
-            cursor.moveToNext();
-            final ContentValues values = new ContentValues();
-            DatabaseUtils.cursorRowToContentValues(cursor, values);
-            if (values.containsKey(Document.COLUMN_DISPLAY_NAME)) {
-                values.put(Document.COLUMN_DISPLAY_NAME, mResources.getString(
-                        R.string.root_name,
-                        values.getAsString(Document.COLUMN_DISPLAY_NAME),
-                        storageName));
-            }
-            values.put(Document.COLUMN_FLAGS, storageFlags);
-            final MatrixCursor output = new MatrixCursor(projection, 1);
-            MtpDatabase.putValuesToCursor(values, output);
-            return output;
-        } finally {
-            cursor.close();
-        }
-    }
-
-    @Override
-    public Cursor queryChildDocuments(String parentDocumentId,
-            String[] projection, String sortOrder) throws FileNotFoundException {
-        if (DEBUG) {
-            Log.d(TAG, "queryChildDocuments: " + parentDocumentId);
-        }
-        if (projection == null) {
-            projection = MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION;
-        }
-        Identifier parentIdentifier = mDatabase.createIdentifier(parentDocumentId);
-        try {
-            openDevice(parentIdentifier.mDeviceId);
-            if (parentIdentifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE) {
-                final String[] storageDocIds = mDatabase.getStorageDocumentIds(parentDocumentId);
-                if (storageDocIds.length == 0) {
-                    // Remote device does not provide storages. Maybe it is locked.
-                    return createErrorCursor(projection, R.string.error_locked_device);
-                } else if (storageDocIds.length > 1) {
-                    // Returns storage list from database.
-                    return mDatabase.queryChildDocuments(projection, parentDocumentId);
-                }
-
-                // Exact one storage is found. Skip storage and returns object in the single
-                // storage.
-                parentIdentifier = mDatabase.createIdentifier(storageDocIds[0]);
-            }
-
-            // Returns object list from document loader.
-            return getDocumentLoader(parentIdentifier).queryChildDocuments(
-                    projection, parentIdentifier);
-        } catch (BusyDeviceException exception) {
-            return createErrorCursor(projection, R.string.error_busy_device);
-        } catch (IOException exception) {
-            Log.e(MtpDocumentsProvider.TAG, "queryChildDocuments", exception);
-            throw new FileNotFoundException(exception.getMessage());
-        }
-    }
-
-    @Override
-    public ParcelFileDescriptor openDocument(
-            String documentId, String mode, CancellationSignal signal)
-                    throws FileNotFoundException {
-        if (DEBUG) {
-            Log.d(TAG, "openDocument: " + documentId);
-        }
-        final Identifier identifier = mDatabase.createIdentifier(documentId);
-        try {
-            openDevice(identifier.mDeviceId);
-            final MtpDeviceRecord device = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord;
-            // Turn off MODE_CREATE because openDocument does not allow to create new files.
-            final int modeFlag =
-                    ParcelFileDescriptor.parseMode(mode) & ~ParcelFileDescriptor.MODE_CREATE;
-            if ((modeFlag & ParcelFileDescriptor.MODE_READ_ONLY) != 0) {
-                long fileSize;
-                try {
-                    fileSize = getFileSize(documentId);
-                } catch (UnsupportedOperationException exception) {
-                    fileSize = -1;
-                }
-                if (MtpDeviceRecord.isPartialReadSupported(
-                        device.operationsSupported, fileSize)) {
-
-                    return mStorageManager.openProxyFileDescriptor(
-                            modeFlag,
-                            new MtpProxyFileDescriptorCallback(Integer.parseInt(documentId)));
-                } else {
-                    // If getPartialObject{|64} are not supported for the device, returns
-                    // non-seekable pipe FD instead.
-                    return getPipeManager(identifier).readDocument(mMtpManager, identifier);
-                }
-            } else if ((modeFlag & ParcelFileDescriptor.MODE_WRITE_ONLY) != 0) {
-                // TODO: Clear the parent document loader task (if exists) and call notify
-                // when writing is completed.
-                if (MtpDeviceRecord.isWritingSupported(device.operationsSupported)) {
-                    return mStorageManager.openProxyFileDescriptor(
-                            modeFlag,
-                            new MtpProxyFileDescriptorCallback(Integer.parseInt(documentId)));
-                } else {
-                    throw new UnsupportedOperationException(
-                            "The device does not support writing operation.");
-                }
-            } else {
-                // TODO: Add support for "rw" mode.
-                throw new UnsupportedOperationException("The provider does not support 'rw' mode.");
-            }
-        } catch (FileNotFoundException | RuntimeException error) {
-            Log.e(MtpDocumentsProvider.TAG, "openDocument", error);
-            throw error;
-        } catch (IOException error) {
-            Log.e(MtpDocumentsProvider.TAG, "openDocument", error);
-            throw new IllegalStateException(error);
-        }
-    }
-
-    @Override
-    public AssetFileDescriptor openDocumentThumbnail(
-            String documentId,
-            Point sizeHint,
-            CancellationSignal signal) throws FileNotFoundException {
-        final Identifier identifier = mDatabase.createIdentifier(documentId);
-        try {
-            openDevice(identifier.mDeviceId);
-            return new AssetFileDescriptor(
-                    getPipeManager(identifier).readThumbnail(mMtpManager, identifier),
-                    0,  // Start offset.
-                    AssetFileDescriptor.UNKNOWN_LENGTH);
-        } catch (IOException error) {
-            Log.e(MtpDocumentsProvider.TAG, "openDocumentThumbnail", error);
-            throw new FileNotFoundException(error.getMessage());
-        }
-    }
-
-    @Override
-    public void deleteDocument(String documentId) throws FileNotFoundException {
-        try {
-            final Identifier identifier = mDatabase.createIdentifier(documentId);
-            openDevice(identifier.mDeviceId);
-            final Identifier parentIdentifier = mDatabase.getParentIdentifier(documentId);
-            mMtpManager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
-            mDatabase.deleteDocument(documentId);
-            getDocumentLoader(parentIdentifier).cancelTask(parentIdentifier);
-            notifyChildDocumentsChange(parentIdentifier.mDocumentId);
-            if (parentIdentifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE) {
-                // If the parent is storage, the object might be appeared as child of device because
-                // we skip storage when the device has only one storage.
-                final Identifier deviceIdentifier = mDatabase.getParentIdentifier(
-                        parentIdentifier.mDocumentId);
-                notifyChildDocumentsChange(deviceIdentifier.mDocumentId);
-            }
-        } catch (IOException error) {
-            Log.e(MtpDocumentsProvider.TAG, "deleteDocument", error);
-            throw new FileNotFoundException(error.getMessage());
-        }
-    }
-
-    @Override
-    public void onTrimMemory(int level) {
-        synchronized (mDeviceListLock) {
-            for (final DeviceToolkit toolkit : mDeviceToolkits.values()) {
-                toolkit.mDocumentLoader.clearCompletedTasks();
-            }
-        }
-    }
-
-    @Override
-    public String createDocument(String parentDocumentId, String mimeType, String displayName)
-            throws FileNotFoundException {
-        if (DEBUG) {
-            Log.d(TAG, "createDocument: " + displayName);
-        }
-        final Identifier parentId;
-        final MtpDeviceRecord record;
-        final ParcelFileDescriptor[] pipe;
-        try {
-            parentId = mDatabase.createIdentifier(parentDocumentId);
-            openDevice(parentId.mDeviceId);
-            record = getDeviceToolkit(parentId.mDeviceId).mDeviceRecord;
-            if (!MtpDeviceRecord.isWritingSupported(record.operationsSupported)) {
-                throw new UnsupportedOperationException(
-                        "Writing operation is not supported by the device.");
-            }
-
-            final int parentObjectHandle;
-            final int storageId;
-            switch (parentId.mDocumentType) {
-                case MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE:
-                    final String[] storageDocumentIds =
-                            mDatabase.getStorageDocumentIds(parentId.mDocumentId);
-                    if (storageDocumentIds.length == 1) {
-                        final String newDocumentId =
-                                createDocument(storageDocumentIds[0], mimeType, displayName);
-                        notifyChildDocumentsChange(parentDocumentId);
-                        return newDocumentId;
-                    } else {
-                        throw new UnsupportedOperationException(
-                                "Cannot create a file under the device.");
-                    }
-                case MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE:
-                    storageId = parentId.mStorageId;
-                    parentObjectHandle = -1;
-                    break;
-                case MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT:
-                    storageId = parentId.mStorageId;
-                    parentObjectHandle = parentId.mObjectHandle;
-                    break;
-                default:
-                    throw new IllegalArgumentException("Unexpected document type.");
-            }
-
-            pipe = ParcelFileDescriptor.createReliablePipe();
-            int objectHandle = -1;
-            MtpObjectInfo info = null;
-            try {
-                pipe[0].close();  // 0 bytes for a new document.
-
-                final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ?
-                        MtpConstants.FORMAT_ASSOCIATION :
-                        MediaFile.getFormatCode(displayName, mimeType);
-                info = new MtpObjectInfo.Builder()
-                        .setStorageId(storageId)
-                        .setParent(parentObjectHandle)
-                        .setFormat(formatCode)
-                        .setName(displayName)
-                        .build();
-
-                final String[] parts = FileUtils.splitFileName(mimeType, displayName);
-                final String baseName = parts[0];
-                final String extension = parts[1];
-                for (int i = 0; i <= 32; i++) {
-                    final MtpObjectInfo infoUniqueName;
-                    if (i == 0) {
-                        infoUniqueName = info;
-                    } else {
-                        String suffixedName = baseName + " (" + i + " )";
-                        if (!extension.isEmpty()) {
-                            suffixedName += "." + extension;
-                        }
-                        infoUniqueName =
-                                new MtpObjectInfo.Builder(info).setName(suffixedName).build();
-                    }
-                    try {
-                        objectHandle = mMtpManager.createDocument(
-                                parentId.mDeviceId, infoUniqueName, pipe[1]);
-                        break;
-                    } catch (SendObjectInfoFailure exp) {
-                        // This can be caused when we have an existing file with the same name.
-                        continue;
-                    }
-                }
-            } finally {
-                pipe[1].close();
-            }
-            if (objectHandle == -1) {
-                throw new IllegalArgumentException(
-                        "The file name \"" + displayName + "\" is conflicted with existing files " +
-                        "and the provider failed to find unique name.");
-            }
-            final MtpObjectInfo infoWithHandle =
-                    new MtpObjectInfo.Builder(info).setObjectHandle(objectHandle).build();
-            final String documentId = mDatabase.putNewDocument(
-                    parentId.mDeviceId, parentDocumentId, record.operationsSupported,
-                    infoWithHandle, 0l);
-            getDocumentLoader(parentId).cancelTask(parentId);
-            notifyChildDocumentsChange(parentDocumentId);
-            return documentId;
-        } catch (FileNotFoundException | RuntimeException error) {
-            Log.e(TAG, "createDocument", error);
-            throw error;
-        } catch (IOException error) {
-            Log.e(TAG, "createDocument", error);
-            throw new IllegalStateException(error);
-        }
-    }
-
-    @Override
-    public Path findDocumentPath(String parentDocumentId, String childDocumentId)
-            throws FileNotFoundException {
-        final LinkedList<String> ids = new LinkedList<>();
-        final Identifier childIdentifier = mDatabase.createIdentifier(childDocumentId);
-
-        Identifier i = childIdentifier;
-        outer: while (true) {
-            if (i.mDocumentId.equals(parentDocumentId)) {
-                ids.addFirst(i.mDocumentId);
-                break;
-            }
-            switch (i.mDocumentType) {
-                case MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT:
-                    ids.addFirst(i.mDocumentId);
-                    i = mDatabase.getParentIdentifier(i.mDocumentId);
-                    break;
-                case MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE: {
-                    // Check if there is the multiple storage.
-                    final Identifier deviceIdentifier =
-                            mDatabase.getParentIdentifier(i.mDocumentId);
-                    final String[] storageIds =
-                            mDatabase.getStorageDocumentIds(deviceIdentifier.mDocumentId);
-                    // Add storage's document ID to the path only when the device has multiple
-                    // storages.
-                    if (storageIds.length > 1) {
-                        ids.addFirst(i.mDocumentId);
-                        break outer;
-                    }
-                    i = deviceIdentifier;
-                    break;
-                }
-                case MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE:
-                    ids.addFirst(i.mDocumentId);
-                    break outer;
-            }
-        }
-
-        if (parentDocumentId != null) {
-            return new Path(null, ids);
-        } else {
-            return new Path(/* Should be same with root ID */ i.mDocumentId, ids);
-        }
-    }
-
-    @Override
-    public boolean isChildDocument(String parentDocumentId, String documentId) {
-        try {
-            Identifier identifier = mDatabase.createIdentifier(documentId);
-            while (true) {
-                if (parentDocumentId.equals(identifier.mDocumentId)) {
-                    return true;
-                }
-                if (identifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE) {
-                    return false;
-                }
-                identifier = mDatabase.getParentIdentifier(identifier.mDocumentId);
-            }
-        } catch (FileNotFoundException error) {
-            return false;
-        }
-    }
-
-    @Override
-    public @Nullable Bundle getDocumentMetadata(String docId) throws FileNotFoundException {
-        String mimeType = getDocumentType(docId);
-
-        if (!MetadataReader.isSupportedMimeType(mimeType)) {
-            return null;
-        }
-
-        InputStream stream = null;
-        try {
-            stream = new ParcelFileDescriptor.AutoCloseInputStream(
-                    openDocument(docId, "r", null));
-            Bundle metadata = new Bundle();
-            MetadataReader.getMetadata(metadata, stream, mimeType, null);
-            return metadata;
-        } catch (IOException e) {
-            Log.e(TAG, "An error occurred retrieving the metadata", e);
-            return null;
-        } finally {
-            IoUtils.closeQuietly(stream);
-        }
-    }
-
-    void openDevice(int deviceId) throws IOException {
-        synchronized (mDeviceListLock) {
-            if (mDeviceToolkits.containsKey(deviceId)) {
-                return;
-            }
-            if (DEBUG) {
-                Log.d(TAG, "Open device " + deviceId);
-            }
-            final MtpDeviceRecord device = mMtpManager.openDevice(deviceId);
-            final DeviceToolkit toolkit =
-                    new DeviceToolkit(mMtpManager, mResolver, mDatabase, device);
-            mDeviceToolkits.put(deviceId, toolkit);
-            mIntentSender.sendUpdateNotificationIntent(getOpenedDeviceRecordsCache());
-            try {
-                mRootScanner.resume().await();
-            } catch (InterruptedException error) {
-                Log.e(TAG, "openDevice", error);
-            }
-            // Resume document loader to remap disconnected document ID. Must be invoked after the
-            // root scanner resumes.
-            toolkit.mDocumentLoader.resume();
-        }
-    }
-
-    void closeDevice(int deviceId) throws IOException, InterruptedException {
-        synchronized (mDeviceListLock) {
-            closeDeviceInternal(deviceId);
-            mIntentSender.sendUpdateNotificationIntent(getOpenedDeviceRecordsCache());
-        }
-        mRootScanner.resume();
-    }
-
-    MtpDeviceRecord[] getOpenedDeviceRecordsCache() {
-        synchronized (mDeviceListLock) {
-            final MtpDeviceRecord[] records = new MtpDeviceRecord[mDeviceToolkits.size()];
-            int i = 0;
-            for (final DeviceToolkit toolkit : mDeviceToolkits.values()) {
-                records[i] = toolkit.mDeviceRecord;
-                i++;
-            }
-            return records;
-        }
-    }
-
-    /**
-     * Obtains document ID for the given device ID.
-     * @param deviceId
-     * @return document ID
-     * @throws FileNotFoundException device ID has not been build.
-     */
-    public String getDeviceDocumentId(int deviceId) throws FileNotFoundException {
-        return mDatabase.getDeviceDocumentId(deviceId);
-    }
-
-    /**
-     * Resumes root scanner to handle the update of device list.
-     */
-    void resumeRootScanner() {
-        if (DEBUG) {
-            Log.d(MtpDocumentsProvider.TAG, "resumeRootScanner");
-        }
-        mRootScanner.resume();
-    }
-
-    /**
-     * Finalize the content provider for unit tests.
-     */
-    @Override
-    public void shutdown() {
-        synchronized (mDeviceListLock) {
-            try {
-                // Copy the opened key set because it will be modified when closing devices.
-                final Integer[] keySet =
-                        mDeviceToolkits.keySet().toArray(new Integer[mDeviceToolkits.size()]);
-                for (final int id : keySet) {
-                    closeDeviceInternal(id);
-                }
-                mRootScanner.pause();
-            } catch (InterruptedException | IOException | TimeoutException e) {
-                // It should fail unit tests by throwing runtime exception.
-                throw new RuntimeException(e);
-            } finally {
-                mDatabase.close();
-                super.shutdown();
-            }
-        }
-    }
-
-    private void notifyChildDocumentsChange(String parentDocumentId) {
-        mResolver.notifyChange(
-                DocumentsContract.buildChildDocumentsUri(AUTHORITY, parentDocumentId),
-                null,
-                false);
-    }
-
-    /**
-     * Clears MTP identifier in the database.
-     */
-    private void resume() {
-        synchronized (mDeviceListLock) {
-            mDatabase.getMapper().clearMapping();
-        }
-    }
-
-    private void closeDeviceInternal(int deviceId) throws IOException, InterruptedException {
-        // TODO: Flush the device before closing (if not closed externally).
-        if (!mDeviceToolkits.containsKey(deviceId)) {
-            return;
-        }
-        if (DEBUG) {
-            Log.d(TAG, "Close device " + deviceId);
-        }
-        getDeviceToolkit(deviceId).close();
-        mDeviceToolkits.remove(deviceId);
-        mMtpManager.closeDevice(deviceId);
-    }
-
-    private DeviceToolkit getDeviceToolkit(int deviceId) throws FileNotFoundException {
-        synchronized (mDeviceListLock) {
-            final DeviceToolkit toolkit = mDeviceToolkits.get(deviceId);
-            if (toolkit == null) {
-                throw new FileNotFoundException();
-            }
-            return toolkit;
-        }
-    }
-
-    private PipeManager getPipeManager(Identifier identifier) throws FileNotFoundException {
-        return getDeviceToolkit(identifier.mDeviceId).mPipeManager;
-    }
-
-    private DocumentLoader getDocumentLoader(Identifier identifier) throws FileNotFoundException {
-        return getDeviceToolkit(identifier.mDeviceId).mDocumentLoader;
-    }
-
-    private long getFileSize(String documentId) throws FileNotFoundException {
-        final Cursor cursor = mDatabase.queryDocument(
-                documentId,
-                MtpDatabase.strings(Document.COLUMN_SIZE, Document.COLUMN_DISPLAY_NAME));
-        try {
-            if (cursor.moveToNext()) {
-                if (cursor.isNull(0)) {
-                    throw new UnsupportedOperationException();
-                }
-                return cursor.getLong(0);
-            } else {
-                throw new FileNotFoundException();
-            }
-        } finally {
-            cursor.close();
-        }
-    }
-
-    /**
-     * Creates empty cursor with specific error message.
-     *
-     * @param projection Column names.
-     * @param stringResId String resource ID of error message.
-     * @return Empty cursor with error message.
-     */
-    private Cursor createErrorCursor(String[] projection, int stringResId) {
-        final Bundle bundle = new Bundle();
-        bundle.putString(DocumentsContract.EXTRA_ERROR, mResources.getString(stringResId));
-        final Cursor cursor = new MatrixCursor(projection);
-        cursor.setExtras(bundle);
-        return cursor;
-    }
-
-    private static class DeviceToolkit implements AutoCloseable {
-        public final PipeManager mPipeManager;
-        public final DocumentLoader mDocumentLoader;
-        public final MtpDeviceRecord mDeviceRecord;
-
-        public DeviceToolkit(MtpManager manager,
-                             ContentResolver resolver,
-                             MtpDatabase database,
-                             MtpDeviceRecord record) {
-            mPipeManager = new PipeManager(database);
-            mDocumentLoader = new DocumentLoader(record, manager, resolver, database);
-            mDeviceRecord = record;
-        }
-
-        @Override
-        public void close() throws InterruptedException {
-            mPipeManager.close();
-            mDocumentLoader.close();
-        }
-    }
-
-    private class MtpProxyFileDescriptorCallback extends ProxyFileDescriptorCallback {
-        private final int mInode;
-        private MtpFileWriter mWriter;
-
-        MtpProxyFileDescriptorCallback(int inode) {
-            mInode = inode;
-        }
-
-        @Override
-        public long onGetSize() throws ErrnoException {
-            try {
-                return getFileSize(String.valueOf(mInode));
-            } catch (FileNotFoundException e) {
-                Log.e(TAG, e.getMessage(), e);
-                throw new ErrnoException("onGetSize", OsConstants.ENOENT);
-            }
-        }
-
-        @Override
-        public int onRead(long offset, int size, byte[] data) throws ErrnoException {
-            try {
-                final Identifier identifier = mDatabase.createIdentifier(Integer.toString(mInode));
-                final MtpDeviceRecord record = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord;
-                if (MtpDeviceRecord.isSupported(
-                        record.operationsSupported, MtpConstants.OPERATION_GET_PARTIAL_OBJECT_64)) {
-
-                        return (int) mMtpManager.getPartialObject64(
-                                identifier.mDeviceId, identifier.mObjectHandle, offset, size, data);
-
-                }
-                if (0 <= offset && offset <= 0xffffffffL && MtpDeviceRecord.isSupported(
-                        record.operationsSupported, MtpConstants.OPERATION_GET_PARTIAL_OBJECT)) {
-                    return (int) mMtpManager.getPartialObject(
-                            identifier.mDeviceId, identifier.mObjectHandle, offset, size, data);
-                }
-                throw new ErrnoException("onRead", OsConstants.ENOTSUP);
-            } catch (IOException e) {
-                Log.e(TAG, e.getMessage(), e);
-                throw new ErrnoException("onRead", OsConstants.EIO);
-            }
-        }
-
-        @Override
-        public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
-            try {
-                if (mWriter == null) {
-                    mWriter = new MtpFileWriter(mContext, String.valueOf(mInode));
-                }
-                return mWriter.write(offset, size, data);
-            } catch (IOException e) {
-                Log.e(TAG, e.getMessage(), e);
-                throw new ErrnoException("onWrite", OsConstants.EIO);
-            }
-        }
-
-        @Override
-        public void onFsync() throws ErrnoException {
-            tryFsync();
-        }
-
-        @Override
-        public void onRelease() {
-            try {
-                tryFsync();
-            } catch (ErrnoException error) {
-                // Cannot recover from the error at onRelease. Client app should use fsync to
-                // ensure the provider writes data correctly.
-                Log.e(TAG, "Cannot recover from the error at onRelease.", error);
-            } finally {
-                if (mWriter != null) {
-                    IoUtils.closeQuietly(mWriter);
-                }
-            }
-        }
-
-        private void tryFsync() throws ErrnoException {
-            try {
-                if (mWriter != null) {
-                    final MtpDeviceRecord device =
-                            getDeviceToolkit(mDatabase.createIdentifier(
-                                    mWriter.getDocumentId()).mDeviceId).mDeviceRecord;
-                    mWriter.flush(mMtpManager, mDatabase, device.operationsSupported);
-                }
-            } catch (IOException e) {
-                Log.e(TAG, e.getMessage(), e);
-                throw new ErrnoException("onWrite", OsConstants.EIO);
-            }
-        }
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
deleted file mode 100644
index fa1a12030..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Notification;
-import android.app.Service;
-import android.app.NotificationManager;
-import android.content.Intent;
-import android.os.IBinder;
-import android.os.Parcelable;
-import android.service.notification.StatusBarNotification;
-import android.util.Log;
-import com.android.internal.util.Preconditions;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Service to manage lifetime of DocumentsProvider's process.
- * The service prevents the system from killing the process that holds USB connections. The service
- * starts to run when the first MTP device is opened, and stops when the last MTP device is closed.
- */
-public class MtpDocumentsService extends Service {
-    static final String ACTION_UPDATE_NOTIFICATION = "com.android.mtp.UPDATE_NOTIFICATION";
-    static final String EXTRA_DEVICE_IDS = "deviceIds";
-    static final String EXTRA_DEVICE_NOTIFICATIONS = "deviceNotifications";
-
-    private NotificationManager mNotificationManager;
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        // The service is used via intents.
-        return null;
-    }
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mNotificationManager = getSystemService(NotificationManager.class);
-    }
-
-    @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        // If intent is null, the service was restarted.
-        if (intent == null || ACTION_UPDATE_NOTIFICATION.equals(intent.getAction())) {
-            final int[] ids = intent.hasExtra(EXTRA_DEVICE_IDS) ?
-                    intent.getExtras().getIntArray(EXTRA_DEVICE_IDS) : null;
-            final Notification[] notifications = intent.hasExtra(EXTRA_DEVICE_NOTIFICATIONS) ?
-                    castToNotifications(intent.getExtras().getParcelableArray(
-                            EXTRA_DEVICE_NOTIFICATIONS)) : null;
-            return updateForegroundState(ids, notifications) ? START_STICKY : START_NOT_STICKY;
-        }
-        return START_NOT_STICKY;
-    }
-
-    /**
-     * Updates the foreground state of the service.
-     * @return Whether the service is foreground or not.
-     */
-    private boolean updateForegroundState(
-            @Nullable int[] ids, @Nullable Notification[] notifications) {
-        final Set<Integer> openedNotification = new HashSet<>();
-        final int size = ids != null ? ids.length : 0;
-        if (size != 0) {
-            Preconditions.checkArgument(ids != null);
-            Preconditions.checkArgument(notifications != null);
-            Preconditions.checkArgument(ids.length == notifications.length);
-        }
-
-        for (int i = 0; i < size; i++) {
-            if (i == 0) {
-                // Mark this service as foreground with the notification so that the process is
-                // not killed by the system while a MTP device is opened.
-                startForeground(ids[i], notifications[i]);
-            } else {
-                // Only one notification can be shown as a foreground notification. We need to
-                // show the rest as normal notification.
-                mNotificationManager.notify(ids[i], notifications[i]);
-            }
-            openedNotification.add(ids[i]);
-        }
-
-        final StatusBarNotification[] activeNotifications =
-                mNotificationManager.getActiveNotifications();
-        for (final StatusBarNotification notification : activeNotifications) {
-            if (!openedNotification.contains(notification.getId())) {
-                mNotificationManager.cancel(notification.getId());
-            }
-        }
-
-        if (size == 0) {
-            // There is no opened device.
-            stopForeground(true /* removeNotification */);
-            stopSelf();
-            return false;
-        }
-
-        return true;
-    }
-
-    private static @NonNull Notification[] castToNotifications(@NonNull Parcelable[] src) {
-        Preconditions.checkNotNull(src);
-        final Notification[] notifications = new Notification[src.length];
-        for (int i = 0; i < src.length; i++) {
-            notifications[i] = (Notification) src[i];
-        }
-        return notifications;
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpFileWriter.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpFileWriter.java
deleted file mode 100644
index 3e1bedc..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpFileWriter.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.content.Context;
-import android.mtp.MtpObjectInfo;
-import android.os.ParcelFileDescriptor;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
-
-import com.android.internal.util.Preconditions;
-
-import java.io.File;
-import java.io.IOException;
-
-class MtpFileWriter implements AutoCloseable {
-    final ParcelFileDescriptor mCacheFd;
-    final String mDocumentId;
-    boolean mDirty;
-
-    MtpFileWriter(Context context, String documentId) throws IOException {
-        mDocumentId = documentId;
-        mDirty = false;
-        final File tempFile = File.createTempFile("mtp", "tmp", context.getCacheDir());
-        mCacheFd = ParcelFileDescriptor.open(
-                tempFile,
-                ParcelFileDescriptor.MODE_READ_WRITE |
-                ParcelFileDescriptor.MODE_TRUNCATE |
-                ParcelFileDescriptor.MODE_CREATE);
-        tempFile.delete();
-    }
-
-    String getDocumentId() {
-        return mDocumentId;
-    }
-
-    int write(long offset, int size, byte[] bytes) throws IOException, ErrnoException {
-        Preconditions.checkArgumentNonnegative(offset, "offset");
-        Preconditions.checkArgumentNonnegative(size, "size");
-        Preconditions.checkArgument(size <= bytes.length);
-        if (size == 0) {
-            return 0;
-        }
-        mDirty = true;
-        Os.lseek(mCacheFd.getFileDescriptor(), offset, OsConstants.SEEK_SET);
-        return Os.write(mCacheFd.getFileDescriptor(), bytes, 0, size);
-    }
-
-    void flush(MtpManager manager, MtpDatabase database, int[] operationsSupported)
-            throws IOException, ErrnoException {
-        // Skip unnecessary flush.
-        if (!mDirty) {
-            return;
-        }
-
-        // Get the placeholder object info.
-        final Identifier identifier = database.createIdentifier(mDocumentId);
-        final MtpObjectInfo placeholderObjectInfo =
-                manager.getObjectInfo(identifier.mDeviceId, identifier.mObjectHandle);
-
-        // Delete the target object info if it already exists (as a placeholder).
-        manager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
-
-        // Create the target object info with a correct file size and upload the file.
-        final long size = Os.lseek(mCacheFd.getFileDescriptor(), 0, OsConstants.SEEK_END);
-        final MtpObjectInfo targetObjectInfo = new MtpObjectInfo.Builder(placeholderObjectInfo)
-                .setCompressedSize(size)
-                .build();
-
-        Os.lseek(mCacheFd.getFileDescriptor(), 0, OsConstants.SEEK_SET);
-        final int newObjectHandle = manager.createDocument(
-                identifier.mDeviceId, targetObjectInfo, mCacheFd);
-
-        final MtpObjectInfo newObjectInfo = manager.getObjectInfo(
-                identifier.mDeviceId, newObjectHandle);
-        final Identifier parentIdentifier =
-                database.getParentIdentifier(identifier.mDocumentId);
-        database.updateObject(
-                identifier.mDocumentId,
-                identifier.mDeviceId,
-                parentIdentifier.mDocumentId,
-                operationsSupported,
-                newObjectInfo,
-                size);
-
-        mDirty = false;
-    }
-
-    @Override
-    public void close() throws IOException {
-        mCacheFd.close();
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
deleted file mode 100644
index a7de631..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.hardware.usb.UsbConstants;
-import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbDeviceConnection;
-import android.hardware.usb.UsbInterface;
-import android.hardware.usb.UsbManager;
-import android.mtp.MtpConstants;
-import android.mtp.MtpDevice;
-import android.mtp.MtpDeviceInfo;
-import android.mtp.MtpEvent;
-import android.mtp.MtpObjectInfo;
-import android.mtp.MtpStorageInfo;
-import android.os.CancellationSignal;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-
-/**
- * The model wrapping android.mtp API.
- */
-class MtpManager {
-    final static int OBJECT_HANDLE_ROOT_CHILDREN = -1;
-
-    /**
-     * Subclass for PTP.
-     */
-    private static final int SUBCLASS_STILL_IMAGE_CAPTURE = 1;
-
-    /**
-     * Subclass for Android style MTP.
-     */
-    private static final int SUBCLASS_MTP = 0xff;
-
-    /**
-     * Protocol for Picture Transfer Protocol (PIMA 15470).
-     */
-    private static final int PROTOCOL_PICTURE_TRANSFER = 1;
-
-    /**
-     * Protocol for Android style MTP.
-     */
-    private static final int PROTOCOL_MTP = 0;
-
-    private final UsbManager mManager;
-    private final SparseArray<MtpDevice> mDevices = new SparseArray<>();
-
-    MtpManager(Context context) {
-        mManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
-    }
-
-    synchronized MtpDeviceRecord openDevice(int deviceId) throws IOException {
-        UsbDevice rawDevice = null;
-        for (final UsbDevice candidate : mManager.getDeviceList().values()) {
-            if (candidate.getDeviceId() == deviceId) {
-                rawDevice = candidate;
-                break;
-            }
-        }
-
-        ensureNotNull(rawDevice, "Not found USB device: " + deviceId);
-
-        if (!mManager.hasPermission(rawDevice)) {
-            mManager.grantPermission(rawDevice);
-            if (!mManager.hasPermission(rawDevice)) {
-                throw new IOException("Failed to grant a device permission.");
-            }
-        }
-
-        final MtpDevice device = new MtpDevice(rawDevice);
-
-        final UsbDeviceConnection connection = ensureNotNull(
-                mManager.openDevice(rawDevice),
-                "Failed to open a USB connection.");
-
-        if (!device.open(connection)) {
-            // We cannot open connection when another application use the device.
-            throw new BusyDeviceException();
-        }
-
-        // Handle devices that fail to obtain storages just after opening a MTP session.
-        final int[] storageIds = ensureNotNull(
-                device.getStorageIds(),
-                "Not found MTP storages in the device.");
-
-        mDevices.put(deviceId, device);
-        return createDeviceRecord(rawDevice);
-    }
-
-    synchronized void closeDevice(int deviceId) throws IOException {
-        getDevice(deviceId).close();
-        mDevices.remove(deviceId);
-    }
-
-    synchronized MtpDeviceRecord[] getDevices() {
-        final ArrayList<MtpDeviceRecord> devices = new ArrayList<>();
-        for (UsbDevice device : mManager.getDeviceList().values()) {
-            if (!isMtpDevice(device)) {
-                continue;
-            }
-            devices.add(createDeviceRecord(device));
-        }
-        return devices.toArray(new MtpDeviceRecord[devices.size()]);
-    }
-
-    MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        synchronized (device) {
-            return ensureNotNull(
-                    device.getObjectInfo(objectHandle),
-                    "Failed to get object info: " + objectHandle);
-        }
-    }
-
-    int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
-            throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        synchronized (device) {
-            return ensureNotNull(
-                    device.getObjectHandles(storageId, 0 /* all format */, parentObjectHandle),
-                    "Failed to fetch object handles.");
-        }
-    }
-
-    byte[] getObject(int deviceId, int objectHandle, int expectedSize)
-            throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        synchronized (device) {
-            return ensureNotNull(
-                    device.getObject(objectHandle, expectedSize),
-                    "Failed to fetch object bytes");
-        }
-    }
-
-    long getPartialObject(int deviceId, int objectHandle, long offset, long size, byte[] buffer)
-            throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        synchronized (device) {
-            return device.getPartialObject(objectHandle, offset, size, buffer);
-        }
-    }
-
-    long getPartialObject64(int deviceId, int objectHandle, long offset, long size, byte[] buffer)
-            throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        synchronized (device) {
-            return device.getPartialObject64(objectHandle, offset, size, buffer);
-        }
-    }
-
-    byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        synchronized (device) {
-            return ensureNotNull(
-                    device.getThumbnail(objectHandle),
-                    "Failed to obtain thumbnail bytes");
-        }
-    }
-
-    void deleteDocument(int deviceId, int objectHandle) throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        synchronized (device) {
-            if (!device.deleteObject(objectHandle)) {
-                throw new IOException("Failed to delete document");
-            }
-        }
-    }
-
-    int createDocument(int deviceId, MtpObjectInfo objectInfo,
-            ParcelFileDescriptor source) throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        synchronized (device) {
-            final MtpObjectInfo sendObjectInfoResult = device.sendObjectInfo(objectInfo);
-            if (sendObjectInfoResult == null) {
-                throw new SendObjectInfoFailure();
-            }
-            if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) {
-                if (!device.sendObject(sendObjectInfoResult.getObjectHandle(),
-                        sendObjectInfoResult.getCompressedSizeLong(), source)) {
-                    throw new IOException("Failed to send contents of a document");
-                }
-            }
-            return sendObjectInfoResult.getObjectHandle();
-        }
-    }
-
-    int getParent(int deviceId, int objectHandle) throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        synchronized (device) {
-            final int result = (int) device.getParent(objectHandle);
-            if (result == 0xffffffff) {
-                throw new FileNotFoundException("Not found parent object");
-            }
-            return result;
-        }
-    }
-
-    void importFile(int deviceId, int objectHandle, ParcelFileDescriptor target)
-            throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        synchronized (device) {
-            if (!device.importFile(objectHandle, target)) {
-                throw new IOException("Failed to import file to FD");
-            }
-        }
-    }
-
-    @VisibleForTesting
-    MtpEvent readEvent(int deviceId, CancellationSignal signal) throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        return device.readEvent(signal);
-    }
-
-    long getObjectSizeLong(int deviceId, int objectHandle, int format) throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        return device.getObjectSizeLong(objectHandle, format);
-    }
-
-    private synchronized MtpDevice getDevice(int deviceId) throws IOException {
-        return ensureNotNull(
-                mDevices.get(deviceId),
-                "USB device " + deviceId + " is not opened.");
-    }
-
-    private MtpRoot[] getRoots(int deviceId) throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        synchronized (device) {
-            final int[] storageIds =
-                    ensureNotNull(device.getStorageIds(), "Failed to obtain storage IDs.");
-            final ArrayList<MtpRoot> roots = new ArrayList<>();
-            for (int i = 0; i < storageIds.length; i++) {
-                final MtpStorageInfo info = device.getStorageInfo(storageIds[i]);
-                if (info == null) {
-                    continue;
-                }
-                roots.add(new MtpRoot(device.getDeviceId(), info));
-            }
-            return roots.toArray(new MtpRoot[roots.size()]);
-        }
-    }
-
-    private MtpDeviceRecord createDeviceRecord(UsbDevice device) {
-        final MtpDevice mtpDevice = mDevices.get(device.getDeviceId());
-        final boolean opened = mtpDevice != null;
-        final String name = device.getProductName();
-        MtpRoot[] roots;
-        int[] operationsSupported = null;
-        int[] eventsSupported = null;
-        if (opened) {
-            try {
-                roots = getRoots(device.getDeviceId());
-            } catch (IOException exp) {
-                Log.e(MtpDocumentsProvider.TAG, "Failed to open device", exp);
-                // If we failed to fetch roots for the device, we still returns device model
-                // with an empty set of roots so that the device is shown DocumentsUI as long as
-                // the device is physically connected.
-                roots = new MtpRoot[0];
-            }
-            final MtpDeviceInfo info = mtpDevice.getDeviceInfo();
-            if (info != null) {
-                operationsSupported = info.getOperationsSupported();
-                eventsSupported = info.getEventsSupported();
-            }
-        } else {
-            roots = new MtpRoot[0];
-        }
-        return new MtpDeviceRecord(
-                device.getDeviceId(), name, device.getSerialNumber(), opened, roots,
-                operationsSupported, eventsSupported);
-    }
-
-    static boolean isMtpDevice(UsbDevice device) {
-        for (int i = 0; i < device.getInterfaceCount(); i++) {
-            final UsbInterface usbInterface = device.getInterface(i);
-            if ((usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_STILL_IMAGE &&
-                    usbInterface.getInterfaceSubclass() == SUBCLASS_STILL_IMAGE_CAPTURE &&
-                    usbInterface.getInterfaceProtocol() == PROTOCOL_PICTURE_TRANSFER)) {
-                return true;
-            }
-            if (usbInterface.getInterfaceClass() == UsbConstants.USB_SUBCLASS_VENDOR_SPEC &&
-                    usbInterface.getInterfaceSubclass() == SUBCLASS_MTP &&
-                    usbInterface.getInterfaceProtocol() == PROTOCOL_MTP &&
-                    "MTP".equals(usbInterface.getName())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static <T> T ensureNotNull(@Nullable T t, String errorMessage) throws IOException {
-        if (t != null) {
-            return t;
-        } else {
-            throw new IOException(errorMessage);
-        }
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpRoot.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpRoot.java
deleted file mode 100644
index 8530aaf..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpRoot.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.mtp.MtpStorageInfo;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-class MtpRoot {
-    final int mDeviceId;
-    final int mStorageId;
-    final String mDescription;
-    final long mFreeSpace;
-    final long mMaxCapacity;
-    final String mVolumeIdentifier;
-
-    @VisibleForTesting
-    MtpRoot(int deviceId,
-            int storageId,
-            String description,
-            long freeSpace,
-            long maxCapacity,
-            String volumeIdentifier) {
-        mDeviceId = deviceId;
-        mStorageId = storageId;
-        mDescription = description;
-        mFreeSpace = freeSpace;
-        mMaxCapacity = maxCapacity;
-        mVolumeIdentifier = volumeIdentifier;
-    }
-
-    MtpRoot(int deviceId, MtpStorageInfo storageInfo) {
-        mDeviceId = deviceId;
-        mStorageId = storageInfo.getStorageId();
-        mDescription = storageInfo.getDescription();
-        mFreeSpace = storageInfo.getFreeSpace();
-        mMaxCapacity = storageInfo.getMaxCapacity();
-        mVolumeIdentifier = storageInfo.getVolumeIdentifier();
-    }
-
-    @Override
-    public boolean equals(Object object) {
-        if (!(object instanceof MtpRoot))
-            return false;
-        final MtpRoot other = (MtpRoot) object;
-        return mDeviceId == other.mDeviceId &&
-                mStorageId == other.mStorageId &&
-                mDescription.equals(other.mDescription) &&
-                mFreeSpace == other.mFreeSpace &&
-                mMaxCapacity == other.mMaxCapacity &&
-                mVolumeIdentifier.equals(other.mVolumeIdentifier);
-    }
-
-    @Override
-    public int hashCode() {
-        return mDeviceId ^ mStorageId ^ mDescription.hashCode() ^
-                ((int) mFreeSpace) ^ ((int) mMaxCapacity) ^ mVolumeIdentifier.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        return "MtpRoot{Name: " + mDescription + "}";
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
deleted file mode 100644
index 795bbc1..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import java.io.IOException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-class PipeManager {
-    /**
-     * Milliseconds we wait for background thread when pausing.
-     */
-    private final static long AWAIT_TERMINATION_TIMEOUT = 2000;
-
-    final ExecutorService mExecutor;
-    final MtpDatabase mDatabase;
-
-    PipeManager(MtpDatabase database) {
-        this(database, Executors.newSingleThreadExecutor());
-    }
-
-    PipeManager(MtpDatabase database, ExecutorService executor) {
-        this.mDatabase = database;
-        this.mExecutor = executor;
-    }
-
-    ParcelFileDescriptor readDocument(MtpManager model, Identifier identifier) throws IOException {
-        final Task task = new ImportFileTask(model, identifier);
-        mExecutor.execute(task);
-        return task.getReadingFileDescriptor();
-    }
-
-    ParcelFileDescriptor readThumbnail(MtpManager model, Identifier identifier) throws IOException {
-        final Task task = new GetThumbnailTask(model, identifier);
-        mExecutor.execute(task);
-        return task.getReadingFileDescriptor();
-    }
-
-    private static abstract class Task implements Runnable {
-        protected final MtpManager mManager;
-        protected final Identifier mIdentifier;
-        protected final ParcelFileDescriptor[] mDescriptors;
-
-        Task(MtpManager manager, Identifier identifier) throws IOException {
-            mManager = manager;
-            mIdentifier = identifier;
-            mDescriptors = ParcelFileDescriptor.createReliablePipe();
-        }
-
-        ParcelFileDescriptor getReadingFileDescriptor() {
-            return mDescriptors[0];
-        }
-    }
-
-    private static class ImportFileTask extends Task {
-        ImportFileTask(MtpManager model, Identifier identifier) throws IOException {
-            super(model, identifier);
-        }
-
-        @Override
-        public void run() {
-            try {
-                mManager.importFile(
-                        mIdentifier.mDeviceId, mIdentifier.mObjectHandle, mDescriptors[1]);
-                mDescriptors[1].close();
-            } catch (IOException error) {
-                try {
-                    mDescriptors[1].closeWithError("Failed to stream a file.");
-                } catch (IOException closeError) {
-                    Log.w(MtpDocumentsProvider.TAG, closeError.getMessage());
-                }
-            }
-        }
-    }
-
-    private static class GetThumbnailTask extends Task {
-        GetThumbnailTask(MtpManager model, Identifier identifier) throws IOException {
-            super(model, identifier);
-        }
-
-        @Override
-        public void run() {
-            try {
-                try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
-                        new ParcelFileDescriptor.AutoCloseOutputStream(mDescriptors[1])) {
-                    try {
-                        stream.write(mManager.getThumbnail(
-                                mIdentifier.mDeviceId, mIdentifier.mObjectHandle));
-                    } catch (IOException error) {
-                        mDescriptors[1].closeWithError("Failed to stream a thumbnail.");
-                    }
-                }
-            } catch (IOException closeError) {
-                Log.w(MtpDocumentsProvider.TAG, closeError.getMessage());
-            }
-        }
-    }
-
-    boolean close() throws InterruptedException {
-        mExecutor.shutdownNow();
-        return mExecutor.awaitTermination(AWAIT_TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS);
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java b/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java
deleted file mode 100644
index 19c2c14..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.DocumentsContract;
-import android.util.Log;
-
-import java.io.IOException;
-
-/**
- * Invisible activity to receive intents.
- * To show Files app for the UsbManager.ACTION_USB_DEVICE_ATTACHED intent, the intent should be
- * received by activity. The activity has NoDisplay theme and immediately terminate after routing
- * intent to DocumentsUI.
- */
-public class ReceiverActivity extends Activity {
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(getIntent().getAction())) {
-            final UsbDevice device = getIntent().getParcelableExtra(UsbManager.EXTRA_DEVICE);
-            try {
-                final MtpDocumentsProvider provider = MtpDocumentsProvider.getInstance();
-                provider.openDevice(device.getDeviceId());
-                final String deviceRootId = provider.getDeviceDocumentId(device.getDeviceId());
-                final Uri uri = DocumentsContract.buildRootUri(
-                        MtpDocumentsProvider.AUTHORITY, deviceRootId);
-
-                final Intent intent = new Intent(Intent.ACTION_VIEW);
-                intent.setDataAndType(uri, DocumentsContract.Root.MIME_TYPE_ITEM);
-                intent.addCategory(Intent.CATEGORY_DEFAULT);
-                this.startActivity(intent);
-            } catch (IOException exception) {
-                Log.e(MtpDocumentsProvider.TAG, "Failed to open device", exception);
-            }
-        }
-        finish();
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
deleted file mode 100644
index 20be2ba..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.content.ContentResolver;
-import android.net.Uri;
-import android.os.Process;
-import android.provider.DocumentsContract;
-import android.util.Log;
-
-import java.io.FileNotFoundException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-final class RootScanner {
-    /**
-     * Polling interval in milliseconds used for first SHORT_POLLING_TIMES because it is more
-     * likely to add new root just after the device is added.
-     */
-    private final static long SHORT_POLLING_INTERVAL = 2000;
-
-    /**
-     * Polling interval in milliseconds for low priority polling, when changes are not expected.
-     */
-    private final static long LONG_POLLING_INTERVAL = 30 * 1000;
-
-    /**
-     * @see #SHORT_POLLING_INTERVAL
-     */
-    private final static long SHORT_POLLING_TIMES = 10;
-
-    /**
-     * Milliseconds we wait for background thread when pausing.
-     */
-    private final static long AWAIT_TERMINATION_TIMEOUT = 2000;
-
-    final ContentResolver mResolver;
-    final MtpManager mManager;
-    final MtpDatabase mDatabase;
-
-    ExecutorService mExecutor;
-    private UpdateRootsRunnable mCurrentTask;
-
-    RootScanner(
-            ContentResolver resolver,
-            MtpManager manager,
-            MtpDatabase database) {
-        mResolver = resolver;
-        mManager = manager;
-        mDatabase = database;
-    }
-
-    /**
-     * Notifies a change of the roots list via ContentResolver.
-     */
-    void notifyChange() {
-        final Uri uri = DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY);
-        mResolver.notifyChange(uri, null, false);
-    }
-
-    /**
-     * Starts to check new changes right away.
-     */
-    synchronized CountDownLatch resume() {
-        if (mExecutor == null) {
-            // Only single thread updates the database.
-            mExecutor = Executors.newSingleThreadExecutor();
-        }
-        if (mCurrentTask != null) {
-            // Stop previous task.
-            mCurrentTask.stop();
-        }
-        mCurrentTask = new UpdateRootsRunnable();
-        mExecutor.execute(mCurrentTask);
-        return mCurrentTask.mFirstScanCompleted;
-    }
-
-    /**
-     * Stops background thread and wait for its termination.
-     * @throws InterruptedException
-     */
-    synchronized void pause() throws InterruptedException, TimeoutException {
-        if (mExecutor == null) {
-            return;
-        }
-        mExecutor.shutdownNow();
-        try {
-            if (!mExecutor.awaitTermination(AWAIT_TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS)) {
-                throw new TimeoutException(
-                        "Timeout for terminating RootScanner's background thread.");
-            }
-        } finally {
-            mExecutor = null;
-        }
-    }
-
-    /**
-     * Runnable to scan roots and update the database information.
-     */
-    private final class UpdateRootsRunnable implements Runnable {
-        /**
-         * Count down latch that specifies the runnable is stopped.
-         */
-        final CountDownLatch mStopped = new CountDownLatch(1);
-
-        /**
-         * Count down latch that specifies the first scan is completed.
-         */
-        final CountDownLatch mFirstScanCompleted = new CountDownLatch(1);
-
-        @Override
-        public void run() {
-            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-            int pollingCount = 0;
-            while (mStopped.getCount() > 0) {
-                boolean changed = false;
-
-                // Update devices.
-                final MtpDeviceRecord[] devices = mManager.getDevices();
-                try {
-                    mDatabase.getMapper().startAddingDocuments(null /* parentDocumentId */);
-                    for (final MtpDeviceRecord device : devices) {
-                        if (mDatabase.getMapper().putDeviceDocument(device)) {
-                            changed = true;
-                        }
-                    }
-                    if (mDatabase.getMapper().stopAddingDocuments(
-                            null /* parentDocumentId */)) {
-                        changed = true;
-                    }
-                } catch (FileNotFoundException exception) {
-                    // The top root (ID is null) must exist always.
-                    // FileNotFoundException is unexpected.
-                    Log.e(MtpDocumentsProvider.TAG, "Unexpected FileNotFoundException", exception);
-                    throw new AssertionError("Unexpected exception for the top parent", exception);
-                }
-
-                // Update roots.
-                for (final MtpDeviceRecord device : devices) {
-                    final String documentId = mDatabase.getDocumentIdForDevice(device.deviceId);
-                    if (documentId == null) {
-                        continue;
-                    }
-                    try {
-                        mDatabase.getMapper().startAddingDocuments(documentId);
-                        if (mDatabase.getMapper().putStorageDocuments(
-                                documentId, device.operationsSupported, device.roots)) {
-                            changed = true;
-                        }
-                        if (mDatabase.getMapper().stopAddingDocuments(documentId)) {
-                            changed = true;
-                        }
-                    } catch (FileNotFoundException exception) {
-                        Log.e(MtpDocumentsProvider.TAG, "Parent document is gone.", exception);
-                        continue;
-                    }
-                }
-
-                if (changed) {
-                    notifyChange();
-                }
-                mFirstScanCompleted.countDown();
-                pollingCount++;
-                if (devices.length == 0) {
-                    break;
-                }
-                try {
-                    // Use SHORT_POLLING_PERIOD for the first SHORT_POLLING_TIMES because it is
-                    // more likely to add new root just after the device is added.
-                    // TODO: Use short interval only for a device that is just added.
-                    mStopped.await(pollingCount > SHORT_POLLING_TIMES ?
-                            LONG_POLLING_INTERVAL : SHORT_POLLING_INTERVAL, TimeUnit.MILLISECONDS);
-                } catch (InterruptedException exp) {
-                    break;
-                }
-            }
-        }
-
-        void stop() {
-            mStopped.countDown();
-        }
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/SendObjectInfoFailure.java b/packages/MtpDocumentsProvider/src/com/android/mtp/SendObjectInfoFailure.java
deleted file mode 100644
index db7d777..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/SendObjectInfoFailure.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import java.io.IOException;
-
-/**
- * Exception thrown when sendObjectInfo failed.
- */
-class SendObjectInfoFailure extends IOException {
-    SendObjectInfoFailure() {
-        super("Failed to MtpDevice#sendObjectInfo.");
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java b/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java
deleted file mode 100644
index 629f6df..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.annotation.NonNull;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
-
-/**
- * Sends intent to MtpDocumentsService.
- */
-class ServiceIntentSender {
-    private final static String CHANNEL_ID = "device_notification_channel";
-    private final Context mContext;
-
-    ServiceIntentSender(Context context) {
-        mContext = context;
-
-        // Create notification channel.
-        final NotificationChannel mChannel = new NotificationChannel(
-                CHANNEL_ID,
-                context.getResources().getString(
-                        com.android.internal.R.string.default_notification_channel_label),
-                NotificationManager.IMPORTANCE_LOW);
-        final NotificationManager notificationManager =
-                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-        notificationManager.createNotificationChannel(mChannel);
-    }
-
-    @VisibleForTesting
-    protected ServiceIntentSender() {
-        mContext = null;
-    }
-
-    /**
-     * Notify the change of opened device set.
-     * @param records List of opened devices. Can be empty.
-     */
-    void sendUpdateNotificationIntent(@NonNull MtpDeviceRecord[] records) {
-        Preconditions.checkNotNull(records);
-        final Intent intent = new Intent(MtpDocumentsService.ACTION_UPDATE_NOTIFICATION);
-        intent.setComponent(new ComponentName(mContext, MtpDocumentsService.class));
-        if (records.length != 0) {
-            final int[] ids = new int[records.length];
-            final Notification[] notifications = new Notification[records.length];
-            for (int i = 0; i < records.length; i++) {
-                ids[i] = records[i].deviceId;
-                notifications[i] = createNotification(mContext, records[i]);
-            }
-            intent.putExtra(MtpDocumentsService.EXTRA_DEVICE_IDS, ids);
-            intent.putExtra(MtpDocumentsService.EXTRA_DEVICE_NOTIFICATIONS, notifications);
-            mContext.startForegroundService(intent);
-        } else {
-            mContext.startService(intent);
-        }
-    }
-
-    private static Notification createNotification(Context context, MtpDeviceRecord device) {
-        final String title = context.getResources().getString(
-                R.string.accessing_notification_title,
-                device.name);
-        return new Notification.Builder(context, CHANNEL_ID)
-                .setLocalOnly(true)
-                .setContentTitle(title)
-                .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
-                .setCategory(Notification.CATEGORY_SYSTEM)
-                .setFlag(Notification.FLAG_NO_CLEAR, true)
-                .build();
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/UsbIntentReceiver.java b/packages/MtpDocumentsProvider/src/com/android/mtp/UsbIntentReceiver.java
deleted file mode 100644
index 0489ea8..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/UsbIntentReceiver.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbManager;
-import android.util.Log;
-
-import java.io.IOException;
-
-public class UsbIntentReceiver extends BroadcastReceiver {
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        final UsbDevice device = intent.getExtras().getParcelable(UsbManager.EXTRA_DEVICE);
-        switch (intent.getAction()) {
-            case UsbManager.ACTION_USB_DEVICE_ATTACHED:
-                MtpDocumentsProvider.getInstance().resumeRootScanner();
-                break;
-            case UsbManager.ACTION_USB_DEVICE_DETACHED:
-                try {
-                    MtpDocumentsProvider.getInstance().closeDevice(device.getDeviceId());
-                } catch (IOException | InterruptedException e) {
-                    Log.e(MtpDocumentsProvider.TAG, "Failed to close device", e);
-                }
-                break;
-        }
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/annotations/UsedByNative.java b/packages/MtpDocumentsProvider/src/com/android/mtp/annotations/UsedByNative.java
deleted file mode 100644
index 2ded925..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/annotations/UsedByNative.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-
-/**
- * Annotation that shows the method is used by JNI.
- */
-@Target({ElementType.METHOD, ElementType.FIELD})
-public @interface UsedByNative {
-    /**
-     * JNI file name that uses the method.
-     */
-    String value();
-}
diff --git a/packages/MtpDocumentsProvider/tests/Android.mk b/packages/MtpDocumentsProvider/tests/Android.mk
deleted file mode 100644
index 11daac3..0000000
--- a/packages/MtpDocumentsProvider/tests/Android.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-LOCAL_PACKAGE_NAME := MtpDocumentsProviderTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider
-LOCAL_CERTIFICATE := media
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/packages/MtpDocumentsProvider/tests/AndroidManifest.xml b/packages/MtpDocumentsProvider/tests/AndroidManifest.xml
deleted file mode 100644
index e1307e9..0000000
--- a/packages/MtpDocumentsProvider/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.mtp.tests"
-    android:sharedUserId="android.media">
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-        <activity android:name="com.android.mtp.TestResultActivity"
-                  android:screenOrientation="locked"
-                  android:launchMode="singleInstance">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-
-    <instrumentation android:name="com.android.mtp.TestResultInstrumentation"
-        android:targetPackage="com.android.mtp"
-        android:label="Tests for MtpDocumentsProvider with the UI for output." />
-</manifest>
diff --git a/packages/MtpDocumentsProvider/tests/AndroidTest.xml b/packages/MtpDocumentsProvider/tests/AndroidTest.xml
deleted file mode 100644
index f84131c..0000000
--- a/packages/MtpDocumentsProvider/tests/AndroidTest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<configuration description="Runs Tests for MtpDocumentsProvider with the UI for output.">
-    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
-        <option name="test-file-name" value="MtpDocumentsProviderTests.apk" />
-    </target_preparer>
-
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-tag" value="MtpDocumentsProviderTests" />
-    <test class="com.android.tradefed.testtype.InstrumentationTest" >
-        <option name="package" value="com.android.mtp.tests" />
-        <option name="runner" value="com.android.mtp.TestResultInstrumentation" />
-        <option name="hidden-api-checks" value="false"/>
-    </test>
-</configuration>
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
deleted file mode 100644
index a3c6bd7..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.mtp.MtpObjectInfo;
-import android.net.Uri;
-import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Document;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeoutException;
-
-@MediumTest
-public class DocumentLoaderTest extends AndroidTestCase {
-    private MtpDatabase mDatabase;
-    private BlockableTestMtpManager mManager;
-    private TestContentResolver mResolver;
-    private DocumentLoader mLoader;
-    final private Identifier mParentIdentifier = new Identifier(
-            0, 0, 0, "2", MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE);
-
-    @Override
-    public void setUp() throws Exception {
-        mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-
-        mDatabase.getMapper().startAddingDocuments(null);
-        mDatabase.getMapper().putDeviceDocument(
-                new MtpDeviceRecord(0, "Device", null, true, new MtpRoot[0], null, null));
-        mDatabase.getMapper().stopAddingDocuments(null);
-
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", new int[0], new MtpRoot[] {
-                new MtpRoot(0, 0, "Storage", 1000, 1000, "")
-        });
-        mDatabase.getMapper().stopAddingDocuments("1");
-
-        mManager = new BlockableTestMtpManager(getContext());
-        mResolver = new TestContentResolver();
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        mLoader.close();
-        mDatabase.close();
-    }
-
-    public void testBasic() throws Exception {
-        setUpLoader();
-
-        final Uri uri = DocumentsContract.buildChildDocumentsUri(
-                MtpDocumentsProvider.AUTHORITY, mParentIdentifier.mDocumentId);
-        setUpDocument(mManager, 40);
-        mManager.blockDocument(0, 15);
-        mManager.blockDocument(0, 35);
-
-        {
-            final Cursor cursor = mLoader.queryChildDocuments(
-                    MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier);
-            assertEquals(DocumentLoader.NUM_INITIAL_ENTRIES, cursor.getCount());
-        }
-
-        Thread.sleep(DocumentLoader.NOTIFY_PERIOD_MS);
-        mManager.unblockDocument(0, 15);
-        mResolver.waitForNotification(uri, 1);
-
-        {
-            final Cursor cursor = mLoader.queryChildDocuments(
-                    MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier);
-            assertEquals(
-                    DocumentLoader.NUM_INITIAL_ENTRIES + DocumentLoader.NUM_LOADING_ENTRIES,
-                    cursor.getCount());
-        }
-
-        mManager.unblockDocument(0, 35);
-        mResolver.waitForNotification(uri, 2);
-
-        {
-            final Cursor cursor = mLoader.queryChildDocuments(
-                    MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier);
-            assertEquals(40, cursor.getCount());
-        }
-
-        assertEquals(2, mResolver.getChangeCount(uri));
-    }
-
-    public void testError_GetObjectHandles() throws Exception {
-        mManager = new BlockableTestMtpManager(getContext()) {
-            @Override
-            int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
-                    throws IOException {
-                throw new IOException();
-            }
-        };
-        setUpLoader();
-        mManager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, null);
-        try {
-            try (final Cursor cursor = mLoader.queryChildDocuments(
-                    MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier)) {}
-            fail();
-        } catch (IOException exception) {
-            // Expect exception.
-        }
-    }
-
-    public void testError_GetObjectInfo() throws Exception {
-        mManager = new BlockableTestMtpManager(getContext()) {
-            @Override
-            MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
-                if (objectHandle == DocumentLoader.NUM_INITIAL_ENTRIES) {
-                    throw new IOException();
-                } else {
-                    return super.getObjectInfo(deviceId, objectHandle);
-                }
-            }
-        };
-        setUpLoader();
-        setUpDocument(mManager, DocumentLoader.NUM_INITIAL_ENTRIES);
-        try (final Cursor cursor = mLoader.queryChildDocuments(
-                MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier)) {
-            // Even if MtpManager returns an error for a document, loading must complete.
-            assertFalse(cursor.getExtras().getBoolean(DocumentsContract.EXTRA_LOADING));
-        }
-    }
-
-    public void testCancelTask() throws IOException, InterruptedException, TimeoutException {
-        setUpDocument(mManager,
-                DocumentLoader.NUM_INITIAL_ENTRIES + 1);
-
-        // Block the first iteration in the background thread.
-        mManager.blockDocument(
-                0, DocumentLoader.NUM_INITIAL_ENTRIES + 1);
-        setUpLoader();
-        try (final Cursor cursor = mLoader.queryChildDocuments(
-                MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier)) {
-            assertTrue(cursor.getExtras().getBoolean(DocumentsContract.EXTRA_LOADING));
-        }
-
-        final Uri uri = DocumentsContract.buildChildDocumentsUri(
-                MtpDocumentsProvider.AUTHORITY, mParentIdentifier.mDocumentId);
-        assertEquals(0, mResolver.getChangeCount(uri));
-
-        // Clear task while the first iteration is being blocked.
-        mLoader.cancelTask(mParentIdentifier);
-        mManager.unblockDocument(
-                0, DocumentLoader.NUM_INITIAL_ENTRIES + 1);
-        Thread.sleep(DocumentLoader.NOTIFY_PERIOD_MS);
-        assertEquals(0, mResolver.getChangeCount(uri));
-
-        // Check if it's OK to query invalidated task.
-        try (final Cursor cursor = mLoader.queryChildDocuments(
-                MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier)) {
-            assertTrue(cursor.getExtras().getBoolean(DocumentsContract.EXTRA_LOADING));
-        }
-        mResolver.waitForNotification(uri, 1);
-    }
-
-    private void setUpLoader() {
-        mLoader = new DocumentLoader(
-                new MtpDeviceRecord(
-                        0, "Device", "Key", true, new MtpRoot[0],
-                        TestUtil.OPERATIONS_SUPPORTED, new int[0]),
-                mManager,
-                mResolver,
-                mDatabase);
-    }
-
-    private void setUpDocument(TestMtpManager manager, int count) {
-        int[] childDocuments = new int[count];
-        for (int i = 0; i < childDocuments.length; i++) {
-            final int objectHandle = i + 1;
-            childDocuments[i] = objectHandle;
-            manager.setObjectInfo(0, new MtpObjectInfo.Builder()
-                    .setObjectHandle(objectHandle)
-                    .setName(Integer.toString(i))
-                    .build());
-        }
-        manager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, childDocuments);
-    }
-
-    private static class BlockableTestMtpManager extends TestMtpManager {
-        final private Map<String, CountDownLatch> blockedDocuments = new HashMap<>();
-
-        BlockableTestMtpManager(Context context) {
-            super(context);
-        }
-
-        void blockDocument(int deviceId, int objectHandle) {
-            blockedDocuments.put(pack(deviceId, objectHandle), new CountDownLatch(1));
-        }
-
-        void unblockDocument(int deviceId, int objectHandle) {
-            blockedDocuments.get(pack(deviceId, objectHandle)).countDown();
-        }
-
-        @Override
-        MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
-            final CountDownLatch latch = blockedDocuments.get(pack(deviceId, objectHandle));
-            if (latch != null) {
-                try {
-                    latch.await();
-                } catch(InterruptedException e) {
-                    fail();
-                }
-            }
-            return super.getObjectInfo(deviceId, objectHandle);
-        }
-    }
-}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
deleted file mode 100644
index 32b169e..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ /dev/null
@@ -1,1133 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.database.Cursor;
-import android.media.MediaFile;
-import android.media.MediaFile.MediaFileType;
-import android.mtp.MtpConstants;
-import android.mtp.MtpObjectInfo;
-import android.net.Uri;
-import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract.Root;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.io.FileNotFoundException;
-import java.util.Arrays;
-
-import static android.provider.DocumentsContract.Document.*;
-import static com.android.mtp.MtpDatabase.strings;
-import static com.android.mtp.MtpDatabaseConstants.*;
-import static com.android.mtp.TestUtil.OPERATIONS_SUPPORTED;
-
-@SmallTest
-public class MtpDatabaseTest extends AndroidTestCase {
-    private static final String[] COLUMN_NAMES = new String[] {
-        DocumentsContract.Document.COLUMN_DOCUMENT_ID,
-        MtpDatabaseConstants.COLUMN_DEVICE_ID,
-        MtpDatabaseConstants.COLUMN_STORAGE_ID,
-        MtpDatabaseConstants.COLUMN_OBJECT_HANDLE,
-        DocumentsContract.Document.COLUMN_MIME_TYPE,
-        DocumentsContract.Document.COLUMN_DISPLAY_NAME,
-        DocumentsContract.Document.COLUMN_SUMMARY,
-        DocumentsContract.Document.COLUMN_LAST_MODIFIED,
-        DocumentsContract.Document.COLUMN_ICON,
-        DocumentsContract.Document.COLUMN_FLAGS,
-        DocumentsContract.Document.COLUMN_SIZE,
-        MtpDatabaseConstants.COLUMN_DOCUMENT_TYPE
-    };
-
-    private final TestResources resources = new TestResources();
-    MtpDatabase mDatabase;
-
-    @Override
-    public void setUp() {
-        mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-    }
-
-    @Override
-    public void tearDown() {
-        mDatabase.close();
-        mDatabase = null;
-    }
-
-    private static int getInt(Cursor cursor, String columnName) {
-        return cursor.getInt(cursor.getColumnIndex(columnName));
-    }
-
-    private static boolean isNull(Cursor cursor, String columnName) {
-        return cursor.isNull(cursor.getColumnIndex(columnName));
-    }
-
-    private static String getString(Cursor cursor, String columnName) {
-        return cursor.getString(cursor.getColumnIndex(columnName));
-    }
-
-    public void testPutSingleStorageDocuments() throws Exception {
-        addTestDevice();
-
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 1, "Storage", 1000, 2000, "")
-        });
-        mDatabase.getMapper().stopAddingDocuments("1");
-
-        {
-            final Cursor cursor = mDatabase.queryRootDocuments(COLUMN_NAMES);
-            assertEquals(1, cursor.getCount());
-
-            cursor.moveToNext();
-            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
-            assertEquals(1, getInt(cursor, COLUMN_STORAGE_ID));
-            assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
-            assertEquals(
-                    DocumentsContract.Document.MIME_TYPE_DIR, getString(cursor, COLUMN_MIME_TYPE));
-            assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
-            assertTrue(isNull(cursor, COLUMN_SUMMARY));
-            assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
-            assertEquals(R.drawable.ic_root_mtp, getInt(cursor, COLUMN_ICON));
-            assertEquals(Document.FLAG_DIR_SUPPORTS_CREATE, getInt(cursor, COLUMN_FLAGS));
-            assertEquals(1000, getInt(cursor, COLUMN_SIZE));
-            assertEquals(
-                    MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE,
-                    getInt(cursor, COLUMN_DOCUMENT_TYPE));
-
-            cursor.close();
-        }
-
-        {
-            final Cursor cursor = mDatabase.queryRoots(resources, new String [] {
-                    Root.COLUMN_ROOT_ID,
-                    Root.COLUMN_FLAGS,
-                    Root.COLUMN_ICON,
-                    Root.COLUMN_TITLE,
-                    Root.COLUMN_SUMMARY,
-                    Root.COLUMN_DOCUMENT_ID,
-                    Root.COLUMN_AVAILABLE_BYTES,
-                    Root.COLUMN_CAPACITY_BYTES
-            });
-            assertEquals(1, cursor.getCount());
-
-            cursor.moveToNext();
-            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(
-                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
-                    getInt(cursor, Root.COLUMN_FLAGS));
-            assertEquals(R.drawable.ic_root_mtp, getInt(cursor, Root.COLUMN_ICON));
-            assertEquals("Device Storage", getString(cursor, Root.COLUMN_TITLE));
-            assertTrue(isNull(cursor, Root.COLUMN_SUMMARY));
-            assertEquals(1, getInt(cursor, Root.COLUMN_DOCUMENT_ID));
-            assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            assertEquals(2000, getInt(cursor, Root.COLUMN_CAPACITY_BYTES));
-
-            cursor.close();
-        }
-    }
-
-    public void testPutStorageDocuments() throws Exception {
-        addTestDevice();
-
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 1, "Storage", 1000, 2000, ""),
-                new MtpRoot(0, 2, "Storage", 2000, 4000, ""),
-                new MtpRoot(0, 3, "/@#%&<>Storage", 3000, 6000,"")
-        });
-
-        {
-            final Cursor cursor = mDatabase.queryRootDocuments(COLUMN_NAMES);
-            assertEquals(3, cursor.getCount());
-
-            cursor.moveToNext();
-            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
-            assertEquals(1, getInt(cursor, COLUMN_STORAGE_ID));
-            assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
-            assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, getString(cursor, COLUMN_MIME_TYPE));
-            assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
-            assertTrue(isNull(cursor, COLUMN_SUMMARY));
-            assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
-            assertEquals(R.drawable.ic_root_mtp, getInt(cursor, COLUMN_ICON));
-            assertEquals(Document.FLAG_DIR_SUPPORTS_CREATE, getInt(cursor, COLUMN_FLAGS));
-            assertEquals(1000, getInt(cursor, COLUMN_SIZE));
-            assertEquals(
-                    MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE, getInt(cursor, COLUMN_DOCUMENT_TYPE));
-
-            cursor.moveToNext();
-            assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
-
-            cursor.moveToNext();
-            assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals("/@#%&<>Storage", getString(cursor, COLUMN_DISPLAY_NAME));
-
-            cursor.close();
-        }
-    }
-
-    private MtpObjectInfo createDocument(int objectHandle, String name, int format, int size) {
-        final MtpObjectInfo.Builder builder = new MtpObjectInfo.Builder();
-        builder.setObjectHandle(objectHandle);
-        builder.setName(name);
-        builder.setFormat(format);
-        builder.setCompressedSize(size);
-        return builder.build();
-    }
-
-    public void testPutChildDocuments() throws Exception {
-        addTestDevice();
-        addTestStorage("1");
-
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-                createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-                createDocument(101, "image.jpg", MtpConstants.FORMAT_EXIF_JPEG, 2 * 1024 * 1024),
-                createDocument(102, "music.mp3", MtpConstants.FORMAT_MP3, 3 * 1024 * 1024)
-        }, new long[] { 1024L, 2L * 1024L * 1024L, 3L * 1024L * 1024L});
-
-        final Cursor cursor = mDatabase.queryChildDocuments(COLUMN_NAMES, "2");
-        assertEquals(3, cursor.getCount());
-
-        cursor.moveToNext();
-        assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
-        assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
-        assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID));
-        assertEquals(100, getInt(cursor, COLUMN_OBJECT_HANDLE));
-        assertEquals("text/plain", getString(cursor, COLUMN_MIME_TYPE));
-        assertEquals("note.txt", getString(cursor, COLUMN_DISPLAY_NAME));
-        assertTrue(isNull(cursor, COLUMN_SUMMARY));
-        assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
-        assertTrue(isNull(cursor, COLUMN_ICON));
-        assertEquals(
-                COLUMN_FLAGS,
-                DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
-                DocumentsContract.Document.FLAG_SUPPORTS_WRITE,
-                cursor.getInt(9));
-        assertEquals(1024, getInt(cursor, COLUMN_SIZE));
-        assertEquals(
-                MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, getInt(cursor, COLUMN_DOCUMENT_TYPE));
-
-        cursor.moveToNext();
-        assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
-        assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
-        assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID));
-        assertEquals(101, getInt(cursor, COLUMN_OBJECT_HANDLE));
-        assertEquals("image/jpeg", getString(cursor, COLUMN_MIME_TYPE));
-        assertEquals("image.jpg", getString(cursor, COLUMN_DISPLAY_NAME));
-        assertTrue(isNull(cursor, COLUMN_SUMMARY));
-        assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
-        assertTrue(isNull(cursor, COLUMN_ICON));
-        assertEquals(
-                COLUMN_FLAGS,
-                DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
-                DocumentsContract.Document.FLAG_SUPPORTS_WRITE |
-                DocumentsContract.Document.FLAG_SUPPORTS_METADATA,
-                cursor.getInt(9));
-        assertEquals(2 * 1024 * 1024, getInt(cursor, COLUMN_SIZE));
-        assertEquals(
-                MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, getInt(cursor, COLUMN_DOCUMENT_TYPE));
-
-        cursor.moveToNext();
-        assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID));
-        assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
-        assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID));
-        assertEquals(102, getInt(cursor, COLUMN_OBJECT_HANDLE));
-        assertEquals("audio/mpeg", getString(cursor, COLUMN_MIME_TYPE));
-        assertEquals("music.mp3", getString(cursor, COLUMN_DISPLAY_NAME));
-        assertTrue(isNull(cursor, COLUMN_SUMMARY));
-        assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
-        assertTrue(isNull(cursor, COLUMN_ICON));
-        assertEquals(
-                COLUMN_FLAGS,
-                DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
-                DocumentsContract.Document.FLAG_SUPPORTS_WRITE,
-                cursor.getInt(9));
-        assertEquals(3 * 1024 * 1024, getInt(cursor, COLUMN_SIZE));
-        assertEquals(
-                MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, getInt(cursor, COLUMN_DOCUMENT_TYPE));
-
-        cursor.close();
-    }
-
-    public void testPutChildDocuments_operationsSupported() throws Exception {
-        addTestDevice();
-        addTestStorage("1");
-
-        // Put a document with empty supported operations.
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", new int[0], new MtpObjectInfo[] {
-                createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024)
-        }, new long[] { 1024L });
-        mDatabase.getMapper().stopAddingDocuments("2");
-
-        try (final Cursor cursor =
-                mDatabase.queryChildDocuments(strings(Document.COLUMN_FLAGS), "2")) {
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(0, cursor.getInt(0));
-        }
-
-        // Put a document with writable operations.
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", new int[] {
-                MtpConstants.OPERATION_SEND_OBJECT,
-                MtpConstants.OPERATION_SEND_OBJECT_INFO,
-        }, new MtpObjectInfo[] {
-                createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024)
-        }, new long[] { 1024L });
-        mDatabase.getMapper().stopAddingDocuments("2");
-
-        try (final Cursor cursor =
-                mDatabase.queryChildDocuments(strings(Document.COLUMN_FLAGS), "2")) {
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(Document.FLAG_SUPPORTS_WRITE, cursor.getInt(0));
-        }
-
-        // Put a document with deletable operations.
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", new int[] {
-                MtpConstants.OPERATION_DELETE_OBJECT
-        }, new MtpObjectInfo[] {
-                createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024)
-        }, new long[] { 1024L });
-        mDatabase.getMapper().stopAddingDocuments("2");
-
-        try (final Cursor cursor =
-                mDatabase.queryChildDocuments(strings(Document.COLUMN_FLAGS), "2")) {
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(Document.FLAG_SUPPORTS_DELETE, cursor.getInt(0));
-        }
-    }
-
-    public void testRestoreIdForRootDocuments() throws Exception {
-        final String[] columns = new String[] {
-                DocumentsContract.Document.COLUMN_DOCUMENT_ID,
-                MtpDatabaseConstants.COLUMN_STORAGE_ID,
-                DocumentsContract.Document.COLUMN_DISPLAY_NAME
-        };
-
-        // Add device and two storages.
-        addTestDevice();
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 100, "Storage A", 1000, 0, ""),
-                new MtpRoot(0, 101, "Storage B", 1001, 0, "")
-        });
-
-        {
-            final Cursor cursor = mDatabase.queryRootDocuments(columns);
-            assertEquals(2, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
-            assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME));
-            cursor.moveToNext();
-            assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(101, getInt(cursor, COLUMN_STORAGE_ID));
-            assertEquals("Storage B", getString(cursor, COLUMN_DISPLAY_NAME));
-            cursor.close();
-        }
-
-        // Clear mapping and add a device.
-        mDatabase.getMapper().clearMapping();
-        addTestDevice();
-
-        {
-            final Cursor cursor = mDatabase.queryRootDocuments(columns);
-            assertEquals(0, cursor.getCount());
-            cursor.close();
-        }
-
-        // Add two storages, but one's name is different from previous one.
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 200, "Storage A", 2000, 0, ""),
-                new MtpRoot(0, 202, "Storage C", 2002, 0, "")
-        });
-        mDatabase.getMapper().stopAddingDocuments("1");
-
-        {
-            // After compeleting mapping, Storage A can be obtained with new storage ID.
-            final Cursor cursor = mDatabase.queryRootDocuments(columns);
-            assertEquals(2, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID));
-            assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME));
-            cursor.moveToNext();
-            assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(202, getInt(cursor, COLUMN_STORAGE_ID));
-            assertEquals("Storage C", getString(cursor, COLUMN_DISPLAY_NAME));
-            cursor.close();
-        }
-    }
-
-    public void testRestoreIdForChildDocuments() throws Exception {
-        final String[] columns = new String[] {
-                DocumentsContract.Document.COLUMN_DOCUMENT_ID,
-                MtpDatabaseConstants.COLUMN_OBJECT_HANDLE,
-                DocumentsContract.Document.COLUMN_DISPLAY_NAME
-        };
-
-        addTestDevice();
-        addTestStorage("1");
-
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-                createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-                createDocument(101, "image.jpg", MtpConstants.FORMAT_EXIF_JPEG, 2 * 1024 * 1024),
-                createDocument(102, "music.mp3", MtpConstants.FORMAT_MP3, 3 * 1024 * 1024)
-        }, new long[] { 1024L, 2L * 1024L * 1024L, 3L * 1024L * 1024L});
-        mDatabase.getMapper().clearMapping();
-
-        addTestDevice();
-        addTestStorage("1");
-
-        {
-            // Don't return objects that lost MTP object handles.
-            final Cursor cursor = mDatabase.queryChildDocuments(columns, "2");
-            assertEquals(0, cursor.getCount());
-            cursor.close();
-        }
-
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-                createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-                createDocument(203, "video.mp4", MtpConstants.FORMAT_MP4_CONTAINER, 1024),
-        }, new long[] { 1024L, 1024L });
-        mDatabase.getMapper().stopAddingDocuments("2");
-
-        {
-            final Cursor cursor = mDatabase.queryChildDocuments(columns, "2");
-            assertEquals(2, cursor.getCount());
-
-            cursor.moveToNext();
-            assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(200, getInt(cursor, COLUMN_OBJECT_HANDLE));
-            assertEquals("note.txt", getString(cursor, COLUMN_DISPLAY_NAME));
-
-            cursor.moveToNext();
-            assertEquals(6, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(203, getInt(cursor, COLUMN_OBJECT_HANDLE));
-            assertEquals("video.mp4", getString(cursor, COLUMN_DISPLAY_NAME));
-
-            cursor.close();
-        }
-    }
-
-    public void testRestoreIdForDifferentDevices() throws Exception {
-        final String[] columns = new String[] {
-                DocumentsContract.Document.COLUMN_DOCUMENT_ID,
-                MtpDatabaseConstants.COLUMN_STORAGE_ID,
-                DocumentsContract.Document.COLUMN_DISPLAY_NAME
-        };
-        final String[] rootColumns = new String[] {
-                Root.COLUMN_ROOT_ID,
-                Root.COLUMN_AVAILABLE_BYTES
-        };
-        mDatabase.getMapper().startAddingDocuments(null);
-        mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
-                0, "Device A", "Device key A", true, new MtpRoot[0], null, null));
-        mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
-                1, "Device B", "Device key B", true, new MtpRoot[0], null, null));
-        mDatabase.getMapper().stopAddingDocuments(null);
-
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 100, "Storage", 0, 0, "")
-        });
-        mDatabase.getMapper().putStorageDocuments("2", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(1, 100, "Storage", 0, 0, "")
-        });
-
-        {
-            final Cursor cursor = mDatabase.queryRootDocuments(columns);
-            assertEquals(2, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
-            assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
-            cursor.moveToNext();
-            assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
-            assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
-            cursor.close();
-        }
-
-        {
-            final Cursor cursor = mDatabase.queryRoots(resources, rootColumns);
-            assertEquals(2, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(0, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.moveToNext();
-            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(0, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.close();
-        }
-
-        mDatabase.getMapper().clearMapping();
-
-        mDatabase.getMapper().startAddingDocuments(null);
-        mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
-                0, "Device A", "Device key A", true, new MtpRoot[0], null, null));
-        mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
-                1, "Device B", "Device key B", true, new MtpRoot[0], null, null));
-        mDatabase.getMapper().stopAddingDocuments(null);
-
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 200, "Storage", 2000, 0, "")
-        });
-        mDatabase.getMapper().putStorageDocuments("2", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(1, 300, "Storage", 3000, 0, "")
-        });
-        mDatabase.getMapper().stopAddingDocuments("1");
-        mDatabase.getMapper().stopAddingDocuments("2");
-
-        {
-            final Cursor cursor = mDatabase.queryRootDocuments(columns);
-            assertEquals(2, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID));
-            assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
-            cursor.moveToNext();
-            assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(300, getInt(cursor, COLUMN_STORAGE_ID));
-            assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
-            cursor.close();
-        }
-
-        {
-            final Cursor cursor = mDatabase.queryRoots(resources, rootColumns);
-            assertEquals(2, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(2000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.moveToNext();
-            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(3000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.close();
-        }
-    }
-
-    public void testRestoreIdForDifferentParents() throws Exception {
-        final String[] columns = new String[] {
-                DocumentsContract.Document.COLUMN_DOCUMENT_ID,
-                MtpDatabaseConstants.COLUMN_OBJECT_HANDLE
-        };
-
-        // Add device, storage, and two directories.
-        addTestDevice();
-        addTestStorage("1");
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-                createDocument(50, "A", MtpConstants.FORMAT_ASSOCIATION, 0),
-                createDocument(51, "B", MtpConstants.FORMAT_ASSOCIATION, 0),
-        }, new long[] { 0L, 0L });
-        mDatabase.getMapper().stopAddingDocuments("2");
-
-        // Put note.txt in each directory.
-        mDatabase.getMapper().startAddingDocuments("3");
-        mDatabase.getMapper().startAddingDocuments("4");
-        mDatabase.getMapper().putChildDocuments(0, "3", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-                createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-        }, new long[] { 1024L });
-        mDatabase.getMapper().putChildDocuments(0, "4", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-                createDocument(101, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-        }, new long[] { 1024L });
-
-        // Clear mapping.
-        mDatabase.getMapper().clearMapping();
-
-        // Add device, storage, and two directories again.
-        addTestDevice();
-        addTestStorage("1");
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-                createDocument(50, "A", MtpConstants.FORMAT_ASSOCIATION, 0),
-                createDocument(51, "B", MtpConstants.FORMAT_ASSOCIATION, 0),
-        }, new long[] { 0L, 0L });
-        mDatabase.getMapper().stopAddingDocuments("2");
-
-        // Add note.txt in each directory again.
-        mDatabase.getMapper().startAddingDocuments("3");
-        mDatabase.getMapper().startAddingDocuments("4");
-        mDatabase.getMapper().putChildDocuments(0, "3", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-                createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-        }, new long[] { 1024L });
-        mDatabase.getMapper().putChildDocuments(0, "4", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-                createDocument(201, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-        }, new long[] { 1024L });
-        mDatabase.getMapper().stopAddingDocuments("3");
-        mDatabase.getMapper().stopAddingDocuments("4");
-
-        // Check if the two note.txt are mapped correctly.
-        {
-            final Cursor cursor = mDatabase.queryChildDocuments(columns, "3");
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(200, getInt(cursor, COLUMN_OBJECT_HANDLE));
-            cursor.close();
-        }
-        {
-            final Cursor cursor = mDatabase.queryChildDocuments(columns, "4");
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(6, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(201, getInt(cursor, COLUMN_OBJECT_HANDLE));
-            cursor.close();
-        }
-    }
-
-    public void testClearMtpIdentifierBeforeResolveRootDocuments() throws Exception {
-        final String[] columns = new String[] {
-                DocumentsContract.Document.COLUMN_DOCUMENT_ID,
-                MtpDatabaseConstants.COLUMN_STORAGE_ID,
-                DocumentsContract.Document.COLUMN_DISPLAY_NAME
-        };
-        final String[] rootColumns = new String[] {
-                Root.COLUMN_ROOT_ID,
-                Root.COLUMN_AVAILABLE_BYTES
-        };
-
-        addTestDevice();
-
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 100, "Storage", 0, 0, ""),
-        });
-        mDatabase.getMapper().clearMapping();
-
-        addTestDevice();
-
-        try (final Cursor cursor = mDatabase.queryRoots(resources, rootColumns)) {
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals("1", getString(cursor, Root.COLUMN_ROOT_ID));
-        }
-
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 200, "Storage", 2000, 0, ""),
-        });
-        mDatabase.getMapper().clearMapping();
-
-        addTestDevice();
-
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 300, "Storage", 3000, 0, ""),
-        });
-        mDatabase.getMapper().stopAddingDocuments("1");
-
-        {
-            final Cursor cursor = mDatabase.queryRootDocuments(columns);
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(300, getInt(cursor, COLUMN_STORAGE_ID));
-            assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
-            cursor.close();
-        }
-        {
-            final Cursor cursor = mDatabase.queryRoots(resources, rootColumns);
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(3000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.close();
-        }
-    }
-
-    public void testPutSameNameRootsAfterClearing() throws Exception {
-        final String[] columns = new String[] {
-                DocumentsContract.Document.COLUMN_DOCUMENT_ID,
-                MtpDatabaseConstants.COLUMN_STORAGE_ID,
-                DocumentsContract.Document.COLUMN_DISPLAY_NAME
-        };
-
-        // Add a device and a storage.
-        addTestDevice();
-        addTestStorage("1");
-
-        // Disconnect devices.
-        mDatabase.getMapper().clearMapping();
-
-        // Add a device and two storages that has same name.
-        addTestDevice();
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 200, "Storage", 2000, 0, ""),
-                new MtpRoot(0, 201, "Storage", 2001, 0, ""),
-        });
-        mDatabase.getMapper().stopAddingDocuments("1");
-
-        {
-            final Cursor cursor = mDatabase.queryRootDocuments(columns);
-            assertEquals(2, cursor.getCount());
-
-            // First storage reuse document ID of previous storage.
-            cursor.moveToNext();
-            // One reuses exisitng document ID 1.
-            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID));
-            assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
-
-            // Second one has new document ID.
-            cursor.moveToNext();
-            assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(201, getInt(cursor, COLUMN_STORAGE_ID));
-            assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
-
-            cursor.close();
-        }
-    }
-
-    public void testReplaceExistingRoots() throws Exception {
-        addTestDevice();
-
-        // The client code should be able to replace existing rows with new information.
-        // Add one.
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 100, "Storage A", 0, 0, ""),
-        });
-        mDatabase.getMapper().stopAddingDocuments("1");
-        // Replace it.
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 100, "Storage B", 1000, 1000, ""),
-        });
-        mDatabase.getMapper().stopAddingDocuments("1");
-        {
-            final String[] columns = new String[] {
-                    DocumentsContract.Document.COLUMN_DOCUMENT_ID,
-                    MtpDatabaseConstants.COLUMN_STORAGE_ID,
-                    DocumentsContract.Document.COLUMN_DISPLAY_NAME
-            };
-            final Cursor cursor = mDatabase.queryRootDocuments(columns);
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
-            assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
-            assertEquals("Storage B", getString(cursor, COLUMN_DISPLAY_NAME));
-            cursor.close();
-        }
-        {
-            final String[] columns = new String[] {
-                    Root.COLUMN_ROOT_ID,
-                    Root.COLUMN_TITLE,
-                    Root.COLUMN_AVAILABLE_BYTES
-            };
-            final Cursor cursor = mDatabase.queryRoots(resources, columns);
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals("Device Storage B", getString(cursor, Root.COLUMN_TITLE));
-            assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.close();
-        }
-    }
-
-    public void testFailToReplaceExisitingUnmappedRoots() throws Exception {
-        // The client code should not be able to replace rows before resolving 'unmapped' rows.
-        // Add one.
-        addTestDevice();
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 100, "Storage A", 0, 0, ""),
-        });
-        mDatabase.getMapper().clearMapping();
-
-        addTestDevice();
-        try (final Cursor oldCursor =
-                mDatabase.queryRoots(resources, strings(Root.COLUMN_ROOT_ID))) {
-            assertEquals(1, oldCursor.getCount());
-            oldCursor.moveToNext();
-            assertEquals("1", getString(oldCursor, Root.COLUMN_ROOT_ID));
-
-            // Add one.
-            mDatabase.getMapper().startAddingDocuments("1");
-            mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                    new MtpRoot(0, 101, "Storage B", 1000, 1000, ""),
-            });
-            // Add one more before resolving unmapped documents.
-            mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                    new MtpRoot(0, 102, "Storage B", 1000, 1000, ""),
-            });
-            mDatabase.getMapper().stopAddingDocuments("1");
-
-            // Because the roots shares the same name, the roots should have new IDs.
-            try (final Cursor newCursor = mDatabase.queryChildDocuments(
-                    strings(Document.COLUMN_DOCUMENT_ID), "1")) {
-                assertEquals(2, newCursor.getCount());
-                newCursor.moveToNext();
-                assertFalse(oldCursor.getString(0).equals(newCursor.getString(0)));
-                newCursor.moveToNext();
-                assertFalse(oldCursor.getString(0).equals(newCursor.getString(0)));
-            }
-        }
-    }
-
-    public void testQueryDocuments() throws Exception {
-        addTestDevice();
-        addTestStorage("1");
-
-        final Cursor cursor = mDatabase.queryDocument("2", strings(Document.COLUMN_DISPLAY_NAME));
-        assertEquals(1, cursor.getCount());
-        cursor.moveToNext();
-        assertEquals("Storage", getString(cursor, Document.COLUMN_DISPLAY_NAME));
-        cursor.close();
-    }
-
-    public void testQueryRoots() throws Exception {
-        // Add device document.
-        addTestDevice();
-
-        // It the device does not have storages, it shows a device root.
-        {
-            final Cursor cursor = mDatabase.queryRoots(resources, strings(Root.COLUMN_TITLE));
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals("Device", cursor.getString(0));
-            cursor.close();
-        }
-
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 100, "Storage A", 0, 0, "")
-        });
-        mDatabase.getMapper().stopAddingDocuments("1");
-
-        // It the device has single storage, it shows a storage root.
-        {
-            final Cursor cursor = mDatabase.queryRoots(resources, strings(Root.COLUMN_TITLE));
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals("Device Storage A", cursor.getString(0));
-            cursor.close();
-        }
-
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 100, "Storage A", 0, 0, ""),
-                new MtpRoot(0, 101, "Storage B", 0, 0, "")
-        });
-        mDatabase.getMapper().stopAddingDocuments("1");
-
-        // It the device has multiple storages, it shows a device root.
-        {
-            final Cursor cursor = mDatabase.queryRoots(resources, strings(Root.COLUMN_TITLE));
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals("Device", cursor.getString(0));
-            cursor.close();
-        }
-    }
-
-    public void testGetParentId() throws FileNotFoundException {
-        addTestDevice();
-
-        mDatabase.getMapper().startAddingDocuments("1");
-        mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 100, "Storage A", 0, 0, ""),
-        });
-        mDatabase.getMapper().stopAddingDocuments("1");
-
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-                createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-        }, new long[] { 1024L });
-        mDatabase.getMapper().stopAddingDocuments("2");
-
-        assertEquals("2", mDatabase.getParentIdentifier("3").mDocumentId);
-    }
-
-    public void testDeleteDocument() throws Exception {
-        addTestDevice();
-        addTestStorage("1");
-
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-                createDocument(200, "dir", MtpConstants.FORMAT_ASSOCIATION, 1024),
-        }, new long[] { 1024L });
-        mDatabase.getMapper().stopAddingDocuments("2");
-
-        mDatabase.getMapper().startAddingDocuments("3");
-        mDatabase.getMapper().putChildDocuments(0, "3", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-                createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-        }, new long[] { 1024L });
-        mDatabase.getMapper().stopAddingDocuments("3");
-
-        mDatabase.deleteDocument("3");
-
-        {
-            // Do not query deleted documents.
-            final Cursor cursor =
-                    mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "2");
-            assertEquals(0, cursor.getCount());
-            cursor.close();
-        }
-
-        {
-            // Child document should be deleted also.
-            final Cursor cursor =
-                    mDatabase.queryDocument("4", strings(Document.COLUMN_DOCUMENT_ID));
-            assertEquals(0, cursor.getCount());
-            cursor.close();
-        }
-    }
-
-    public void testPutNewDocument() throws Exception {
-        addTestDevice();
-        addTestStorage("1");
-
-        assertEquals(
-                "3",
-                mDatabase.putNewDocument(
-                        0, "2", OPERATIONS_SUPPORTED,
-                        createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-                        1024L));
-
-        {
-            final Cursor cursor =
-                    mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "2");
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals("3", cursor.getString(0));
-            cursor.close();
-        }
-
-        // The new document should not be mapped with existing invalidated document.
-        mDatabase.getMapper().clearMapping();
-        addTestDevice();
-        addTestStorage("1");
-
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.putNewDocument(
-                0, "2", OPERATIONS_SUPPORTED,
-                createDocument(201, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
-                1024L);
-        mDatabase.getMapper().stopAddingDocuments("2");
-
-        {
-            final Cursor cursor =
-                    mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "2");
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals("4", cursor.getString(0));
-            cursor.close();
-        }
-    }
-
-    public void testGetDocumentIdForDevice() throws Exception {
-        addTestDevice();
-        assertEquals("1", mDatabase.getDocumentIdForDevice(0));
-    }
-
-    public void testGetClosedDevice() throws Exception {
-        mDatabase.getMapper().startAddingDocuments(null);
-        mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
-                0, "Device", null /* deviceKey */, /* opened is */ false, new MtpRoot[0], null,
-                null));
-        mDatabase.getMapper().stopAddingDocuments(null);
-
-        final String[] columns = new String [] {
-                DocumentsContract.Root.COLUMN_ROOT_ID,
-                DocumentsContract.Root.COLUMN_TITLE,
-                DocumentsContract.Root.COLUMN_AVAILABLE_BYTES
-        };
-        try (final Cursor cursor = mDatabase.queryRoots(resources, columns)) {
-            assertEquals(1, cursor.getCount());
-            assertTrue(cursor.moveToNext());
-            assertEquals(1, cursor.getLong(0));
-            assertEquals("Device", cursor.getString(1));
-            assertTrue(cursor.isNull(2));
-        }
-    }
-
-    public void testMappingWithoutKey() throws FileNotFoundException {
-        mDatabase.getMapper().startAddingDocuments(null);
-        mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
-                0, "Device", null /* device key */, /* opened is */ true, new MtpRoot[0], null,
-                null));
-        mDatabase.getMapper().stopAddingDocuments(null);
-
-        mDatabase.getMapper().startAddingDocuments(null);
-        mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
-                0, "Device", null /* device key */, /* opened is */ true, new MtpRoot[0], null,
-                null));
-        mDatabase.getMapper().stopAddingDocuments(null);
-
-        try (final Cursor cursor =
-                mDatabase.queryRoots(resources, strings(DocumentsContract.Root.COLUMN_ROOT_ID))) {
-            assertEquals(1, cursor.getCount());
-            assertTrue(cursor.moveToNext());
-            assertEquals(1, cursor.getLong(0));
-        }
-    }
-
-    public void testMappingFailsWithoutKey() throws FileNotFoundException {
-        mDatabase.getMapper().startAddingDocuments(null);
-        mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
-                0, "Device", null /* device key */, /* opened is */ true, new MtpRoot[0], null,
-                null));
-        mDatabase.getMapper().stopAddingDocuments(null);
-
-        // MTP identifier is cleared here. Mapping no longer works without device key.
-        mDatabase.getMapper().startAddingDocuments(null);
-        mDatabase.getMapper().stopAddingDocuments(null);
-
-        mDatabase.getMapper().startAddingDocuments(null);
-        mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
-                0, "Device", null /* device key */, /* opened is */ true, new MtpRoot[0], null,
-                null));
-        mDatabase.getMapper().stopAddingDocuments(null);
-
-        try (final Cursor cursor =
-                mDatabase.queryRoots(resources, strings(DocumentsContract.Root.COLUMN_ROOT_ID))) {
-            assertEquals(1, cursor.getCount());
-            assertTrue(cursor.moveToNext());
-            assertEquals(2, cursor.getLong(0));
-        }
-    }
-
-    public void testUpdateDocumentWithoutChange() throws FileNotFoundException {
-        mDatabase.getMapper().startAddingDocuments(null);
-        assertTrue(mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
-                0, "Device", "device_key", /* opened is */ true, new MtpRoot[0], null,
-                null)));
-        assertFalse(mDatabase.getMapper().stopAddingDocuments(null));
-
-        mDatabase.getMapper().startAddingDocuments(null);
-        assertFalse(mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
-                0, "Device", "device_key", /* opened is */ true, new MtpRoot[0], null,
-                null)));
-        assertFalse(mDatabase.getMapper().stopAddingDocuments(null));
-    }
-
-    public void testSetBootCount() {
-        assertEquals(0, mDatabase.getLastBootCount());
-        mDatabase.setLastBootCount(10);
-        assertEquals(10, mDatabase.getLastBootCount());
-        try {
-            mDatabase.setLastBootCount(-1);
-            fail();
-        } catch (IllegalArgumentException e) {}
-    }
-
-    public void testCleanDatabase() throws FileNotFoundException {
-        // Add tree.
-        addTestDevice();
-        addTestStorage("1");
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-                createDocument(100, "apple.txt", MtpConstants.FORMAT_TEXT, 1024),
-                createDocument(101, "orange.txt", MtpConstants.FORMAT_TEXT, 1024),
-        }, new long[] { 1024L, 1024L });
-        mDatabase.getMapper().stopAddingDocuments("2");
-
-        // Disconnect the device.
-        mDatabase.getMapper().startAddingDocuments(null);
-        mDatabase.getMapper().stopAddingDocuments(null);
-
-        // Clean database.
-        mDatabase.cleanDatabase(new Uri[] {
-                DocumentsContract.buildDocumentUri(MtpDocumentsProvider.AUTHORITY, "3")
-        });
-
-        // Add tree again.
-        addTestDevice();
-        addTestStorage("1");
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-                createDocument(100, "apple.txt", MtpConstants.FORMAT_TEXT, 1024),
-                createDocument(101, "orange.txt", MtpConstants.FORMAT_TEXT, 1024),
-        }, new long[] { 1024L, 1024L });
-        mDatabase.getMapper().stopAddingDocuments("2");
-
-        try (final Cursor cursor = mDatabase.queryChildDocuments(
-                strings(COLUMN_DOCUMENT_ID, Document.COLUMN_DISPLAY_NAME), "2")) {
-            assertEquals(2, cursor.getCount());
-
-            // Persistent uri uses the same ID.
-            cursor.moveToNext();
-            assertEquals("3", cursor.getString(0));
-            assertEquals("apple.txt", cursor.getString(1));
-
-            // Others does not.
-            cursor.moveToNext();
-            assertEquals("5", cursor.getString(0));
-            assertEquals("orange.txt", cursor.getString(1));
-        }
-    }
-
-    public void testFormatCodeForMpeg() throws FileNotFoundException {
-        addTestDevice();
-        addTestStorage("1");
-        mDatabase.getMapper().startAddingDocuments("2");
-        mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
-            createDocument(100, "audio.m4a", MtpConstants.FORMAT_MPEG, 1000),
-            createDocument(101, "video.m4v", MtpConstants.FORMAT_MPEG, 1000),
-            createDocument(102, "unknown.mp4", MtpConstants.FORMAT_MPEG, 1000),
-            createDocument(103, "inconsistent.txt", MtpConstants.FORMAT_MPEG, 1000),
-            createDocument(104, "noext", MtpConstants.FORMAT_UNDEFINED, 1000),
-        }, new long[] { 1000L, 1000L, 1000L, 1000L, 1000L });
-        mDatabase.getMapper().stopAddingDocuments("2");
-        try (final Cursor cursor = mDatabase.queryChildDocuments(
-                strings(COLUMN_DISPLAY_NAME,  COLUMN_MIME_TYPE),
-                "2")) {
-            assertEquals(5, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals("audio.m4a", cursor.getString(0));
-            assertEquals("audio/mp4", cursor.getString(1));
-            cursor.moveToNext();
-            assertEquals("video.m4v", cursor.getString(0));
-            assertEquals("video/mp4", cursor.getString(1));
-            cursor.moveToNext();
-            // Assume that the file is video as we don't have any hints to find out if the file is
-            // video or audio.
-            assertEquals("unknown.mp4", cursor.getString(0));
-            assertEquals("video/mp4", cursor.getString(1));
-            // Don't return mime type that is inconsistent with format code.
-            cursor.moveToNext();
-            assertEquals("inconsistent.txt", cursor.getString(0));
-            assertEquals("video/mpeg", cursor.getString(1));
-            cursor.moveToNext();
-            assertEquals("noext", cursor.getString(0));
-            assertEquals("application/octet-stream", cursor.getString(1));
-        }
-    }
-
-    private void addTestDevice() throws FileNotFoundException {
-        TestUtil.addTestDevice(mDatabase);
-    }
-
-    private void addTestStorage(String parentId) throws FileNotFoundException {
-        TestUtil.addTestStorage(mDatabase, parentId);
-    }
-}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
deleted file mode 100644
index 65c86df..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ /dev/null
@@ -1,1040 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.database.Cursor;
-import android.mtp.MtpConstants;
-import android.mtp.MtpObjectInfo;
-import android.net.Uri;
-import android.os.ParcelFileDescriptor;
-import android.os.storage.StorageManager;
-import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract.Path;
-import android.provider.DocumentsContract.Root;
-import android.system.Os;
-import android.system.OsConstants;
-import android.provider.DocumentsContract;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.Queue;
-import java.util.concurrent.TimeoutException;
-
-import static com.android.mtp.MtpDatabase.strings;
-import static com.android.mtp.TestUtil.OPERATIONS_SUPPORTED;
-
-@MediumTest
-public class MtpDocumentsProviderTest extends AndroidTestCase {
-    private final static Uri ROOTS_URI =
-            DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY);
-    private TestContentResolver mResolver;
-    private MtpDocumentsProvider mProvider;
-    private TestMtpManager mMtpManager;
-    private final TestResources mResources = new TestResources();
-    private MtpDatabase mDatabase;
-
-    @Override
-    public void setUp() throws IOException {
-        mResolver = new TestContentResolver();
-        mMtpManager = new TestMtpManager(getContext());
-    }
-
-    @Override
-    public void tearDown() {
-        mProvider.shutdown();
-        MtpDatabase.deleteDatabase(getContext());
-    }
-
-    public void testOpenAndCloseDevice() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        mMtpManager.addValidDevice(new MtpDeviceRecord(
-                0,
-                "Device A",
-                null /* deviceKey */,
-                false /* unopened */,
-                new MtpRoot[] {
-                    new MtpRoot(
-                            0 /* deviceId */,
-                            1 /* storageId */,
-                            "Storage A" /* volume description */,
-                            1024 /* free space */,
-                            2048 /* total space */,
-                            "" /* no volume identifier */)
-                },
-                OPERATIONS_SUPPORTED,
-                null));
-
-        mProvider.resumeRootScanner();
-        mResolver.waitForNotification(ROOTS_URI, 1);
-
-        mProvider.openDevice(0);
-        mResolver.waitForNotification(ROOTS_URI, 2);
-
-        mProvider.closeDevice(0);
-        mResolver.waitForNotification(ROOTS_URI, 3);
-    }
-
-    public void testOpenAndCloseErrorDevice() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        try {
-            mProvider.openDevice(1);
-            fail();
-        } catch (Throwable error) {
-            assertTrue(error instanceof IOException);
-        }
-        assertEquals(0, mProvider.getOpenedDeviceRecordsCache().length);
-
-        // Check if the following notification is the first one or not.
-        mMtpManager.addValidDevice(new MtpDeviceRecord(
-                0,
-                "Device A",
-                null /* deviceKey */,
-                false /* unopened */,
-                new MtpRoot[] {
-                    new MtpRoot(
-                            0 /* deviceId */,
-                            1 /* storageId */,
-                            "Storage A" /* volume description */,
-                            1024 /* free space */,
-                            2048 /* total space */,
-                            "" /* no volume identifier */)
-                },
-                OPERATIONS_SUPPORTED,
-                null));
-        mProvider.resumeRootScanner();
-        mResolver.waitForNotification(ROOTS_URI, 1);
-        mProvider.openDevice(0);
-        mResolver.waitForNotification(ROOTS_URI, 2);
-    }
-
-    public void testOpenDeviceOnDemand() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        mMtpManager.addValidDevice(new MtpDeviceRecord(
-                0,
-                "Device A",
-                null /* deviceKey */,
-                false /* unopened */,
-                new MtpRoot[] {
-                    new MtpRoot(
-                            0 /* deviceId */,
-                            1 /* storageId */,
-                            "Storage A" /* volume description */,
-                            1024 /* free space */,
-                            2048 /* total space */,
-                            "" /* no volume identifier */)
-                },
-                OPERATIONS_SUPPORTED,
-                null));
-        mMtpManager.setObjectHandles(0, 1, -1, new int[0]);
-        mProvider.resumeRootScanner();
-        mResolver.waitForNotification(ROOTS_URI, 1);
-        final String[] columns = new String[] {
-                DocumentsContract.Root.COLUMN_TITLE,
-                DocumentsContract.Root.COLUMN_DOCUMENT_ID
-        };
-        try (final Cursor cursor = mProvider.queryRoots(columns)) {
-            assertEquals(1, cursor.getCount());
-            assertTrue(cursor.moveToNext());
-            assertEquals("Device A", cursor.getString(0));
-            assertEquals(1, cursor.getLong(1));
-        }
-        {
-            final MtpDeviceRecord[] openedDevice = mProvider.getOpenedDeviceRecordsCache();
-            assertEquals(0, openedDevice.length);
-        }
-        // Device is opened automatically when querying its children.
-        try (final Cursor cursor = mProvider.queryChildDocuments("1", null, (String) null)) {}
-
-        {
-            final MtpDeviceRecord[] openedDevice = mProvider.getOpenedDeviceRecordsCache();
-            assertEquals(1, openedDevice.length);
-            assertEquals(0, openedDevice[0].deviceId);
-        }
-    }
-
-    public void testQueryRoots() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        mMtpManager.addValidDevice(new MtpDeviceRecord(
-                0,
-                "Device A",
-                "Device key A",
-                false /* unopened */,
-                new MtpRoot[] {
-                        new MtpRoot(
-                                0 /* deviceId */,
-                                1 /* storageId */,
-                                "Storage A" /* volume description */,
-                                1024 /* free space */,
-                                2048 /* total space */,
-                                "" /* no volume identifier */)
-                },
-                OPERATIONS_SUPPORTED,
-                null));
-        mMtpManager.addValidDevice(new MtpDeviceRecord(
-                1,
-                "Device B",
-                "Device key B",
-                false /* unopened */,
-                new MtpRoot[] {
-                    new MtpRoot(
-                            1 /* deviceId */,
-                            1 /* storageId */,
-                            "Storage B" /* volume description */,
-                            2048 /* free space */,
-                            4096 /* total space */,
-                            "Identifier B" /* no volume identifier */)
-                },
-                new int[0] /* No operations supported */,
-                null));
-
-        {
-            mProvider.openDevice(0);
-            mResolver.waitForNotification(ROOTS_URI, 1);
-            final Cursor cursor = mProvider.queryRoots(null);
-            assertEquals(2, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals("1", cursor.getString(0));
-            assertEquals(
-                    Root.FLAG_SUPPORTS_IS_CHILD |
-                    Root.FLAG_SUPPORTS_CREATE |
-                    Root.FLAG_LOCAL_ONLY,
-                    cursor.getInt(1));
-            assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
-            assertEquals("Device A Storage A", cursor.getString(3));
-            assertEquals("1", cursor.getString(4));
-            assertEquals(1024, cursor.getInt(5));
-        }
-
-        {
-            mProvider.openDevice(1);
-            mResolver.waitForNotification(ROOTS_URI, 2);
-            final Cursor cursor = mProvider.queryRoots(null);
-            assertEquals(2, cursor.getCount());
-            cursor.moveToNext();
-            cursor.moveToNext();
-            assertEquals("2", cursor.getString(0));
-            assertEquals(
-                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_LOCAL_ONLY, cursor.getInt(1));
-            assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
-            assertEquals("Device B Storage B", cursor.getString(3));
-            assertEquals("2", cursor.getString(4));
-            assertEquals(2048, cursor.getInt(5));
-        }
-    }
-
-    public void testQueryRoots_error() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        mMtpManager.addValidDevice(new MtpDeviceRecord(
-                0,
-                "Device A",
-                "Device key A",
-                false /* unopened */,
-                new MtpRoot[0],
-                OPERATIONS_SUPPORTED,
-                null));
-        mMtpManager.addValidDevice(new MtpDeviceRecord(
-                1,
-                "Device B",
-                "Device key B",
-                false /* unopened */,
-                new MtpRoot[] {
-                    new MtpRoot(
-                            1 /* deviceId */,
-                            1 /* storageId */,
-                            "Storage B" /* volume description */,
-                            2048 /* free space */,
-                            4096 /* total space */,
-                            "Identifier B" /* no volume identifier */)
-                },
-                OPERATIONS_SUPPORTED,
-                null));
-        {
-            mProvider.openDevice(0);
-            mResolver.waitForNotification(ROOTS_URI, 1);
-
-            mProvider.openDevice(1);
-            mResolver.waitForNotification(ROOTS_URI, 2);
-
-            final Cursor cursor = mProvider.queryRoots(null);
-            assertEquals(2, cursor.getCount());
-
-            cursor.moveToNext();
-            assertEquals("1", cursor.getString(0));
-            assertEquals(
-                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
-                    cursor.getInt(1));
-            assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
-            assertEquals("Device A", cursor.getString(3));
-            assertEquals("1", cursor.getString(4));
-            assertEquals(0, cursor.getInt(5));
-
-            cursor.moveToNext();
-            assertEquals("2", cursor.getString(0));
-            assertEquals(
-                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
-                    cursor.getInt(1));
-            assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
-            assertEquals("Device B Storage B", cursor.getString(3));
-            assertEquals("2", cursor.getString(4));
-            assertEquals(2048, cursor.getInt(5));
-        }
-    }
-
-    public void testQueryDocument() throws IOException, InterruptedException, TimeoutException {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") });
-        setupDocuments(
-                0,
-                0,
-                MtpManager.OBJECT_HANDLE_ROOT_CHILDREN,
-                "1",
-                new MtpObjectInfo[] {
-                        new MtpObjectInfo.Builder()
-                                .setObjectHandle(100)
-                                .setFormat(MtpConstants.FORMAT_EXIF_JPEG)
-                                .setName("image.jpg")
-                                .setDateModified(1422716400000L)
-                                .setCompressedSize(1024 * 1024 * 5)
-                                .setThumbCompressedSize(50 * 1024)
-                                .build()
-                });
-
-        final Cursor cursor = mProvider.queryDocument("3", null);
-        assertEquals(1, cursor.getCount());
-
-        cursor.moveToNext();
-
-        assertEquals("3", cursor.getString(0));
-        assertEquals("image/jpeg", cursor.getString(1));
-        assertEquals("image.jpg", cursor.getString(2));
-        assertEquals(1422716400000L, cursor.getLong(3));
-        assertEquals(
-                DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
-                DocumentsContract.Document.FLAG_SUPPORTS_WRITE |
-                DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL |
-                DocumentsContract.Document.FLAG_SUPPORTS_METADATA,
-                cursor.getInt(4));
-        assertEquals(1024 * 1024 * 5, cursor.getInt(5));
-    }
-
-    public void testQueryDocument_directory()
-            throws IOException, InterruptedException, TimeoutException {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") });
-        setupDocuments(
-                0,
-                0,
-                MtpManager.OBJECT_HANDLE_ROOT_CHILDREN,
-                "1",
-                new MtpObjectInfo[] {
-                        new MtpObjectInfo.Builder()
-                                .setObjectHandle(2)
-                                .setStorageId(1)
-                                .setFormat(MtpConstants.FORMAT_ASSOCIATION)
-                                .setName("directory")
-                                .setDateModified(1422716400000L)
-                                .build()
-                });
-
-        final Cursor cursor = mProvider.queryDocument("3", null);
-        assertEquals(1, cursor.getCount());
-
-        cursor.moveToNext();
-        assertEquals("3", cursor.getString(0));
-        assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(1));
-        assertEquals("directory", cursor.getString(2));
-        assertEquals(1422716400000L, cursor.getLong(3));
-        assertEquals(
-                DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
-                DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE,
-                cursor.getInt(4));
-        assertEquals(0, cursor.getInt(5));
-    }
-
-    public void testQueryDocument_forStorage()
-            throws IOException, InterruptedException, TimeoutException {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] {
-                new MtpRoot(
-                        0 /* deviceId */,
-                        1 /* storageId */,
-                        "Storage A" /* volume description */,
-                        1024 /* free space */,
-                        4096 /* total space */,
-                        "" /* no volume identifier */)
-        });
-        final Cursor cursor = mProvider.queryDocument("2", null);
-        assertEquals(1, cursor.getCount());
-
-        cursor.moveToNext();
-        assertEquals("2", cursor.getString(0));
-        assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(1));
-        assertEquals("Storage A", cursor.getString(2));
-        assertTrue(cursor.isNull(3));
-        assertEquals(DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE, cursor.getInt(4));
-        assertEquals(3072, cursor.getInt(5));
-    }
-
-    public void testQueryDocument_forDeviceWithSingleStorage()
-            throws IOException, InterruptedException, TimeoutException {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] {
-                new MtpRoot(
-                        0 /* deviceId */,
-                        1 /* storageId */,
-                        "Storage A" /* volume description */,
-                        1024 /* free space */,
-                        4096 /* total space */,
-                        "" /* no volume identifier */)
-        });
-        final Cursor cursor = mProvider.queryDocument("1", null);
-        assertEquals(1, cursor.getCount());
-
-        cursor.moveToNext();
-        assertEquals("1", cursor.getString(0));
-        assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(1));
-        assertEquals("Device Storage A", cursor.getString(2));
-        assertTrue(cursor.isNull(3));
-        assertEquals(DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE, cursor.getInt(4));
-        assertTrue(cursor.isNull(5));
-    }
-
-    public void testQueryDocument_forDeviceWithTwoStorages()
-            throws IOException, InterruptedException, TimeoutException {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] {
-                new MtpRoot(
-                        0 /* deviceId */,
-                        1 /* storageId */,
-                        "Storage A" /* volume description */,
-                        1024 /* free space */,
-                        4096 /* total space */,
-                        "" /* no volume identifier */),
-                new MtpRoot(
-                        0 /* deviceId */,
-                        2 /* storageId */,
-                        "Storage B" /* volume description */,
-                        1024 /* free space */,
-                        4096 /* total space */,
-                        "" /* no volume identifier */)
-        });
-        final Cursor cursor = mProvider.queryDocument("1", null);
-        assertEquals(1, cursor.getCount());
-
-        cursor.moveToNext();
-        assertEquals("1", cursor.getString(0));
-        assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(1));
-        assertEquals("Device", cursor.getString(2));
-        assertTrue(cursor.isNull(3));
-        assertEquals(0, cursor.getInt(4));
-        assertTrue(cursor.isNull(5));
-    }
-
-    public void testQueryChildDocuments() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") });
-        setupDocuments(
-                0,
-                0,
-                MtpManager.OBJECT_HANDLE_ROOT_CHILDREN,
-                "1",
-                new MtpObjectInfo[] {
-                        new MtpObjectInfo.Builder()
-                                .setObjectHandle(100)
-                                .setFormat(MtpConstants.FORMAT_EXIF_JPEG)
-                                .setName("image.jpg")
-                                .setCompressedSize(1024 * 1024 * 5)
-                                .setThumbCompressedSize(5 * 1024)
-                                .setProtectionStatus(MtpConstants.PROTECTION_STATUS_READ_ONLY)
-                                .build()
-                });
-
-        final Cursor cursor = mProvider.queryChildDocuments("1", null, (String) null);
-        assertEquals(1, cursor.getCount());
-
-        assertTrue(cursor.moveToNext());
-        assertEquals("3", cursor.getString(0));
-        assertEquals("image/jpeg", cursor.getString(1));
-        assertEquals("image.jpg", cursor.getString(2));
-        assertEquals(0, cursor.getLong(3));
-        assertEquals(Document.FLAG_SUPPORTS_THUMBNAIL
-                | Document.FLAG_SUPPORTS_METADATA, cursor.getInt(4));
-        assertEquals(1024 * 1024 * 5, cursor.getInt(5));
-
-        cursor.close();
-    }
-
-    public void testQueryChildDocuments_cursorError() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        try {
-            mProvider.queryChildDocuments("1", null, (String) null);
-            fail();
-        } catch (FileNotFoundException error) {}
-    }
-
-    public void testQueryChildDocuments_documentError() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") });
-        mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });
-        try (final Cursor cursor = mProvider.queryChildDocuments("1", null, (String) null)) {
-            assertEquals(0, cursor.getCount());
-            assertFalse(cursor.getExtras().getBoolean(DocumentsContract.EXTRA_LOADING));
-        }
-    }
-
-    public void testDeleteDocument() throws IOException, InterruptedException, TimeoutException {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] {
-                new MtpRoot(0, 0, "Storage", 0, 0, "")
-        });
-        setupDocuments(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, "1", new MtpObjectInfo[] {
-                new MtpObjectInfo.Builder()
-                    .setName("test.txt")
-                    .setObjectHandle(1)
-                    .setParent(-1)
-                    .build()
-        });
-
-        mProvider.deleteDocument("3");
-        assertEquals(1, mResolver.getChangeCount(
-                DocumentsContract.buildChildDocumentsUri(
-                        MtpDocumentsProvider.AUTHORITY, "1")));
-    }
-
-    public void testDeleteDocument_error()
-            throws IOException, InterruptedException, TimeoutException {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] {
-                new MtpRoot(0, 0, "Storage", 0, 0, "")
-        });
-        setupDocuments(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, "1", new MtpObjectInfo[] {
-                new MtpObjectInfo.Builder()
-                    .setName("test.txt")
-                    .setObjectHandle(1)
-                    .setParent(-1)
-                    .build()
-        });
-        try {
-            mProvider.deleteDocument("4");
-            fail();
-        } catch (Throwable e) {
-            assertTrue(e instanceof IOException);
-        }
-        assertEquals(0, mResolver.getChangeCount(
-                DocumentsContract.buildChildDocumentsUri(
-                        MtpDocumentsProvider.AUTHORITY, "1")));
-    }
-
-    public void testOpenDocument() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] {
-                new MtpRoot(0, 0, "Storage", 0, 0, "")
-        });
-        final byte[] bytes = "Hello world".getBytes();
-        setupDocuments(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, "1", new MtpObjectInfo[] {
-                new MtpObjectInfo.Builder()
-                        .setName("test.txt")
-                        .setObjectHandle(1)
-                        .setCompressedSize(bytes.length)
-                        .setParent(-1)
-                        .build()
-        });
-        mMtpManager.setImportFileBytes(0, 1, bytes);
-        try (final ParcelFileDescriptor fd = mProvider.openDocument("3", "r", null)) {
-            final byte[] readBytes = new byte[5];
-            assertEquals(6, Os.lseek(fd.getFileDescriptor(), 6, OsConstants.SEEK_SET));
-            assertEquals(5, Os.read(fd.getFileDescriptor(), readBytes, 0, 5));
-            assertTrue(Arrays.equals("world".getBytes(), readBytes));
-
-            assertEquals(0, Os.lseek(fd.getFileDescriptor(), 0, OsConstants.SEEK_SET));
-            assertEquals(5, Os.read(fd.getFileDescriptor(), readBytes, 0, 5));
-            assertTrue(Arrays.equals("Hello".getBytes(), readBytes));
-        }
-    }
-
-    public void testOpenDocument_shortBytes() throws Exception {
-        mMtpManager = new TestMtpManager(getContext()) {
-            @Override
-            MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
-                if (objectHandle == 1) {
-                    return new MtpObjectInfo.Builder(super.getObjectInfo(deviceId, objectHandle))
-                            .setObjectHandle(1).setCompressedSize(1024 * 1024).build();
-                }
-
-                return super.getObjectInfo(deviceId, objectHandle);
-            }
-        };
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] {
-                new MtpRoot(0, 0, "Storage", 0, 0, "")
-        });
-        final byte[] bytes = "Hello world".getBytes();
-        setupDocuments(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, "1", new MtpObjectInfo[] {
-                new MtpObjectInfo.Builder()
-                        .setName("test.txt")
-                        .setObjectHandle(1)
-                        .setCompressedSize(bytes.length)
-                        .setParent(-1)
-                        .build()
-        });
-        mMtpManager.setImportFileBytes(0, 1, bytes);
-        try (final ParcelFileDescriptor fd = mProvider.openDocument("3", "r", null)) {
-            final byte[] readBytes = new byte[1024 * 1024];
-            assertEquals(11, Os.read(fd.getFileDescriptor(), readBytes, 0, readBytes.length));
-        }
-    }
-
-    public void testOpenDocument_writing() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] {
-                new MtpRoot(0, 100, "Storage", 0, 0, "")
-        });
-        final String documentId = mProvider.createDocument("2", "text/plain", "test.txt");
-        {
-            final ParcelFileDescriptor fd = mProvider.openDocument(documentId, "w", null);
-            try (ParcelFileDescriptor.AutoCloseOutputStream stream =
-                    new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
-                stream.write("Hello".getBytes());
-                fd.getFileDescriptor().sync();
-            }
-        }
-        {
-            final ParcelFileDescriptor fd = mProvider.openDocument(documentId, "r", null);
-            try (ParcelFileDescriptor.AutoCloseInputStream stream =
-                    new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
-                final byte[] bytes = new byte[5];
-                stream.read(bytes);
-                assertTrue(Arrays.equals("Hello".getBytes(), bytes));
-            }
-        }
-    }
-
-    public void testBusyDevice() throws Exception {
-        mMtpManager = new TestMtpManager(getContext()) {
-            @Override
-            synchronized MtpDeviceRecord openDevice(int deviceId)
-                    throws IOException {
-                throw new BusyDeviceException();
-            }
-        };
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        mMtpManager.addValidDevice(new MtpDeviceRecord(
-                0, "Device A", null /* deviceKey */, false /* unopened */, new MtpRoot[0],
-                OPERATIONS_SUPPORTED, null));
-
-        mProvider.resumeRootScanner();
-        mResolver.waitForNotification(ROOTS_URI, 1);
-
-        try (final Cursor cursor = mProvider.queryRoots(null)) {
-            assertEquals(1, cursor.getCount());
-        }
-
-        try (final Cursor cursor = mProvider.queryChildDocuments("1", null, (String) null)) {
-            assertEquals(0, cursor.getCount());
-            assertEquals(
-                    "error_busy_device",
-                    cursor.getExtras().getString(DocumentsContract.EXTRA_ERROR));
-        }
-    }
-
-    public void testLockedDevice() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        mMtpManager.addValidDevice(new MtpDeviceRecord(
-                0, "Device A", null, false /* unopened */, new MtpRoot[0], OPERATIONS_SUPPORTED,
-                null));
-
-        mProvider.resumeRootScanner();
-        mResolver.waitForNotification(ROOTS_URI, 1);
-
-        try (final Cursor cursor = mProvider.queryRoots(null)) {
-            assertEquals(1, cursor.getCount());
-        }
-
-        try (final Cursor cursor = mProvider.queryChildDocuments("1", null, (String) null)) {
-            assertEquals(0, cursor.getCount());
-            assertEquals(
-                    "error_locked_device",
-                    cursor.getExtras().getString(DocumentsContract.EXTRA_ERROR));
-        }
-    }
-
-    public void testMappingDisconnectedDocuments() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        mMtpManager.addValidDevice(new MtpDeviceRecord(
-                0,
-                "Device A",
-                "device key",
-                true /* opened */,
-                new MtpRoot[] {
-                    new MtpRoot(
-                            0 /* deviceId */,
-                            1 /* storageId */,
-                            "Storage A" /* volume description */,
-                            1024 /* free space */,
-                            2048 /* total space */,
-                            "" /* no volume identifier */)
-                },
-                OPERATIONS_SUPPORTED,
-                null));
-
-        final String[] names = strings("Directory A", "Directory B", "Directory C");
-        final int objectHandleOffset = 100;
-        for (int i = 0; i < names.length; i++) {
-            final int parentHandle = i == 0 ?
-                    MtpManager.OBJECT_HANDLE_ROOT_CHILDREN : objectHandleOffset + i - 1;
-            final int objectHandle = i + objectHandleOffset;
-            mMtpManager.setObjectHandles(0, 1, parentHandle, new int[] { objectHandle });
-            mMtpManager.setObjectInfo(
-                    0,
-                    new MtpObjectInfo.Builder()
-                            .setName(names[i])
-                            .setObjectHandle(objectHandle)
-                            .setFormat(MtpConstants.FORMAT_ASSOCIATION)
-                            .setStorageId(1)
-                            .build());
-        }
-
-        mProvider.resumeRootScanner();
-        mResolver.waitForNotification(ROOTS_URI, 1);
-
-        final int documentIdOffset = 2;
-        for (int i = 0; i < names.length; i++) {
-            try (final Cursor cursor = mProvider.queryChildDocuments(
-                    String.valueOf(documentIdOffset + i),
-                    strings(Document.COLUMN_DOCUMENT_ID, Document.COLUMN_DISPLAY_NAME),
-                    (String) null)) {
-                assertEquals(1, cursor.getCount());
-                cursor.moveToNext();
-                assertEquals(String.valueOf(documentIdOffset + i + 1), cursor.getString(0));
-                assertEquals(names[i], cursor.getString(1));
-            }
-        }
-
-        mProvider.closeDevice(0);
-        mResolver.waitForNotification(ROOTS_URI, 2);
-
-        mProvider.openDevice(0);
-        mResolver.waitForNotification(ROOTS_URI, 3);
-
-        for (int i = 0; i < names.length; i++) {
-            mResolver.waitForNotification(DocumentsContract.buildChildDocumentsUri(
-                    MtpDocumentsProvider.AUTHORITY,
-                    String.valueOf(documentIdOffset + i)), 1);
-            try (final Cursor cursor = mProvider.queryChildDocuments(
-                    String.valueOf(documentIdOffset + i),
-                    strings(Document.COLUMN_DOCUMENT_ID),
-                    (String) null)) {
-                assertEquals(1, cursor.getCount());
-                cursor.moveToNext();
-                assertEquals(String.valueOf(documentIdOffset + i + 1), cursor.getString(0));
-            }
-        }
-    }
-
-    public void testCreateDocument() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] {
-                new MtpRoot(0, 100, "Storage A", 100, 100, null)
-        });
-        final String documentId = mProvider.createDocument("1", "text/plain", "note.txt");
-        final Uri deviceUri = DocumentsContract.buildChildDocumentsUri(
-                MtpDocumentsProvider.AUTHORITY, "1");
-        final Uri storageUri = DocumentsContract.buildChildDocumentsUri(
-                MtpDocumentsProvider.AUTHORITY, "2");
-        mResolver.waitForNotification(storageUri, 1);
-        mResolver.waitForNotification(deviceUri, 1);
-        try (final Cursor cursor = mProvider.queryDocument(documentId, null)) {
-            assertTrue(cursor.moveToNext());
-            assertEquals(
-                    "note.txt",
-                    cursor.getString(cursor.getColumnIndex(Document.COLUMN_DISPLAY_NAME)));
-            assertEquals(
-                    "text/plain",
-                    cursor.getString(cursor.getColumnIndex(Document.COLUMN_MIME_TYPE)));
-        }
-    }
-
-    public void testCreateDocument_noWritingSupport() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        mMtpManager.addValidDevice(new MtpDeviceRecord(
-                0, "Device A", null /* deviceKey */, false /* unopened */,
-                new MtpRoot[] {
-                        new MtpRoot(
-                                0 /* deviceId */,
-                                1 /* storageId */,
-                                "Storage A" /* volume description */,
-                                1024 /* free space */,
-                                2048 /* total space */,
-                                "" /* no volume identifier */)
-                },
-                new int[0] /* no operations supported */, null));
-        mProvider.resumeRootScanner();
-        mResolver.waitForNotification(ROOTS_URI, 1);
-        try {
-            mProvider.createDocument("1", "text/palin", "note.txt");
-            fail();
-        } catch (UnsupportedOperationException exception) {}
-    }
-
-    public void testOpenDocument_noWritingSupport() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        mMtpManager.addValidDevice(new MtpDeviceRecord(
-                0, "Device A", null /* deviceKey */, false /* unopened */,
-                new MtpRoot[] {
-                        new MtpRoot(
-                                0 /* deviceId */,
-                                1 /* storageId */,
-                                "Storage A" /* volume description */,
-                                1024 /* free space */,
-                                2048 /* total space */,
-                                "" /* no volume identifier */)
-                },
-                new int[0] /* no operations supported */, null));
-        mMtpManager.setObjectHandles(
-                0, 1, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, new int[] { 100 });
-        mMtpManager.setObjectInfo(
-                0, new MtpObjectInfo.Builder().setObjectHandle(100).setName("note.txt").build());
-        mProvider.resumeRootScanner();
-        mResolver.waitForNotification(ROOTS_URI, 1);
-        try (final Cursor cursor = mProvider.queryChildDocuments(
-                "1", strings(Document.COLUMN_DOCUMENT_ID), (String) null)) {
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals("3", cursor.getString(0));
-        }
-        try {
-            mProvider.openDocument("3", "w", null);
-            fail();
-        } catch (UnsupportedOperationException exception) {}
-    }
-
-    public void testObjectSizeLong() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") });
-        mMtpManager.setObjectSizeLong(0, 100, MtpConstants.FORMAT_EXIF_JPEG, 0x400000000L);
-        setupDocuments(
-                0,
-                0,
-                MtpManager.OBJECT_HANDLE_ROOT_CHILDREN,
-                "1",
-                new MtpObjectInfo[] {
-                        new MtpObjectInfo.Builder()
-                                .setObjectHandle(100)
-                                .setFormat(MtpConstants.FORMAT_EXIF_JPEG)
-                                .setName("image.jpg")
-                                .setCompressedSize(0xffffffffl)
-                                .build()
-                });
-
-        final Cursor cursor = mProvider.queryDocument("3", new String[] {
-                DocumentsContract.Document.COLUMN_SIZE
-        });
-        assertEquals(1, cursor.getCount());
-
-        cursor.moveToNext();
-        assertEquals(0x400000000L, cursor.getLong(0));
-    }
-
-    public void testFindDocumentPath_singleStorage_toRoot() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") });
-        setupHierarchyDocuments("1");
-
-        final Path path = mProvider.findDocumentPath(null, "15");
-        assertEquals("1", path.getRootId());
-        assertEquals(4, path.getPath().size());
-        assertEquals("1", path.getPath().get(0));
-        assertEquals("3", path.getPath().get(1));
-        assertEquals("6", path.getPath().get(2));
-        assertEquals("15", path.getPath().get(3));
-    }
-
-    public void testFindDocumentPath_singleStorage_toDoc() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") });
-        setupHierarchyDocuments("1");
-
-        final Path path = mProvider.findDocumentPath("3", "18");
-        assertNull(path.getRootId());
-        assertEquals(3, path.getPath().size());
-        assertEquals("3", path.getPath().get(0));
-        assertEquals("7", path.getPath().get(1));
-        assertEquals("18", path.getPath().get(2));
-    }
-
-    public void testFindDocumentPath_multiStorage_toRoot() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] {
-                new MtpRoot(0, 0, "Storage A", 1000, 1000, ""),
-                new MtpRoot(0, 1, "Storage B", 1000, 1000, "") });
-        setupHierarchyDocuments("2");
-
-        final Path path = mProvider.findDocumentPath(null, "16");
-        assertEquals("2", path.getRootId());
-        assertEquals(4, path.getPath().size());
-        assertEquals("2", path.getPath().get(0));
-        assertEquals("4", path.getPath().get(1));
-        assertEquals("7", path.getPath().get(2));
-        assertEquals("16", path.getPath().get(3));
-    }
-
-    public void testFindDocumentPath_multiStorage_toDoc() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] {
-                new MtpRoot(0, 0, "Storage A", 1000, 1000, ""),
-                new MtpRoot(0, 1, "Storage B", 1000, 1000, "") });
-        setupHierarchyDocuments("2");
-
-        final Path path = mProvider.findDocumentPath("4", "19");
-        assertNull(path.getRootId());
-        assertEquals(3, path.getPath().size());
-        assertEquals("4", path.getPath().get(0));
-        assertEquals("8", path.getPath().get(1));
-        assertEquals("19", path.getPath().get(2));
-    }
-
-    public void testIsChildDocument() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") });
-        setupHierarchyDocuments("1");
-        assertTrue(mProvider.isChildDocument("1", "1"));
-        assertTrue(mProvider.isChildDocument("1", "14"));
-        assertTrue(mProvider.isChildDocument("2", "14"));
-        assertTrue(mProvider.isChildDocument("5", "14"));
-        assertFalse(mProvider.isChildDocument("3", "14"));
-        assertFalse(mProvider.isChildDocument("6", "14"));
-    }
-
-    private void setupProvider(int flag) {
-        mDatabase = new MtpDatabase(getContext(), flag);
-        mProvider = new MtpDocumentsProvider();
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        assertTrue(mProvider.onCreateForTesting(
-                getContext(),
-                mResources,
-                mMtpManager,
-                mResolver,
-                mDatabase,
-                storageManager,
-                new TestServiceIntentSender()));
-    }
-
-    private String[] getStrings(Cursor cursor) {
-        try {
-            final String[] results = new String[cursor.getCount()];
-            for (int i = 0; cursor.moveToNext(); i++) {
-                results[i] = cursor.getString(0);
-            }
-            return results;
-        } finally {
-            cursor.close();
-        }
-    }
-
-    private String[] setupRoots(int deviceId, MtpRoot[] roots)
-            throws InterruptedException, TimeoutException, IOException {
-        final int changeCount = mResolver.getChangeCount(ROOTS_URI);
-        mMtpManager.addValidDevice(
-                new MtpDeviceRecord(deviceId, "Device", null /* deviceKey */, false /* unopened */,
-                roots, OPERATIONS_SUPPORTED, null));
-        mProvider.openDevice(deviceId);
-        mResolver.waitForNotification(ROOTS_URI, changeCount + 1);
-        return getStrings(mProvider.queryRoots(strings(DocumentsContract.Root.COLUMN_ROOT_ID)));
-    }
-
-    private String[] setupDocuments(
-            int deviceId,
-            int storageId,
-            int parentHandle,
-            String parentDocumentId,
-            MtpObjectInfo[] objects) throws FileNotFoundException {
-        final int[] handles = new int[objects.length];
-        int i = 0;
-        for (final MtpObjectInfo info : objects) {
-            handles[i++] = info.getObjectHandle();
-            mMtpManager.setObjectInfo(deviceId, info);
-        }
-        mMtpManager.setObjectHandles(deviceId, storageId, parentHandle, handles);
-        return getStrings(mProvider.queryChildDocuments(
-                parentDocumentId,
-                strings(DocumentsContract.Document.COLUMN_DOCUMENT_ID),
-                (String) null));
-    }
-
-    static class HierarchyDocument {
-        int depth;
-        String documentId;
-        int objectHandle;
-        int parentHandle;
-
-        HierarchyDocument createChildDocument(int newHandle) {
-            final HierarchyDocument doc = new HierarchyDocument();
-            doc.depth = depth - 1;
-            doc.objectHandle = newHandle;
-            doc.parentHandle = objectHandle;
-            return doc;
-        }
-
-        MtpObjectInfo toObjectInfo() {
-            return new MtpObjectInfo.Builder()
-                    .setName("doc_" + documentId)
-                    .setFormat(depth > 0 ?
-                            MtpConstants.FORMAT_ASSOCIATION : MtpConstants.FORMAT_TEXT)
-                    .setObjectHandle(objectHandle)
-                    .setParent(parentHandle)
-                    .build();
-        }
-    }
-
-    private void setupHierarchyDocuments(String documentId) throws Exception {
-        final Queue<HierarchyDocument> ids = new LinkedList<>();
-        final HierarchyDocument firstDocument = new HierarchyDocument();
-        firstDocument.depth = 3;
-        firstDocument.documentId = documentId;
-        firstDocument.objectHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
-        ids.add(firstDocument);
-
-        int objectHandle = 100;
-        while (!ids.isEmpty()) {
-            final HierarchyDocument document = ids.remove();
-            final HierarchyDocument[] children = new HierarchyDocument[] {
-                    document.createChildDocument(objectHandle++),
-                    document.createChildDocument(objectHandle++),
-                    document.createChildDocument(objectHandle++),
-            };
-            final String[] childDocIds = setupDocuments(
-                    0, 0, document.objectHandle, document.documentId, new MtpObjectInfo[] {
-                            children[0].toObjectInfo(),
-                            children[1].toObjectInfo(),
-                            children[2].toObjectInfo(),
-                    });
-            children[0].documentId = childDocIds[0];
-            children[1].documentId = childDocIds[1];
-            children[2].documentId = childDocIds[2];
-
-            if (children[0].depth > 0) {
-                ids.add(children[0]);
-                ids.add(children[1]);
-                ids.add(children[2]);
-            }
-        }
-    }
-}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
deleted file mode 100644
index 5ada14f..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.content.Context;
-import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbManager;
-import android.mtp.MtpConstants;
-import android.mtp.MtpEvent;
-import android.mtp.MtpObjectInfo;
-import android.os.CancellationSignal;
-import android.os.OperationCanceledException;
-import android.os.ParcelFileDescriptor;
-import android.os.SystemClock;
-import android.test.InstrumentationTestCase;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.concurrent.Callable;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.TimeUnit;
-
-@RealDeviceTest
-public class MtpManagerTest extends InstrumentationTestCase {
-    private static final int TIMEOUT_MS = 1000;
-    UsbManager mUsbManager;
-    MtpManager mManager;
-    UsbDevice mUsbDevice;
-
-    @Override
-    public void setUp() throws Exception {
-        mUsbManager = getContext().getSystemService(UsbManager.class);
-        mManager = new MtpManager(getContext());
-        mUsbDevice = TestUtil.setupMtpDevice(getInstrumentation(), mUsbManager, mManager);
-    }
-
-    @Override
-    public void tearDown() throws IOException {
-        mManager.closeDevice(mUsbDevice.getDeviceId());
-    }
-
-    @Override
-    public TestResultInstrumentation getInstrumentation() {
-        return (TestResultInstrumentation) super.getInstrumentation();
-    }
-
-    public void testCancelEvent() throws Exception {
-        final CancellationSignal signal = new CancellationSignal();
-        final FutureTask<Boolean> future = new FutureTask<Boolean>(
-                new Callable<Boolean>() {
-                    @Override
-                    public Boolean call() throws IOException {
-                        try {
-                            while (true) {
-                                mManager.readEvent(mUsbDevice.getDeviceId(), signal);
-                            }
-                        } catch (OperationCanceledException exception) {
-                            return true;
-                        }
-                    }
-                });
-        final Thread thread = new Thread(future);
-        thread.start();
-        SystemClock.sleep(TIMEOUT_MS);
-        signal.cancel();
-        assertTrue(future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-    }
-
-    public void testOperationsSupported() {
-        final MtpDeviceRecord[] records = mManager.getDevices();
-        assertEquals(1, records.length);
-        assertNotNull(records[0].operationsSupported);
-        getInstrumentation().show(Arrays.toString(records[0].operationsSupported));
-    }
-
-    public void testEventsSupported() {
-        final MtpDeviceRecord[] records = mManager.getDevices();
-        assertEquals(1, records.length);
-        assertNotNull(records[0].eventsSupported);
-        getInstrumentation().show(Arrays.toString(records[0].eventsSupported));
-    }
-
-    public void testDeviceKey() {
-        final MtpDeviceRecord[] records = mManager.getDevices();
-        assertEquals(1, records.length);
-        assertNotNull(records[0].deviceKey);
-        getInstrumentation().show("deviceKey: " + records[0].deviceKey);
-    }
-
-    public void testEventObjectAdded() throws Exception {
-        while (true) {
-            getInstrumentation().show("Please take a photo by using connected MTP device.");
-            final CancellationSignal signal = new CancellationSignal();
-            MtpEvent event = mManager.readEvent(mUsbDevice.getDeviceId(), signal);
-            if (event.getEventCode() != MtpEvent.EVENT_OBJECT_ADDED) {
-                continue;
-            }
-            assertTrue(event.getObjectHandle() != 0);
-            break;
-        }
-    }
-
-    public void testCreateDocumentAndGetPartialObject() throws Exception {
-        int storageId = 0;
-        for (final MtpDeviceRecord record : mManager.getDevices()) {
-            if (record.deviceId == mUsbDevice.getDeviceId()) {
-                storageId = record.roots[0].mStorageId;
-                break;
-            }
-        }
-        assertTrue("Valid storage not found.", storageId != 0);
-
-        final String testFileName = "MtpManagerTest_testFile.txt";
-        for (final int handle : mManager.getObjectHandles(
-                mUsbDevice.getDeviceId(), storageId, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN)) {
-            if (mManager.getObjectInfo(mUsbDevice.getDeviceId(), handle)
-                    .getName().equals(testFileName)) {
-                mManager.deleteDocument(mUsbDevice.getDeviceId(), handle);
-                break;
-            }
-        }
-
-        final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
-        final byte[] expectedBytes = "Hello Android!".getBytes("ascii");
-        try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
-                new ParcelFileDescriptor.AutoCloseOutputStream(fds[1])) {
-            stream.write(expectedBytes);
-        }
-        final int objectHandle = mManager.createDocument(
-                mUsbDevice.getDeviceId(),
-                new MtpObjectInfo.Builder()
-                        .setStorageId(storageId)
-                        .setName(testFileName)
-                        .setCompressedSize(expectedBytes.length)
-                        .setFormat(MtpConstants.FORMAT_TEXT)
-                        .build(),
-                fds[0]);
-        final byte[] bytes = new byte[100];
-        assertEquals(5, mManager.getPartialObject(
-                mUsbDevice.getDeviceId(), objectHandle, 0, 5, bytes));
-        assertEquals("Hello", new String(bytes, 0, 5, "ascii"));
-        assertEquals(8, mManager.getPartialObject(
-                mUsbDevice.getDeviceId(), objectHandle, 6, 100, bytes));
-        assertEquals("Android!", new String(bytes, 0, 8, "ascii"));
-    }
-
-    private Context getContext() {
-        return getInstrumentation().getContext();
-    }
-}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
deleted file mode 100644
index 53dc3db..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.os.ParcelFileDescriptor;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import java.io.IOException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-@MediumTest
-public class PipeManagerTest extends AndroidTestCase {
-    private static final byte[] HELLO_BYTES = new byte[] { 'h', 'e', 'l', 'l', 'o' };
-
-    private TestMtpManager mtpManager;
-    private ExecutorService mExecutor;
-    private PipeManager mPipeManager;
-    private MtpDatabase mDatabase;
-
-    @Override
-    public void setUp() {
-        mtpManager = new TestMtpManager(getContext());
-        mExecutor = Executors.newSingleThreadExecutor();
-        mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        mPipeManager = new PipeManager(mDatabase, mExecutor);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        assertTrue(mPipeManager.close());
-        mDatabase.close();
-    }
-
-    public void testReadDocument_basic() throws Exception {
-        mtpManager.setImportFileBytes(0, 1, HELLO_BYTES);
-        final ParcelFileDescriptor descriptor = mPipeManager.readDocument(
-                mtpManager,
-                new Identifier(0, 0, 1, null, MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT));
-        assertDescriptor(descriptor, HELLO_BYTES);
-    }
-
-    public void testReadDocument_error() throws Exception {
-        final ParcelFileDescriptor descriptor = mPipeManager.readDocument(
-                mtpManager,
-                new Identifier(0, 0, 1, null, MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT));
-        assertDescriptorError(descriptor);
-    }
-
-    public void testReadThumbnail_basic() throws Exception {
-        mtpManager.setThumbnail(0, 1, HELLO_BYTES);
-        final ParcelFileDescriptor descriptor = mPipeManager.readThumbnail(
-                mtpManager,
-                new Identifier(0, 0, 1, null, MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT));
-        assertDescriptor(descriptor, HELLO_BYTES);
-    }
-
-    public void testReadThumbnail_error() throws Exception {
-        final ParcelFileDescriptor descriptor = mPipeManager.readThumbnail(
-                mtpManager,
-                new Identifier(0, 0, 1, null, MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT));
-        assertDescriptorError(descriptor);
-    }
-
-    private void assertDescriptor(ParcelFileDescriptor descriptor, byte[] expectedBytes)
-            throws IOException, InterruptedException {
-        mExecutor.shutdown();
-        assertTrue(mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS));
-        try (final ParcelFileDescriptor.AutoCloseInputStream stream =
-                new ParcelFileDescriptor.AutoCloseInputStream(descriptor)) {
-            byte[] results = new byte[100];
-            assertEquals(expectedBytes.length, stream.read(results));
-            for (int i = 0; i < expectedBytes.length; i++) {
-                assertEquals(expectedBytes[i], results[i]);
-            }
-        }
-    }
-
-    private void assertDescriptorError(ParcelFileDescriptor descriptor)
-            throws InterruptedException {
-        mExecutor.shutdown();
-        assertTrue(mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS));
-        try {
-            descriptor.checkError();
-            fail();
-        } catch (Throwable error) {
-            assertTrue(error instanceof IOException);
-        }
-    }
-}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java
deleted file mode 100644
index 22daaf2..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE, ElementType.METHOD})
-@interface RealDeviceTest {}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestContentResolver.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestContentResolver.java
deleted file mode 100644
index 7e772c3..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestContentResolver.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.test.mock.MockContentResolver;
-
-import junit.framework.Assert;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Phaser;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-class TestContentResolver extends MockContentResolver {
-    private static final int TIMEOUT_PERIOD_MS = 3000;
-    private final Map<Uri, Phaser> mPhasers = new HashMap<>();
-
-    @Override
-    public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
-        getPhaser(uri).arrive();
-    }
-
-
-    void waitForNotification(Uri uri, int count) throws InterruptedException, TimeoutException {
-        Assert.assertEquals(count, getPhaser(uri).awaitAdvanceInterruptibly(
-                count - 1, TIMEOUT_PERIOD_MS, TimeUnit.MILLISECONDS));
-    }
-
-    int getChangeCount(Uri uri) {
-        if (mPhasers.containsKey(uri)) {
-            return mPhasers.get(uri).getPhase();
-        } else {
-            return 0;
-        }
-    }
-
-    private synchronized Phaser getPhaser(Uri uri) {
-        Phaser phaser = mPhasers.get(uri);
-        if (phaser == null) {
-            phaser = new Phaser(1);
-            mPhasers.put(uri, phaser);
-        }
-        return phaser;
-    }
-}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
deleted file mode 100644
index f20bbec..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.content.Context;
-import android.mtp.MtpObjectInfo;
-import android.os.ParcelFileDescriptor;
-import android.util.SparseArray;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-import junit.framework.Assert;
-
-public class TestMtpManager extends MtpManager {
-    public static final int CREATED_DOCUMENT_HANDLE = 1000;
-
-    protected static String pack(int... args) {
-        return Arrays.toString(args);
-    }
-
-    private final SparseArray<MtpDeviceRecord> mDevices = new SparseArray<>();
-    private final Map<String, MtpObjectInfo> mObjectInfos = new HashMap<>();
-    private final Map<String, int[]> mObjectHandles = new HashMap<>();
-    private final Map<String, byte[]> mThumbnailBytes = new HashMap<>();
-    private final Map<String, byte[]> mImportFileBytes = new HashMap<>();
-    private final Map<String, Long> mObjectSizeLongs = new HashMap<>();
-
-    TestMtpManager(Context context) {
-        super(context);
-    }
-
-    void addValidDevice(MtpDeviceRecord device) {
-        mDevices.put(device.deviceId, device);
-    }
-
-    void setObjectHandles(int deviceId, int storageId, int parentHandle, int[] objectHandles) {
-        mObjectHandles.put(pack(deviceId, storageId, parentHandle), objectHandles);
-    }
-
-    void setObjectInfo(int deviceId, MtpObjectInfo objectInfo) {
-        mObjectInfos.put(pack(deviceId, objectInfo.getObjectHandle()), objectInfo);
-    }
-
-    void setImportFileBytes(int deviceId, int objectHandle, byte[] bytes) {
-        mImportFileBytes.put(pack(deviceId, objectHandle), bytes);
-    }
-
-    byte[] getImportFileBytes(int deviceId, int objectHandle) {
-        return mImportFileBytes.get(pack(deviceId, objectHandle));
-    }
-
-    void setThumbnail(int deviceId, int objectHandle, byte[] bytes) {
-        mThumbnailBytes.put(pack(deviceId, objectHandle), bytes);
-    }
-
-    void setObjectSizeLong(int deviceId, int objectHandle, int format, long value) {
-        mObjectSizeLongs.put(pack(deviceId, objectHandle, format), value);
-    }
-
-    @Override
-    synchronized MtpDeviceRecord[] getDevices() {
-        final MtpDeviceRecord[] result = new MtpDeviceRecord[mDevices.size()];
-        for (int i = 0; i < mDevices.size(); i++) {
-            final MtpDeviceRecord device = mDevices.valueAt(i);
-            if (device.opened) {
-                result[i] = device;
-            } else {
-                result[i] = new MtpDeviceRecord(
-                        device.deviceId, device.name, device.deviceKey, device.opened,
-                        new MtpRoot[0], null, null);
-            }
-        }
-        return result;
-    }
-
-    @Override
-    synchronized MtpDeviceRecord openDevice(int deviceId) throws IOException {
-        final MtpDeviceRecord device = mDevices.get(deviceId);
-        if (device == null) {
-            throw new IOException();
-        }
-        final MtpDeviceRecord record = new MtpDeviceRecord(
-                device.deviceId, device.name, device.deviceKey, true, device.roots,
-                device.operationsSupported, device.eventsSupported);
-        mDevices.put(deviceId, record);
-        return record;
-    }
-
-    @Override
-    synchronized void closeDevice(int deviceId) throws IOException {
-        final MtpDeviceRecord device = mDevices.get(deviceId);
-        if (device == null) {
-            throw new IOException();
-        }
-        mDevices.put(
-                deviceId,
-                new MtpDeviceRecord(device.deviceId, device.name, device.deviceKey, false,
-                        device.roots, device.operationsSupported, device.eventsSupported));
-    }
-
-    @Override
-    MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
-        final String key = pack(deviceId, objectHandle);
-        if (mObjectInfos.containsKey(key)) {
-            return mObjectInfos.get(key);
-        } else {
-            throw new IOException("getObjectInfo error: " + key);
-        }
-    }
-
-    @Override
-    int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle) throws IOException {
-        final String key = pack(deviceId, storageId, parentObjectHandle);
-        if (mObjectHandles.containsKey(key)) {
-            return mObjectHandles.get(key);
-        } else {
-            throw new IOException("getObjectHandles error: " + key);
-        }
-    }
-
-    @Override
-    void importFile(int deviceId, int objectHandle, ParcelFileDescriptor target)
-            throws IOException {
-        final String key = pack(deviceId, objectHandle);
-        if (mImportFileBytes.containsKey(key)) {
-            try (final ParcelFileDescriptor.AutoCloseOutputStream outputStream =
-                    new ParcelFileDescriptor.AutoCloseOutputStream(target)) {
-                outputStream.write(mImportFileBytes.get(key));
-            }
-        } else {
-            throw new IOException("importFile error: " + key);
-        }
-    }
-
-    @Override
-    int createDocument(int deviceId, MtpObjectInfo objectInfo, ParcelFileDescriptor source)
-            throws IOException {
-        Assert.assertNotSame(0, objectInfo.getStorageId());
-        Assert.assertNotSame(-1, objectInfo.getStorageId());
-        Assert.assertNotSame(0, objectInfo.getParent());
-        final String key = pack(deviceId, CREATED_DOCUMENT_HANDLE);
-        if (mObjectInfos.containsKey(key)) {
-            throw new IOException();
-        }
-        final MtpObjectInfo newInfo = new MtpObjectInfo.Builder(objectInfo).
-                setObjectHandle(CREATED_DOCUMENT_HANDLE).build();
-        mObjectInfos.put(key, newInfo);
-        if (objectInfo.getFormat() != 0x3001) {
-            try (final ParcelFileDescriptor.AutoCloseInputStream inputStream =
-                    new ParcelFileDescriptor.AutoCloseInputStream(source)) {
-                final byte[] buffer = new byte[objectInfo.getCompressedSize()];
-                if (inputStream.read(buffer, 0, objectInfo.getCompressedSize()) !=
-                        objectInfo.getCompressedSize()) {
-                    throw new IOException();
-                }
-
-                mImportFileBytes.put(pack(deviceId, CREATED_DOCUMENT_HANDLE), buffer);
-            }
-        }
-        return CREATED_DOCUMENT_HANDLE;
-    }
-
-    @Override
-    byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
-        final String key = pack(deviceId, objectHandle);
-        if (mThumbnailBytes.containsKey(key)) {
-            return mThumbnailBytes.get(key);
-        } else {
-            throw new IOException("getThumbnail error: " + key);
-        }
-    }
-
-    @Override
-    void deleteDocument(int deviceId, int objectHandle) throws IOException {
-        final String key = pack(deviceId, objectHandle);
-        if (mObjectInfos.containsKey(key)) {
-            mObjectInfos.remove(key);
-        } else {
-            throw new IOException();
-        }
-    }
-
-    @Override
-    int getParent(int deviceId, int objectHandle) throws IOException {
-        final String key = pack(deviceId, objectHandle);
-        if (mObjectInfos.containsKey(key)) {
-            return mObjectInfos.get(key).getParent();
-        } else {
-            throw new IOException();
-        }
-    }
-
-    @Override
-    byte[] getObject(int deviceId, int objectHandle, int expectedSize) throws IOException {
-        return mImportFileBytes.get(pack(deviceId, objectHandle));
-    }
-
-    @Override
-    long getPartialObject(int deviceId, int objectHandle, long offset, long size, byte[] buffer)
-            throws IOException {
-        final byte[] bytes = mImportFileBytes.get(pack(deviceId, objectHandle));
-        int i = 0;
-        while (i < size && i + offset < bytes.length) {
-            buffer[i] = bytes[(int) (i + offset)];
-            i++;
-        }
-        return i;
-    }
-
-    @Override
-    long getObjectSizeLong(int deviceId, int objectHandle, int format) throws IOException {
-        final String key = pack(deviceId, objectHandle, format);
-        if (mObjectSizeLongs.containsKey(key)) {
-            return mObjectSizeLongs.get(key);
-        } else {
-            throw new IOException();
-        }
-    }
-}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
deleted file mode 100644
index 8676b5a..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.test.mock.MockResources;
-
-class TestResources extends MockResources {
-    @Override
-    public String getString(int id) throws NotFoundException {
-        switch (id) {
-            case R.string.root_name:
-                return "%1$s %2$s";
-            case R.string.error_busy_device:
-                return "error_busy_device";
-            case R.string.error_locked_device:
-                return "error_locked_device";
-        }
-        throw new NotFoundException();
-    }
-
-    @Override
-    public String getString(int id, Object... formatArgs) throws NotFoundException {
-        return String.format(getString(id), formatArgs);
-    }
-}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultActivity.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultActivity.java
deleted file mode 100644
index 9f2bb2a..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultActivity.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-
-/**
- * Activity that shows the test results instead of adb while using USB port to connect MTP device.
- */
-public class TestResultActivity extends Activity {
-    private final static String TAG = "MtpDocumentsProviderTest";
-    private TextView mTextView;
-
-    static void show(Context context, String message) {
-        Log.d(TAG, message);
-        final Intent intent = new Intent(context, TestResultActivity.class);
-        intent.putExtra("message", message);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        context.startActivity(intent);
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        final LinearLayout linearLayout = new LinearLayout(this);
-        linearLayout.setOrientation(LinearLayout.VERTICAL);
-        setContentView(linearLayout);
-
-        mTextView = new TextView(this);
-        mTextView.setText(getIntent().getStringExtra("message") + "\n");
-        linearLayout.addView(
-                mTextView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
-    }
-
-    @Override
-    protected void onNewIntent(Intent intent) {
-        super.onNewIntent(intent);
-        mTextView.setText(mTextView.getText() + intent.getStringExtra("message") + "\n");
-    }
-}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java
deleted file mode 100644
index 4e4cf78..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.os.Bundle;
-import android.test.InstrumentationTestRunner;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.Test;
-import junit.framework.TestListener;
-
-/**
- * Instrumentation that can show the test result in the TestResultActivity.
- * It's useful when it runs testcases with a real USB device and could not use USB port for ADB.
- */
-public class TestResultInstrumentation extends InstrumentationTestRunner implements TestListener {
-    private boolean mHasError = false;
-
-    @Override
-    public void onCreate(Bundle arguments) {
-        if (arguments == null) {
-            arguments = new Bundle();
-        }
-        final boolean includeRealDeviceTest =
-                Boolean.parseBoolean(arguments.getString("realDeviceTest", "false"));
-        if (!includeRealDeviceTest) {
-            arguments.putString("notAnnotation", "com.android.mtp.RealDeviceTest");
-        }
-        super.onCreate(arguments);
-        if (includeRealDeviceTest) {
-            // Show the test result by using activity because we need to disconnect USB cable
-            // from adb host while testing with real MTP device.
-            addTestListener(this);
-        }
-    }
-
-    @Override
-    public void addError(Test test, Throwable t) {
-        mHasError = true;
-        show("ERROR", test, t);
-    }
-
-    @Override
-    public void addFailure(Test test, AssertionFailedError t) {
-        mHasError = true;
-        show("FAIL", test, t);
-    }
-
-    @Override
-    public void endTest(Test test) {
-        if (!mHasError) {
-            show("PASS", test, null);
-        }
-    }
-
-    @Override
-    public void startTest(Test test) {
-        mHasError = false;
-    }
-
-    void show(String message) {
-        TestResultActivity.show(getContext(), "    " + message);
-    }
-
-    private void show(String tag, Test test, Throwable t) {
-        String message = "";
-        if (t != null && t.getMessage() != null) {
-            message = t.getMessage();
-        }
-        TestResultActivity.show(
-                getContext(), String.format("[%s] %s %s", tag, test.toString(), message));
-    }
-}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java
deleted file mode 100644
index 17b3086..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-class TestServiceIntentSender extends ServiceIntentSender {
-    @Override
-    void sendUpdateNotificationIntent(MtpDeviceRecord[] record) {}
-}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
deleted file mode 100644
index 8805d19..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbDeviceConnection;
-import android.hardware.usb.UsbManager;
-import android.mtp.MtpConstants;
-import android.os.SystemClock;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Objects;
-
-/**
- * Static utility methods for testing.
- */
-final class TestUtil {
-    private TestUtil() {}
-
-    static final int[] OPERATIONS_SUPPORTED = new int[] {
-            MtpConstants.OPERATION_GET_PARTIAL_OBJECT,
-            MtpConstants.OPERATION_SEND_OBJECT,
-            MtpConstants.OPERATION_SEND_OBJECT_INFO,
-            MtpConstants.OPERATION_DELETE_OBJECT,
-            MtpConstants.OPERATION_GET_OBJECT_PROP_DESC,
-            MtpConstants.OPERATION_GET_OBJECT_PROP_VALUE
-    };
-
-    /**
-     * Requests permission for a MTP device and returns the first MTP device that has at least one
-     * storage.
-     */
-    static UsbDevice setupMtpDevice(
-            TestResultInstrumentation instrumentation,
-            UsbManager usbManager,
-            MtpManager manager) {
-        while (true) {
-            try {
-                final UsbDevice device = findMtpDevice(usbManager, manager);
-                waitForStorages(instrumentation, manager, device.getDeviceId());
-                return device;
-            } catch (IOException exp) {
-                instrumentation.show(Objects.toString(exp.getMessage()));
-                SystemClock.sleep(1000);
-                // When the MTP device is Android, and it changes the USB device type from
-                // "Charging" to "MTP", the device ID will be updated. We need to find a device
-                // again.
-                continue;
-            }
-        }
-    }
-
-    static void addTestDevice(MtpDatabase database) throws FileNotFoundException {
-        database.getMapper().startAddingDocuments(null);
-        database.getMapper().putDeviceDocument(new MtpDeviceRecord(
-                0, "Device", "device_key", /* opened is */ true, new MtpRoot[0],
-                OPERATIONS_SUPPORTED, null));
-        database.getMapper().stopAddingDocuments(null);
-    }
-
-    static void addTestStorage(MtpDatabase database, String parentId) throws FileNotFoundException {
-        database.getMapper().startAddingDocuments(parentId);
-        database.getMapper().putStorageDocuments(parentId, OPERATIONS_SUPPORTED, new MtpRoot[] {
-                new MtpRoot(0, 100, "Storage", 1024, 1024, ""),
-        });
-        database.getMapper().stopAddingDocuments(parentId);
-    }
-
-    private static UsbDevice findMtpDevice(
-            UsbManager usbManager,
-            MtpManager manager) throws IOException {
-        final HashMap<String,UsbDevice> devices = usbManager.getDeviceList();
-        if (devices.size() == 0) {
-            throw new IOException("Device not found.");
-        }
-        final UsbDevice device = devices.values().iterator().next();
-        // Tries to get ownership of the device in case that another application use it.
-        if (usbManager.hasPermission(device)) {
-            final UsbDeviceConnection connection = usbManager.openDevice(device);
-            for (int i = 0; i < device.getInterfaceCount(); i++) {
-                // Since the test runs real environment, we need to call claim interface with
-                // force = true to rob interfaces from other applications.
-                connection.claimInterface(device.getInterface(i), true);
-                connection.releaseInterface(device.getInterface(i));
-            }
-            connection.close();
-        }
-        manager.openDevice(device.getDeviceId());
-        return device;
-    }
-
-    private static void waitForStorages(
-            TestResultInstrumentation instrumentation,
-            MtpManager manager,
-            int deviceId) throws IOException {
-        while (true) {
-            MtpDeviceRecord device = null;
-            for (final MtpDeviceRecord deviceCandidate : manager.getDevices()) {
-                if (deviceCandidate.deviceId == deviceId) {
-                    device = deviceCandidate;
-                    break;
-                }
-            }
-            if (device == null) {
-                throw new IOException("Device was detached.");
-            }
-            if (device.roots.length == 0) {
-                instrumentation.show("Wait for storages.");
-                SystemClock.sleep(1000);
-                continue;
-            }
-            return;
-        }
-    }
-}
diff --git a/packages/PrintSpooler/res/values-or/strings.xml b/packages/PrintSpooler/res/values-or/strings.xml
index 7eeac87..f385391 100644
--- a/packages/PrintSpooler/res/values-or/strings.xml
+++ b/packages/PrintSpooler/res/values-or/strings.xml
@@ -72,7 +72,7 @@
     <string name="select_to_add_printers" msgid="3800709038689830974">"ପ୍ରିଣ୍ଟର ଯୋଡ଼ିବାକୁ ଚୟନ କରନ୍ତୁ"</string>
     <string name="enable_print_service" msgid="3482815747043533842">"ସକ୍ଷମ କରିବା ପାଇଁ ଚୟନ କରନ୍ତୁ"</string>
     <string name="enabled_services_title" msgid="7036986099096582296">"ସକ୍ଷମ କରାଯାଇଥିବା ସର୍ଭିସ୍‌"</string>
-    <string name="recommended_services_title" msgid="3799434882937956924">"ସୁପାରିସ କରାଯାଇଥିବା ସର୍ଭିସ୍‌"</string>
+    <string name="recommended_services_title" msgid="3799434882937956924">"ସୁପାରିଶ କରାଯାଇଥିବା ସର୍ଭିସ୍‌"</string>
     <string name="disabled_services_title" msgid="7313253167968363211">"ଅକ୍ଷମ କରାଯାଇଥିବା ସର୍ଭିସ୍‌"</string>
     <string name="all_services_title" msgid="5578662754874906455">"ସମସ୍ତ ସର୍ଭିସ୍‌"</string>
     <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
diff --git a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
index dcb014d..b4b4c63 100644
--- a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
+++ b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
@@ -65,7 +65,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="true"
-            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
+            android:textAppearance="?android:attr/textAppearanceListItem"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal"/>
 
@@ -79,7 +79,7 @@
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
                 android:layout_weight="1"
-                android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"
+                android:textAppearance="?android:attr/textAppearanceSmall"
                 android:textAlignment="viewStart"
                 android:textColor="?android:attr/textColorSecondary"/>
 
@@ -88,7 +88,7 @@
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
                 android:layout_weight="1"
-                android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"
+                android:textAppearance="?android:attr/textAppearanceSmall"
                 android:textAlignment="viewEnd"
                 android:textColor="?android:attr/textColorSecondary"
                 android:maxLines="1"
diff --git a/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
index 08287ac..05e008c 100644
--- a/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
+++ b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
@@ -22,7 +22,6 @@
 import android.view.View;
 import android.widget.TextView;
 
-import androidx.core.content.res.TypedArrayUtils;
 import androidx.preference.CheckBoxPreference;
 import androidx.preference.PreferenceViewHolder;
 
@@ -58,32 +57,29 @@
     /**
      * Perform inflation from XML and apply a class-specific base style.
      *
-     * @param context      The {@link Context} this is associated with, through which it can
-     *                     access the current theme, resources, {@link SharedPreferences}, etc.
-     * @param attrs        The attributes of the XML tag that is inflating the preference
-     * @param defStyleAttr An attribute in the current theme that contains a reference to a style
-     *                     resource that supplies default values for the view. Can be 0 to not
-     *                     look for defaults.
+     * @param context  The {@link Context} this is associated with, through which it can
+     *                 access the current theme, resources, {@link SharedPreferences}, etc.
+     * @param attrs    The attributes of the XML tag that is inflating the preference
+     * @param defStyle An attribute in the current theme that contains a reference to a style
+     *                 resource that supplies default values for the view. Can be 0 to not
+     *                 look for defaults.
      */
     public RadioButtonPreference(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
-        setLayoutResource(R.layout.preference_radio);
-        setIconSpaceReserved(false);
+        init();
     }
 
 
     /**
      * Perform inflation from XML and apply a class-specific base style.
      *
-     * @param context      The {@link Context} this is associated with, through which it can
-     *                     access the current theme, resources, {@link SharedPreferences}, etc.
-     * @param attrs        The attributes of the XML tag that is inflating the preference
+     * @param context The {@link Context} this is associated with, through which it can
+     *                access the current theme, resources, {@link SharedPreferences}, etc.
+     * @param attrs   The attributes of the XML tag that is inflating the preference
      */
     public RadioButtonPreference(Context context, AttributeSet attrs) {
-        this(context, attrs, TypedArrayUtils.getAttr(context,
-                androidx.preference.R.attr.preferenceStyle,
-                android.R.attr.preferenceStyle));
+        super(context, attrs);
+        init();
     }
 
     /**
@@ -158,4 +154,10 @@
         }
         mAppendixVisibility = visibility;
     }
+
+    private void init() {
+        setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
+        setLayoutResource(R.layout.preference_radio);
+        setIconSpaceReserved(false);
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
index 7100acc..1557618 100644
--- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
@@ -16,12 +16,14 @@
 
 package com.android.settingslib.widget;
 
+import android.annotation.StringRes;
 import android.content.Context;
 import android.text.TextUtils;
 import android.text.method.LinkMovementMethod;
 import android.util.AttributeSet;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
 import androidx.core.content.res.TypedArrayUtils;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceViewHolder;
@@ -72,10 +74,68 @@
     }
 
     private void init() {
-        setIcon(R.drawable.ic_info_outline_24);
+        if (getIcon() == null) {
+            setIcon(R.drawable.ic_info_outline_24);
+        }
         setOrder(ORDER_FOOTER);
         if (TextUtils.isEmpty(getKey())) {
             setKey(KEY_FOOTER);
         }
     }
+
+    /**
+     * The builder is convenient to creat a dynamic FooterPreference.
+     */
+    public static class Builder {
+        private Context mContext;
+        private String mKey;
+        private CharSequence mTitle;
+
+        public Builder(@NonNull Context context) {
+            mContext = context;
+        }
+
+        /**
+         * To set the key value of the {@link FooterPreference}.
+         * @param key The key value.
+         */
+        public Builder setKey(@NonNull String key) {
+            mKey = key;
+            return this;
+        }
+
+        /**
+         * To set the title of the {@link FooterPreference}.
+         * @param title The title.
+         */
+        public Builder setTitle(CharSequence title) {
+            mTitle = title;
+            return this;
+        }
+
+        /**
+         * To set the title of the {@link FooterPreference}.
+         * @param titleResId The resource id of the title.
+         */
+        public Builder setTitle(@StringRes int titleResId) {
+            mTitle = mContext.getText(titleResId);
+            return this;
+        }
+
+        /**
+         * To generate the {@link FooterPreference}.
+         */
+        public FooterPreference build() {
+            final FooterPreference footerPreference = new FooterPreference(mContext);
+            footerPreference.setSelectable(false);
+            if (TextUtils.isEmpty(mTitle)) {
+                throw new IllegalArgumentException("Footer title cannot be empty!");
+            }
+            footerPreference.setTitle(mTitle);
+            if (!TextUtils.isEmpty(mKey)) {
+                footerPreference.setKey(mKey);
+            }
+            return footerPreference;
+        }
+    }
 }
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index 9bc2d75..839899e 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -11,6 +11,7 @@
                  android:restoreAnyVersion="true"
                  android:icon="@mipmap/ic_launcher_settings"
                  android:defaultToDeviceProtectedStorage="true"
+                 android:forceQueryable="true"
                  android:directBootAware="true">
 
         <provider android:name="SettingsProvider"
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 8689eef..bb9a5e4 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -123,7 +123,6 @@
     <uses-permission android:name="android.permission.BIND_APPWIDGET" />
     <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
     <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
-    <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" />
     <uses-permission android:name="android.permission.CHANGE_APP_IDLE_STATE" />
     <uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 2727880..58e1d47 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -199,9 +199,9 @@
     // Passed to Message.obtain() when msg.arg2 is not used.
     private static final int UNUSED_ARG2 = -2;
 
-    // Maximum progress displayed (like 99.00%).
-    private static final int CAPPED_PROGRESS = 9900;
-    private static final int CAPPED_MAX = 10000;
+    // Maximum progress displayed in %.
+    private static final int CAPPED_PROGRESS = 99;
+    private static final int CAPPED_MAX = 100;
 
     /** Show the progress log every this percent. */
     private static final int LOG_PROGRESS_STEP = 10;
@@ -582,9 +582,9 @@
         ParcelFileDescriptor screenshotFd = createReadWriteFile(BUGREPORT_DIR,
                 bugreportName + ".png");
         if (screenshotFd == null) {
-            Log.e(TAG, "Screenshot parcel file descriptor is null.");
-            // TODO(b/123617758): Delete bugreport file created above
+            Log.e(TAG, "Screenshot parcel file descriptor is null. Deleting bugreport file");
             FileUtils.closeQuietly(bugreportFd);
+            new File(BUGREPORT_DIR, String.format("%s.zip", bugreportName)).delete();
             return;
         }
         mBugreportManager = (BugreportManager) mContext.getSystemService(
@@ -972,18 +972,8 @@
     private void onBugreportFinished(int id) {
         BugreportInfo info = getInfo(id);
         final File bugreportFile = new File(BUGREPORT_DIR, info.name + ".zip");
-        if (bugreportFile == null) {
-            // Should never happen, an id always has a file linked to it.
-            Log.wtf(TAG, "Missing file " + bugreportFile.getPath() + " does not exist.");
-            return;
-        }
         final int max = -1; // this is to log metrics for dumpstate duration.
         File screenshotFile = new File(BUGREPORT_DIR, info.name + ".png");
-        if (screenshotFile == null) {
-            // Should never happen, an id always has a file linked to it.
-            Log.wtf(TAG, "Missing file " + screenshotFile.getPath() + " does not exist.");
-            return;
-        }
         // If the screenshot file did not get populated implies this type of bugreport does not
         // need the screenshot file; setting the file to null so that empty file doesnt get shared
         if (screenshotFile.length() == 0) {
@@ -2164,8 +2154,7 @@
 
         @Override
         public void onProgress(int progress) throws RemoteException {
-            updateProgressInfo(info, progress, 100 /* progress is already a percentage;
-                    so max = 100 */);
+            checkProgressUpdated(info, progress);
         }
 
         @Override
@@ -2178,26 +2167,6 @@
             // TODO(b/111441001): implement
         }
 
-        @Override
-        public void onProgressUpdated(int progress) throws RemoteException {
-            checkProgressUpdated(info, progress);
-        }
-
-        @Override
-        public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
-            Log.d(TAG, "onMaxProgressUpdated: " + maxProgress);
-            info.realMax = maxProgress;
-        }
-
-        @Override
-        public void onSectionComplete(String title, int status, int size, int durationMs)
-                throws RemoteException {
-            if (DEBUG) {
-                Log.v(TAG, "Title: " + title + " Status: " + status + " Size: " + size
-                        + " Duration: " + durationMs + "ms");
-            }
-        }
-
         public void dump(String prefix, PrintWriter pw) {
             pw.print(prefix); pw.print("token: "); pw.println(token);
         }
@@ -2205,27 +2174,10 @@
     }
 
     private void checkProgressUpdated(BugreportInfo info, int progress) {
-        /*
-         * Checks whether the progress changed in a way that should be displayed to the user:
-         * - info.progress / info.max represents the displayed progress
-         * - info.realProgress / info.realMax represents the real progress
-         * - since the real progress can decrease, the displayed progress is only updated if it
-         *   increases
-         * - the displayed progress is capped at a maximum (like 99%)
-         */
-        info.realProgress = progress;
-        final int oldPercentage = (CAPPED_MAX * info.progress) / info.max;
-        int newPercentage = (CAPPED_MAX * info.realProgress) / info.realMax;
-        int max = info.realMax;
-
-        if (newPercentage > CAPPED_PROGRESS) {
-            progress = newPercentage = CAPPED_PROGRESS;
-            max = CAPPED_MAX;
+        if (progress > CAPPED_PROGRESS) {
+            progress = CAPPED_PROGRESS;
         }
-
-        if (progress == 0 || newPercentage > oldPercentage) {
-            updateProgressInfo(info, progress, max);
-        }
+        updateProgressInfo(info, progress, CAPPED_MAX);
     }
 
     private void updateProgressInfo(BugreportInfo info, int progress, int max) {
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index 7f39a19..d44bfbc 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -152,6 +152,6 @@
       <item quantity="one">Die SIM-Karte ist jetzt deaktiviert. Gib den PUK-Code ein, um fortzufahren. Du hast noch <xliff:g id="_NUMBER_0">%d</xliff:g> Versuch, bevor die SIM-Karte endgültig gesperrt wird. Weitere Informationen erhältst du von deinem Mobilfunkanbieter.</item>
     </plurals>
     <string name="clock_title_default" msgid="6645600990069154049">"Standard"</string>
-    <string name="clock_title_bubble" msgid="1286365278681892114">"Blase"</string>
+    <string name="clock_title_bubble" msgid="1286365278681892114">"Bubble"</string>
     <string name="clock_title_analog" msgid="4047401488577315053">"Analog"</string>
 </resources>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 21c2c6b..1bfc4c0 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -24,48 +24,7 @@
     android:outlineProvider="none"
     android:elevation="5dp" > <!-- Put it above the status bar header -->
 
-    <LinearLayout
-        android:id="@+id/keyguard_indication_area"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
-        android:layout_gravity="bottom|center_horizontal"
-        android:orientation="horizontal">
-
-        <include layout="@layout/left_docked_overlay" />
-
-        <LinearLayout
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:layout_gravity="center_vertical|center_horizontal"
-            android:orientation="vertical">
-
-            <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
-                android:id="@+id/keyguard_indication_enterprise_disclosure"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:gravity="center"
-                android:paddingStart="@dimen/keyguard_indication_text_padding"
-                android:paddingEnd="@dimen/keyguard_indication_text_padding"
-                android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
-                android:visibility="gone" />
-
-            <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
-                android:id="@+id/keyguard_indication_text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:gravity="center"
-                android:paddingStart="@dimen/keyguard_indication_text_padding"
-                android:paddingEnd="@dimen/keyguard_indication_text_padding"
-                android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
-                android:accessibilityLiveRegion="polite" />
-
-        </LinearLayout>
-
-        <include layout="@layout/right_docked_overlay" />
-
-    </LinearLayout>
+    <include layout="@layout/keyguard_indication_area_overlay" />
 
     <FrameLayout
         android:id="@+id/preview_container"
diff --git a/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml b/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml
new file mode 100644
index 0000000..cc30a68
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/keyguard_indication_area"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
+    android:layout_gravity="bottom|center_horizontal"
+    android:orientation="vertical">
+
+  <include layout="@layout/keyguard_indication_text_view" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_indication_text_view.xml b/packages/SystemUI/res/layout/keyguard_indication_text_view.xml
new file mode 100644
index 0000000..2b2100c
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyguard_indication_text_view.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
+        android:id="@+id/keyguard_indication_enterprise_disclosure"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:paddingStart="@dimen/keyguard_indication_text_padding"
+        android:paddingEnd="@dimen/keyguard_indication_text_padding"
+        android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
+        android:visibility="gone"/>
+
+    <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
+        android:id="@+id/keyguard_indication_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:paddingStart="@dimen/keyguard_indication_text_padding"
+        android:paddingEnd="@dimen/keyguard_indication_text_padding"
+        android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
+        android:accessibilityLiveRegion="polite"/>
+</merge>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/left_docked_overlay.xml b/packages/SystemUI/res/layout/left_docked_overlay.xml
deleted file mode 100644
index 430143c..0000000
--- a/packages/SystemUI/res/layout/left_docked_overlay.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<!-- empty stub -->
-<merge />
diff --git a/packages/SystemUI/res/layout/right_docked_overlay.xml b/packages/SystemUI/res/layout/right_docked_overlay.xml
deleted file mode 100644
index 430143c..0000000
--- a/packages/SystemUI/res/layout/right_docked_overlay.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<!-- empty stub -->
-<merge />
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 08fb0b3..90ead35 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -255,8 +255,8 @@
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lommelygten er tændt."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lommelygten er slukket."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lommelygten er tændt."</string>
-    <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="4406577213290173911">"Invertering af farver er slået fra."</string>
-    <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="6897462320184911126">"Invertering af farver er slået til."</string>
+    <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="4406577213290173911">"Ombytning af farver er slået fra."</string>
+    <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="6897462320184911126">"Ombytning af farver er slået til."</string>
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobilhotspot er slået fra."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilhotspot er slået til."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Casting af din skærm er stoppet."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 408254f..9b3974b 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -656,7 +656,7 @@
     <string name="notification_silence_title" msgid="5763240612242137433">"Lautlos"</string>
     <string name="notification_alert_title" msgid="8031196611815490340">"Benachrichtigen"</string>
     <string name="notification_channel_summary_low" msgid="3387466082089715555">"Benachrichtigungen werden ohne Ton oder Vibration angekündigt, um deine Konzentration nicht zu stören."</string>
-    <string name="notification_channel_summary_default" msgid="5994062840431965586">"Benachrichtigungen werden mit einem Ton oder einer Vibration angekündigt, um dich auf sie aufmerksam zu machen."</string>
+    <string name="notification_channel_summary_default" msgid="5994062840431965586">"Benachrichtigungen werden mit einem Ton oder einer Vibration angekündigt."</string>
     <string name="notification_unblockable_desc" msgid="4556908766584964102">"Diese Benachrichtigungen können nicht geändert werden."</string>
     <string name="notification_multichannel_desc" msgid="4695920306092240550">"Die Benachrichtigungsgruppe kann hier nicht konfiguriert werden"</string>
     <string name="notification_delegate_header" msgid="2857691673814814270">"Weitergeleitete Benachrichtigung"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 37aae55..d6c8d09 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -553,7 +553,7 @@
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
     <string name="stream_voice_call" msgid="4410002696470423714">"Llamada"</string>
     <string name="stream_system" msgid="7493299064422163147">"Sistema"</string>
-    <string name="stream_ring" msgid="8213049469184048338">"Hacer sonar"</string>
+    <string name="stream_ring" msgid="8213049469184048338">"Timbre"</string>
     <string name="stream_music" msgid="9086982948697544342">"Multimedia"</string>
     <string name="stream_alarm" msgid="5209444229227197703">"Alarma"</string>
     <string name="stream_notification" msgid="2563720670905665031">"Notificación"</string>
@@ -561,7 +561,7 @@
     <string name="stream_dtmf" msgid="2447177903892477915">"Multifrecuencia de tono doble"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Accesibilidad"</string>
     <string name="ring_toggle_title" msgid="3281244519428819576">"Llamadas"</string>
-    <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Hacer sonar"</string>
+    <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Timbre"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"Vibrar"</string>
     <string name="volume_ringer_status_silent" msgid="6896394161022916369">"Silenciar"</string>
     <string name="qs_status_phone_vibrate" msgid="204362991135761679">"Teléfono en vibración"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index a3069a1..552d12e 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -886,7 +886,7 @@
     <string name="qs_dnd_prompt_app" msgid="7978037419334156034">"Le mode Ne pas déranger a été activé par une application (<xliff:g id="ID_1">%s</xliff:g>)."</string>
     <string name="qs_dnd_prompt_auto_rule_app" msgid="2599343675391111951">"Le mode Ne pas déranger a été activé par une règle automatique ou une application."</string>
     <string name="qs_dnd_until" msgid="3469471136280079874">"Jusqu\'à <xliff:g id="ID_1">%s</xliff:g>"</string>
-    <string name="qs_dnd_keep" msgid="1825009164681928736">"Garder"</string>
+    <string name="qs_dnd_keep" msgid="1825009164681928736">"Conserver"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Remplacer"</string>
     <string name="running_foreground_services_title" msgid="381024150898615683">"Applications qui fonctionnent en arrière-plan"</string>
     <string name="running_foreground_services_msg" msgid="6326247670075574355">"Touchez pour afficher des détails sur l\'utilisation de la pile et des données"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 263fe8a..3fa2a48 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -46,8 +46,8 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"ब्लूटूथ टीदर किया गया"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"इनपुट का तरीका सेट करें"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"सामान्य कीबोर्ड"</string>
-    <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_DEVICE">%2$s</xliff:g> के एक्सेस की अनुमति दें?"</string>
-    <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> के एक्सेस की अनुमति दें?"</string>
+    <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_DEVICE">%2$s</xliff:g> के ऐक्सेस की अनुमति दें?"</string>
+    <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> के ऐक्सेस की अनुमति दें?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> के लिए <xliff:g id="APPLICATION">%1$s</xliff:g> खोलें?"</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> के लिए <xliff:g id="APPLICATION">%1$s</xliff:g> खोलें?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"इस USB सहायक डिवाइस के साथ कोई भी इंस्टॉल ऐप्स  काम नहीं करता. इस सहायक डिवाइस के बारे में यहां ज़्यादा जानें: <xliff:g id="URL">%1$s</xliff:g>"</string>
@@ -205,7 +205,7 @@
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"पूरी सूचनाएं देखें"</string>
     <string name="accessibility_remove_notification" msgid="3603099514902182350">"सूचना साफ़ करें"</string>
     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS सक्षम."</string>
-    <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS प्राप्त करना."</string>
+    <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS पाना."</string>
     <string name="accessibility_tty_enabled" msgid="4613200365379426561">"टेलीटाइपराइटर सक्षम."</string>
     <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"रिंगर कंपन (वाइब्रेशन)."</string>
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"रिंगर मौन."</string>
@@ -452,8 +452,8 @@
     <string name="battery_saver_notification_title" msgid="8614079794522291840">"बैटरी सेवर चालू है"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"निष्‍पादन और पृष्ठभूमि डेटा को कम करता है"</string>
     <string name="battery_saver_notification_action_text" msgid="132118784269455533">"बैटरी सेवर बंद करें"</string>
-    <string name="media_projection_dialog_text" msgid="8585357687598538511">"रिकॉर्ड या कास्ट करते समय, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपकी स्क्रीन पर दिखाई जा रही या आपके डिवाइस पर चलाई जा रही संवेदनशील जानकारी एक्सेस कर सकता है. इस जानकारी में ऑडियो, पासवर्ड, भुगतान की जानकारी, फ़ोटो और मैसेज शामिल हैं."</string>
-    <string name="media_projection_dialog_service_text" msgid="3075544489835858258">"रिकॉर्ड या कास्ट करते समय, यह सेवा देने वाला ऐप्लिकेशन आपकी स्क्रीन पर दिखाई जा रही या आपके डिवाइस पर चलाई जा रही संवेदनशील जानकारी एक्सेस कर सकता है. इस जानकारी में ऑडियो, पासवर्ड, भुगतान की जानकारी, फ़ोटो और मैसेज शामिल हैं."</string>
+    <string name="media_projection_dialog_text" msgid="8585357687598538511">"रिकॉर्ड या कास्ट करते समय, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपकी स्क्रीन पर दिखाई जा रही या आपके डिवाइस पर चलाई जा रही संवेदनशील जानकारी ऐक्सेस कर सकता है. इस जानकारी में ऑडियो, पासवर्ड, भुगतान की जानकारी, फ़ोटो और मैसेज शामिल हैं."</string>
+    <string name="media_projection_dialog_service_text" msgid="3075544489835858258">"रिकॉर्ड या कास्ट करते समय, यह सेवा देने वाला ऐप्लिकेशन आपकी स्क्रीन पर दिखाई जा रही या आपके डिवाइस पर चलाई जा रही संवेदनशील जानकारी ऐक्सेस कर सकता है. इस जानकारी में ऑडियो, पासवर्ड, भुगतान की जानकारी, फ़ोटो और मैसेज शामिल हैं."</string>
     <string name="media_projection_dialog_title" msgid="8124184308671641248">"कास्ट करने/रिकॉर्ड करने के दौरान संवेदनशील जानकारी का सबके सामने आ जाना"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"फिर से न दिखाएं"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"सभी को हटाएं"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 20f638d..676208b 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -747,7 +747,7 @@
     <string name="data_saver" msgid="5037565123367048522">"डेटा सेव्हर"</string>
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"डेटा सेव्हर चालू आहे"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"डेटा सेव्हर बंद आहे"</string>
-    <string name="switch_bar_on" msgid="1142437840752794229">"चालू"</string>
+    <string name="switch_bar_on" msgid="1142437840752794229">"सुरू"</string>
     <string name="switch_bar_off" msgid="8803270596930432874">"बंद"</string>
     <string name="nav_bar" msgid="1993221402773877607">"नॅव्हिगेशन बार"</string>
     <string name="nav_bar_layout" msgid="3664072994198772020">"लेआउट"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 83a7aaa..1f75490 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -544,7 +544,7 @@
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="6134833683151189507">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Kreu\" për ta hequr nga gozhdimi."</string>
     <string name="screen_pinning_toast" msgid="2266705122951934150">"Për të hequr gozhdimin e këtij ekrani, prek dhe mbaj butonat \"Prapa\" dhe \"Përmbledhja\"."</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="8252402309499161281">"Për të hequr gozhdimin e këtij ekrani, prek dhe mbaj butonat \"Prapa\" dhe \"Kreu\"."</string>
-    <string name="screen_pinning_positive" msgid="3783985798366751226">"E kuptova!"</string>
+    <string name="screen_pinning_positive" msgid="3783985798366751226">"E kuptova"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Jo, faleminderit!"</string>
     <string name="screen_pinning_start" msgid="1022122128489278317">"Ekrani u gozhdua"</string>
     <string name="screen_pinning_exit" msgid="5187339744262325372">"Ekrani u hoq nga gozhdimi"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 9f8f45e..6e8b097 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -761,7 +761,7 @@
     <item msgid="8175437057325747277">"ஏதுமில்லை"</item>
   </string-array>
   <string-array name="nav_bar_layouts">
-    <item msgid="8077901629964902399">"இயல்பானது"</item>
+    <item msgid="8077901629964902399">"சராசரி"</item>
     <item msgid="8256205964297588988">"சுருக்கமானது"</item>
     <item msgid="8719936228094005878">"இடப்புறம் சாய்ந்தது"</item>
     <item msgid="586019486955594690">"வலப்புறம் சாய்ந்தது"</item>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index affca3d..025efac 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -741,7 +741,7 @@
     <string name="battery" msgid="7498329822413202973">"Pin"</string>
     <string name="clock" msgid="7416090374234785905">"Đồng hồ"</string>
     <string name="headset" msgid="4534219457597457353">"Tai nghe"</string>
-    <string name="accessibility_long_click_tile" msgid="6687350750091842525">"Mở cài đặt"</string>
+    <string name="accessibility_long_click_tile" msgid="6687350750091842525">"Mở phần cài đặt"</string>
     <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Đã kết nối tai nghe"</string>
     <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Đã kết nối tai nghe"</string>
     <string name="data_saver" msgid="5037565123367048522">"Trình tiết kiệm dữ liệu"</string>
@@ -817,7 +817,7 @@
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Ứng dụng không hỗ trợ chia đôi màn hình."</string>
     <string name="forced_resizable_secondary_display" msgid="4230857851756391925">"Ứng dụng có thể không hoạt động trên màn hình phụ."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="7793821742158306742">"Ứng dụng không hỗ trợ khởi chạy trên màn hình phụ."</string>
-    <string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Mở cài đặt."</string>
+    <string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Mở phần cài đặt."</string>
     <string name="accessibility_quick_settings_expand" msgid="2375165227880477530">"Mở cài đặt nhanh."</string>
     <string name="accessibility_quick_settings_collapse" msgid="1792625797142648105">"Đóng cài đặt nhanh."</string>
     <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Đã đặt báo thức."</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 340cb3a..6e8e823 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -196,9 +196,6 @@
     <!-- Doze: duration to avoid false pickup gestures triggered by notification vibrations -->
     <integer name="doze_pickup_vibration_threshold">2000</integer>
 
-    <!-- Doze: can we assume the pickup sensor includes a proximity check? -->
-    <bool name="doze_pickup_performs_proximity_check">false</bool>
-
     <!-- Type of a sensor that provides a low-power estimate of the desired display
          brightness, suitable to listen to while the device is asleep (e.g. during
          always-on display) -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7feacb4..fab7242 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -958,6 +958,9 @@
     <!-- Message shown when lock screen is tapped or face authentication fails. [CHAR LIMIT=60] -->
     <string name="keyguard_unlock">Swipe up to open</string>
 
+    <!-- Message shown when face authentication fails and the pin pad is visible. [CHAR LIMIT=60] -->
+    <string name="keyguard_retry">Swipe up to try again</string>
+
     <!-- Text on keyguard screen and in Quick Settings footer indicating that the device is enterprise-managed by a Device Owner [CHAR LIMIT=60] -->
     <string name="do_disclosure_generic">This device is managed by your organization</string>
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java
index 342cb75..8a244bf 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java
@@ -21,6 +21,9 @@
 
 import com.android.systemui.shared.recents.model.Task.TaskKey;
 
+import java.util.ArrayList;
+import java.util.Collection;
+
 /**
  * Base class for both strong and LRU task key cache.
  */
@@ -76,6 +79,15 @@
         mKeys.remove(key.id);
     }
 
+    /** @return {@link Collection} of {@link TaskKey} */
+    public Collection<TaskKey> getValues() {
+        Collection<TaskKey> result = new ArrayList<>(mKeys.size());
+        for (int i = 0; i < mKeys.size(); i++) {
+            result.add(mKeys.valueAt(i));
+        }
+        return result;
+    }
+
     /** Removes all the entries in the cache. */
     public final synchronized void evictAll() {
         evictAllCache();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
index e106c65..bc57b08 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
@@ -49,7 +49,7 @@
 
             @Override
             protected void entryRemoved(boolean evicted, Integer taskId, V oldV, V newV) {
-                if (mEvictionCallback != null) {
+                if (mEvictionCallback != null && evicted) {
                     mEvictionCallback.onEntryEvicted(mKeys.get(taskId));
                 }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 13fc702..82287873 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -31,6 +31,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.RecentTaskInfo;
 import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
 import android.app.AppGlobals;
@@ -235,9 +236,9 @@
                     }
 
                     @Override
-                    public void onAnimationCanceled(boolean deferredWithScreenshot) {
+                    public void onAnimationCanceled(TaskSnapshot taskSnapshot) {
                         animationHandler.onAnimationCanceled(
-                                deferredWithScreenshot ? new ThumbnailData() : null);
+                                taskSnapshot != null ? new ThumbnailData(taskSnapshot) : null);
                     }
                 };
             }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java
index 9fdecfb..aeb0415 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SystemGestureExclusionListenerCompat.java
@@ -34,9 +34,11 @@
             new ISystemGestureExclusionListener.Stub() {
                 @Override
                 public void onSystemGestureExclusionChanged(int displayId,
-                        Region systemGestureExclusion) {
+                        Region systemGestureExclusion, Region unrestrictedOrNull) {
                     if (displayId == mDisplayId) {
-                        onExclusionChanged(systemGestureExclusion);
+                        Region unrestricted = (unrestrictedOrNull == null)
+                                ? systemGestureExclusion : unrestrictedOrNull;
+                        onExclusionChanged(systemGestureExclusion, unrestricted);
                     }
                 }
             };
@@ -47,11 +49,29 @@
     }
 
     /**
-     * Called when the exclusion region has changed
+     * Called when the exclusion region has changed.
+     *
+     * TODO: remove, once all subclasses have migrated to
+     *       {@link #onExclusionChanged(Region, Region)}.
      */
     public abstract void onExclusionChanged(Region systemGestureExclusion);
 
     /**
+     * Called when the exclusion region has changed.
+     *
+     * @param systemGestureExclusion the system gesture exclusion to be applied
+     * @param systemGestureExclusionUnrestricted what would be the system gesture exclusion, if
+     *           there were no restrictions being applied. For logging purposes only.
+     *
+     */
+    public void onExclusionChanged(Region systemGestureExclusion,
+            Region systemGestureExclusionUnrestricted) {
+        // TODO: make abstract, once all subclasses have migrated away from
+        //       onExclusionChanged(Region)
+        onExclusionChanged(systemGestureExclusion);
+    }
+
+    /**
      * Registers the listener for getting exclusion rect changes.
      */
     public void register() {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index c215d0f..7757161 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -95,6 +95,11 @@
     public void onTaskDisplayChanged(int taskId, int newDisplayId) { }
 
     /**
+     * Called when any additions or deletions to the recent tasks list have been made.
+     */
+    public void onRecentTaskListUpdated() { }
+
+    /**
      * Checks that the current user matches the process. Since
      * {@link android.app.ITaskStackListener} is not multi-user aware, handlers of
      * {@link TaskStackChangeListener} should make this call to verify that we don't act on events
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index d570a58..a7f4396 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -213,6 +213,11 @@
         mHandler.obtainMessage(H.ON_TASK_DISPLAY_CHANGED, taskId, newDisplayId).sendToTarget();
     }
 
+    @Override
+    public void onRecentTaskListUpdated() throws RemoteException {
+        mHandler.obtainMessage(H.ON_TASK_LIST_UPDATED).sendToTarget();
+    }
+
     private final class H extends Handler {
         private static final int ON_TASK_STACK_CHANGED = 1;
         private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
@@ -234,6 +239,7 @@
         private static final int ON_BACK_PRESSED_ON_TASK_ROOT = 18;
         private static final int ON_SINGLE_TASK_DISPLAY_DRAWN = 19;
         private static final int ON_TASK_DISPLAY_CHANGED = 20;
+        private static final int ON_TASK_LIST_UPDATED = 21;
 
 
         public H(Looper looper) {
@@ -382,6 +388,12 @@
                         }
                         break;
                     }
+                    case ON_TASK_LIST_UPDATED: {
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onRecentTaskListUpdated();
+                        }
+                        break;
+                    }
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index a4b6958..517abac 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -253,6 +253,7 @@
     protected void onUserInput() {
         if (mCallback != null) {
             mCallback.userActivity();
+            mCallback.onUserInput();
         }
         mSecurityMessageDisplay.setMessage("");
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 55ddfc3..56b38f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -274,6 +274,7 @@
         @Override
         public void onPatternCellAdded(List<LockPatternView.Cell> pattern) {
             mCallback.userActivity();
+            mCallback.onUserInput();
         }
 
         @Override
@@ -336,6 +337,7 @@
                     });
             if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
                 mCallback.userActivity();
+                mCallback.onUserInput();
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
index cbfbffb..49dcfff 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
@@ -55,4 +55,9 @@
     default void onCancelClicked() {
         // No-op
     }
+
+    /**
+     * Invoked whenever users are typing their password or drawing a pattern.
+     */
+    void onUserInput();
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 8059dcf..169c97b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -596,6 +596,11 @@
             }
         }
 
+        @Override
+        public void onUserInput() {
+            mUpdateMonitor.cancelFaceAuth();
+        }
+
         public void dismiss(boolean authenticated, int targetId) {
             mSecurityCallback.dismiss(authenticated, targetId);
         }
@@ -640,6 +645,8 @@
         @Override
         public void dismiss(boolean securityVerified, int targetUserId) { }
         @Override
+        public void onUserInput() { }
+        @Override
         public void reset() {}
     };
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 76bed23..1a5a60c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -867,11 +867,6 @@
                     getCurrentUser());
         }
 
-        // The face timeout message is not very actionable, let's ask the user to
-        // manually retry.
-        if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
-            errString = mContext.getString(R.string.keyguard_unlock);
-        }
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -1669,6 +1664,13 @@
         updateFaceListeningState();
     }
 
+    /**
+     * In case face auth is running, cancel it.
+     */
+    public void cancelFaceAuth() {
+        stopListeningForFace();
+    }
+
     private void updateFaceListeningState() {
         // If this message exists, we should not authenticate again until this message is
         // consumed by the handler
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 4a4fead..cf9c470 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -339,7 +339,7 @@
         intent.setComponent(assistComponent);
         intent.putExtras(args);
 
-        if (structureEnabled) {
+        if (structureEnabled && AssistUtils.isDisclosureEnabled(mContext)) {
             showDisclosure();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 923ca20..de08a8c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -182,7 +182,7 @@
 
         mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */,
                 true /* singleTaskInstance */);
-
+        // Set ActivityView's alpha value as zero, since there is no view content to be shown.
         setContentVisibility(false);
         addView(mActivityView);
 
diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
index d3e8b3d..3ca1f59 100644
--- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
@@ -68,9 +68,11 @@
         mBackdropColors.setMainColor(Color.BLACK);
 
         // Listen to all users instead of only the current one.
-        wallpaperManager.removeOnColorsChangedListener(this);
-        wallpaperManager.addOnColorsChangedListener(this, null /* handler */,
-                UserHandle.USER_ALL);
+        if (wallpaperManager.isWallpaperSupported()) {
+            wallpaperManager.removeOnColorsChangedListener(this);
+            wallpaperManager.addOnColorsChangedListener(this, null /* handler */,
+                    UserHandle.USER_ALL);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index f6a921d..f79bb3a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -107,8 +107,7 @@
                         config.dozePickupSensorAvailable(),
                         DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */,
                         false /* touchscreen */,
-                        false /* ignoresSetting */,
-                        mDozeParameters.getPickupPerformsProxCheck()),
+                        false /* ignoresSetting */),
                 new TriggerSensor(
                         findSensorWithType(config.doubleTapSensorType()),
                         Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
@@ -205,11 +204,8 @@
     public void updateListening() {
         boolean anyListening = false;
         for (TriggerSensor s : mSensors) {
-            // We don't want to be listening while we're PAUSED (prox sensor is covered)
-            // except when the sensor is already gated by prox.
-            boolean listen = mListening && (!mPaused || s.performsProxCheck());
-            s.setListening(listen);
-            if (listen) {
+            s.setListening(mListening);
+            if (mListening) {
                 anyListening = true;
             }
         }
@@ -384,7 +380,6 @@
         private final boolean mReportsTouchCoordinates;
         private final boolean mSettingDefault;
         private final boolean mRequiresTouchscreen;
-        private final boolean mSensorPerformsProxCheck;
 
         protected boolean mRequested;
         protected boolean mRegistered;
@@ -401,14 +396,12 @@
                 boolean configured, int pulseReason, boolean reportsTouchCoordinates,
                 boolean requiresTouchscreen) {
             this(sensor, setting, settingDef, configured, pulseReason, reportsTouchCoordinates,
-                    requiresTouchscreen, false /* ignoresSetting */,
-                    false /* sensorPerformsProxCheck */);
+                    requiresTouchscreen, false /* ignoresSetting */);
         }
 
         private TriggerSensor(Sensor sensor, String setting, boolean settingDef,
                 boolean configured, int pulseReason, boolean reportsTouchCoordinates,
-                boolean requiresTouchscreen, boolean ignoresSetting,
-                boolean sensorPerformsProxCheck) {
+                boolean requiresTouchscreen, boolean ignoresSetting) {
             mSensor = sensor;
             mSetting = setting;
             mSettingDefault = settingDef;
@@ -417,7 +410,6 @@
             mReportsTouchCoordinates = reportsTouchCoordinates;
             mRequiresTouchscreen = requiresTouchscreen;
             mIgnoresSetting = ignoresSetting;
-            mSensorPerformsProxCheck = sensorPerformsProxCheck;
         }
 
         public void setListening(boolean listen) {
@@ -491,23 +483,13 @@
                     screenX = event.values[0];
                     screenY = event.values[1];
                 }
-                mCallback.onSensorPulse(mPulseReason, mSensorPerformsProxCheck, screenX, screenY,
-                        event.values);
+                mCallback.onSensorPulse(mPulseReason, screenX, screenY, event.values);
                 if (!mRegistered) {
                     updateListening();  // reregister, this sensor only fires once
                 }
             }));
         }
 
-        /**
-         * If the sensor itself performs proximity checks, to avoid pocket dialing.
-         * Gated sensors don't need to be stopped when the {@link DozeMachine} is
-         * {@link DozeMachine.State#DOZE_AOD_PAUSED}.
-         */
-        public boolean performsProxCheck() {
-            return mSensorPerformsProxCheck;
-        }
-
         public void registerSettingsObserver(ContentObserver settingsObserver) {
             if (mConfigured && !TextUtils.isEmpty(mSetting)) {
                 mResolver.registerContentObserver(
@@ -603,8 +585,7 @@
                     return;
                 }
                 if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event));
-                mCallback.onSensorPulse(mPulseReason, true /* sensorPerformsProxCheck */, -1, -1,
-                        event.getValues());
+                mCallback.onSensorPulse(mPulseReason, -1, -1, event.getValues());
             }));
         }
     }
@@ -614,13 +595,11 @@
         /**
          * Called when a sensor requests a pulse
          * @param pulseReason Requesting sensor, e.g. {@link DozeLog#REASON_SENSOR_PICKUP}
-         * @param sensorPerformedProxCheck true if the sensor already checked for FAR proximity.
          * @param screenX the location on the screen where the sensor fired or -1
- *                if the sensor doesn't support reporting screen locations.
+         *                if the sensor doesn't support reporting screen locations.
          * @param screenY the location on the screen where the sensor fired or -1
          * @param rawValues raw values array from the event.
          */
-        void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck,
-                float screenX, float screenY, float[] rawValues);
+        void onSensorPulse(int pulseReason, float screenX, float screenY, float[] rawValues);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 310f04a..00bfb3f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -41,6 +41,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.Preconditions;
 import com.android.systemui.Dependency;
+import com.android.systemui.R;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.Assert;
@@ -156,8 +157,7 @@
     }
 
     @VisibleForTesting
-    void onSensor(int pulseReason, boolean sensorPerformedProxCheck,
-            float screenX, float screenY, float[] rawValues) {
+    void onSensor(int pulseReason, float screenX, float screenY, float[] rawValues) {
         boolean isDoubleTap = pulseReason == DozeLog.REASON_SENSOR_DOUBLE_TAP;
         boolean isTap = pulseReason == DozeLog.REASON_SENSOR_TAP;
         boolean isPickup = pulseReason == DozeLog.REASON_SENSOR_PICKUP;
@@ -169,10 +169,11 @@
         if (isWakeDisplay) {
             onWakeScreen(wakeEvent, mMachine.isExecutingTransition() ? null : mMachine.getState());
         } else if (isLongPress) {
-            requestPulse(pulseReason, sensorPerformedProxCheck, null /* onPulseSupressedListener */);
+            requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
+                    null /* onPulseSupressedListener */);
         } else if (isWakeLockScreen) {
             if (wakeEvent) {
-                requestPulse(pulseReason, sensorPerformedProxCheck,
+                requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
                         null /* onPulseSupressedListener */);
             }
         } else {
@@ -191,8 +192,7 @@
                 } else {
                     mDozeHost.extendPulse(pulseReason);
                 }
-            }, sensorPerformedProxCheck
-                    || (mDockManager != null && mDockManager.isDocked()), pulseReason);
+            }, true /* alreadyPerformedProxCheck */, pulseReason);
         }
 
         if (isPickup) {
@@ -278,7 +278,7 @@
                             .setType(MetricsEvent.TYPE_OPEN)
                             .setSubtype(DozeLog.REASON_SENSOR_WAKE_UP));
                 }
-            }, false /* alreadyPerformedProxCheck */, DozeLog.REASON_SENSOR_WAKE_UP);
+            }, true /* alreadyPerformedProxCheck */, DozeLog.REASON_SENSOR_WAKE_UP);
         } else {
             boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
             boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
@@ -433,7 +433,11 @@
 
         public void check() {
             Preconditions.checkState(!mFinished && !mRegistered);
-            final Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+            Sensor sensor = DozeSensors.findSensorWithType(mSensorManager,
+                    mContext.getString(R.string.doze_brightness_sensor_type));
+            if (sensor == null) {
+                sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+            }
             if (sensor == null) {
                 if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: No sensor found");
                 finishWithResult(RESULT_UNKNOWN);
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index fb8b6c7..75dc397 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -64,6 +64,8 @@
     private static final int CHARGE_CYCLE_PERCENT_RESET = 45;
     private static final long SIX_HOURS_MILLIS = Duration.ofHours(6).toMillis();
     public static final int NO_ESTIMATE_AVAILABLE = -1;
+    private static final String BOOT_COUNT_KEY = "boot_count";
+    private static final String PREFS = "powerui_prefs";
 
     private final Handler mHandler = new Handler();
     @VisibleForTesting
@@ -118,7 +120,7 @@
 
         // Check to see if we need to let the user know that the phone previously shut down due
         // to the temperature being too high.
-        showThermalShutdownDialog();
+        showWarnOnThermalShutdown();
 
         // Register an observer to configure mEnableSkinTemperatureWarning and perform the
         // registration of skin thermal event listener upon Settings change.
@@ -542,10 +544,23 @@
         }
     }
 
-    private void showThermalShutdownDialog() {
-        if (mPowerManager.getLastShutdownReason()
-                == PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN) {
-            mWarnings.showThermalShutdownWarning();
+    private void showWarnOnThermalShutdown() {
+        int bootCount = -1;
+        int lastReboot = mContext.getSharedPreferences(PREFS, 0).getInt(BOOT_COUNT_KEY, -1);
+        try {
+            bootCount = Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.BOOT_COUNT);
+        } catch (Settings.SettingNotFoundException e) {
+            Slog.e(TAG, "Failed to read system boot count from Settings.Global.BOOT_COUNT");
+        }
+        // Only show the thermal shutdown warning when there is a thermal reboot.
+        if (bootCount > lastReboot) {
+            mContext.getSharedPreferences(PREFS, 0).edit().putInt(BOOT_COUNT_KEY,
+                    bootCount).apply();
+            if (mPowerManager.getLastShutdownReason()
+                    == PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN) {
+                mWarnings.showThermalShutdownWarning();
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index f0413cd..be8a8fd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -111,13 +111,25 @@
                 + mQSPanel.getMeasuredHeight() + getPaddingBottom();
         super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
-
         // QSCustomizer will always be the height of the screen, but do this after
         // other measuring to avoid changing the height of the QS.
         mQSCustomizer.measure(widthMeasureSpec,
                 MeasureSpec.makeMeasureSpec(getDisplayHeight(), MeasureSpec.EXACTLY));
     }
 
+
+    @Override
+    protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
+            int parentHeightMeasureSpec, int heightUsed) {
+        // Do not measure QSPanel again when doing super.onMeasure.
+        // This prevents the pages in PagedTileLayout to be remeasured with a different (incorrect)
+        // size to the one used for determining the number of rows and then the number of pages.
+        if (child != mQSPanel) {
+            super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
+                    parentHeightMeasureSpec, heightUsed);
+        }
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 4be93df..bba64d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -562,11 +562,11 @@
             return;
         }
 
-        String message = mContext.getString(R.string.keyguard_unlock);
         if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+            String message = mContext.getString(R.string.keyguard_retry);
             mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
         } else if (mKeyguardUpdateMonitor.isScreenOn()) {
-            showTransientIndication(message);
+            showTransientIndication(mContext.getString(R.string.keyguard_unlock));
             hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
         }
     }
@@ -676,7 +676,11 @@
                 return;
             }
             animatePadlockError();
-            if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+            if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
+                // The face timeout message is not very actionable, let's ask the user to
+                // manually retry.
+                showSwipeUpToUnlock();
+            } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState);
             } else if (updateMonitor.isScreenOn()) {
                 showTransientIndication(errString);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index c67512c..f3201ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -54,7 +54,6 @@
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.SystemUI;
 import com.android.systemui.UiOffloadThread;
-import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.util.NotificationChannels;
@@ -138,15 +137,6 @@
                 }
             };
 
-    private final TaskStackChangeListener mTaskListener =
-            new TaskStackChangeListener() {
-                @Override
-                public void onTaskStackChanged() {
-                    // Listen for changes to stacks and then check which instant apps are
-                    // foreground.
-                    updateForegroundInstantApps();
-                }
-            };
 
     private void updateForegroundInstantApps() {
         NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index 1ce4934..0009292 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -420,7 +420,14 @@
             }
         }
 
-        Collections.sort(mSortedAndFiltered, mRankingComparator);
+        if (mSortedAndFiltered.size() == 1) {
+            // HACK: We need the comparator to run on all children in order to set the
+            // isHighPriority field. If there is only one child, then the comparison won't be run,
+            // so we have to trigger it manually. Get rid of this code as soon as possible.
+            mRankingComparator.compare(mSortedAndFiltered.get(0), mSortedAndFiltered.get(0));
+        } else {
+            Collections.sort(mSortedAndFiltered, mRankingComparator);
+        }
     }
 
     public void dump(PrintWriter pw, String indent) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 6e84089..65e744b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1208,12 +1208,12 @@
             mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
         }
         if (mGuts != null) {
-            View oldGuts = mGuts;
+            NotificationGuts oldGuts = mGuts;
             int index = indexOfChild(oldGuts);
             removeView(oldGuts);
             mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
                     R.layout.notification_guts, this, false);
-            mGuts.setVisibility(oldGuts.getVisibility());
+            mGuts.setVisibility(oldGuts.isExposed() ? VISIBLE : GONE);
             addView(mGuts, index);
         }
         View oldMenu = mMenuRow == null ? null : mMenuRow.getMenuView();
@@ -1366,7 +1366,9 @@
         if (isChildInGroup()) {
             mTranslationWhenRemoved += getNotificationParent().getTranslationY();
         }
-        mPrivateLayout.setRemoved();
+        for (NotificationContentView l : mLayouts) {
+            l.setRemoved();
+        }
     }
 
     public boolean wasChildInGroupWhenRemoved() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 90f6324..0c5b27b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1542,6 +1542,15 @@
         if (mHeadsUpRemoteInput != null) {
             mHeadsUpRemoteInput.setRemoved();
         }
+        if (mExpandedWrapper != null) {
+            mExpandedWrapper.setRemoved();
+        }
+        if (mContractedWrapper != null) {
+            mContractedWrapper.setRemoved();
+        }
+        if (mHeadsUpWrapper != null) {
+            mHeadsUpWrapper.setRemoved();
+        }
     }
 
     public void setContentHeightAnimating(boolean animating) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index 20e8b73..1116106 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -39,6 +39,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.widget.MediaNotificationView;
 import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.TransformableView;
@@ -67,6 +68,7 @@
     private View mSeekBarView;
     private Context mContext;
     private MetricsLogger mMetricsLogger;
+    private boolean mIsViewVisible;
 
     @VisibleForTesting
     protected SeekBar.OnSeekBarChangeListener mSeekListener =
@@ -88,11 +90,46 @@
         }
     };
 
+    private MediaNotificationView.VisibilityChangeListener mVisibilityListener =
+            new MediaNotificationView.VisibilityChangeListener() {
+        @Override
+        public void onAggregatedVisibilityChanged(boolean isVisible) {
+            mIsViewVisible = isVisible;
+            if (isVisible && mMediaController != null) {
+                // Restart timer if we're currently playing and didn't already have one going
+                PlaybackState state = mMediaController.getPlaybackState();
+                if (state != null && state.getState() == PlaybackState.STATE_PLAYING
+                        && mSeekBarTimer == null && mSeekBarView != null
+                        && mSeekBarView.getVisibility() != View.GONE) {
+                    startTimer();
+                }
+            } else {
+                clearTimer();
+            }
+        }
+    };
+
+    private View.OnAttachStateChangeListener mAttachStateListener =
+            new View.OnAttachStateChangeListener() {
+        @Override
+        public void onViewAttachedToWindow(View v) {
+        }
+
+        @Override
+        public void onViewDetachedFromWindow(View v) {
+            mIsViewVisible = false;
+        }
+    };
+
     private MediaController.Callback mMediaCallback = new MediaController.Callback() {
         @Override
         public void onSessionDestroyed() {
             clearTimer();
             mMediaController.unregisterCallback(this);
+            if (mView instanceof MediaNotificationView) {
+                ((MediaNotificationView) mView).removeVisibilityListener(mVisibilityListener);
+                mView.removeOnAttachStateChangeListener(mAttachStateListener);
+            }
         }
 
         @Override
@@ -126,10 +163,17 @@
         mContext = ctx;
         mMediaManager = Dependency.get(NotificationMediaManager.class);
         mMetricsLogger = Dependency.get(MetricsLogger.class);
+
+        if (mView instanceof MediaNotificationView) {
+            MediaNotificationView mediaView = (MediaNotificationView) mView;
+            mediaView.addVisibilityListener(mVisibilityListener);
+            mView.addOnAttachStateChangeListener(mAttachStateListener);
+        }
     }
 
     private void resolveViews() {
         mActions = mView.findViewById(com.android.internal.R.id.media_actions);
+        mIsViewVisible = mView.isShown();
 
         final MediaSession.Token token = mRow.getEntry().notification.getNotification().extras
                 .getParcelable(Notification.EXTRA_MEDIA_SESSION);
@@ -208,24 +252,37 @@
 
     private void startTimer() {
         clearTimer();
-        mSeekBarTimer = new Timer(true /* isDaemon */);
-        mSeekBarTimer.schedule(new TimerTask() {
-            @Override
-            public void run() {
-                mHandler.post(mOnUpdateTimerTick);
-            }
-        }, 0, PROGRESS_UPDATE_INTERVAL);
+        if (mIsViewVisible) {
+            mSeekBarTimer = new Timer(true /* isDaemon */);
+            mSeekBarTimer.schedule(new TimerTask() {
+                @Override
+                public void run() {
+                    mHandler.post(mOnUpdateTimerTick);
+                }
+            }, 0, PROGRESS_UPDATE_INTERVAL);
+        }
     }
 
     private void clearTimer() {
         if (mSeekBarTimer != null) {
-            // TODO: also trigger this when the notification panel is collapsed
             mSeekBarTimer.cancel();
             mSeekBarTimer.purge();
             mSeekBarTimer = null;
         }
     }
 
+    @Override
+    public void setRemoved() {
+        clearTimer();
+        if (mMediaController != null) {
+            mMediaController.unregisterCallback(mMediaCallback);
+        }
+        if (mView instanceof MediaNotificationView) {
+            ((MediaNotificationView) mView).removeVisibilityListener(mVisibilityListener);
+            mView.removeOnAttachStateChangeListener(mAttachStateListener);
+        }
+    }
+
     private boolean canSeekMedia(@Nullable PlaybackState state) {
         if (state == null) {
             return false;
@@ -261,7 +318,6 @@
         public void run() {
             if (mMediaController != null && mSeekBar != null) {
                 PlaybackState playbackState = mMediaController.getPlaybackState();
-
                 if (playbackState != null) {
                     updatePlaybackUi(playbackState);
                 } else {
@@ -274,6 +330,10 @@
     };
 
     private void updatePlaybackUi(PlaybackState state) {
+        if (mSeekBar == null || mSeekBarElapsedTime == null) {
+            return;
+        }
+
         long position = state.getPosition();
         mSeekBar.setProgress((int) position);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 47906a7..3950003 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -261,6 +261,12 @@
         mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
     }
 
+    /**
+     * Called to indicate this view is removed
+     */
+    public void setRemoved() {
+    }
+
     public int getCustomBackgroundColor() {
         // Parent notifications should always use the normal background color
         return mRow.isSummaryWithChildren() ? 0 : mBackgroundColor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 10b48e7..bb6a38e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -207,10 +207,6 @@
         return SystemProperties.get(propName, mContext.getString(resId));
     }
 
-    public boolean getPickupPerformsProxCheck() {
-        return mContext.getResources().getBoolean(R.bool.doze_pickup_performs_proximity_check);
-    }
-
     public int getPulseVisibleDurationExtended() {
         return 2 * getPulseVisibleDuration();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index f9cdde8..6a74779 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -31,6 +31,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.util.Log;
 import android.util.MathUtils;
 import android.view.Gravity;
@@ -66,7 +67,8 @@
 public class EdgeBackGestureHandler implements DisplayListener {
 
     private static final String TAG = "EdgeBackGestureHandler";
-    private static final int MAX_LONG_PRESS_TIMEOUT = 250;
+    private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt(
+            "gestures.back_timeout", 250);
 
     private final IPinnedStackListener.Stub mImeChangedListener = new IPinnedStackListener.Stub() {
         @Override
@@ -103,7 +105,7 @@
             new ISystemGestureExclusionListener.Stub() {
                 @Override
                 public void onSystemGestureExclusionChanged(int displayId,
-                        Region systemGestureExclusion) {
+                        Region systemGestureExclusion, Region unrestrictedOrNull) {
                     if (displayId == mDisplayId) {
                         mMainExecutor.execute(() -> mExcludeRegion.set(systemGestureExclusion));
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index d2023ec..dcb349b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -79,10 +79,13 @@
 
         IWallpaperManager service = IWallpaperManager.Stub.asInterface(
                 ServiceManager.getService(Context.WALLPAPER_SERVICE));
-        try {
-            service.setLockWallpaperCallback(this);
-        } catch (RemoteException e) {
-            Log.e(TAG, "System dead?" + e);
+        if (service != null) {
+            // Service is disabled on some devices like Automotive
+            try {
+                service.setLockWallpaperCallback(this);
+            } catch (RemoteException e) {
+                Log.e(TAG, "System dead?" + e);
+            }
         }
     }
 
@@ -108,6 +111,11 @@
     public LoaderResult loadBitmap(int currentUserId, UserHandle selectedUser) {
         // May be called on any thread - only use thread safe operations.
 
+        if (!mWallpaperManager.isWallpaperSupported()) {
+            // When wallpaper is not supported, show the system wallpaper
+            return LoaderResult.success(null);
+        }
+
         // Prefer the selected user (when specified) over the current user for the FLAG_SET_LOCK
         // wallpaper.
         final int lockWallpaperUserId =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 6bfa048..f689a3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -619,6 +619,10 @@
         // Always disable recents when alternate car mode UI is active and for secondary displays.
         boolean disableRecent = isRecentsButtonDisabled();
 
+        // Disable the home handle if both hone and recents are disabled
+        boolean disableHomeHandle = disableRecent
+                && ((mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
+
         boolean disableBack = !useAltBack && (isGesturalMode(mNavBarMode)
                 || ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0));
 
@@ -649,6 +653,7 @@
         getBackButton().setVisibility(disableBack      ? View.INVISIBLE : View.VISIBLE);
         getHomeButton().setVisibility(disableHome      ? View.INVISIBLE : View.VISIBLE);
         getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
+        getHomeHandle().setVisibility(disableHomeHandle ? View.INVISIBLE : View.VISIBLE);
     }
 
     @VisibleForTesting
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 01dcbc7..c171730 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1266,6 +1266,15 @@
             // earlier so the state is already up to date when dragging down.
             setListening(true);
         }
+        if (isQsSplitEnabled() && !mKeyguardShowing) {
+            if (mQsExpandImmediate) {
+                mNotificationStackScroller.setVisibility(View.GONE);
+                mQsFrame.setVisibility(View.VISIBLE);
+            } else {
+                mNotificationStackScroller.setVisibility(View.VISIBLE);
+                mQsFrame.setVisibility(View.GONE);
+            }
+        }
         return false;
     }
 
@@ -1539,6 +1548,10 @@
 
         mBarState = statusBarState;
         mKeyguardShowing = keyguardShowing;
+        if (mKeyguardShowing && isQsSplitEnabled()) {
+            mNotificationStackScroller.setVisibility(View.VISIBLE);
+            mQsFrame.setVisibility(View.VISIBLE);
+        }
 
         if (oldState == StatusBarState.KEYGUARD
                 && (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index c706062..b45914b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -133,6 +133,12 @@
             mBlankScreen = mDisplayRequiresBlanking;
             mAnimationDuration = mWakeLockScreenSensorActive
                     ? ScrimController.ANIMATION_DURATION_LONG : ScrimController.ANIMATION_DURATION;
+
+            // Wake sensor will show the wallpaper, let's fade from black. Otherwise it will
+            // feel like the screen is flashing if the wallpaper is light.
+            if (mWakeLockScreenSensorActive && previousState == AOD) {
+                updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+            }
         }
 
         @Override
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 4f9df43..90aba87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -480,15 +480,17 @@
     private NotificationMediaManager mMediaManager;
     protected NotificationLockscreenUserManager mLockscreenUserManager;
     protected NotificationRemoteInputManager mRemoteInputManager;
+    private boolean mWallpaperSupported;
 
     private final BroadcastReceiver mWallpaperChangedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            WallpaperManager wallpaperManager = context.getSystemService(WallpaperManager.class);
-            if (wallpaperManager == null) {
-                Log.w(TAG, "WallpaperManager not available");
+            if (!mWallpaperSupported) {
+                // Receiver should not have been registered at all...
+                Log.wtf(TAG, "WallpaperManager not supported");
                 return;
             }
+            WallpaperManager wallpaperManager = context.getSystemService(WallpaperManager.class);
             WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
             final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean(
                     com.android.internal.R.bool.config_dozeSupportsAodWallpaper);
@@ -715,11 +717,18 @@
 
         createAndAddWindows(result);
 
-        // Make sure we always have the most current wallpaper info.
-        IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
-        mContext.registerReceiverAsUser(mWallpaperChangedReceiver, UserHandle.ALL,
-                wallpaperChangedFilter, null /* broadcastPermission */, null /* scheduler */);
-        mWallpaperChangedReceiver.onReceive(mContext, null);
+        mWallpaperSupported =
+                mContext.getSystemService(WallpaperManager.class).isWallpaperSupported();
+
+        if (mWallpaperSupported) {
+            // Make sure we always have the most current wallpaper info.
+            IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
+            mContext.registerReceiverAsUser(mWallpaperChangedReceiver, UserHandle.ALL,
+                    wallpaperChangedFilter, null /* broadcastPermission */, null /* scheduler */);
+            mWallpaperChangedReceiver.onReceive(mContext, null);
+        } else if (DEBUG) {
+            Log.v(TAG, "start(): no wallpaper service ");
+        }
 
         // Set up the initial notification state. This needs to happen before CommandQueue.disable()
         setUpPresenter();
@@ -754,12 +763,14 @@
         mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,
                 null);
 
-        IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
-                ServiceManager.getService(Context.WALLPAPER_SERVICE));
-        try {
-            wallpaperManager.setInAmbientMode(false /* ambientMode */, 0L /* duration */);
-        } catch (RemoteException e) {
-            // Just pass, nothing critical.
+        if (mWallpaperSupported) {
+            IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
+                    ServiceManager.getService(Context.WALLPAPER_SERVICE));
+            try {
+                wallpaperManager.setInAmbientMode(false /* ambientMode */, 0L /* duration */);
+            } catch (RemoteException e) {
+                // Just pass, nothing critical.
+            }
         }
 
         // end old BaseStatusBar.start().
@@ -2311,6 +2322,7 @@
         pw.println(Settings.Global.zenModeToString(Settings.Global.getInt(
                 mContext.getContentResolver(), Settings.Global.ZEN_MODE,
                 Settings.Global.ZEN_MODE_OFF)));
+        pw.print("  mWallpaperSupported= "); pw.println(mWallpaperSupported);
 
         if (mStatusBarView != null) {
             dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
@@ -2691,7 +2703,9 @@
     public void setLockscreenUser(int newUserId) {
         mLockscreenWallpaper.setCurrentUser(newUserId);
         mScrimController.setCurrentUser(newUserId);
-        mWallpaperChangedReceiver.onReceive(mContext, null);
+        if (mWallpaperSupported) {
+            mWallpaperChangedReceiver.onReceive(mContext, null);
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 7b133f2..24d6c4c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -1020,12 +1020,11 @@
         row.icon.setAlpha(iconEnabled ? 1 : 0.5f);
         final int iconRes =
                 isRingVibrate ? R.drawable.ic_volume_ringer_vibrate
-                : isRingSilent || zenMuted ? row.iconMuteRes
-                : ss.routedToBluetooth ?
-                        (ss.muted ? R.drawable.ic_volume_media_bt_mute
-                                : R.drawable.ic_volume_media_bt)
-                : mAutomute && ss.level == 0 ? row.iconMuteRes
-                : (ss.muted ? row.iconMuteRes : row.iconRes);
+                        : isRingSilent || zenMuted ? row.iconMuteRes
+                                : ss.routedToBluetooth
+                                        ? isStreamMuted(ss) ? R.drawable.ic_volume_media_bt_mute
+                                                : R.drawable.ic_volume_media_bt
+                                        : isStreamMuted(ss) ? row.iconMuteRes : row.iconRes;
         row.icon.setImageResource(iconRes);
         row.iconState =
                 iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE
@@ -1087,6 +1086,10 @@
         updateVolumeRowSliderH(row, enableSlider, vlevel);
     }
 
+    private boolean isStreamMuted(final StreamState streamState) {
+        return (mAutomute && streamState.level == 0) || streamState.muted;
+    }
+
     private void updateVolumeRowTintH(VolumeRow row, boolean isActive) {
         if (isActive) {
             row.slider.requestFocus();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index 2ed0970..0c124ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -37,7 +37,6 @@
         when(params.getPulseOnSigMotion()).thenReturn(false);
         when(params.getPickupVibrationThreshold()).thenReturn(0);
         when(params.getProxCheckBeforePulse()).thenReturn(true);
-        when(params.getPickupPerformsProxCheck()).thenReturn(true);
         when(params.getPolicy()).thenReturn(mock(AlwaysOnDisplayPolicy.class));
         when(params.doubleTapReportsTouchCoordinates()).thenReturn(false);
         when(params.getDisplayNeedsBlanking()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index 7df45a3..cd6d1e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -19,7 +19,6 @@
 import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -79,8 +78,6 @@
     private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy;
     @Mock
     private TriggerSensor mTriggerSensor;
-    @Mock
-    private TriggerSensor mProxGatedTriggerSensor;
     private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
     private TestableLooper mTestableLooper;
     private DozeSensors mDozeSensors;
@@ -88,7 +85,6 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        when(mProxGatedTriggerSensor.performsProxCheck()).thenReturn(true);
         mTestableLooper = TestableLooper.get(this);
         when(mAmbientDisplayConfiguration.getWakeLockScreenDebounce()).thenReturn(5000L);
         when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
@@ -106,14 +102,14 @@
         mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class));
         mTestableLooper.processAllMessages();
         verify(mCallback).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN),
-                anyBoolean(), anyFloat(), anyFloat(), eq(null));
+                anyFloat(), anyFloat(), eq(null));
 
         mDozeSensors.requestTemporaryDisable();
         reset(mCallback);
         mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class));
         mTestableLooper.processAllMessages();
         verify(mCallback, never()).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN),
-                anyBoolean(), anyFloat(), anyFloat(), eq(null));
+                anyFloat(), anyFloat(), eq(null));
     }
 
     @Test
@@ -132,20 +128,17 @@
     }
 
     @Test
-    public void testSetPaused_onlyPausesNonGatedSensors() {
+    public void testSetPaused_doesntPause_sensors() {
         mDozeSensors.setListening(true);
         verify(mTriggerSensor).setListening(eq(true));
-        verify(mProxGatedTriggerSensor).setListening(eq(true));
 
-        clearInvocations(mTriggerSensor, mProxGatedTriggerSensor);
+        clearInvocations(mTriggerSensor);
         mDozeSensors.setPaused(true);
-        verify(mTriggerSensor).setListening(eq(false));
-        verify(mProxGatedTriggerSensor).setListening(eq(true));
-
-        clearInvocations(mTriggerSensor, mProxGatedTriggerSensor);
-        mDozeSensors.setPaused(false);
         verify(mTriggerSensor).setListening(eq(true));
-        verify(mProxGatedTriggerSensor).setListening(eq(true));
+
+        clearInvocations(mTriggerSensor);
+        mDozeSensors.setListening(false);
+        verify(mTriggerSensor).setListening(eq(false));
     }
 
     private class TestableDozeSensors extends DozeSensors {
@@ -161,7 +154,7 @@
                     mWakeLockScreenListener = (PluginSensor) sensor;
                 }
             }
-            mSensors = new TriggerSensor[] {mTriggerSensor, mProxGatedTriggerSensor};
+            mSensors = new TriggerSensor[] {mTriggerSensor};
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index d464223..e190f99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -20,7 +20,6 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -134,28 +133,4 @@
         mTriggers.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.FINISH);
         verify(mDockManagerFake).removeListener(any());
     }
-
-    @Test
-    public void testOnSensor_whenUndockedWithNearAndDoubleTapScreen_shouldNotWakeUp() {
-        mSensors.getMockProximitySensor().sendProximityResult(false /* far */);
-
-        mTriggers.onSensor(DozeLog.REASON_SENSOR_DOUBLE_TAP,
-                false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
-                null /* rawValues */);
-        verify(mMachine, never()).wakeUp();
-    }
-
-    @Test
-    public void testOnSensor_whenDockedWithNearAndDoubleTapScreen_shouldWakeUp() {
-        doReturn(true).when(mDockManagerFake).isDocked();
-        doReturn(true).when(mParameters).getDisplayNeedsBlanking();
-        mSensors.getMockProximitySensor().sendProximityResult(false /* far */);
-
-        mTriggers.onSensor(DozeLog.REASON_SENSOR_DOUBLE_TAP,
-                false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
-                null /* rawValues */);
-
-        verify(mHost).setAodDimmingScrim(eq(1f));
-        verify(mMachine).wakeUp();
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java
index eb71dd6..de6c87c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java
@@ -20,6 +20,10 @@
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertNull;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -27,10 +31,10 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import org.mockito.junit.MockitoJUnitRunner;
 
 @SmallTest
-@RunWith(JUnit4.class)
+@RunWith(MockitoJUnitRunner.class)
 public class TaskKeyLruCacheTest extends SysuiTestCase {
     private static int sCacheSize = 3;
     private static int sIdTask1 = 1;
@@ -38,13 +42,18 @@
     private static int sIdTask3 = 3;
     private static int sIdUser1 = 1;
 
-    TaskKeyCache<Integer> mCache = new TaskKeyLruCache<>(sCacheSize, null);
-    Task.TaskKey mKey1;
-    Task.TaskKey mKey2;
-    Task.TaskKey mKey3;
+    TaskKeyLruCache.EvictionCallback mEvictionCallback;
+
+    TaskKeyLruCache<Integer> mCache;
+    private Task.TaskKey mKey1;
+    private Task.TaskKey mKey2;
+    private Task.TaskKey mKey3;
 
     @Before
     public void setup() {
+        mEvictionCallback = mock(TaskKeyLruCache.EvictionCallback.class);
+        mCache = new TaskKeyLruCache<>(sCacheSize, mEvictionCallback);
+
         mKey1 = new Task.TaskKey(sIdTask1, 0, null, null, sIdUser1, System.currentTimeMillis());
         mKey2 = new Task.TaskKey(sIdTask2, 0, null, null, sIdUser1, System.currentTimeMillis());
         mKey3 = new Task.TaskKey(sIdTask3, 0, null, null, sIdUser1, System.currentTimeMillis());
@@ -90,6 +99,7 @@
         assertNull(mCache.get(mKey1));
         assertEquals(3, mCache.mKeys.size());
         assertEquals(mKey2, mCache.mKeys.valueAt(0));
+        verify(mEvictionCallback, times(1)).onEntryEvicted(mKey1);
     }
 
     @Test
@@ -102,5 +112,29 @@
 
         assertNull(mCache.get(mKey2));
         assertEquals(2, mCache.mKeys.size());
+        verify(mEvictionCallback, times(0)).onEntryEvicted(mKey2);
+    }
+
+    @Test
+    public void put_evictionCallback_notCalled() {
+        mCache.put(mKey1, 1);
+        verify(mEvictionCallback, times(0)).onEntryEvicted(mKey1);
+    }
+
+    @Test
+    public void evictAll_evictionCallback_called() {
+        mCache.put(mKey1, 1);
+        mCache.evictAllCache();
+        verify(mEvictionCallback, times(1)).onEntryEvicted(mKey1);
+    }
+
+    @Test
+    public void trimAll_evictionCallback_called() {
+        mCache.put(mKey1, 1);
+        mCache.put(mKey2, 2);
+        mCache.trimToSize(-1);
+        verify(mEvictionCallback, times(1)).onEntryEvicted(mKey1);
+        verify(mEvictionCallback, times(1)).onEntryEvicted(mKey2);
+
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
index 260555f..e2d8e56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
@@ -23,6 +23,7 @@
 import static android.app.Notification.CATEGORY_EVENT;
 import static android.app.Notification.CATEGORY_MESSAGE;
 import static android.app.Notification.CATEGORY_REMINDER;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 
@@ -62,6 +63,8 @@
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.ArraySet;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.systemui.Dependency;
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.InitController;
@@ -85,8 +88,6 @@
 import java.util.List;
 import java.util.Map;
 
-import androidx.test.filters.SmallTest;
-
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
@@ -114,6 +115,7 @@
         MockitoAnnotations.initMocks(this);
         when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
         when(mMockStatusBarNotification.cloneLight()).thenReturn(mMockStatusBarNotification);
+        when(mMockStatusBarNotification.getKey()).thenReturn("mock_key");
 
         when(mMockPackageManager.checkUidPermission(
                 eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
@@ -232,6 +234,7 @@
         Notification n = mMockStatusBarNotification.getNotification();
         n.flags = Notification.FLAG_FOREGROUND_SERVICE;
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        entry.setRow(mRow);
         mNotificationData.add(entry);
         Bundle override = new Bundle();
         override.putInt(OVERRIDE_VIS_EFFECTS, 255);
@@ -250,6 +253,7 @@
         n = nb.build();
         when(mMockStatusBarNotification.getNotification()).thenReturn(n);
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        entry.setRow(mRow);
         mNotificationData.add(entry);
         Bundle override = new Bundle();
         override.putInt(OVERRIDE_VIS_EFFECTS, 255);
@@ -263,6 +267,7 @@
     public void testIsExemptFromDndVisualSuppression_system() {
         initStatusBarNotification(false);
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        entry.setRow(mRow);
         entry.mIsSystemNotification = true;
         mNotificationData.add(entry);
         Bundle override = new Bundle();
@@ -277,6 +282,7 @@
     public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
         initStatusBarNotification(false);
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        entry.setRow(mRow);
         entry.mIsSystemNotification = true;
         Bundle override = new Bundle();
         override.putInt(OVERRIDE_VIS_EFFECTS, NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT);
@@ -529,6 +535,62 @@
         assertEquals(-1, mNotificationData.mRankingComparator.compare(a, b));
     }
 
+    @Test
+    public void testSort_properlySetsIsTopBucket() {
+
+        Notification notification = new Notification.Builder(mContext, "test")
+                .build();
+        StatusBarNotification sbn = new StatusBarNotification(
+                "pkg",
+                "pkg",
+                0,
+                "tag",
+                0,
+                0,
+                notification,
+                mContext.getUser(),
+                "",
+                0);
+
+        Bundle override = new Bundle();
+        override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_DEFAULT);
+        mNotificationData.rankingOverrides.put(sbn.getKey(), override);
+
+        NotificationEntry entry = new NotificationEntry(sbn);
+        entry.setRow(mRow);
+        mNotificationData.add(entry);
+
+        assertTrue(entry.isTopBucket());
+    }
+
+    @Test
+    public void testSort_properlySetsIsNotTopBucket() {
+        Notification notification = new Notification.Builder(mContext, "test")
+                .build();
+        StatusBarNotification sbn = new StatusBarNotification(
+                "pkg",
+                "pkg",
+                0,
+                "tag",
+                0,
+                0,
+                notification,
+                mContext.getUser(),
+                "",
+                0);
+
+        Bundle override = new Bundle();
+        override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
+        mNotificationData.rankingOverrides.put(sbn.getKey(), override);
+
+        NotificationEntry entry = new NotificationEntry(sbn);
+        entry.setRow(mRow);
+
+        mNotificationData.add(entry);
+
+        assertFalse(entry.isTopBucket());
+    }
+
     private void initStatusBarNotification(boolean allowDuringSetup) {
         Bundle bundle = new Bundle();
         bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
diff --git a/packages/VpnDialogs/res/values-hi/strings.xml b/packages/VpnDialogs/res/values-hi/strings.xml
index 34b79cb..eed0858 100644
--- a/packages/VpnDialogs/res/values-hi/strings.xml
+++ b/packages/VpnDialogs/res/values-hi/strings.xml
@@ -22,7 +22,7 @@
     <string name="session" msgid="6470628549473641030">"सत्र:"</string>
     <string name="duration" msgid="3584782459928719435">"अवधि:"</string>
     <string name="data_transmitted" msgid="7988167672982199061">"भेजे गए:"</string>
-    <string name="data_received" msgid="4062776929376067820">"प्राप्त:"</string>
+    <string name="data_received" msgid="4062776929376067820">"पाया:"</string>
     <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> बाइट / <xliff:g id="NUMBER_1">%2$s</xliff:g> पैकेट"</string>
     <string name="always_on_disconnected_title" msgid="1906740176262776166">"हमेशा चालू रहने वाले VPN से नहीं जुड़ पा रहा है"</string>
     <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> को हर समय जुड़े रहने के लिए सेट अप किया गया है, लेकिन वह इस समय नहीं जुड़ पा रहा है. जब तक आपका फ़ोन <xliff:g id="VPN_APP_1">%1$s</xliff:g> से नहीं जुड़ जाता, तब तक वह सार्वजनिक नेटवर्क का इस्तेमाल करेगा."</string>
diff --git a/services/art-profile-boot b/services/art-profile-boot
new file mode 100644
index 0000000..23d7090
--- /dev/null
+++ b/services/art-profile-boot
@@ -0,0 +1,326 @@
+Lcom/android/server/SystemServer;->run()V
+Lcom/android/server/SystemServer;->main([Ljava/lang/String;)V
+Lcom/android/server/SystemServer;->startBootstrapServices()V
+Lcom/android/server/pm/PackageManagerService;->main(Landroid/content/Context;Lcom/android/server/pm/Installer;ZZ)Lcom/android/server/pm/PackageManagerService;
+Lcom/android/server/pm/PackageManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/Installer;ZZ)V
+Lcom/android/server/pm/Settings;->readLPw(Ljava/util/List;)Z
+Lcom/android/server/pm/Settings;->readPackageLPw(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/Settings;->readInstallPermissionsLPr(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/pm/permission/PermissionsState;)V
+Lcom/android/server/pm/permission/PermissionsState;->grantPermission(Lcom/android/server/pm/permission/BasePermission;I)I
+Lcom/android/server/pm/permission/PermissionsState;->grantInstallPermission(Lcom/android/server/pm/permission/BasePermission;)I
+Lcom/android/server/-$$Lambda$YWiwiKm_Qgqb55C6tTuq_n2JzdY;->run()V
+Lcom/android/server/pm/PackageSignatures;->readXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/util/ArrayList;)V
+Lcom/android/server/pm/permission/PermissionsState;->computeGids(I)[I
+Lcom/android/server/am/-$$Lambda$BatteryExternalStatsWorker$ddVY5lmqswnSjXppAxPTOHbuzzQ;->run()V
+Lcom/android/server/SystemServiceManager;->startService(Lcom/android/server/SystemService;)V
+Lcom/android/server/SystemServiceManager;->startService(Ljava/lang/Class;)Lcom/android/server/SystemService;
+Lcom/android/server/SystemServiceManager;->startService(Ljava/lang/String;)Lcom/android/server/SystemService;
+Lcom/android/server/pm/permission/PermissionsState;->hasPermission(Ljava/lang/String;I)Z
+Lcom/android/server/pm/permission/PermissionsState;->hasPermissionRequiringReview(I)Z
+Lcom/android/server/am/ActivityManagerService$Lifecycle;-><init>(Landroid/content/Context;)V
+Lcom/android/server/am/ActivityManagerService;-><init>(Landroid/content/Context;Lcom/android/server/wm/ActivityTaskManagerService;)V
+Lcom/android/server/pm/Settings;->readSharedUserLPw(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/permission/PermissionsState;->updatePermissionFlags(Lcom/android/server/pm/permission/BasePermission;III)Z
+Lcom/android/server/pm/permission/PermissionsState;->ensurePermissionData(Lcom/android/server/pm/permission/BasePermission;)Lcom/android/server/pm/permission/PermissionsState$PermissionData;
+Lcom/android/server/am/BatteryExternalStatsWorker$1;->run()V
+Lcom/android/server/am/BatteryExternalStatsWorker;->updateExternalStatsLocked(Ljava/lang/String;IZZZ)V
+Lcom/android/server/pm/permission/PermissionsState$PermissionData;->grant(I)Z
+Lcom/android/server/am/BatteryExternalStatsWorker$2;->run()V
+Lcom/android/server/pm/permission/PermissionSettings;->getPermission(Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission;
+Lcom/android/server/pm/permission/PermissionSettings;->getPermissionLocked(Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission;
+Lcom/android/server/pm/permission/PermissionSettings;->getPermissionTreeLocked(Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission;
+Lcom/android/server/pm/Settings;->readDisabledSysPackageLPw(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/permission/PermissionsState$PermissionData;->updateFlags(III)Z
+Lcom/android/server/pm/PackageSignatures;->readCertsListXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/util/ArrayList;Ljava/util/ArrayList;IZLandroid/content/pm/PackageParser$SigningDetails$Builder;)I
+Lcom/android/server/pm/permission/PermissionsState$PermissionData;-><init>(Lcom/android/server/pm/permission/PermissionsState$PermissionData;)V
+Lcom/android/server/pm/permission/PermissionSettings;->readPermissions(Landroid/util/ArrayMap;Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/permission/PermissionSettings;->readPermissions(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->readStateForUserSyncLPr(I)V
+Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->parseRuntimePermissionsLPr(Lorg/xmlpull/v1/XmlPullParser;I)V
+Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->parsePermissionsLPr(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/pm/permission/PermissionsState;I)V
+Lcom/android/server/pm/permission/BasePermission;->readLPw(Ljava/util/Map;Lorg/xmlpull/v1/XmlPullParser;)Z
+Lcom/android/server/pm/Settings;->writeKernelMappingLPr()V
+Lcom/android/server/pm/Settings;->writeKernelMappingLPr(Lcom/android/server/pm/PackageSetting;)V
+Lcom/android/server/pm/Settings;->writeKernelMappingLPr(Ljava/lang/String;I[I)V
+Lcom/android/server/pm/Settings;->readPackageRestrictionsLPr(I)V
+Lcom/android/server/am/ActivityManagerService$Injector;->getAppOpsService(Ljava/io/File;Landroid/os/Handler;)Lcom/android/server/appop/AppOpsService;
+Lcom/android/server/appop/AppOpsService;-><init>(Ljava/io/File;Landroid/os/Handler;)V
+Lcom/android/server/appop/AppOpsService;->readState()V
+Lcom/android/server/am/ProcessStatsService;-><init>(Lcom/android/server/am/ActivityManagerService;Ljava/io/File;)V
+Lcom/android/server/pm/PackageManagerService;->scanDirTracedLI(Ljava/io/File;IIJ)V
+Lcom/android/server/pm/PackageManagerService;->scanDirLI(Ljava/io/File;IIJ)V
+Lcom/android/server/pm/PackageManagerService;->addForInitLI(Landroid/content/pm/PackageParser$Package;IIJLandroid/os/UserHandle;)Landroid/content/pm/PackageParser$Package;
+Lcom/android/server/pm/PackageManagerService;->scanPackageChildLI(Landroid/content/pm/PackageParser$Package;IIJLandroid/os/UserHandle;)Landroid/content/pm/PackageParser$Package;
+Lcom/android/server/pm/KeySetManagerService;->readKeySetsLPw(Lorg/xmlpull/v1/XmlPullParser;Landroid/util/ArrayMap;)V
+Lcom/android/server/pm/ParallelPackageParser;->lambda$submit$0$ParallelPackageParser(Ljava/io/File;I)V
+Lcom/android/server/pm/-$$Lambda$ParallelPackageParser$FTtinPrp068lVeI7K6bC1tNE3iM;->run()V
+Lcom/android/server/pm/ParallelPackageParser;->parsePackage(Landroid/content/pm/PackageParser;Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
+Lcom/android/server/appop/AppOpsService;->readPackage(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/Settings;->addPackageLPw(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IJIILjava/lang/String;Ljava/util/List;[Ljava/lang/String;[J)Lcom/android/server/pm/PackageSetting;
+Lcom/android/server/appop/AppOpsService;->readUid(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)V
+Lcom/android/server/appop/AppOpsService;->readUidOps(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/PackageSetting;-><init>(Lcom/android/server/pm/PackageSetting;)V
+Lcom/android/server/pm/PackageSetting;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JIILjava/lang/String;Ljava/util/List;I[Ljava/lang/String;[J)V
+Lcom/android/server/pm/SELinuxMMAC;->readInstallPolicy()Z
+Lcom/android/server/pm/KeySetManagerService;->readKeysLPw(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/Settings;->writeIntToFile(Ljava/io/File;I)V
+Lcom/android/server/pm/PackageSettingBase;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JIILjava/lang/String;Ljava/util/List;[Ljava/lang/String;[J)V
+Lcom/android/server/appop/AppOpsService;->readOp(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/appop/AppOpsService$UidState;Ljava/lang/String;Z)V
+Lcom/android/server/pm/SELinuxMMAC;->readSignerOrThrow(Lorg/xmlpull/v1/XmlPullParser;)Lcom/android/server/pm/Policy;
+Lcom/android/server/pm/Settings;->readComponentsLPr(Lorg/xmlpull/v1/XmlPullParser;)Landroid/util/ArraySet;
+Lcom/android/server/pm/KeySetManagerService;->readPublicKeyLPw(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/pm/PackageManagerService;->scanPackageNewLI(Landroid/content/pm/PackageParser$Package;IIJLandroid/os/UserHandle;)Lcom/android/server/pm/PackageManagerService$ScanResult;
+Lcom/android/server/pm/permission/PermissionsState;->grantRuntimePermission(Lcom/android/server/pm/permission/BasePermission;I)I
+Lcom/android/server/pm/Policy$PolicyBuilder;->addSignature(Ljava/lang/String;)Lcom/android/server/pm/Policy$PolicyBuilder;
+Lcom/android/server/display/DisplayManagerService;-><init>(Landroid/content/Context;)V
+Lcom/android/server/display/DisplayManagerService;-><init>(Landroid/content/Context;Lcom/android/server/display/DisplayManagerService$Injector;)V
+Lcom/android/server/am/ActivityManagerService;->start()V
+Lcom/android/server/am/ActivityManagerService;->startAssociationLocked(ILjava/lang/String;IIJLandroid/content/ComponentName;Ljava/lang/String;)Lcom/android/server/am/ActivityManagerService$Association;
+Lcom/android/server/am/ActivityManagerService;->startIsolatedProcess(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Runnable;)Z
+Lcom/android/server/am/ActivityManagerService;->startObservingNativeCrashes()V
+Lcom/android/server/am/ActivityManagerService;->startPersistentApps(I)V
+Lcom/android/server/am/ActivityManagerService;->startProcessLocked(Ljava/lang/String;Landroid/content/pm/ApplicationInfo;ZILjava/lang/String;Landroid/content/ComponentName;ZZZ)Lcom/android/server/am/ProcessRecord;
+Lcom/android/server/am/ActivityManagerService;->startService(Landroid/app/IApplicationThread;Landroid/content/Intent;Ljava/lang/String;ZLjava/lang/String;I)Landroid/content/ComponentName;
+PLcom/android/server/am/ActivityManagerService;->startUserInBackgroundWithListener(ILandroid/os/IProgressListener;)Z
+Lcom/android/server/am/ActivityManagerService$Lifecycle;->onStart()V
+Lcom/android/server/pm/PackageManagerService;->scanPackageOnlyLI(Lcom/android/server/pm/PackageManagerService$ScanRequest;ZJ)Lcom/android/server/pm/PackageManagerService$ScanResult;
+Lcom/android/server/pm/PackageSettingBase;->modifyUserState(I)Landroid/content/pm/PackageUserState;
+Lcom/android/server/pm/PackageSettingBase;->modifyUserStateComponents(IZZ)Landroid/content/pm/PackageUserState;
+Lcom/android/server/pm/Settings;->readDomainVerificationLPw(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/pm/PackageSettingBase;)V
+Lcom/android/server/pm/PackageSettingBase;->setEnabled(IILjava/lang/String;)V
+Lcom/android/server/am/BatteryStatsService;-><init>(Landroid/content/Context;Ljava/io/File;Landroid/os/Handler;)V
+Lcom/android/server/pm/PackageManagerService;->commitReconciledScanResultLocked(Lcom/android/server/pm/PackageManagerService$ReconciledPackage;)V
+Lcom/android/server/pm/KeySetManagerService;->readKeySetListLPw(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/appop/AppOpsService$Op;->accessed(JILjava/lang/String;II)V
+Lcom/android/server/wm/ActivityTaskManagerService;->initialize(Lcom/android/server/firewall/IntentFirewall;Lcom/android/server/am/PendingIntentController;Landroid/os/Looper;)V
+Lcom/android/server/pm/SettingBase;-><init>(II)V
+Lcom/android/server/pm/PackageManagerService;->locationIsPrivileged(Ljava/lang/String;)Z
+Lcom/android/server/power/PowerManagerService;-><init>(Landroid/content/Context;)V
+Lcom/android/server/power/PowerManagerService;-><init>(Landroid/content/Context;Lcom/android/server/power/PowerManagerService$Injector;)V
+Lcom/android/server/pm/permission/PermissionsState;->enforceValidUserId(I)V
+Lcom/android/server/Watchdog;->getInstance()Lcom/android/server/Watchdog;
+Lcom/android/server/Watchdog;-><init>()V
+Lcom/android/server/pm/PackageManagerService;->commitPackageSettings(Landroid/content/pm/PackageParser$Package;Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/PackageSetting;IZLcom/android/server/pm/PackageManagerService$ReconciledPackage;)V
+Lcom/android/server/pm/PackageSetting;->getPermissionsState()Lcom/android/server/pm/permission/PermissionsState;
+Lcom/android/server/pm/Settings;->registerExistingAppIdLPw(ILcom/android/server/pm/SettingBase;Ljava/lang/Object;)Z
+Lcom/android/server/pm/permission/PermissionManagerService;->create(Landroid/content/Context;Lcom/android/server/pm/permission/DefaultPermissionGrantPolicy$DefaultPermissionGrantedCallback;Ljava/lang/Object;)Lcom/android/server/pm/permission/PermissionManagerServiceInternal;
+Lcom/android/server/pm/Settings;->addSharedUserLPw(Ljava/lang/String;III)Lcom/android/server/pm/SharedUserSetting;
+Lcom/android/server/pm/PackageSettingBase;->init(Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V
+Lcom/android/server/appop/AppOpsService$Op;->updateProxyState(JILjava/lang/String;)V
+Lcom/android/server/display/DisplayManagerService$DisplayAdapterListener;->onDisplayDeviceEvent(Lcom/android/server/display/DisplayDevice;I)V
+Lcom/android/server/wm/ActivityTaskManagerService;->onActivityManagerInternalAdded()V
+Lcom/android/server/SystemService;->publishBinderService(Ljava/lang/String;Landroid/os/IBinder;)V
+Lcom/android/server/am/ActivityManagerService;->initPowerManagement()V
+Lcom/android/server/wm/ActivityTaskManagerService$Lifecycle;-><init>(Landroid/content/Context;)V
+Lcom/android/server/display/DisplayManagerService;->onStart()V
+Lcom/android/server/pm/Settings;->readPreferredActivitiesLPw(Lorg/xmlpull/v1/XmlPullParser;I)V
+Lcom/android/server/pm/PackageKeySetData;-><init>()V
+Lcom/android/server/display/DisplayManagerService;->registerDefaultDisplayAdapters()V
+Lcom/android/server/display/LocalDisplayAdapter;->registerLocked()V
+Lcom/android/server/ServiceThread;->run()V
+Lcom/android/server/display/DisplayModeDirector;-><init>(Landroid/content/Context;Landroid/os/Handler;)V
+Lcom/android/server/pm/Settings;->addPackageSettingLPw(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/SharedUserSetting;)V
+Lcom/android/server/pm/permission/PermissionManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/permission/DefaultPermissionGrantPolicy$DefaultPermissionGrantedCallback;Ljava/lang/Object;)V
+Lcom/android/server/appop/AppOpsService;->getUidStateLocked(IZ)Lcom/android/server/appop/AppOpsService$UidState;
+Lcom/android/server/am/BatteryStatsService;->fillRailDataStats(Lcom/android/internal/os/RailStats;)V
+Lcom/android/server/pm/SELinuxMMAC;->getSeInfo(Landroid/content/pm/PackageParser$Package;ZII)Ljava/lang/String;
+Lcom/android/server/pm/PackageManagerService;->collectCertificatesLI(Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$Package;ZZ)V
+Lcom/android/server/pm/PackageManagerService;->reconcilePackagesLocked(Lcom/android/server/pm/PackageManagerService$ReconcileRequest;Lcom/android/server/pm/KeySetManagerService;)Ljava/util/Map;
+Lcom/android/server/pm/permission/BasePermission;->readInt(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Ljava/lang/String;I)I
+Lcom/android/server/pm/UserManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/PackageManagerService;Lcom/android/server/pm/UserDataPreparer;Ljava/lang/Object;)V
+Lcom/android/server/pm/UserManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/PackageManagerService;Lcom/android/server/pm/UserDataPreparer;Ljava/lang/Object;Ljava/io/File;)V
+Lcom/android/server/display/LocalDisplayAdapter;->tryConnectDisplayLocked(J)V
+Lcom/android/server/pm/PreferredActivity;-><init>(Landroid/content/IntentFilter;I[Landroid/content/ComponentName;Landroid/content/ComponentName;Z)V
+Lcom/android/server/pm/PackageManagerService;->preparePackageParserCache()Ljava/io/File;
+Lcom/android/server/pm/Policy$PolicyBuilder;->build()Lcom/android/server/pm/Policy;
+Lcom/android/server/LockGuard;->installLock(Ljava/lang/Object;I)Ljava/lang/Object;
+Lcom/android/server/LockGuard;->installLock(Ljava/lang/Object;IZ)Ljava/lang/Object;
+Lcom/android/server/SystemServiceManager;->startBootPhase(I)V
+Lcom/android/server/display/PersistentDataStore;->load()V
+Lcom/android/server/display/PersistentDataStore;->loadDisplaysFromXml(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/display/PersistentDataStore;->loadFromXml(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/display/PersistentDataStore;->loadRememberedWifiDisplaysFromXml(Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/wm/AppWarnings;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;Landroid/content/Context;Landroid/os/Handler;Landroid/os/Handler;Ljava/io/File;)V
+Lcom/android/server/pm/PreferredComponent;-><init>(Lcom/android/server/pm/PreferredComponent$Callbacks;I[Landroid/content/ComponentName;Landroid/content/ComponentName;Z)V
+Lcom/android/server/pm/PreferredComponent;-><init>(Lcom/android/server/pm/PreferredComponent$Callbacks;Lorg/xmlpull/v1/XmlPullParser;)V
+Lcom/android/server/display/DisplayManagerService;->handleDisplayDeviceAdded(Lcom/android/server/display/DisplayDevice;)V
+Lcom/android/server/display/DisplayManagerService;->handleDisplayDeviceAddedLocked(Lcom/android/server/display/DisplayDevice;)V
+Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice;->getDisplayDeviceInfoLocked()Lcom/android/server/display/DisplayDeviceInfo;
+Lcom/android/server/pm/PackageSettingBase;->setUserState(IJIZZZZIZLjava/lang/String;Landroid/content/pm/SuspendDialogInfo;Landroid/os/PersistableBundle;Landroid/os/PersistableBundle;ZZLjava/lang/String;Landroid/util/ArraySet;Landroid/util/ArraySet;IIILjava/lang/String;)V
+Lcom/android/server/pm/Installer;->onStart()V
+Lcom/android/server/pm/Installer;->connect()V
+Lcom/android/server/lights/LightsService$LightImpl;-><init>(Lcom/android/server/lights/LightsService;Landroid/content/Context;I)V
+Lcom/android/server/pm/PackageManagerService;->addBuiltInSharedLibraryLocked(Ljava/lang/String;Ljava/lang/String;)Z
+Lcom/android/server/LockGuard;->findOrCreateLockInfo(Ljava/lang/Object;)Lcom/android/server/LockGuard$LockInfo;
+Lcom/android/server/lights/LightsService;-><init>(Landroid/content/Context;)V
+Lcom/android/server/pm/Policy;->getMatchedSeInfo(Landroid/content/pm/PackageParser$Package;)Ljava/lang/String;
+Lcom/android/server/ServiceThread;-><init>(Ljava/lang/String;IZ)V
+Lcom/android/server/wm/ActivityTaskManagerService;->createStackSupervisor()Lcom/android/server/wm/ActivityStackSupervisor;
+Lcom/android/server/Watchdog;->addMonitor(Lcom/android/server/Watchdog$Monitor;)V
+Lcom/android/server/wm/ActivityStackSupervisor;->initPowerManagement()V
+Lcom/android/server/wm/ActivityTaskManagerService;->onInitPowerManagement()V
+Lcom/android/server/pm/KeySetManagerService;->addScannedPackageLPw(Landroid/content/pm/PackageParser$Package;)V
+Lcom/android/server/am/BatteryStatsService;->initPowerManagement()V
+Lcom/android/server/wm/ActivityTaskManagerService;-><init>(Landroid/content/Context;)V
+Lcom/android/server/am/ProcessList;-><init>()V
+Lcom/android/server/pm/PackageManagerService;->commitSharedLibraryInfoLocked(Landroid/content/pm/SharedLibraryInfo;)V
+Lcom/android/server/pm/PackageManagerServiceUtils;->getLastModifiedTime(Landroid/content/pm/PackageParser$Package;)J
+Lcom/android/server/am/ProcessStatsService;->updateFile()V
+Lcom/android/server/pm/Policy$PolicyBuilder;->setGlobalSeinfoOrThrow(Ljava/lang/String;)Lcom/android/server/pm/Policy$PolicyBuilder;
+Lcom/android/server/wm/AppWarnings;->readConfigFromFileAmsThread()V
+Lcom/android/server/am/BatteryStatsService;->fillLowPowerStats(Lcom/android/internal/os/RpmStats;)V
+Lcom/android/server/display/DisplayManagerService;->handleDisplayDeviceChanged(Lcom/android/server/display/DisplayDevice;)V
+Lcom/android/server/firewall/IntentFirewall;-><init>(Lcom/android/server/firewall/IntentFirewall$AMSInterface;Landroid/os/Handler;)V
+Lcom/android/server/pm/PackageSettingBase;->getNotInstalledUserIds()[I
+Lcom/android/server/appop/AppOpsService$UidState;->evalForegroundOps(Landroid/util/SparseArray;)V
+Lcom/android/server/SystemServerInitThreadPool;->submit(Ljava/lang/Runnable;Ljava/lang/String;)Ljava/util/concurrent/Future;
+Lcom/android/server/pm/KeySetManagerService;->addSigningKeySetToPackageLPw(Lcom/android/server/pm/PackageSetting;Landroid/util/ArraySet;)V
+Lcom/android/server/pm/ComponentResolver;->addAllComponents(Landroid/content/pm/PackageParser$Package;Z)V
+Lcom/android/server/appop/AppOpsService;->publish(Landroid/content/Context;)V
+Lcom/android/server/power/PowerManagerService;->onStart()V
+Lcom/android/server/os/DeviceIdentifiersPolicyService;->onStart()V
+Lcom/android/server/uri/UriGrantsManagerService$Lifecycle;-><init>(Landroid/content/Context;)V
+Lcom/android/server/pm/PackageManagerService;->applyPolicy(Landroid/content/pm/PackageParser$Package;IILandroid/content/pm/PackageParser$Package;)V
+Lcom/android/server/pm/KeySetManagerService;->addRefCountsFromSavedPackagesLPw(Landroid/util/ArrayMap;)V
+Lcom/android/server/am/OomAdjuster;-><init>(Lcom/android/server/am/ActivityManagerService;Lcom/android/server/am/ProcessList;Lcom/android/server/am/ActiveUids;)V
+Lcom/android/server/am/ProcessList;->init(Lcom/android/server/am/ActivityManagerService;Lcom/android/server/am/ActiveUids;)V
+Lcom/android/server/pm/PackageManagerService$ScanRequest;-><init>(Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/SharedUserSetting;Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Ljava/lang/String;IIZLandroid/os/UserHandle;)V
+Lcom/android/server/pm/Settings;->writeUserRestrictionsLPw(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;)V
+PLcom/android/server/pm/permission/PermissionsState;-><init>(Lcom/android/server/pm/permission/PermissionsState;)V
+Lcom/android/server/pm/UserManagerService;->readUserListLP()V
+Lcom/android/server/RescueParty;->isUsbActive()Z
+Lcom/android/server/RescueParty;->isDisabled()Z
+Lcom/android/server/pm/SharedUserSetting;->addPackage(Lcom/android/server/pm/PackageSetting;)V
+Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice;-><init>(Lcom/android/server/display/LocalDisplayAdapter;Landroid/os/IBinder;J[Landroid/view/SurfaceControl$PhysicalDisplayInfo;I[I[IIZ)V
+Lcom/android/server/am/BatteryStatsService$WakeupReasonThread;->run()V
+Lcom/android/server/pm/PackageSettingBase;->doCopy(Lcom/android/server/pm/PackageSettingBase;)V
+Lcom/android/server/SystemServerInitThreadPool;->get()Lcom/android/server/SystemServerInitThreadPool;
+Lcom/android/server/pm/PreferredActivity;->onReadTag(Ljava/lang/String;Lorg/xmlpull/v1/XmlPullParser;)Z
+Lcom/android/server/FgThread;->getHandler()Landroid/os/Handler;
+Lcom/android/server/FgThread;->ensureThreadLocked()V
+Lcom/android/server/IntentResolver;->addFilter(Landroid/content/IntentFilter;)V
+Lcom/android/server/IntentResolver;->addFilter(Landroid/util/ArrayMap;Ljava/lang/String;Landroid/content/IntentFilter;)V
+Lcom/android/server/pm/PackageManagerService;->assertPackageIsValid(Landroid/content/pm/PackageParser$Package;II)V
+Lcom/android/server/pm/PackageManagerService;->getSettingsVersionForPackage(Landroid/content/pm/PackageParser$Package;)Lcom/android/server/pm/Settings$VersionInfo;
+Lcom/android/server/pm/KeySetManagerService;->getPublicKeysFromKeySetLPr(J)Landroid/util/ArraySet;
+Lcom/android/server/pm/ComponentResolver;->addActivitiesLocked(Landroid/content/pm/PackageParser$Package;Ljava/util/List;Z)V
+Lcom/android/server/pm/PackageManagerServiceCompilerMapping;->checkProperties()V
+Lcom/android/server/pm/Settings;->getSettingLPr(I)Lcom/android/server/pm/SettingBase;
+Lcom/android/server/uri/UriGrantsManagerService;-><init>(Landroid/content/Context;)V
+Lcom/android/server/pm/Settings;-><init>(Ljava/io/File;Lcom/android/server/pm/permission/PermissionSettings;Ljava/lang/Object;)V
+Lcom/android/server/uri/UriGrantsManagerService$Lifecycle;->onStart()V
+Lcom/android/server/wm/ActivityTaskManagerService$Lifecycle;->onStart()V
+Lcom/android/server/pm/PackageSetting;->updateFrom(Lcom/android/server/pm/PackageSetting;)V
+Lcom/android/server/display/DisplayModeDirector$SettingsObserver;-><init>(Lcom/android/server/display/DisplayModeDirector;Landroid/content/Context;Landroid/os/Handler;)V
+Lcom/android/server/power/batterysaver/BatterySaverController;-><init>(Ljava/lang/Object;Landroid/content/Context;Landroid/os/Looper;Lcom/android/server/power/batterysaver/BatterySaverPolicy;Lcom/android/server/power/batterysaver/BatterySavingStats;)V
+Lcom/android/server/wm/ActivityStackSupervisor;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;Landroid/os/Looper;)V
+Lcom/android/server/PackageWatchdog;-><init>(Landroid/content/Context;)V
+Lcom/android/server/PackageWatchdog;->getInstance(Landroid/content/Context;)Lcom/android/server/PackageWatchdog;
+Lcom/android/server/pm/Settings;->getAllUsers(Lcom/android/server/pm/UserManagerService;)Ljava/util/List;
+Lcom/android/server/Watchdog;->addThread(Landroid/os/Handler;)V
+Lcom/android/server/Watchdog;->addThread(Landroid/os/Handler;J)V
+Lcom/android/server/wm/RecentTasks;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;Lcom/android/server/wm/ActivityStackSupervisor;)V
+Lcom/android/server/pm/PackageSettingBase;->updateFrom(Lcom/android/server/pm/PackageSettingBase;)Lcom/android/server/pm/PackageSettingBase;
+Lcom/android/server/pm/UserManagerService;->getUsers(Z)Ljava/util/List;
+Lcom/android/server/firewall/IntentFirewall;->readRulesDir(Ljava/io/File;)V
+Lcom/android/server/wm/TaskChangeNotificationController;-><init>(Ljava/lang/Object;Lcom/android/server/wm/ActivityStackSupervisor;Landroid/os/Handler;)V
+Lcom/android/server/am/BatteryExternalStatsWorker;->awaitControllerInfo(Landroid/os/SynchronousResultReceiver;)Landroid/os/Parcelable;
+Lcom/android/server/display/DisplayManagerService;->addLogicalDisplayLocked(Lcom/android/server/display/DisplayDevice;)Lcom/android/server/display/LogicalDisplay;
+Lcom/android/server/display/DisplayManagerService;->updateLogicalDisplaysLocked()Z
+Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice;->updatePhysicalDisplayInfoLocked([Landroid/view/SurfaceControl$PhysicalDisplayInfo;I[I[II)Z
+Lcom/android/server/display/DisplayDeviceInfo;->toString()Ljava/lang/String;
+Lcom/android/server/UiThread;->run()V
+Lcom/android/server/pm/PackageKeySetData;->setProperSigningKeySet(J)V
+Lcom/android/server/UiThread;->ensureThreadLocked()V
+Lcom/android/server/UiThread;->getHandler()Landroid/os/Handler;
+Lcom/android/server/pm/Settings;->getPackageLPr(Ljava/lang/String;)Lcom/android/server/pm/PackageSetting;
+Lcom/android/server/IoThread;->ensureThreadLocked()V
+Lcom/android/server/IoThread;->getHandler()Landroid/os/Handler;
+Lcom/android/server/pm/Settings;->getInternalVersion()Lcom/android/server/pm/Settings$VersionInfo;
+Lcom/android/server/appop/AppOpsService$Op;->running(JJII)V
+Lcom/android/server/appop/AppOpsService$Op;->updateAccessTimeAndDuration(JJII)V
+Lcom/android/server/appop/AppOpsService$Op;->rejected(JILjava/lang/String;II)V
+Lcom/android/server/DisplayThread;->ensureThreadLocked()V
+Lcom/android/server/DisplayThread;->getHandler()Landroid/os/Handler;
+Lcom/android/server/am/UserController;-><init>(Lcom/android/server/am/UserController$Injector;)V
+Lcom/android/server/AnimationThread;->ensureThreadLocked()V
+Lcom/android/server/AnimationThread;->getHandler()Landroid/os/Handler;
+Lcom/android/server/wm/SurfaceAnimationThread;->ensureThreadLocked()V
+Lcom/android/server/wm/SurfaceAnimationThread;->getHandler()Landroid/os/Handler;
+Lcom/android/server/wm/ActivityStackSupervisor;->initialize()V
+Lcom/android/server/pm/PackageSettingBase;->readUserState(I)Landroid/content/pm/PackageUserState;
+Lcom/android/server/pm/PackageManagerServiceUtils;->getCompressedFiles(Ljava/lang/String;)[Ljava/io/File;
+Lcom/android/server/pm/Settings;->insertPackageSettingLPw(Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$Package;)V
+Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->addActivity(Landroid/content/pm/PackageParser$Activity;Ljava/lang/String;Ljava/util/List;)V
+Lcom/android/server/pm/Installer;->invalidateMounts()V
+Lcom/android/server/power/PowerManagerService$NativeWrapper;->nativeInit(Lcom/android/server/power/PowerManagerService;)V
+Lcom/android/server/power/ThermalManagerService;->onStart()V
+Lcom/android/server/am/OomAdjProfiler;-><init>()V
+Lcom/android/server/pm/PackageManagerService;->maybeClearProfilesForUpgradesLI(Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$Package;)V
+Lcom/android/server/am/ActivityManagerConstants;-><init>(Lcom/android/server/am/ActivityManagerService;Landroid/os/Handler;)V
+Lcom/android/server/IntentResolver;-><init>()V
+Lcom/android/server/pm/Settings;->updatePackageSetting(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/SharedUserSetting;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IILjava/util/List;Lcom/android/server/pm/UserManagerService;[Ljava/lang/String;[J)V
+Lcom/android/server/PackageWatchdog;->loadFromFile()V
+Lcom/android/server/power/batterysaver/BatterySaverPolicy;-><init>(Ljava/lang/Object;Landroid/content/Context;Lcom/android/server/power/batterysaver/BatterySavingStats;)V
+Lcom/android/server/power/AttentionDetector;-><init>(Ljava/lang/Runnable;Ljava/lang/Object;)V
+Lcom/android/server/pm/dex/DexManager;-><init>(Landroid/content/Context;Landroid/content/pm/IPackageManager;Lcom/android/server/pm/PackageDexOptimizer;Lcom/android/server/pm/Installer;Ljava/lang/Object;)V
+Lcom/android/server/appop/AppOpsService$Op;-><init>(Lcom/android/server/appop/AppOpsService$UidState;Ljava/lang/String;I)V
+Lcom/android/server/pm/UserManagerService;->readUserLP(I)Lcom/android/server/pm/UserManagerService$UserData;
+Lcom/android/server/pm/UserManagerService;->readUserLP(ILjava/io/InputStream;)Lcom/android/server/pm/UserManagerService$UserData;
+Lcom/android/server/pm/UserRestrictionsUtils;->readRestrictions(Lorg/xmlpull/v1/XmlPullParser;)Landroid/os/Bundle;
+Lcom/android/server/pm/UserRestrictionsUtils;->readRestrictions(Lorg/xmlpull/v1/XmlPullParser;Landroid/os/Bundle;)V
+Lcom/android/server/pm/PackageManagerService;->adjustScanFlags(ILcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Landroid/os/UserHandle;Landroid/content/pm/PackageParser$Package;)I
+Lcom/android/server/pm/SettingBase;->setFlags(I)V
+Lcom/android/server/display/LogicalDisplay;->updateLocked(Ljava/util/List;)V
+Lcom/android/server/Watchdog$HandlerChecker;->run()V
+Lcom/android/server/Watchdog;->run()V
+Lcom/android/server/display/DisplayAdapter$1;->run()V
+Lcom/android/server/display/DisplayManagerService$DisplayManagerHandler;->handleMessage(Landroid/os/Message;)V
+Lcom/android/server/pm/PackageManagerServiceCompilerMapping;->getAndCheckValidity(I)Ljava/lang/String;
+Lcom/android/server/pm/ParallelPackageParser;->take()Lcom/android/server/pm/ParallelPackageParser$ParseResult;
+Lcom/android/server/pm/KeySetManagerService;->assertScannedPackageValid(Landroid/content/pm/PackageParser$Package;)V
+Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice$1;->run()V
+Lcom/android/server/pm/PackageManagerServiceUtils;->verifySignatures(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$SigningDetails;ZZ)Z
+Lcom/android/server/pm/PackageManagerService;->getSharedLibLatestVersionSetting(Lcom/android/server/pm/PackageManagerService$ScanResult;)Lcom/android/server/pm/PackageSetting;
+Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice$1;->setDisplayBrightness(I)V
+Lcom/android/server/pm/PackageManagerService;->getLatestSharedLibraVersionLPr(Landroid/content/pm/PackageParser$Package;)Landroid/content/pm/SharedLibraryInfo;
+Lcom/android/server/pm/PackageManagerServiceCompilerMapping;->getSystemPropertyName(I)Ljava/lang/String;
+Lcom/android/server/lights/LightsService$LightImpl;->setLightLocked(IIIII)V
+Lcom/android/server/lights/LightsService$LightImpl;->setBrightness(I)V
+Lcom/android/server/lights/LightsService$LightImpl;->setBrightness(II)V
+Lcom/android/server/Watchdog$HandlerChecker;->scheduleCheckLocked()V
+Lcom/android/server/pm/permission/PermissionsState;->copyFrom(Lcom/android/server/pm/permission/PermissionsState;)V
+Lcom/android/server/pm/permission/PermissionManagerService$PermissionManagerServiceInternalImpl;->addAllPermissionGroups(Landroid/content/pm/PackageParser$Package;Z)V
+Lcom/android/server/RecoverySystemService;->onStart()V
+Lcom/android/server/display/DisplayManagerService;->onBootPhase(I)V
+Lcom/android/server/am/ProcessList;->updateOomLevels(IIZ)V
+Lcom/android/server/am/OomAdjProfiler;->batteryPowerChanged(Z)V
+Lcom/android/server/pm/UserManagerService;->hasManageUsersOrPermission(Ljava/lang/String;)Z
+Lcom/android/server/am/OomAdjProfiler;->scheduleSystemServerCpuTimeUpdate()V
+Lcom/android/server/pm/PackageManagerService$ReconcileRequest;-><init>(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Lcom/android/server/pm/PackageManagerService$1;)V
+Lcom/android/server/pm/PackageManagerService$ReconcileRequest;-><init>(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V
+Lcom/android/server/wm/ConfigurationContainer;->onConfigurationChanged(Landroid/content/res/Configuration;)V
+Lcom/android/server/wm/RootActivityContainer;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;)V
+Lcom/android/server/wm/ActivityTaskManagerService;->createRecentTasks()Lcom/android/server/wm/RecentTasks;
+Lcom/android/server/am/OomAdjuster;->updateOomAdjLocked()V
+Lcom/android/server/am/OomAdjuster;->updateOomAdjLocked(Lcom/android/server/am/ProcessRecord;Z)Z
+Lcom/android/server/am/ActivityManagerService;->updateOomAdjLocked()V
+Lcom/android/server/am/ActivityManagerService;->updateOomAdjLocked(Lcom/android/server/am/ProcessRecord;Z)Z
+Lcom/android/server/pm/Settings;->getRenamedPackageLPr(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/server/am/OomAdjProfiler;->updateSystemServerCpuTime(ZZ)V
+Lcom/android/server/pm/UserManagerService;->getInstance()Lcom/android/server/pm/UserManagerService;
+Lcom/android/server/pm/permission/PermissionManagerService$PermissionManagerServiceInternalImpl;->addAllPermissions(Landroid/content/pm/PackageParser$Package;Z)V
+Lcom/android/server/power/PowerManagerService$Injector;->createBatterySaverPolicy(Ljava/lang/Object;Landroid/content/Context;Lcom/android/server/power/batterysaver/BatterySavingStats;)Lcom/android/server/power/batterysaver/BatterySaverPolicy;
+Lcom/android/server/power/ThermalManagerService;-><init>(Landroid/content/Context;)V
+Lcom/android/server/power/ThermalManagerService;-><init>(Landroid/content/Context;Lcom/android/server/power/ThermalManagerService$ThermalHalWrapper;)V
+Lcom/android/server/display/PersistentDataStore$Injector;->openRead()Ljava/io/InputStream;
+Lcom/android/server/pm/PackageManagerService$ReconciledPackage;-><init>(Lcom/android/server/pm/PackageManagerService$InstallArgs;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageManagerService$PackageInstalledInfo;Lcom/android/server/pm/PackageManagerService$PrepareResult;Lcom/android/server/pm/PackageManagerService$ScanResult;Lcom/android/server/pm/PackageManagerService$DeletePackageAction;Ljava/util/List;Landroid/content/pm/PackageParser$SigningDetails;ZZLcom/android/server/pm/PackageManagerService$1;)V
+Lcom/android/server/pm/ComponentResolver;-><init>(Lcom/android/server/pm/UserManagerService;Landroid/content/pm/PackageManagerInternal;Ljava/lang/Object;)V
+Lcom/android/server/wm/LaunchParamsController;->registerDefaultModifiers(Lcom/android/server/wm/ActivityStackSupervisor;)V
+Lcom/android/server/Watchdog$OpenFdMonitor;->create()Lcom/android/server/Watchdog$OpenFdMonitor;
+Lcom/android/server/SystemServiceManager;->warnIfTooLong(JLcom/android/server/SystemService;Ljava/lang/String;)V
+Lcom/android/server/am/UserController$Injector;->getLockPatternUtils()Lcom/android/internal/widget/LockPatternUtils;
+Lcom/android/server/am/PendingIntentController;-><init>(Landroid/os/Looper;Lcom/android/server/am/UserController;)V
+Lcom/android/server/am/BroadcastQueue;-><init>(Lcom/android/server/am/ActivityManagerService;Landroid/os/Handler;Ljava/lang/String;Lcom/android/server/am/BroadcastConstants;Z)V
+Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice$1;->setDisplayState(I)V
+Lcom/android/server/am/BatteryStatsService$WakeupReasonThread;->waitWakeup()Ljava/lang/String;
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 46c2a85..b4ee0b1 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2402,7 +2402,9 @@
 
                 // Update the view states first...
                 mCurrentViewId = viewState.id;
-                viewState.setCurrentValue(value);
+                if (value != null) {
+                    viewState.setCurrentValue(value);
+                }
 
                 if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) {
                     if (sDebug) Slog.d(TAG, "Ignoring VIEW_ENTERED on URL BAR (id=" + id + ")");
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index d5a7c81..dc0bdb3 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -31,14 +31,11 @@
 import android.app.job.JobParameters;
 import android.app.job.JobScheduler;
 import android.app.job.JobService;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.os.Binder;
-import android.os.FileUtils;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.Trace;
@@ -49,13 +46,10 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
-import com.android.server.SystemConfig;
 import com.android.server.SystemService;
 
-import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.Collections;
 import java.util.Set;
 
 /**
@@ -74,64 +68,16 @@
     @VisibleForTesting
     static final String DUMP_RUNNING_USERS_MESSAGE = "Backup Manager is running for users:";
 
-    // The published binder is a singleton Trampoline object that calls through to the proper code.
-    // This indirection lets us turn down the heavy implementation object on the fly without
-    // disturbing binders that have been cached elsewhere in the system.
-    private static Trampoline sInstance;
-
-    static Trampoline getInstance() {
-        // Always constructed during system bring up, so no need to lazy-init.
-        return sInstance;
-    }
-
     private final Context mContext;
     private final Trampoline mTrampoline;
 
     // Keeps track of all unlocked users registered with this service. Indexed by user id.
     private final SparseArray<UserBackupManagerService> mServiceUsers = new SparseArray<>();
 
-    private Set<ComponentName> mTransportWhitelist;
-
-    private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
-                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-                if (userId > 0) { // for only non system users
-                    onRemovedNonSystemUser(userId);
-                }
-            }
-        }
-    };
-
     /** Instantiate a new instance of {@link BackupManagerService}. */
     public BackupManagerService(Context context, Trampoline trampoline) {
         mContext = checkNotNull(context);
         mTrampoline = checkNotNull(trampoline);
-
-        // Set up our transport options.
-        SystemConfig systemConfig = SystemConfig.getInstance();
-        mTransportWhitelist = systemConfig.getBackupTransportWhitelist();
-        if (mTransportWhitelist == null) {
-            mTransportWhitelist = Collections.emptySet();
-        }
-
-        mContext.registerReceiver(mUserRemovedReceiver,
-                new IntentFilter(Intent.ACTION_USER_REMOVED));
-    }
-
-    /**
-     * Remove backup state for non system {@code userId} when the user is removed from the device.
-     * For non system users, backup state is stored in both the user's own dir and the system dir.
-     * When the user is removed, the user's own dir gets removed by the OS. This method ensures that
-     * the part of the user backup state which is in the system dir also gets removed.
-     */
-    private void onRemovedNonSystemUser(int userId) {
-        Slog.i(TAG, "Removing state for non system user " + userId);
-        File dir = UserBackupManagerFiles.getStateDirInSystemDir(userId);
-        if (!FileUtils.deleteContentsAndDir(dir)) {
-            Slog.w(TAG, "Failed to delete state dir for removed user: " + userId);
-        }
     }
 
     /**
@@ -157,7 +103,7 @@
      * UserBackupManagerService} and registering it with this service.
      */
     @VisibleForTesting
-    protected void startServiceForUser(int userId) {
+    protected void startServiceForUser(int userId, Set<ComponentName> transportWhitelist) {
         if (mServiceUsers.get(userId) != null) {
             Slog.i(TAG, "userId " + userId + " already started, so not starting again");
             return;
@@ -165,7 +111,7 @@
 
         UserBackupManagerService userBackupManagerService =
                 UserBackupManagerService.createAndInitializeService(
-                        userId, mContext, mTrampoline, mTransportWhitelist);
+                        userId, mContext, mTrampoline, transportWhitelist);
         startServiceForUser(userId, userBackupManagerService);
     }
 
@@ -195,16 +141,20 @@
     }
 
     boolean isAbleToServeUser(int userId) {
-        return getServiceUsers().get(UserHandle.USER_SYSTEM) != null
-                && getServiceUsers().get(userId) != null;
+        return getUserServices().get(UserHandle.USER_SYSTEM) != null
+                && getUserServices().get(userId) != null;
     }
 
     /**
-     *  Returns a lst of users currently unlocked that have a
-     *  {@link UserBackupManagerService} registered.
+     *  Returns a list of users currently unlocked that have a {@link UserBackupManagerService}
+     *  registered.
+     *
+     *  Warning: Do NOT modify returned object as it's used inside.
+     *
+     *  TODO: Return a copy or only expose read-only information through other means.
      */
     @VisibleForTesting
-    public SparseArray<UserBackupManagerService> getServiceUsers() {
+    public SparseArray<UserBackupManagerService> getUserServices() {
         return mServiceUsers;
     }
 
@@ -370,19 +320,6 @@
                 : userBackupManagerService.listAllTransportComponents();
     }
 
-    /** Report all system whitelisted transports. */
-    @Nullable
-    public String[] getTransportWhitelist() {
-        // No permission check, intentionally.
-        String[] whitelistedTransports = new String[mTransportWhitelist.size()];
-        int i = 0;
-        for (ComponentName component : mTransportWhitelist) {
-            whitelistedTransports[i] = component.flattenToShortString();
-            i++;
-        }
-        return whitelistedTransports;
-    }
-
     /**
      * Update the attributes of the transport identified by {@code transportComponent}. If the
      * specified transport has not been bound at least once (for registration), this call will be
@@ -495,7 +432,8 @@
 
     /**
      * Returns a {@link UserHandle} for the user that has {@code ancestralSerialNumber} as the
-     * serial number of the its ancestral work profile.
+     * serial number of the its ancestral work profile or null if there is no {@link
+     * UserBackupManagerService} associated with that user.
      *
      * <p> The ancestral work profile is set by {@link #setAncestralSerialNumber(long)}
      * and it corresponds to the profile that was used to restore to the callers profile.
@@ -504,16 +442,18 @@
     public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
         int callingUserId = Binder.getCallingUserHandle().getIdentifier();
         long oldId = Binder.clearCallingIdentity();
-        int[] userIds;
+        final int[] userIds;
         try {
-            userIds = mContext.getSystemService(UserManager.class).getProfileIds(callingUserId,
-                    false);
+            userIds =
+                    mContext
+                            .getSystemService(UserManager.class)
+                            .getProfileIds(callingUserId, false);
         } finally {
             Binder.restoreCallingIdentity(oldId);
         }
 
         for (int userId : userIds) {
-            UserBackupManagerService userBackupManagerService = getServiceUsers().get(userId);
+            UserBackupManagerService userBackupManagerService = getUserServices().get(userId);
             if (userBackupManagerService != null) {
                 if (userBackupManagerService.getAncestralSerialNumber() == ancestralSerialNumber) {
                     return UserHandle.of(userId);
@@ -880,28 +820,35 @@
     }
 
     /** Implementation to receive lifecycle event callbacks for system services. */
-    public static final class Lifecycle extends SystemService {
+    public static class Lifecycle extends SystemService {
         public Lifecycle(Context context) {
+            this(context, new Trampoline(context));
+        }
+
+        @VisibleForTesting
+        Lifecycle(Context context, Trampoline trampoline) {
             super(context);
-            sInstance = new Trampoline(context);
+            Trampoline.sInstance = trampoline;
         }
 
         @Override
         public void onStart() {
-            publishBinderService(Context.BACKUP_SERVICE, sInstance);
+            publishService(Context.BACKUP_SERVICE, Trampoline.sInstance);
         }
 
         @Override
         public void onUnlockUser(int userId) {
-            if (userId == UserHandle.USER_SYSTEM) {
-                sInstance.initializeService();
-            }
-            sInstance.unlockUser(userId);
+            Trampoline.sInstance.onUnlockUser(userId);
         }
 
         @Override
         public void onStopUser(int userId) {
-            sInstance.stopUser(userId);
+            Trampoline.sInstance.onStopUser(userId);
+        }
+
+        @VisibleForTesting
+        void publishService(String name, IBinder service) {
+            publishBinderService(name, service);
         }
     }
 }
diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java
index 088e1f9..19a8543 100644
--- a/services/backup/java/com/android/server/backup/FullBackupJob.java
+++ b/services/backup/java/com/android/server/backup/FullBackupJob.java
@@ -91,7 +91,7 @@
             mParamsForUser.put(userId, params);
         }
 
-        Trampoline service = BackupManagerService.getInstance();
+        Trampoline service = Trampoline.getInstance();
         return service.beginFullBackup(userId, this);
     }
 
@@ -105,7 +105,7 @@
             }
         }
 
-        Trampoline service = BackupManagerService.getInstance();
+        Trampoline service = Trampoline.getInstance();
         service.endFullBackup(userId);
 
         return false;
diff --git a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
index ac43fc3..7b5dbd7 100644
--- a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
+++ b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
@@ -144,7 +144,7 @@
         }
 
         // Time to run a key/value backup!
-        Trampoline service = BackupManagerService.getInstance();
+        Trampoline service = Trampoline.getInstance();
         try {
             service.backupNowForUser(userId);
         } catch (RemoteException e) {}
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index f4b6645..59d9c0e 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -16,8 +16,11 @@
 
 package com.android.server.backup;
 
+import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.server.backup.BackupManagerService.TAG;
 
+import static java.util.Collections.emptySet;
+
 import android.Manifest;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -29,10 +32,13 @@
 import android.app.backup.IFullBackupRestoreObserver;
 import android.app.backup.IRestoreSession;
 import android.app.backup.ISelectBackupTransportCallback;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.Binder;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -40,19 +46,21 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemProperties;
-import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
+import com.android.server.SystemConfig;
 import com.android.server.backup.utils.RandomAccessFileUtils;
 
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.Set;
 
 /**
  * A proxy to the {@link BackupManagerService} implementation.
@@ -73,9 +81,6 @@
  * Temporary disabling is controlled by {@link #setBackupServiceActive(int, boolean)} through
  * privileged callers (currently {@link DevicePolicyManager}). This is called on {@link
  * UserHandle#USER_SYSTEM} and disables backup for all users.
- *
- * <p>Creation of the backup service is done when {@link UserHandle#USER_SYSTEM} is unlocked. The
- * system user is unlocked before any other users.
  */
 public class Trampoline extends IBackupManager.Stub {
     /**
@@ -101,6 +106,12 @@
 
     private static final String BACKUP_THREAD = "backup";
 
+    static Trampoline sInstance;
+
+    static Trampoline getInstance() {
+        return checkNotNull(sInstance);
+    }
+
     private final Context mContext;
     private final UserManager mUserManager;
 
@@ -109,8 +120,24 @@
     // TODD(b/121198006): remove this object and synchronized all methods on "this".
     private final Object mStateLock = new Object();
 
-    private volatile BackupManagerService mService;
+    // TODO: This is not marked as final because of test code. Since we'll merge BMS and Trampoline,
+    // it doesn't make sense to refactor for final. It's never null.
+    @VisibleForTesting
+    protected volatile BackupManagerService mService;
     private final Handler mHandler;
+    private final Set<ComponentName> mTransportWhitelist;
+
+    private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+                if (userId > 0) { // for only non system users
+                    mHandler.post(() -> onRemovedNonSystemUser(userId));
+                }
+            }
+        }
+    };
 
     public Trampoline(Context context) {
         mContext = context;
@@ -120,6 +147,18 @@
         handlerThread.start();
         mHandler = new Handler(handlerThread.getLooper());
         mUserManager = UserManager.get(context);
+        mService = new BackupManagerService(mContext, this);
+        Set<ComponentName> transportWhitelist =
+                SystemConfig.getInstance().getBackupTransportWhitelist();
+        mTransportWhitelist = (transportWhitelist == null) ? emptySet() : transportWhitelist;
+        mContext.registerReceiver(
+                mUserRemovedReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED));
+    }
+
+    // TODO: Remove this when we implement DI by injecting in the construtor.
+    @VisibleForTesting
+    Handler getBackupHandler() {
+        return mHandler;
     }
 
     protected boolean isBackupDisabled() {
@@ -150,6 +189,20 @@
         return UserBackupManagerFiles.getStateFileInSystemDir(BACKUP_ACTIVATED_FILENAME, userId);
     }
 
+    /**
+     * Remove backup state for non system {@code userId} when the user is removed from the device.
+     * For non system users, backup state is stored in both the user's own dir and the system dir.
+     * When the user is removed, the user's own dir gets removed by the OS. This method ensures that
+     * the part of the user backup state which is in the system dir also gets removed.
+     */
+    private void onRemovedNonSystemUser(int userId) {
+        Slog.i(TAG, "Removing state for non system user " + userId);
+        File dir = UserBackupManagerFiles.getStateDirInSystemDir(userId);
+        if (!FileUtils.deleteContentsAndDir(dir)) {
+            Slog.w(TAG, "Failed to delete state dir for removed user: " + userId);
+        }
+    }
+
     // TODO (b/124359804) move to util method in FileUtils
     private void createFile(File file) throws IOException {
         if (file.exists()) {
@@ -205,7 +258,7 @@
     // This method should not perform any I/O (e.g. do not call isBackupActivatedForUser),
     // it's used in multiple places where I/O waits would cause system lock-ups.
     private boolean isUserReadyForBackup(int userId) {
-        return mService != null && mService.isAbleToServeUser(userId);
+        return mService.isAbleToServeUser(userId);
     }
 
     /**
@@ -230,68 +283,55 @@
         return mUserManager;
     }
 
-    protected BackupManagerService createBackupManagerService() {
-        return new BackupManagerService(mContext, this);
-    }
-
     protected void postToHandler(Runnable runnable) {
         mHandler.post(runnable);
     }
 
     /**
-     * Called from {@link BackupManagerService.Lifecycle} when the system user is unlocked. Attempts
-     * to initialize {@link BackupManagerService}. Offloads work onto the handler thread {@link
-     * #mHandlerThread} to keep unlock time low.
-     */
-    void initializeService() {
-        postToHandler(
-                () -> {
-                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup init");
-                    if (mGlobalDisable) {
-                        Slog.i(TAG, "Backup service not supported");
-                        return;
-                    }
-                    synchronized (mStateLock) {
-                        if (mService == null) {
-                            mService = createBackupManagerService();
-                        }
-                    }
-                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-                });
-    }
-
-    /**
      * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is unlocked.
      * Starts the backup service for this user if backup is active for this user. Offloads work onto
-     * the handler thread {@link #mHandlerThread} to keep unlock time low.
+     * the handler thread {@link #mHandlerThread} to keep unlock time low since backup is not
+     * essential for device functioning.
      */
-    void unlockUser(int userId) {
+    void onUnlockUser(int userId) {
         postToHandler(() -> startServiceForUser(userId));
     }
 
     private void startServiceForUser(int userId) {
         // We know that the user is unlocked here because it is called from setBackupServiceActive
         // and unlockUser which have these guarantees. So we can check if the file exists.
-        if (mService != null && isBackupActivatedForUser(userId)) {
-            Slog.i(TAG, "Starting service for user: " + userId);
-            mService.startServiceForUser(userId);
+        if (mGlobalDisable) {
+            Slog.i(TAG, "Backup service not supported");
+            return;
         }
+        if (!isBackupActivatedForUser(userId)) {
+            Slog.i(TAG, "Backup not activated for user " + userId);
+            return;
+        }
+        Slog.i(TAG, "Starting service for user: " + userId);
+        mService.startServiceForUser(userId, mTransportWhitelist);
     }
 
     /**
      * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is stopped.
      * Offloads work onto the handler thread {@link #mHandlerThread} to keep stopping time low.
      */
-    void stopUser(int userId) {
+    void onStopUser(int userId) {
         postToHandler(
                 () -> {
-                    if (mService != null) {
+                    if (!mGlobalDisable) {
                         Slog.i(TAG, "Stopping service for user: " + userId);
                         mService.stopServiceForUser(userId);
                     }
                 });
     }
 
+    /** Returns {@link UserBackupManagerService} for user {@code userId}. */
+    @Nullable
+    public UserBackupManagerService getUserService(int userId) {
+        return mService.getUserServices().get(userId);
+    }
+
     /**
      * The system user and managed profiles can only be acted on by callers in the system or root
      * processes. Other users can be acted on by callers who have both android.permission.BACKUP and
@@ -350,9 +390,6 @@
         synchronized (mStateLock) {
             Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active");
             if (makeActive) {
-                if (mService == null) {
-                    mService = createBackupManagerService();
-                }
                 try {
                     activateBackupForUserLocked(userId);
                 } catch (IOException e) {
@@ -380,7 +417,7 @@
                 }
                 //TODO(b/121198006): loop through active users that have work profile and
                 // stop them as well.
-                stopUser(userId);
+                onStopUser(userId);
             }
         }
     }
@@ -388,8 +425,7 @@
     // IBackupManager binder API
 
     /**
-     * Querying activity state of backup service. Calling this method before initialize yields
-     * undefined result.
+     * Querying activity state of backup service.
      *
      * @param userId The user in which the activity state of backup service is queried.
      * @return true if the service is active.
@@ -397,7 +433,7 @@
     @Override
     public boolean isBackupServiceActive(int userId) {
         synchronized (mStateLock) {
-            return mService != null && isBackupActivatedForUser(userId);
+            return !mGlobalDisable && isBackupActivatedForUser(userId);
         }
     }
 
@@ -598,8 +634,8 @@
     @Override
     @Nullable
     public ComponentName getCurrentTransportComponentForUser(int userId) {
-        return (isUserReadyForBackup(userId)) ? mService.getCurrentTransportComponent(userId)
-                : null;
+        return (isUserReadyForBackup(userId))
+                ? mService.getCurrentTransportComponent(userId) : null;
     }
 
     @Override
@@ -614,14 +650,24 @@
 
     @Override
     public ComponentName[] listAllTransportComponentsForUser(int userId) throws RemoteException {
-        return (isUserReadyForBackup(userId)) ? mService.listAllTransportComponents(userId)
-                : null;
+        return (isUserReadyForBackup(userId))
+                ? mService.listAllTransportComponents(userId) : null;
     }
 
     @Override
     public String[] getTransportWhitelist() {
         int userId = binderGetCallingUserId();
-        return (isUserReadyForBackup(userId)) ? mService.getTransportWhitelist() : null;
+        if (!isUserReadyForBackup(userId)) {
+            return null;
+        }
+        // No permission check, intentionally.
+        String[] whitelistedTransports = new String[mTransportWhitelist.size()];
+        int i = 0;
+        for (ComponentName component : mTransportWhitelist) {
+            whitelistedTransports[i] = component.flattenToShortString();
+            i++;
+        }
+        return whitelistedTransports;
     }
 
     @Override
@@ -648,8 +694,8 @@
     @Override
     public String selectBackupTransportForUser(int userId, String transport)
             throws RemoteException {
-        return (isUserReadyForBackup(userId)) ? mService.selectBackupTransport(userId, transport)
-                : null;
+        return (isUserReadyForBackup(userId))
+                ? mService.selectBackupTransport(userId, transport) : null;
     }
 
     @Override
@@ -700,8 +746,8 @@
     @Override
     public Intent getDataManagementIntentForUser(int userId, String transport)
             throws RemoteException {
-        return isUserReadyForBackup(userId) ? mService.getDataManagementIntent(userId, transport)
-                : null;
+        return isUserReadyForBackup(userId)
+                ? mService.getDataManagementIntent(userId, transport) : null;
     }
 
     @Override
@@ -784,15 +830,15 @@
 
     @Override
     @Nullable public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
-        if (mService != null) {
-            return mService.getUserForAncestralSerialNumber(ancestralSerialNumber);
+        if (mGlobalDisable) {
+            return null;
         }
-        return null;
+        return mService.getUserForAncestralSerialNumber(ancestralSerialNumber);
     }
 
     @Override
     public void setAncestralSerialNumber(long ancestralSerialNumber) {
-        if (mService != null) {
+        if (!mGlobalDisable) {
             mService.setAncestralSerialNumber(ancestralSerialNumber);
         }
     }
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index ed4e596..d599aab 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -166,6 +166,53 @@
 
 /** System service that performs backup/restore operations. */
 public class UserBackupManagerService {
+    /**
+     * Wrapper over {@link PowerManager.WakeLock} to prevent double-free exceptions on release()
+     * after quit().
+     */
+    public static class BackupWakeLock {
+        private final PowerManager.WakeLock mPowerManagerWakeLock;
+        private boolean mHasQuit = false;
+
+        public BackupWakeLock(PowerManager.WakeLock powerManagerWakeLock) {
+            mPowerManagerWakeLock = powerManagerWakeLock;
+        }
+
+        /** Acquires the {@link PowerManager.WakeLock} if hasn't been quit. */
+        public synchronized void acquire() {
+            if (mHasQuit) {
+                Slog.v(TAG, "Ignore wakelock acquire after quit: " + mPowerManagerWakeLock.getTag());
+                return;
+            }
+            mPowerManagerWakeLock.acquire();
+        }
+
+        /** Releases the {@link PowerManager.WakeLock} if hasn't been quit. */
+        public synchronized void release() {
+            if (mHasQuit) {
+                Slog.v(TAG, "Ignore wakelock release after quit: " + mPowerManagerWakeLock.getTag());
+                return;
+            }
+            mPowerManagerWakeLock.release();
+        }
+
+        /**
+         * Returns true if the {@link PowerManager.WakeLock} has been acquired but not yet released.
+         */
+        public synchronized boolean isHeld() {
+            return mPowerManagerWakeLock.isHeld();
+        }
+
+        /** Release the {@link PowerManager.WakeLock} till it isn't held. */
+        public synchronized void quit() {
+            while (mPowerManagerWakeLock.isHeld()) {
+                Slog.v(TAG, "Releasing wakelock: " + mPowerManagerWakeLock.getTag());
+                mPowerManagerWakeLock.release();
+            }
+            mHasQuit = true;
+        }
+    }
+
     // Persistently track the need to do a full init.
     private static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
 
@@ -252,7 +299,6 @@
     private final @UserIdInt int mUserId;
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
     private final TransportManager mTransportManager;
-    private final HandlerThread mUserBackupThread;
 
     private final Context mContext;
     private final PackageManager mPackageManager;
@@ -263,7 +309,7 @@
     private final AlarmManager mAlarmManager;
     private final IStorageManager mStorageManager;
     private final BackupManagerConstants mConstants;
-    private final PowerManager.WakeLock mWakelock;
+    private final BackupWakeLock mWakelock;
     private final BackupHandler mBackupHandler;
 
     private final IBackupManager mBackupManagerBinder;
@@ -487,8 +533,7 @@
         mAgentTimeoutParameters.start();
 
         checkNotNull(userBackupThread, "userBackupThread cannot be null");
-        mUserBackupThread = userBackupThread;
-        mBackupHandler = new BackupHandler(this, userBackupThread.getLooper());
+        mBackupHandler = new BackupHandler(this, userBackupThread);
 
         // Set up our bookkeeping
         final ContentResolver resolver = context.getContentResolver();
@@ -588,7 +633,10 @@
         mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);
 
         // Power management
-        mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*-" + userId);
+        mWakelock = new BackupWakeLock(
+                mPowerManager.newWakeLock(
+                        PowerManager.PARTIAL_WAKE_LOCK,
+                        "*backup*-" + userId + "-" + userBackupThread.getThreadId()));
 
         // Set up the various sorts of package tracking we do
         mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
@@ -608,7 +656,7 @@
         mContext.unregisterReceiver(mRunBackupReceiver);
         mContext.unregisterReceiver(mRunInitReceiver);
         mContext.unregisterReceiver(mPackageTrackingReceiver);
-        mUserBackupThread.quit();
+        mBackupHandler.stop();
     }
 
     public @UserIdInt int getUserId() {
@@ -668,7 +716,7 @@
         mSetupComplete = setupComplete;
     }
 
-    public PowerManager.WakeLock getWakelock() {
+    public BackupWakeLock getWakelock() {
         return mWakelock;
     }
 
@@ -679,7 +727,7 @@
     @VisibleForTesting
     public void setWorkSource(@Nullable WorkSource workSource) {
         // TODO: This is for testing, unfortunately WakeLock is final and WorkSource is not exposed
-        mWakelock.setWorkSource(workSource);
+        mWakelock.mPowerManagerWakeLock.setWorkSource(workSource);
     }
 
     public Handler getBackupHandler() {
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index ba153bf..059b1b9 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -23,7 +23,7 @@
 import android.app.backup.RestoreSet;
 import android.content.Intent;
 import android.os.Handler;
-import android.os.Looper;
+import android.os.HandlerThread;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -83,19 +83,47 @@
     // backup task state machine tick
     public static final int MSG_BACKUP_RESTORE_STEP = 20;
     public static final int MSG_OP_COMPLETE = 21;
+    // Release the wakelock. This is used to ensure we don't hold it after
+    // a user is removed. This will also terminate the looper thread.
+    public static final int MSG_STOP = 22;
 
     private final UserBackupManagerService backupManagerService;
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
-    public BackupHandler(UserBackupManagerService backupManagerService, Looper looper) {
-        super(looper);
+    private final HandlerThread mBackupThread;
+    private volatile boolean mIsStopping = false;
+
+    public BackupHandler(
+            UserBackupManagerService backupManagerService, HandlerThread backupThread) {
+        super(backupThread.getLooper());
+        mBackupThread = backupThread;
         this.backupManagerService = backupManagerService;
         mAgentTimeoutParameters = Preconditions.checkNotNull(
                 backupManagerService.getAgentTimeoutParameters(),
                 "Timeout parameters cannot be null");
     }
 
+    /**
+     * Put the BackupHandler into a stopping state where the remaining messages on the queue will be
+     * silently dropped and the {@link WakeLock} held by the {@link UserBackupManagerService} will
+     * then be released.
+     */
+    public void stop() {
+        mIsStopping = true;
+        sendMessage(obtainMessage(BackupHandler.MSG_STOP));
+    }
+
     public void handleMessage(Message msg) {
+        if (msg.what == MSG_STOP) {
+            Slog.v(TAG, "Stopping backup handler");
+            backupManagerService.getWakelock().quit();
+            mBackupThread.quitSafely();
+        }
+
+        if (mIsStopping) {
+            // If we're finishing all other types of messages should be ignored
+            return;
+        }
 
         TransportManager transportManager = backupManagerService.getTransportManager();
         switch (msg.what) {
diff --git a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
index 97711e3..96d61e5 100644
--- a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
+++ b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
@@ -23,7 +23,6 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.os.PowerManager;
 import android.util.Slog;
 
 import com.android.server.backup.UserBackupManagerService;
@@ -57,7 +56,8 @@
 
                 mUserBackupManagerService.clearPendingInits();
 
-                PowerManager.WakeLock wakelock = mUserBackupManagerService.getWakelock();
+                UserBackupManagerService.BackupWakeLock wakelock =
+                        mUserBackupManagerService.getWakelock();
                 wakelock.acquire();
                 OnTaskFinishedListener listener = caller -> wakelock.release();
 
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index 10304c3..5a57cdc 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -34,7 +34,6 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Message;
-import android.os.PowerManager;
 import android.util.Slog;
 
 import com.android.server.backup.TransportManager;
@@ -110,7 +109,7 @@
             // comes in.
             mBackupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
 
-            PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock();
+            UserBackupManagerService.BackupWakeLock wakelock = mBackupManagerService.getWakelock();
             wakelock.acquire();
 
             // Prevent lambda from leaking 'this'
@@ -392,7 +391,7 @@
         Handler backupHandler = mBackupManagerService.getBackupHandler();
         backupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
 
-        PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock();
+        UserBackupManagerService.BackupWakeLock wakelock = mBackupManagerService.getWakelock();
         wakelock.acquire();
         if (MORE_DEBUG) {
             Slog.d(TAG, callerLogString);
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index d162441..fede487 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -2604,8 +2604,7 @@
             mConstants.dumpProto(proto, AlarmManagerServiceDumpProto.SETTINGS);
 
             if (mAppStateTracker != null) {
-                mAppStateTracker.dumpProto(proto,
-                        AlarmManagerServiceDumpProto.FORCE_APP_STANDBY_TRACKER);
+                mAppStateTracker.dumpProto(proto, AlarmManagerServiceDumpProto.APP_STATE_TRACKER);
             }
 
             proto.write(AlarmManagerServiceDumpProto.IS_INTERACTIVE, mInteractive);
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index 3a7b5d6..2c67c50 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -56,8 +56,8 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.StatLogger;
-import com.android.server.ForceAppStandbyTrackerProto.ExemptedPackage;
-import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
+import com.android.server.AppStateTrackerProto.ExemptedPackage;
+import com.android.server.AppStateTrackerProto.RunAnyInBackgroundRestrictedPackages;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -1308,43 +1308,42 @@
         synchronized (mLock) {
             final long token = proto.start(fieldId);
 
-            proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY, mForceAllAppsStandby);
-            proto.write(ForceAppStandbyTrackerProto.IS_SMALL_BATTERY_DEVICE,
-                    isSmallBatteryDevice());
-            proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY_FOR_SMALL_BATTERY,
+            proto.write(AppStateTrackerProto.FORCED_APP_STANDBY_FEATURE_ENABLED,
+                    mForcedAppStandbyEnabled);
+            proto.write(AppStateTrackerProto.FORCE_ALL_APPS_STANDBY,
+                    isForceAllAppsStandbyEnabled());
+            proto.write(AppStateTrackerProto.IS_SMALL_BATTERY_DEVICE, isSmallBatteryDevice());
+            proto.write(AppStateTrackerProto.FORCE_ALL_APPS_STANDBY_FOR_SMALL_BATTERY,
                     mForceAllAppStandbyForSmallBattery);
-            proto.write(ForceAppStandbyTrackerProto.IS_PLUGGED_IN, mIsPluggedIn);
+            proto.write(AppStateTrackerProto.IS_PLUGGED_IN, mIsPluggedIn);
 
             for (int i = 0; i < mActiveUids.size(); i++) {
                 if (mActiveUids.valueAt(i)) {
-                    proto.write(ForceAppStandbyTrackerProto.ACTIVE_UIDS,
-                            mActiveUids.keyAt(i));
+                    proto.write(AppStateTrackerProto.ACTIVE_UIDS, mActiveUids.keyAt(i));
                 }
             }
 
             for (int i = 0; i < mForegroundUids.size(); i++) {
                 if (mForegroundUids.valueAt(i)) {
-                    proto.write(ForceAppStandbyTrackerProto.FOREGROUND_UIDS,
-                            mForegroundUids.keyAt(i));
+                    proto.write(AppStateTrackerProto.FOREGROUND_UIDS, mForegroundUids.keyAt(i));
                 }
             }
 
             for (int appId : mPowerWhitelistedAllAppIds) {
-                proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
+                proto.write(AppStateTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
             }
 
             for (int appId : mPowerWhitelistedUserAppIds) {
-                proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_USER_WHITELIST_APP_IDS, appId);
+                proto.write(AppStateTrackerProto.POWER_SAVE_USER_WHITELIST_APP_IDS, appId);
             }
 
             for (int appId : mTempWhitelistedAppIds) {
-                proto.write(ForceAppStandbyTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
+                proto.write(AppStateTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
             }
 
             for (int i = 0; i < mExemptedPackages.size(); i++) {
                 for (int j = 0; j < mExemptedPackages.sizeAt(i); j++) {
-                    final long token2 = proto.start(
-                            ForceAppStandbyTrackerProto.EXEMPTED_PACKAGES);
+                    final long token2 = proto.start(AppStateTrackerProto.EXEMPTED_PACKAGES);
 
                     proto.write(ExemptedPackage.USER_ID, mExemptedPackages.keyAt(i));
                     proto.write(ExemptedPackage.PACKAGE_NAME, mExemptedPackages.valueAt(i, j));
@@ -1355,14 +1354,14 @@
 
             for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
                 final long token2 = proto.start(
-                        ForceAppStandbyTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES);
+                        AppStateTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES);
                 proto.write(RunAnyInBackgroundRestrictedPackages.UID, uidAndPackage.first);
                 proto.write(RunAnyInBackgroundRestrictedPackages.PACKAGE_NAME,
                         uidAndPackage.second);
                 proto.end(token2);
             }
 
-            mStatLogger.dumpProto(proto, ForceAppStandbyTrackerProto.STATS);
+            mStatLogger.dumpProto(proto, AppStateTrackerProto.STATS);
 
             proto.end(token);
         }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 293ab02..e67ccc4 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -150,7 +150,6 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.Xml;
 
@@ -168,7 +167,6 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.MessageUtils;
-import com.android.internal.util.WakeupMessage;
 import com.android.internal.util.XmlUtils;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.connectivity.AutodestructReference;
@@ -305,7 +303,8 @@
     /** Flag indicating if background data is restricted. */
     private boolean mRestrictBackground;
 
-    final private Context mContext;
+    private final Context mContext;
+    private final Dependencies mDeps;
     // 0 is full bad, 100 is full good
     private int mDefaultInetConditionPublished = 0;
 
@@ -586,11 +585,6 @@
     private NetworkNotificationManager mNotifier;
     private LingerMonitor mLingerMonitor;
 
-    // sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
-    private static final int MIN_NET_ID = 100; // some reserved marks
-    private static final int MAX_NET_ID = 65535 - 0x0400; // Top 1024 bits reserved by IpSecService
-    private int mNextNetId = MIN_NET_ID;
-
     // sequence number of NetworkRequests
     private int mNextNetworkRequestId = 1;
 
@@ -834,19 +828,113 @@
         }
     };
 
+    /**
+     * Dependencies of ConnectivityService, for injection in tests.
+     */
+    @VisibleForTesting
+    public static class Dependencies {
+        /**
+         * Get system properties to use in ConnectivityService.
+         */
+        public MockableSystemProperties getSystemProperties() {
+            return new MockableSystemProperties();
+        }
+
+        /**
+         * Create a HandlerThread to use in ConnectivityService.
+         */
+        public HandlerThread makeHandlerThread() {
+            return new HandlerThread("ConnectivityServiceThread");
+        }
+
+        /**
+         * Get a reference to the NetworkStackClient.
+         */
+        public NetworkStackClient getNetworkStack() {
+            return NetworkStackClient.getInstance();
+        }
+
+        /**
+         * @see Tethering
+         */
+        public Tethering makeTethering(@NonNull Context context,
+                @NonNull INetworkManagementService nms,
+                @NonNull INetworkStatsService statsService,
+                @NonNull INetworkPolicyManager policyManager,
+                @NonNull TetheringDependencies tetheringDeps) {
+            return new Tethering(context, nms, statsService, policyManager,
+                    IoThread.get().getLooper(), getSystemProperties(), tetheringDeps);
+        }
+
+        /**
+         * @see ProxyTracker
+         */
+        public ProxyTracker makeProxyTracker(@NonNull Context context,
+                @NonNull Handler connServiceHandler) {
+            return new ProxyTracker(context, connServiceHandler, EVENT_PROXY_HAS_CHANGED);
+        }
+
+        /**
+         * @see NetIdManager
+         */
+        public NetIdManager makeNetIdManager() {
+            return new NetIdManager();
+        }
+
+        /**
+         * @see NetworkUtils#queryUserAccess(int, int)
+         */
+        public boolean queryUserAccess(int uid, int netId) {
+            return NetworkUtils.queryUserAccess(uid, netId);
+        }
+
+        /**
+         * @see MultinetworkPolicyTracker
+         */
+        public MultinetworkPolicyTracker makeMultinetworkPolicyTracker(
+                @NonNull Context c, @NonNull Handler h, @NonNull Runnable r) {
+            return new MultinetworkPolicyTracker(c, h, r);
+        }
+
+        /**
+         * @see ServiceManager#checkService(String)
+         */
+        public boolean hasService(@NonNull String name) {
+            return ServiceManager.checkService(name) != null;
+        }
+
+        /**
+         * @see IpConnectivityMetrics.Logger
+         */
+        public IpConnectivityMetrics.Logger getMetricsLogger() {
+            return checkNotNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
+                    "no IpConnectivityMetrics service");
+        }
+
+        /**
+         * @see IpConnectivityMetrics
+         */
+        public IIpConnectivityMetrics getIpConnectivityMetrics() {
+            return IIpConnectivityMetrics.Stub.asInterface(
+                    ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
+        }
+    }
+
     public ConnectivityService(Context context, INetworkManagementService netManager,
             INetworkStatsService statsService, INetworkPolicyManager policyManager) {
-        this(context, netManager, statsService, policyManager,
-            getDnsResolver(), new IpConnectivityLog(), NetdService.getInstance());
+        this(context, netManager, statsService, policyManager, getDnsResolver(),
+                new IpConnectivityLog(), NetdService.getInstance(), new Dependencies());
     }
 
     @VisibleForTesting
     protected ConnectivityService(Context context, INetworkManagementService netManager,
             INetworkStatsService statsService, INetworkPolicyManager policyManager,
-            IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd) {
+            IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd, Dependencies deps) {
         if (DBG) log("ConnectivityService starting up");
 
-        mSystemProperties = getSystemProperties();
+        mDeps = checkNotNull(deps, "missing Dependencies");
+        mSystemProperties = mDeps.getSystemProperties();
+        mNetIdManager = mDeps.makeNetIdManager();
 
         mMetricsLog = logger;
         mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
@@ -863,7 +951,7 @@
         mDefaultWifiRequest = createDefaultInternetRequestForTransport(
                 NetworkCapabilities.TRANSPORT_WIFI, NetworkRequest.Type.BACKGROUND_REQUEST);
 
-        mHandlerThread = new HandlerThread("ConnectivityServiceThread");
+        mHandlerThread = mDeps.makeHandlerThread();
         mHandlerThread.start();
         mHandler = new InternalHandler(mHandlerThread.getLooper());
         mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
@@ -881,7 +969,7 @@
                 LocalServices.getService(NetworkPolicyManagerInternal.class),
                 "missing NetworkPolicyManagerInternal");
         mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver");
-        mProxyTracker = makeProxyTracker();
+        mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
 
         mNetd = netd;
         mKeyStore = KeyStore.getInstance();
@@ -949,7 +1037,7 @@
 
         // Do the same for Ethernet, since it's often not specified in the configs, although many
         // devices can use it via USB host adapters.
-        if (mNetConfigs[TYPE_ETHERNET] == null && hasService(Context.ETHERNET_SERVICE)) {
+        if (mNetConfigs[TYPE_ETHERNET] == null && mDeps.hasService(Context.ETHERNET_SERVICE)) {
             mLegacyTypeTracker.addSupportedType(TYPE_ETHERNET);
             mNetworksDefined++;
         }
@@ -969,7 +1057,8 @@
 
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
 
-        mTethering = makeTethering();
+        mTethering = deps.makeTethering(mContext, mNMS, mStatsService, mPolicyManager,
+                makeTetheringDependencies());
 
         mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
 
@@ -1028,7 +1117,7 @@
                 LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
         mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
 
-        mMultinetworkPolicyTracker = createMultinetworkPolicyTracker(
+        mMultinetworkPolicyTracker = mDeps.makeMultinetworkPolicyTracker(
                 mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
         mMultinetworkPolicyTracker.start();
 
@@ -1038,10 +1127,8 @@
         registerPrivateDnsSettingsCallbacks();
     }
 
-    @VisibleForTesting
-    protected Tethering makeTethering() {
-        // TODO: Move other elements into @Overridden getters.
-        final TetheringDependencies deps = new TetheringDependencies() {
+    private TetheringDependencies makeTetheringDependencies() {
+        return new TetheringDependencies() {
             @Override
             public boolean isTetheringSupported() {
                 return ConnectivityService.this.isTetheringSupported();
@@ -1051,14 +1138,6 @@
                 return mDefaultRequest;
             }
         };
-        return new Tethering(mContext, mNMS, mStatsService, mPolicyManager,
-                IoThread.get().getLooper(), new MockableSystemProperties(),
-                deps);
-    }
-
-    @VisibleForTesting
-    protected ProxyTracker makeProxyTracker() {
-        return new ProxyTracker(mContext, mHandler, EVENT_PROXY_HAS_CHANGED);
     }
 
     private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
@@ -1150,22 +1229,6 @@
         return mNextNetworkRequestId++;
     }
 
-    @VisibleForTesting
-    protected int reserveNetId() {
-        synchronized (mNetworkForNetId) {
-            for (int i = MIN_NET_ID; i <= MAX_NET_ID; i++) {
-                int netId = mNextNetId;
-                if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID;
-                // Make sure NetID unused.  http://b/16815182
-                if (!mNetIdInUse.get(netId)) {
-                    mNetIdInUse.put(netId, true);
-                    return netId;
-                }
-            }
-        }
-        throw new IllegalStateException("No free netIds");
-    }
-
     private NetworkState getFilteredNetworkState(int networkType, int uid) {
         if (mLegacyTypeTracker.isTypeSupported(networkType)) {
             final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
@@ -1797,11 +1860,8 @@
         }
     };
 
-    @VisibleForTesting
-    protected void registerNetdEventCallback() {
-        final IIpConnectivityMetrics ipConnectivityMetrics =
-                IIpConnectivityMetrics.Stub.asInterface(
-                        ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
+    private void registerNetdEventCallback() {
+        final IIpConnectivityMetrics ipConnectivityMetrics = mDeps.getIpConnectivityMetrics();
         if (ipConnectivityMetrics == null) {
             Slog.wtf(TAG, "Missing IIpConnectivityMetrics");
             return;
@@ -2237,12 +2297,6 @@
     protected static final String DEFAULT_TCP_BUFFER_SIZES = "4096,87380,110208,4096,16384,110208";
     private static final String DEFAULT_TCP_RWND_KEY = "net.tcp.default_init_rwnd";
 
-    // Overridden for testing purposes to avoid writing to SystemProperties.
-    @VisibleForTesting
-    protected MockableSystemProperties getSystemProperties() {
-        return new MockableSystemProperties();
-    }
-
     private void updateTcpBufferSizes(String tcpBufferSizes) {
         String[] values = null;
         if (tcpBufferSizes != null) {
@@ -2632,8 +2686,9 @@
                     }
                     if (valid != nai.lastValidated) {
                         if (wasDefault) {
-                            metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity(
-                                    SystemClock.elapsedRealtime(), valid);
+                            mDeps.getMetricsLogger()
+                                    .defaultNetworkMetrics().logDefaultNetworkValidity(
+                                            SystemClock.elapsedRealtime(), valid);
                         }
                         final int oldScore = nai.getCurrentScore();
                         nai.lastValidated = valid;
@@ -2968,8 +3023,8 @@
                     final boolean wasDefault = isDefaultNetwork(nai);
                     synchronized (mNetworkForNetId) {
                         mNetworkForNetId.remove(nai.network.netId);
-                        mNetIdInUse.delete(nai.network.netId);
                     }
+                    mNetIdManager.releaseNetId(nai.network.netId);
                     // Just in case.
                     mLegacyTypeTracker.remove(nai, wasDefault);
                 }
@@ -3016,7 +3071,7 @@
             // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
             // whose timestamps tell how long it takes to recover a default network.
             long now = SystemClock.elapsedRealtime();
-            metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
+            mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
         }
         notifyIfacesChangedForNetworkStats();
         // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
@@ -3070,9 +3125,7 @@
             destroyNativeNetwork(nai);
             mDnsManager.removeNetwork(nai.network);
         }
-        synchronized (mNetworkForNetId) {
-            mNetIdInUse.delete(nai.network.netId);
-        }
+        mNetIdManager.releaseNetId(nai.network.netId);
     }
 
     private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
@@ -4156,7 +4209,7 @@
                 return null;
             }
             return getLinkPropertiesProxyInfo(activeNetwork);
-        } else if (queryUserAccess(Binder.getCallingUid(), network.netId)) {
+        } else if (mDeps.queryUserAccess(Binder.getCallingUid(), network.netId)) {
             // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
             // caller may not have.
             return getLinkPropertiesProxyInfo(network);
@@ -4165,10 +4218,6 @@
         return null;
     }
 
-    @VisibleForTesting
-    protected boolean queryUserAccess(int uid, int netId) {
-        return NetworkUtils.queryUserAccess(uid, netId);
-    }
 
     private ProxyInfo getLinkPropertiesProxyInfo(Network network) {
         final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
@@ -4761,7 +4810,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             // Concatenate the range of types onto the range of NetIDs.
-            int id = MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
+            int id = NetIdManager.MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
             mNotifier.setProvNotificationVisible(visible, id, action);
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -5372,10 +5421,9 @@
     @GuardedBy("mNetworkForNetId")
     private final SparseArray<NetworkAgentInfo> mNetworkForNetId = new SparseArray<>();
     // NOTE: Accessed on multiple threads, synchronized with mNetworkForNetId.
-    // An entry is first added to mNetIdInUse, prior to mNetworkForNetId, so
+    // An entry is first reserved with NetIdManager, prior to being added to mNetworkForNetId, so
     // there may not be a strict 1:1 correlation between the two.
-    @GuardedBy("mNetworkForNetId")
-    private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
+    private final NetIdManager mNetIdManager;
 
     // NetworkAgentInfo keyed off its connecting messenger
     // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays
@@ -5477,9 +5525,9 @@
         // satisfies mDefaultRequest.
         final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
         final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
-                new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
-                mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mDnsResolver,
-                mNMS, factorySerialNumber);
+                new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
+                currentScore, mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd,
+                mDnsResolver, mNMS, factorySerialNumber);
         // Make sure the network capabilities reflect what the agent info says.
         nai.setNetworkCapabilities(mixInCapabilities(nai, nc));
         final String extraInfo = networkInfo.getExtraInfo();
@@ -5488,7 +5536,7 @@
         if (DBG) log("registerNetworkAgent " + nai);
         final long token = Binder.clearCallingIdentity();
         try {
-            getNetworkStack().makeNetworkMonitor(
+            mDeps.getNetworkStack().makeNetworkMonitor(
                     nai.network, name, new NetworkMonitorCallbacks(nai));
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -5500,11 +5548,6 @@
         return nai.network.netId;
     }
 
-    @VisibleForTesting
-    protected NetworkStackClient getNetworkStack() {
-        return NetworkStackClient.getInstance();
-    }
-
     private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) {
         nai.onNetworkMonitorCreated(networkMonitor);
         if (VDBG) log("Got NetworkAgent Messenger");
@@ -6313,7 +6356,7 @@
             // Notify system services that this network is up.
             makeDefault(newNetwork);
             // Log 0 -> X and Y -> X default network transitions, where X is the new default.
-            metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
+            mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
                     now, newNetwork, oldDefaultNetwork);
             // Have a new default network, release the transition wakelock in
             scheduleReleaseNetworkTransitionWakelock();
@@ -6990,27 +7033,6 @@
         return nwm.getWatchlistConfigHash();
     }
 
-    @VisibleForTesting
-    MultinetworkPolicyTracker createMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
-        return new MultinetworkPolicyTracker(c, h, r);
-    }
-
-    @VisibleForTesting
-    public WakeupMessage makeWakeupMessage(Context c, Handler h, String s, int cmd, Object obj) {
-        return new WakeupMessage(c, h, s, cmd, 0, 0, obj);
-    }
-
-    @VisibleForTesting
-    public boolean hasService(String name) {
-        return ServiceManager.checkService(name) != null;
-    }
-
-    @VisibleForTesting
-    protected IpConnectivityMetrics.Logger metricsLogger() {
-        return checkNotNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
-                "no IpConnectivityMetrics service");
-    }
-
     private void logNetworkEvent(NetworkAgentInfo nai, int evtype) {
         int[] transports = nai.networkCapabilities.getTransportTypes();
         mMetricsLog.log(nai.network.netId, transports, new NetworkEvent(evtype));
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 173d5b0..e531412 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -181,18 +181,16 @@
 
     @Override
     public boolean remove() throws RemoteException {
-        return getGsiService().removeGsiInstall();
+        return getGsiService().removeGsi();
     }
 
     @Override
-    public boolean setEnable(boolean enable) throws RemoteException {
+    public boolean setEnable(boolean enable, boolean oneShot) throws RemoteException {
         IGsiService gsiService = getGsiService();
         if (enable) {
-            final int status = gsiService.getGsiBootStatus();
-            final boolean singleBoot = (status == IGsiService.BOOT_STATUS_SINGLE_BOOT);
-            return gsiService.setGsiBootable(singleBoot) == 0;
+            return gsiService.enableGsi(oneShot) == 0;
         } else {
-            return gsiService.disableGsiInstall();
+            return gsiService.disableGsi();
         }
     }
 
@@ -200,9 +198,4 @@
     public boolean write(byte[] buf) throws RemoteException {
         return getGsiService().commitGsiChunkFromMemory(buf);
     }
-
-    @Override
-    public boolean commit() throws RemoteException {
-        return getGsiService().setGsiBootable(true) == 0;
-    }
 }
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index fe22dcd..a629b3f 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -750,10 +750,10 @@
         }
     }
 
-    // These values have been reserved in ConnectivityService
+    // These values have been reserved in NetIdManager
     @VisibleForTesting static final int TUN_INTF_NETID_START = 0xFC00;
 
-    @VisibleForTesting static final int TUN_INTF_NETID_RANGE = 0x0400;
+    public static final int TUN_INTF_NETID_RANGE = 0x0400;
 
     private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray();
     private int mNextTunnelNetIdIndex = 0;
diff --git a/services/core/java/com/android/server/NetIdManager.java b/services/core/java/com/android/server/NetIdManager.java
new file mode 100644
index 0000000..11533be
--- /dev/null
+++ b/services/core/java/com/android/server/NetIdManager.java
@@ -0,0 +1,76 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.util.SparseBooleanArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * Class used to reserve and release net IDs.
+ *
+ * <p>Instances of this class are thread-safe.
+ */
+public class NetIdManager {
+    // Sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
+    public static final int MIN_NET_ID = 100; // some reserved marks
+    // Top IDs reserved by IpSecService
+    public static final int MAX_NET_ID = 65535 - IpSecService.TUN_INTF_NETID_RANGE;
+
+    @GuardedBy("mNetIdInUse")
+    private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
+
+    @GuardedBy("mNetIdInUse")
+    private int mLastNetId = MIN_NET_ID - 1;
+
+    /**
+     * Get the first netId that follows the provided lastId and is available.
+     */
+    private static int getNextAvailableNetIdLocked(
+            int lastId, @NonNull SparseBooleanArray netIdInUse) {
+        int netId = lastId;
+        for (int i = MIN_NET_ID; i <= MAX_NET_ID; i++) {
+            netId = netId < MAX_NET_ID ? netId + 1 : MIN_NET_ID;
+            if (!netIdInUse.get(netId)) {
+                return netId;
+            }
+        }
+        throw new IllegalStateException("No free netIds");
+    }
+
+    /**
+     * Reserve a new ID for a network.
+     */
+    public int reserveNetId() {
+        synchronized (mNetIdInUse) {
+            mLastNetId = getNextAvailableNetIdLocked(mLastNetId, mNetIdInUse);
+            // Make sure NetID unused.  http://b/16815182
+            mNetIdInUse.put(mLastNetId, true);
+            return mLastNetId;
+        }
+    }
+
+    /**
+     * Clear a previously reserved ID for a network.
+     */
+    public void releaseNetId(int id) {
+        synchronized (mNetIdInUse) {
+            mNetIdInUse.delete(id);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index b0efd43..49ef164 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -25,6 +25,7 @@
 import android.app.ActivityManagerInternal;
 import android.app.IActivityManager;
 import android.app.IUidObserver;
+import android.app.SearchManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -94,11 +95,23 @@
 
     private static final int KEY_CAMERA = 0;
     private static final int KEY_HOME = 1;
+    private static final int KEY_ASSISTANT = 2;
+
+    // Pin the camera application.
+    private static boolean PROP_PIN_CAMERA = SystemProperties.getBoolean(
+            "pinner.pin_camera", true);
+    // Pin using pinlist.meta when pinning apps.
+    private static boolean PROP_PIN_PINLIST = SystemProperties.getBoolean(
+            "pinner.use_pinlist", true);
+    // Pin the whole odex/vdex/etc file when pinning apps.
+    private static boolean PROP_PIN_ODEX = SystemProperties.getBoolean(
+            "pinner.whole_odex", true);
 
     private static final int MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); // 80MB max for camera app.
     private static final int MAX_HOME_PIN_SIZE = 6 * (1 << 20); // 6MB max for home app.
+    private static final int MAX_ASSISTANT_PIN_SIZE = 60 * (1 << 20); // 60MB max for assistant app.
 
-    @IntDef({KEY_CAMERA, KEY_HOME})
+    @IntDef({KEY_CAMERA, KEY_HOME, KEY_ASSISTANT})
     @Retention(RetentionPolicy.SOURCE)
     public @interface AppKey {}
 
@@ -107,6 +120,7 @@
     private final ActivityManagerInternal mAmInternal;
     private final IActivityManager mAm;
     private final UserManager mUserManager;
+    private SearchManager mSearchManager;
 
     /** The list of the statically pinned files. */
     @GuardedBy("this")
@@ -157,12 +171,21 @@
                 com.android.internal.R.bool.config_pinnerCameraApp);
         boolean shouldPinHome = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_pinnerHomeApp);
+        boolean shouldPinAssistant = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_pinnerAssistantApp);
         if (shouldPinCamera) {
-            mPinKeys.add(KEY_CAMERA);
+            if (PROP_PIN_CAMERA) {
+                mPinKeys.add(KEY_CAMERA);
+            } else if (DEBUG) {
+                Slog.i(TAG, "Pinner - skip pinning camera app");
+            }
         }
         if (shouldPinHome) {
             mPinKeys.add(KEY_HOME);
         }
+        if (shouldPinAssistant) {
+            mPinKeys.add(KEY_ASSISTANT);
+        }
         mPinnerHandler = new PinnerHandler(BackgroundThread.get().getLooper());
 
         mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
@@ -193,6 +216,15 @@
         sendPinAppsMessage(UserHandle.USER_SYSTEM);
     }
 
+    @Override
+    public void onBootPhase(int phase) {
+        // SearchManagerService is started after PinnerService, wait for PHASE_SYSTEM_SERVICES_READY
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
+            sendPinAppsMessage(UserHandle.USER_SYSTEM);
+        }
+    }
+
     /**
      * Repin apps on user switch.
      * <p>
@@ -394,6 +426,14 @@
         return getApplicationInfoForIntent(intent, userHandle, false);
     }
 
+    private ApplicationInfo getAssistantInfo(int userHandle) {
+        if (mSearchManager != null) {
+            Intent intent = mSearchManager.getAssistIntent(false);
+            return getApplicationInfoForIntent(intent, userHandle, true);
+        }
+        return null;
+    }
+
     private ApplicationInfo getApplicationInfoForIntent(Intent intent, int userHandle,
             boolean defaultToSystemApp) {
         if (intent == null) {
@@ -506,6 +546,8 @@
                 return getCameraInfo(userHandle);
             case KEY_HOME:
                 return getHomeInfo(userHandle);
+            case KEY_ASSISTANT:
+                return getAssistantInfo(userHandle);
             default:
                 return null;
         }
@@ -520,6 +562,8 @@
                 return "Camera";
             case KEY_HOME:
                 return "Home";
+            case KEY_ASSISTANT:
+                return "Assistant";
             default:
                 return null;
         }
@@ -534,6 +578,8 @@
                 return MAX_CAMERA_PIN_SIZE;
             case KEY_HOME:
                 return MAX_HOME_PIN_SIZE;
+            case KEY_ASSISTANT:
+                return MAX_ASSISTANT_PIN_SIZE;
             default:
                 return 0;
         }
@@ -589,10 +635,16 @@
             pf = pinFile(file, pinSizeLimit, /*attemptPinIntrospection=*/false);
             if (pf != null) {
                 synchronized (this) {
-                    pinnedApp.mFiles.add(pf);
+                    if (PROP_PIN_ODEX) {
+                      pinnedApp.mFiles.add(pf);
+                    }
                 }
                 if (DEBUG) {
-                    Slog.i(TAG, "Pinned " + pf.fileName);
+                    if (PROP_PIN_ODEX) {
+                        Slog.i(TAG, "Pinned " + pf.fileName);
+                    } else {
+                        Slog.i(TAG, "Pinned [skip] " + pf.fileName);
+                    }
                 }
             }
         }
@@ -686,6 +738,13 @@
      * @return Open input stream or null on any error
      */
     private static InputStream maybeOpenPinMetaInZip(ZipFile zipFile, String fileName) {
+        if (!PROP_PIN_PINLIST) {
+            if (DEBUG) {
+                Slog.i(TAG, "Pin - skip pinlist.meta in " + fileName);
+            }
+            return null;
+        }
+
         ZipEntry pinMetaEntry = zipFile.getEntry(PIN_META_FILENAME);
         InputStream pinMetaStream = null;
         if (pinMetaEntry != null) {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index deff7ef..4fab7c1 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1557,10 +1557,11 @@
     }
 
     private void start() {
-        connect();
+        connectStoraged();
+        connectVold();
     }
 
-    private void connect() {
+    private void connectStoraged() {
         IBinder binder = ServiceManager.getService("storaged");
         if (binder != null) {
             try {
@@ -1569,7 +1570,7 @@
                     public void binderDied() {
                         Slog.w(TAG, "storaged died; reconnecting");
                         mStoraged = null;
-                        connect();
+                        connectStoraged();
                     }
                 }, 0);
             } catch (RemoteException e) {
@@ -1583,7 +1584,17 @@
             Slog.w(TAG, "storaged not found; trying again");
         }
 
-        binder = ServiceManager.getService("vold");
+        if (mStoraged == null) {
+            BackgroundThread.getHandler().postDelayed(() -> {
+                connectStoraged();
+            }, DateUtils.SECOND_IN_MILLIS);
+        } else {
+            onDaemonConnected();
+        }
+    }
+
+    private void connectVold() {
+        IBinder binder = ServiceManager.getService("vold");
         if (binder != null) {
             try {
                 binder.linkToDeath(new DeathRecipient() {
@@ -1591,7 +1602,7 @@
                     public void binderDied() {
                         Slog.w(TAG, "vold died; reconnecting");
                         mVold = null;
-                        connect();
+                        connectVold();
                     }
                 }, 0);
             } catch (RemoteException e) {
@@ -1611,9 +1622,9 @@
             Slog.w(TAG, "vold not found; trying again");
         }
 
-        if (mStoraged == null || mVold == null) {
+        if (mVold == null) {
             BackgroundThread.getHandler().postDelayed(() -> {
-                connect();
+                connectVold();
             }, DateUtils.SECOND_IN_MILLIS);
         } else {
             onDaemonConnected();
@@ -3208,28 +3219,28 @@
             // should be kept in sync with getFreeBytes().
             final File path = storage.findPathForUuid(volumeUuid);
 
-            final long usable = path.getUsableSpace();
-            final long lowReserved = storage.getStorageLowBytes(path);
-            final long fullReserved = storage.getStorageFullBytes(path);
+            long usable = 0;
+            long lowReserved = 0;
+            long fullReserved = 0;
+            long cacheClearable = 0;
 
-            if (stats.isQuotaSupported(volumeUuid)) {
+            if ((flags & StorageManager.FLAG_ALLOCATE_CACHE_ONLY) == 0) {
+                usable = path.getUsableSpace();
+                lowReserved = storage.getStorageLowBytes(path);
+                fullReserved = storage.getStorageFullBytes(path);
+            }
+
+            if ((flags & StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY) == 0
+                    && stats.isQuotaSupported(volumeUuid)) {
                 final long cacheTotal = stats.getCacheBytes(volumeUuid);
                 final long cacheReserved = storage.getStorageCacheBytes(path, flags);
-                final long cacheClearable = Math.max(0, cacheTotal - cacheReserved);
+                cacheClearable = Math.max(0, cacheTotal - cacheReserved);
+            }
 
-                if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
-                    return Math.max(0, (usable + cacheClearable) - fullReserved);
-                } else {
-                    return Math.max(0, (usable + cacheClearable) - lowReserved);
-                }
+            if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
+                return Math.max(0, (usable + cacheClearable) - fullReserved);
             } else {
-                // When we don't have fast quota information, we ignore cached
-                // data and only consider unused bytes.
-                if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
-                    return Math.max(0, usable - fullReserved);
-                } else {
-                    return Math.max(0, usable - lowReserved);
-                }
+                return Math.max(0, (usable + cacheClearable) - lowReserved);
             }
         } catch (IOException e) {
             throw new ParcelableException(e);
@@ -3242,10 +3253,17 @@
     public void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) {
         flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);
 
-        final long allocatableBytes = getAllocatableBytes(volumeUuid, flags, callingPackage);
+        final long allocatableBytes = getAllocatableBytes(volumeUuid,
+                flags | StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY, callingPackage);
         if (bytes > allocatableBytes) {
-            throw new ParcelableException(new IOException("Failed to allocate " + bytes
-                    + " because only " + allocatableBytes + " allocatable"));
+            // If we don't have room without taking cache into account, check to see if we'd have
+            // room if we included freeable cache space.
+            final long cacheClearable = getAllocatableBytes(volumeUuid,
+                    flags | StorageManager.FLAG_ALLOCATE_CACHE_ONLY, callingPackage);
+            if (bytes > allocatableBytes + cacheClearable) {
+                throw new ParcelableException(new IOException("Failed to allocate " + bytes
+                    + " because only " + (allocatableBytes + cacheClearable) + " allocatable"));
+            }
         }
 
         final StorageManager storage = mContext.getSystemService(StorageManager.class);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java b/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java
index 9e5f722..9bf0bd3 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java
@@ -17,6 +17,7 @@
 package com.android.server.accounts;
 
 import android.annotation.NonNull;
+import android.app.ActivityManager;
 import android.os.ShellCommand;
 import android.os.UserHandle;
 
@@ -83,7 +84,7 @@
                 return null;
             }
         }
-        return UserHandle.USER_SYSTEM;
+        return ActivityManager.getCurrentUser();
     }
 
     @Override
@@ -92,9 +93,11 @@
         pw.println("Account manager service commands:");
         pw.println("  help");
         pw.println("    Print this help text.");
-        pw.println("  set-bind-instant-service-allowed [--user <USER_ID>] true|false ");
+        pw.println("  set-bind-instant-service-allowed "
+                + "[--user <USER_ID> (current user if not specified)] true|false ");
         pw.println("    Set whether binding to services provided by instant apps is allowed.");
-        pw.println("  get-bind-instant-service-allowed [--user <USER_ID>]");
+        pw.println("  get-bind-instant-service-allowed "
+                + "[--user <USER_ID> (current user if not specified)]");
         pw.println("    Get whether binding to services provided by instant apps is allowed.");
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4d43e4a..7b20e55 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2373,11 +2373,6 @@
         }
     }
 
-    @VisibleForTesting
-    public ActivityManagerService(Injector injector) {
-        this(injector, null /* handlerThread */);
-    }
-
     /**
      * Provides the basic functionality for activity task related tests when a handler thread is
      * given to initialize the dependency members.
@@ -2424,7 +2419,7 @@
     // handlers to other threads.  So take care to be explicit about the looper.
     public ActivityManagerService(Context systemContext, ActivityTaskManagerService atm) {
         LockGuard.installLock(this, LockGuard.INDEX_ACTIVITY);
-        mInjector = new Injector();
+        mInjector = new Injector(systemContext);
         mContext = systemContext;
 
         mFactoryTest = FactoryTest.getMode();
@@ -5218,6 +5213,10 @@
             }
         }
 
+        // Let the ART runtime in zygote and system_server know that the boot completed.
+        ZYGOTE_PROCESS.bootCompleted();
+        VMRuntime.bootCompleted();
+
         IntentFilter pkgFilter = new IntentFilter();
         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
         pkgFilter.addDataScheme("package");
@@ -8522,32 +8521,6 @@
         }
     }
 
-    void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) {
-        if (pid == Process.myPid()) {
-            Slog.wtf(TAG, "system can't run remote animation");
-            return;
-        }
-        synchronized (ActivityManagerService.this) {
-            final ProcessRecord pr;
-            synchronized (mPidsSelfLocked) {
-                pr = mPidsSelfLocked.get(pid);
-                if (pr == null) {
-                    Slog.w(TAG, "setRunningRemoteAnimation called on unknown pid: " + pid);
-                    return;
-                }
-            }
-            if (pr.runningRemoteAnimation == runningRemoteAnimation) {
-                return;
-            }
-            pr.runningRemoteAnimation = runningRemoteAnimation;
-            if (DEBUG_OOM_ADJ) {
-                Slog.i(TAG, "Setting runningRemoteAnimation=" + pr.runningRemoteAnimation
-                        + " for pid=" + pid);
-            }
-            updateOomAdjLocked(pr, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
-        }
-    }
-
     public final void enterSafeMode() {
         synchronized(this) {
             // It only makes sense to do this before the system is ready
@@ -18102,11 +18075,6 @@
         }
 
         @Override
-        public void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) {
-            ActivityManagerService.this.setRunningRemoteAnimation(pid, runningRemoteAnimation);
-        }
-
-        @Override
         public List<ProcessMemoryState> getMemoryStateForProcesses() {
             List<ProcessMemoryState> processMemoryStates = new ArrayList<>();
             synchronized (mPidsSelfLocked) {
@@ -18930,9 +18898,14 @@
     @VisibleForTesting
     public static class Injector {
         private NetworkManagementInternal mNmi;
+        private Context mContext;
+
+        public Injector(Context context) {
+            mContext = context;
+        }
 
         public Context getContext() {
-            return null;
+            return mContext;
         }
 
         public AppOpsService getAppOpsService(File file, Handler handler) {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 97e5293..7a3d3c2 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1102,10 +1102,13 @@
         // this gives us a baseline and makes sure we don't get into an
         // infinite recursion. If we're re-evaluating due to cycles, use the previously computed
         // values.
-        app.setCurRawAdj(!cycleReEval ? adj : Math.min(adj, app.getCurRawAdj()));
-        app.setCurRawProcState(!cycleReEval
-                ? procState
-                : Math.min(procState, app.getCurRawProcState()));
+        if (cycleReEval) {
+            procState = Math.min(procState, app.getCurRawProcState());
+            adj = Math.min(adj, app.getCurRawAdj());
+            schedGroup = Math.max(schedGroup, app.getCurrentSchedulingGroup());
+        }
+        app.setCurRawAdj(adj);
+        app.setCurRawProcState(procState);
 
         app.hasStartedServices = false;
         app.adjSeq = mAdjSeq;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 563b2f3..ea30842 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -20,6 +20,7 @@
 
 import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityManagerService.MY_PID;
@@ -1348,6 +1349,25 @@
         }
     }
 
+    @Override
+    public void setRunningRemoteAnimation(boolean runningRemoteAnimation) {
+        if (pid == Process.myPid()) {
+            Slog.wtf(TAG, "system can't run remote animation");
+            return;
+        }
+        synchronized (mService) {
+            if (this.runningRemoteAnimation == runningRemoteAnimation) {
+                return;
+            }
+            this.runningRemoteAnimation = runningRemoteAnimation;
+            if (DEBUG_OOM_ADJ) {
+                Slog.i(TAG, "Setting runningRemoteAnimation=" + runningRemoteAnimation
+                        + " for pid=" + pid);
+            }
+            mService.updateOomAdjLocked(this, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
+        }
+    }
+
     public long getInputDispatchingTimeout() {
         return mWindowProcessController.getInputDispatchingTimeout();
     }
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 3007016..6d6a148 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -18,9 +18,11 @@
 
 import static android.app.AppOpsManager.MAX_PRIORITY_UID_STATE;
 import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
+import static android.app.AppOpsManager.OP_CAMERA;
 import static android.app.AppOpsManager.OP_FLAGS_ALL;
 import static android.app.AppOpsManager.OP_NONE;
 import static android.app.AppOpsManager.OP_PLAY_AUDIO;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
 import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
 import static android.app.AppOpsManager.UID_STATE_CACHED;
 import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
@@ -173,6 +175,12 @@
         UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_NONEXISTENT
     };
 
+    private static final int[] OPS_RESTRICTED_ON_SUSPEND = {
+            OP_PLAY_AUDIO,
+            OP_RECORD_AUDIO,
+            OP_CAMERA,
+    };
+
     Context mContext;
     final AtomicFile mFile;
     final Handler mHandler;
@@ -798,7 +806,9 @@
                     final String changedPkg = changedPkgs[i];
                     // We trust packagemanager to insert matching uid and packageNames in the
                     // extras
-                    notifyOpChanged(callbacks, OP_PLAY_AUDIO, changedUid, changedPkg);
+                    for (int code : OPS_RESTRICTED_ON_SUSPEND) {
+                        notifyOpChanged(callbacks, code, changedUid, changedPkg);
+                    }
                 }
             }
         }, packageSuspendFilter);
@@ -1759,6 +1769,9 @@
             return AppOpsManager.opToDefaultMode(code);
         }
 
+        if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
+            return AppOpsManager.MODE_IGNORED;
+        }
         synchronized (this) {
             if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
                 return AppOpsManager.MODE_IGNORED;
@@ -1792,20 +1805,6 @@
     }
 
     private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
-        boolean suspended;
-        try {
-            suspended = isPackageSuspendedForUser(packageName, uid);
-        } catch (IllegalArgumentException ex) {
-            // Package not found.
-            suspended = false;
-        }
-
-        if (suspended) {
-            Slog.i(TAG, "Audio disabled for suspended package=" + packageName
-                    + " for uid=" + uid);
-            return AppOpsManager.MODE_IGNORED;
-        }
-
         synchronized (this) {
             final int mode = checkRestrictionLocked(code, usage, uid, packageName);
             if (mode != AppOpsManager.MODE_ALLOWED) {
@@ -1815,18 +1814,6 @@
         return checkOperation(code, uid, packageName);
     }
 
-    private boolean isPackageSuspendedForUser(String pkg, int uid) {
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return AppGlobals.getPackageManager().isPackageSuspendedForUser(
-                    pkg, UserHandle.getUserId(uid));
-        } catch (RemoteException re) {
-            throw new SecurityException("Could not talk to package manager service");
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
     private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
         final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
         if (usageRestrictions != null) {
@@ -2654,6 +2641,12 @@
         return op;
     }
 
+    private boolean isOpRestrictedDueToSuspend(int code, String packageName, int uid) {
+        final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+        return ArrayUtils.contains(OPS_RESTRICTED_ON_SUSPEND, code)
+                && pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid));
+    }
+
     private boolean isOpRestrictedLocked(int uid, int code, String packageName,
             boolean isPrivileged) {
         int userHandle = UserHandle.getUserId(uid);
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index db55138..65472c9 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -364,28 +364,8 @@
 
                 // check enforcement by the framework
                 boolean handled = false;
-                if (focusLoss == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
-                        && MediaFocusControl.ENFORCE_DUCKING
-                        && frWinner != null) {
-                    // candidate for enforcement by the framework
-                    if (frWinner.mCallingUid != this.mCallingUid) {
-                        if (!forceDuck && ((mGrantFlags
-                                & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0)) {
-                            // the focus loser declared it would pause instead of duck, let it
-                            // handle it (the framework doesn't pause for apps)
-                            handled = false;
-                            Log.v(TAG, "not ducking uid " + this.mCallingUid + " - flags");
-                        } else if (!forceDuck && (MediaFocusControl.ENFORCE_DUCKING_FOR_NEW &&
-                                this.getSdkTarget() <= MediaFocusControl.DUCKING_IN_APP_SDK_LEVEL))
-                        {
-                            // legacy behavior, apps used to be notified when they should be ducking
-                            handled = false;
-                            Log.v(TAG, "not ducking uid " + this.mCallingUid + " - old SDK");
-                        } else {
-                            handled = mFocusController.duckPlayers(frWinner, this, forceDuck);
-                        }
-                    } // else: the focus change is within the same app, so let the dispatching
-                      //       happen as if the framework was not involved.
+                if (frWinner != null) {
+                    handled = frameworkHandleFocusLoss(focusLoss, frWinner, forceDuck);
                 }
 
                 if (handled) {
@@ -415,6 +395,47 @@
         }
     }
 
+    /**
+     * Let the framework handle the focus loss if possible
+     * @param focusLoss
+     * @param frWinner
+     * @param forceDuck
+     * @return true if the framework handled the focus loss
+     */
+    @GuardedBy("MediaFocusControl.mAudioFocusLock")
+    private boolean frameworkHandleFocusLoss(int focusLoss, @NonNull final FocusRequester frWinner,
+                                             boolean forceDuck) {
+        if (frWinner.mCallingUid != this.mCallingUid) {
+            // the focus change is within the same app, so let the dispatching
+            // happen as if the framework was not involved.
+            return false;
+        }
+
+        if (focusLoss == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
+            if (!MediaFocusControl.ENFORCE_DUCKING) {
+                return false;
+            }
+
+            // candidate for enforcement by the framework
+            if (!forceDuck && ((mGrantFlags
+                    & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0)) {
+                // the focus loser declared it would pause instead of duck, let it
+                // handle it (the framework doesn't pause for apps)
+                Log.v(TAG, "not ducking uid " + this.mCallingUid + " - flags");
+                return false;
+            }
+            if (!forceDuck && (MediaFocusControl.ENFORCE_DUCKING_FOR_NEW
+                    && this.getSdkTarget() <= MediaFocusControl.DUCKING_IN_APP_SDK_LEVEL)) {
+                // legacy behavior, apps used to be notified when they should be ducking
+                Log.v(TAG, "not ducking uid " + this.mCallingUid + " - old SDK");
+                return false;
+            }
+
+            return mFocusController.duckPlayers(frWinner, this, forceDuck);
+        }
+        return false;
+    }
+
     int dispatchFocusChange(int focusChange) {
         if (mFocusDispatcher == null) {
             if (MediaFocusControl.DEBUG) { Log.e(TAG, "dispatchFocusChange: no focus dispatcher"); }
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 5c93071..c845981 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -105,12 +105,13 @@
     //=================================================================
     // PlayerFocusEnforcer implementation
     @Override
-    public boolean duckPlayers(FocusRequester winner, FocusRequester loser, boolean forceDuck) {
+    public boolean duckPlayers(@NonNull FocusRequester winner, @NonNull FocusRequester loser,
+                               boolean forceDuck) {
         return mFocusEnforcer.duckPlayers(winner, loser, forceDuck);
     }
 
     @Override
-    public void unduckPlayers(FocusRequester winner) {
+    public void unduckPlayers(@NonNull FocusRequester winner) {
         mFocusEnforcer.unduckPlayers(winner);
     }
 
@@ -742,7 +743,20 @@
         }
     }
 
-    /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */
+    /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int)
+     * @param aa
+     * @param focusChangeHint
+     * @param cb
+     * @param fd
+     * @param clientId
+     * @param callingPackageName
+     * @param flags
+     * @param sdk
+     * @param forceDuck only true if
+     *     {@link android.media.AudioFocusRequest.Builder#setFocusGain(int)} was set to true for
+     *                  accessibility.
+     * @return
+     */
     protected int requestAudioFocus(@NonNull AudioAttributes aa, int focusChangeHint, IBinder cb,
             IAudioFocusDispatcher fd, @NonNull String clientId, @NonNull String callingPackageName,
             int flags, int sdk, boolean forceDuck) {
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 3a25d98..f8ba55b 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -425,7 +425,8 @@
     private final DuckingManager mDuckingManager = new DuckingManager();
 
     @Override
-    public boolean duckPlayers(FocusRequester winner, FocusRequester loser, boolean forceDuck) {
+    public boolean duckPlayers(@NonNull FocusRequester winner, @NonNull FocusRequester loser,
+                               boolean forceDuck) {
         if (DEBUG) {
             Log.v(TAG, String.format("duckPlayers: uids winner=%d loser=%d",
                     winner.getClientUid(), loser.getClientUid()));
@@ -473,7 +474,7 @@
     }
 
     @Override
-    public void unduckPlayers(FocusRequester winner) {
+    public void unduckPlayers(@NonNull FocusRequester winner) {
         if (DEBUG) { Log.v(TAG, "unduckPlayers: uids winner=" + winner.getClientUid()); }
         synchronized (mPlayerLock) {
             mDuckingManager.unduckUid(winner.getClientUid(), mPlayers);
diff --git a/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java b/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java
index 3c834da..89e7b782 100644
--- a/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java
+++ b/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java
@@ -16,6 +16,8 @@
 
 package com.android.server.audio;
 
+import android.annotation.NonNull;
+
 public interface PlayerFocusEnforcer {
 
     /**
@@ -25,11 +27,24 @@
      * @param loser
      * @return
      */
-    public boolean duckPlayers(FocusRequester winner, FocusRequester loser, boolean forceDuck);
+    boolean duckPlayers(@NonNull FocusRequester winner, @NonNull FocusRequester loser,
+                               boolean forceDuck);
 
-    public void unduckPlayers(FocusRequester winner);
+    /**
+     * Unduck the players that had been ducked with
+     * {@link #duckPlayers(FocusRequester, FocusRequester, boolean)}
+     * @param winner
+     */
+    void unduckPlayers(@NonNull FocusRequester winner);
 
-    public void mutePlayersForCall(int[] usagesToMute);
+    /**
+     * Mute players at the beginning of a call
+     * @param usagesToMute array of {@link android.media.AudioAttributes} usages to mute
+     */
+    void mutePlayersForCall(int[] usagesToMute);
 
-    public void unmutePlayersForCall();
+    /**
+     * Unmute players at the end of a call
+     */
+    void unmutePlayersForCall();
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 764fca9..7ab3bdd 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -31,6 +31,7 @@
 import android.util.MutableInt;
 import android.util.Slog;
 
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -186,6 +187,12 @@
 
     @Override
     public void startProgramListUpdates(ProgramList.Filter filter) throws RemoteException {
+        // If the AIDL client provides a null filter, it wants all updates, so use the most broad
+        // filter.
+        if (filter == null) {
+            filter = new ProgramList.Filter(new HashSet<Integer>(),
+                    new HashSet<android.hardware.radio.ProgramSelector.Identifier>(), true, false);
+        }
         synchronized (mLock) {
             checkNotClosedLocked();
             mProgramInfoCache = new ProgramInfoCache(filter);
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 8d1a802..96b7cb3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -580,10 +580,12 @@
         }
 
         if (newExpiry > 0) {
-            mLingerMessage = mConnService.makeWakeupMessage(
+            mLingerMessage = new WakeupMessage(
                     mContext, mHandler,
-                    "NETWORK_LINGER_COMPLETE." + network.netId,
-                    EVENT_NETWORK_LINGER_COMPLETE, this);
+                    "NETWORK_LINGER_COMPLETE." + network.netId /* cmdName */,
+                    EVENT_NETWORK_LINGER_COMPLETE /* cmd */,
+                    0 /* arg1 (unused) */, 0 /* arg2 (unused) */,
+                    this /* obj (NetworkAgentInfo) */);
             mLingerMessage.schedule(newExpiry);
         }
 
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index c45a314..7648636 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -680,6 +680,7 @@
         @Override
         public void onDisplayChanged(int displayId) {
             updateDisplayModes(displayId);
+            mBrightnessObserver.onDisplayChanged(displayId);
         }
 
         private void updateDisplayModes(int displayId) {
@@ -734,8 +735,6 @@
         private AmbientFilter mAmbientFilter;
 
         private final Context mContext;
-        private ScreenStateReceiver mScreenStateReceiver;
-
         // Enable light sensor only when screen is on, peak refresh rate enabled and low power mode
         // off. After initialization, these states will be updated from the same handler thread.
         private boolean mScreenOn = false;
@@ -793,11 +792,7 @@
                     mSensorManager = sensorManager;
                     mLightSensor = lightSensor;
 
-                    // Intent.ACTION_SCREEN_ON is not sticky. Check current screen status.
-                    if (mContext.getSystemService(PowerManager.class).isInteractive()) {
-                        onScreenOn(true);
-                    }
-                    mScreenStateReceiver = new ScreenStateReceiver(mContext);
+                    onScreenOn(isDefaultDisplayOn());
                 }
             }
 
@@ -822,6 +817,12 @@
             }
         }
 
+        public void onDisplayChanged(int displayId) {
+            if (displayId == Display.DEFAULT_DISPLAY) {
+                onScreenOn(isDefaultDisplayOn());
+            }
+        }
+
         public void dumpLocked(PrintWriter pw) {
             pw.println("  BrightnessObserver");
 
@@ -891,8 +892,6 @@
         }
 
         private void onScreenOn(boolean on) {
-            // Not check mShouldObserveAmbientChange because Screen status receiver is registered
-            // only when it is true.
             if (mScreenOn != on) {
                 mScreenOn = on;
                 updateSensorStatus();
@@ -913,6 +912,13 @@
             }
         }
 
+        private boolean isDefaultDisplayOn() {
+            final Display display = mContext.getSystemService(DisplayManager.class)
+                    .getDisplay(Display.DEFAULT_DISPLAY);
+            return display.getState() != Display.STATE_OFF
+                    && mContext.getSystemService(PowerManager.class).isInteractive();
+        }
+
         private final class LightSensorEventListener implements SensorEventListener {
             final private static int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS;
             private float mLastSensorData;
@@ -991,20 +997,5 @@
                 }
             };
         };
-
-        private final class ScreenStateReceiver extends BroadcastReceiver {
-            public ScreenStateReceiver(Context context) {
-                IntentFilter filter = new IntentFilter();
-                filter.addAction(Intent.ACTION_SCREEN_OFF);
-                filter.addAction(Intent.ACTION_SCREEN_ON);
-                filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
-                context.registerReceiver(this, filter, null, mHandler);
-            }
-
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                onScreenOn(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
-            }
-        }
     }
 }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 9510db0..f1f6d50 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -182,7 +182,7 @@
     @IntDef({CHALLENGE_NONE,
             CHALLENGE_FROM_CALLER,
             CHALLENGE_INTERNAL})
-    @interface ChallengeType {};
+    @interface ChallengeType {}
 
     // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
     // Do not call into ActivityManager while holding mSpManager lock.
@@ -1853,26 +1853,11 @@
             return VerifyCredentialResponse.ERROR;
         }
 
-        boolean shouldReEnrollBaseZero = storedHash.type == CREDENTIAL_TYPE_PATTERN
-                && storedHash.isBaseZeroPattern;
-
-        byte[] credentialToVerify;
-        if (shouldReEnrollBaseZero) {
-            credentialToVerify = LockPatternUtils.patternByteArrayToBaseZero(credential);
-        } else {
-            credentialToVerify = credential;
-        }
-
-        response = verifyCredential(userId, storedHash, credentialToVerify,
+        response = verifyCredential(userId, storedHash, credential,
                 challengeType, challenge, progressCallback);
 
         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
             mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
-            if (shouldReEnrollBaseZero) {
-                setLockCredentialInternal(credential, storedHash.type, credentialToVerify,
-                        DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId, false,
-                        /* isLockTiedToParent= */ false);
-            }
         }
 
         return response;
@@ -1937,46 +1922,6 @@
         // of unlocking the user, so yell if calling from the main thread.
         StrictMode.noteDiskRead();
 
-        if (storedHash.version == CredentialHash.VERSION_LEGACY) {
-            final byte[] hash;
-            if (storedHash.type == CREDENTIAL_TYPE_PATTERN) {
-                hash = LockPatternUtils.patternToHash(
-                        LockPatternUtils.byteArrayToPattern(credential));
-            } else {
-                hash = mLockPatternUtils.legacyPasswordToHash(credential, userId).getBytes();
-            }
-            if (Arrays.equals(hash, storedHash.hash)) {
-                if (storedHash.type == CREDENTIAL_TYPE_PATTERN) {
-                    unlockKeystore(LockPatternUtils.patternByteArrayToBaseZero(credential), userId);
-                } else {
-                    unlockKeystore(credential, userId);
-                }
-                // Users with legacy credentials don't have credential-backed
-                // FBE keys, so just pass through a fake token/secret
-                Slog.i(TAG, "Unlocking user with fake token: " + userId);
-                final byte[] fakeToken = String.valueOf(userId).getBytes();
-                unlockUser(userId, fakeToken, fakeToken);
-
-                // migrate credential to GateKeeper
-                setLockCredentialInternal(credential, storedHash.type, null,
-                        storedHash.type == CREDENTIAL_TYPE_PATTERN
-                                ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
-                                : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
-                                /* TODO(roosa): keep the same password quality */,
-                        userId, false, /* isLockTiedToParent= */ false);
-                if (challengeType == CHALLENGE_NONE) {
-                    notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId);
-                    // Use credentials to create recoverable keystore snapshot.
-                    sendCredentialsOnUnlockIfRequired(storedHash.type, credential, userId);
-                    return VerifyCredentialResponse.OK;
-                }
-                // Fall through to get the auth token. Technically this should never happen,
-                // as a user that had a legacy credential would have to unlock their device
-                // before getting to a flow with a challenge, but supporting for consistency.
-            } else {
-                return VerifyCredentialResponse.ERROR;
-            }
-        }
         GateKeeperResponse gateKeeperResponse = getGateKeeperService()
                 .verifyChallenge(userId, challenge, storedHash.hash, credential);
         VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 84ae7c7..29b8aa2 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -77,10 +77,7 @@
 
     private static final String SYSTEM_DIRECTORY = "/system/";
     private static final String LOCK_PATTERN_FILE = "gatekeeper.pattern.key";
-    private static final String BASE_ZERO_LOCK_PATTERN_FILE = "gatekeeper.gesture.key";
-    private static final String LEGACY_LOCK_PATTERN_FILE = "gesture.key";
     private static final String LOCK_PASSWORD_FILE = "gatekeeper.password.key";
-    private static final String LEGACY_LOCK_PASSWORD_FILE = "password.key";
     private static final String CHILD_PROFILE_LOCK_FILE = "gatekeeper.profile.key";
 
     private static final String SYNTHETIC_PASSWORD_DIRECTORY = "spblob/";
@@ -96,59 +93,43 @@
 
     @VisibleForTesting
     public static class CredentialHash {
-        static final int VERSION_LEGACY = 0;
-        static final int VERSION_GATEKEEPER = 1;
+        /** Deprecated private static final int VERSION_LEGACY = 0; */
+        private static final int VERSION_GATEKEEPER = 1;
 
-        private CredentialHash(byte[] hash, @CredentialType int type, int version) {
-            this(hash, type, version, false /* isBaseZeroPattern */);
-        }
-
-        private CredentialHash(
-                byte[] hash, @CredentialType int type, int version, boolean isBaseZeroPattern) {
+        private CredentialHash(byte[] hash, @CredentialType int type) {
             if (type != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
                 if (hash == null) {
-                    throw new RuntimeException("Empty hash for CredentialHash");
+                    throw new IllegalArgumentException("Empty hash for CredentialHash");
                 }
             } else /* type == LockPatternUtils.CREDENTIAL_TYPE_NONE */ {
                 if (hash != null) {
-                    throw new RuntimeException("None type CredentialHash should not have hash");
+                    throw new IllegalArgumentException(
+                            "None type CredentialHash should not have hash");
                 }
             }
             this.hash = hash;
             this.type = type;
-            this.version = version;
-            this.isBaseZeroPattern = isBaseZeroPattern;
-        }
-
-        private static CredentialHash createBaseZeroPattern(byte[] hash) {
-            return new CredentialHash(hash, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
-                    VERSION_GATEKEEPER, true /* isBaseZeroPattern */);
         }
 
         static CredentialHash create(byte[] hash, int type) {
             if (type == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
-                throw new RuntimeException("Bad type for CredentialHash");
+                throw new IllegalArgumentException("Bad type for CredentialHash");
             }
-            return new CredentialHash(hash, type, VERSION_GATEKEEPER);
+            return new CredentialHash(hash, type);
         }
 
         static CredentialHash createEmptyHash() {
-            return new CredentialHash(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
-                    VERSION_GATEKEEPER);
+            return new CredentialHash(null, LockPatternUtils.CREDENTIAL_TYPE_NONE);
         }
 
         byte[] hash;
         @CredentialType int type;
-        int version;
-        boolean isBaseZeroPattern;
 
         public byte[] toBytes() {
-            Preconditions.checkState(!isBaseZeroPattern, "base zero patterns are not serializable");
-
             try {
                 ByteArrayOutputStream os = new ByteArrayOutputStream();
                 DataOutputStream dos = new DataOutputStream(os);
-                dos.write(version);
+                dos.write(VERSION_GATEKEEPER);
                 dos.write(type);
                 if (hash != null && hash.length > 0) {
                     dos.writeInt(hash.length);
@@ -166,7 +147,7 @@
         public static CredentialHash fromBytes(byte[] bytes) {
             try {
                 DataInputStream is = new DataInputStream(new ByteArrayInputStream(bytes));
-                int version = is.read();
+                /* int version = */ is.read();
                 int type = is.read();
                 int hashSize = is.readInt();
                 byte[] hash = null;
@@ -174,7 +155,7 @@
                     hash = new byte[hashSize];
                     is.readFully(hash);
                 }
-                return new CredentialHash(hash, type, version);
+                return new CredentialHash(hash, type);
             } catch (IOException e) {
                 throw new RuntimeException(e);
             }
@@ -269,14 +250,7 @@
     private CredentialHash readPasswordHashIfExists(int userId) {
         byte[] stored = readFile(getLockPasswordFilename(userId));
         if (!ArrayUtils.isEmpty(stored)) {
-            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
-                    CredentialHash.VERSION_GATEKEEPER);
-        }
-
-        stored = readFile(getLegacyLockPasswordFilename(userId));
-        if (!ArrayUtils.isEmpty(stored)) {
-            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
-                    CredentialHash.VERSION_LEGACY);
+            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD);
         }
         return null;
     }
@@ -284,39 +258,22 @@
     private CredentialHash readPatternHashIfExists(int userId) {
         byte[] stored = readFile(getLockPatternFilename(userId));
         if (!ArrayUtils.isEmpty(stored)) {
-            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
-                    CredentialHash.VERSION_GATEKEEPER);
-        }
-
-        stored = readFile(getBaseZeroLockPatternFilename(userId));
-        if (!ArrayUtils.isEmpty(stored)) {
-            return CredentialHash.createBaseZeroPattern(stored);
-        }
-
-        stored = readFile(getLegacyLockPatternFilename(userId));
-        if (!ArrayUtils.isEmpty(stored)) {
-            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
-                    CredentialHash.VERSION_LEGACY);
+            return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN);
         }
         return null;
     }
 
     public CredentialHash readCredentialHash(int userId) {
         CredentialHash passwordHash = readPasswordHashIfExists(userId);
-        CredentialHash patternHash = readPatternHashIfExists(userId);
-        if (passwordHash != null && patternHash != null) {
-            if (passwordHash.version == CredentialHash.VERSION_GATEKEEPER) {
-                return passwordHash;
-            } else {
-                return patternHash;
-            }
-        } else if (passwordHash != null) {
+        if (passwordHash != null) {
             return passwordHash;
-        } else if (patternHash != null) {
-            return patternHash;
-        } else {
-            return CredentialHash.createEmptyHash();
         }
+
+        CredentialHash patternHash = readPatternHashIfExists(userId);
+        if (patternHash != null) {
+            return patternHash;
+        }
+        return CredentialHash.createEmptyHash();
     }
 
     public void removeChildProfileLock(int userId) {
@@ -342,14 +299,11 @@
     }
 
     public boolean hasPassword(int userId) {
-        return hasFile(getLockPasswordFilename(userId)) ||
-            hasFile(getLegacyLockPasswordFilename(userId));
+        return hasFile(getLockPasswordFilename(userId));
     }
 
     public boolean hasPattern(int userId) {
-        return hasFile(getLockPatternFilename(userId)) ||
-            hasFile(getBaseZeroLockPatternFilename(userId)) ||
-            hasFile(getLegacyLockPatternFilename(userId));
+        return hasFile(getLockPatternFilename(userId));
     }
 
     public boolean hasCredential(int userId) {
@@ -470,20 +424,6 @@
     }
 
     @VisibleForTesting
-    String getLegacyLockPatternFilename(int userId) {
-        return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PATTERN_FILE);
-    }
-
-    @VisibleForTesting
-    String getLegacyLockPasswordFilename(int userId) {
-        return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PASSWORD_FILE);
-    }
-
-    private String getBaseZeroLockPatternFilename(int userId) {
-        return getLockCredentialFilePathForUser(userId, BASE_ZERO_LOCK_PATTERN_FILE);
-    }
-
-    @VisibleForTesting
     String getChildProfileLockFile(int userId) {
         return getLockCredentialFilePathForUser(userId, CHILD_PROFILE_LOCK_FILE);
     }
diff --git a/services/core/java/com/android/server/media/OWNERS b/services/core/java/com/android/server/media/OWNERS
index 4bc9373..b460cb5 100644
--- a/services/core/java/com/android/server/media/OWNERS
+++ b/services/core/java/com/android/server/media/OWNERS
@@ -2,5 +2,6 @@
 hdmoon@google.com
 insun@google.com
 jaewan@google.com
+klhyun@google.com
 lajos@google.com
 sungsoo@google.com
diff --git a/services/core/java/com/android/server/om/IdmapDaemon.java b/services/core/java/com/android/server/om/IdmapDaemon.java
new file mode 100644
index 0000000..91824c3
--- /dev/null
+++ b/services/core/java/com/android/server/om/IdmapDaemon.java
@@ -0,0 +1,194 @@
+/*
+ * 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.om;
+
+import static android.content.Context.IDMAP_SERVICE;
+
+import static com.android.server.om.OverlayManagerService.DEBUG;
+import static com.android.server.om.OverlayManagerService.TAG;
+
+import android.os.IBinder;
+import android.os.IIdmap2;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import com.android.server.FgThread;
+
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * To prevent idmap2d from continuously running, the idmap daemon will terminate after 10
+ * seconds without a transaction.
+ **/
+class IdmapDaemon {
+    // The amount of time in milliseconds to wait after a transaction to the idmap service is made
+    // before stopping the service.
+    private static final int SERVICE_TIMEOUT_MS = 10000;
+
+    // The amount of time in milliseconds to wait when attempting to connect to idmap service.
+    private static final int SERVICE_CONNECT_TIMEOUT_MS = 5000;
+
+    private static final Object IDMAP_TOKEN = new Object();
+    private static final String IDMAP_DAEMON = "idmap2d";
+
+    private static IdmapDaemon sInstance;
+    private volatile IIdmap2 mService;
+    private final AtomicInteger mOpenedCount = new AtomicInteger();
+
+    /**
+     * An {@link AutoCloseable} connection to the idmap service. When the connection is closed or
+     * finalized, the idmap service will be stopped after a period of time unless another connection
+     * to the service is open.
+     **/
+    private class Connection implements AutoCloseable {
+        private boolean mOpened = true;
+
+        private Connection() {
+            synchronized (IDMAP_TOKEN) {
+                mOpenedCount.incrementAndGet();
+            }
+        }
+
+        @Override
+        public void close() {
+            synchronized (IDMAP_TOKEN) {
+                if (!mOpened) {
+                    return;
+                }
+
+                mOpened = false;
+                if (mOpenedCount.decrementAndGet() != 0) {
+                    // Only post the callback to stop the service if the service does not have an
+                    // open connection.
+                    return;
+                }
+
+                FgThread.getHandler().postDelayed(() -> {
+                    synchronized (IDMAP_TOKEN) {
+                        // Only stop the service if the service does not have an open connection.
+                        if (mService == null || mOpenedCount.get() != 0) {
+                            return;
+                        }
+
+                        stopIdmapService();
+                        mService = null;
+                    }
+                }, IDMAP_TOKEN, SERVICE_TIMEOUT_MS);
+            }
+        }
+    }
+
+    static IdmapDaemon getInstance() {
+        if (sInstance == null) {
+            sInstance = new IdmapDaemon();
+        }
+        return sInstance;
+    }
+
+    String createIdmap(String targetPath, String overlayPath, int policies, boolean enforce,
+            int userId) throws Exception {
+        try (Connection connection = connect()) {
+            return mService.createIdmap(targetPath, overlayPath, policies, enforce, userId);
+        }
+    }
+
+    boolean removeIdmap(String overlayPath, int userId) throws Exception {
+        try (Connection connection = connect()) {
+            return mService.removeIdmap(overlayPath, userId);
+        }
+    }
+
+    boolean verifyIdmap(String overlayPath, int policies, boolean enforce, int userId)
+            throws Exception {
+        try (Connection connection = connect()) {
+            return mService.verifyIdmap(overlayPath, policies, enforce, userId);
+        }
+    }
+
+    String getIdmapPath(String overlayPath, int userId) throws Exception {
+        try (Connection connection = connect()) {
+            return mService.getIdmapPath(overlayPath, userId);
+        }
+    }
+
+    static void startIdmapService() {
+        SystemProperties.set("ctl.start", IDMAP_DAEMON);
+    }
+
+    static void stopIdmapService() {
+        SystemProperties.set("ctl.stop", IDMAP_DAEMON);
+    }
+
+    private Connection connect() throws Exception {
+        synchronized (IDMAP_TOKEN) {
+            FgThread.getHandler().removeCallbacksAndMessages(IDMAP_TOKEN);
+            if (mService != null) {
+                // Not enough time has passed to stop the idmap service. Reuse the existing
+                // interface.
+                return new Connection();
+            }
+
+            // Start the idmap service if it is not currently running.
+            startIdmapService();
+
+            // Block until the service is found.
+            FutureTask<IBinder> bindIdmap = new FutureTask<>(() -> {
+                while (true) {
+                    try {
+                        IBinder binder = ServiceManager.getService(IDMAP_SERVICE);
+                        if (binder != null) {
+                            return binder;
+                        }
+                    } catch (Exception e) {
+                        Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not retrieved; "
+                                + e.getMessage());
+                    }
+                    Thread.sleep(100);
+                }
+            });
+
+            IBinder binder;
+            try {
+                FgThread.getHandler().postAtFrontOfQueue(bindIdmap);
+                binder = bindIdmap.get(SERVICE_CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            } catch (Exception rethrow) {
+                Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not found;");
+                throw rethrow;
+            }
+
+            try {
+                binder.linkToDeath(() -> {
+                    Slog.w(TAG, "service '" + IDMAP_SERVICE + "' died");
+                }, 0);
+            } catch (RemoteException rethrow) {
+                Slog.e(TAG, "service '" + IDMAP_SERVICE + "' failed to be bound");
+                throw rethrow;
+            }
+
+            mService = IIdmap2.Stub.asInterface(binder);
+            if (DEBUG) {
+                Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected");
+            }
+
+            return new Connection();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 1f20968..288ef0e 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -16,9 +16,6 @@
 
 package com.android.server.om;
 
-import static android.content.Context.IDMAP_SERVICE;
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-
 import static com.android.server.om.OverlayManagerService.DEBUG;
 import static com.android.server.om.OverlayManagerService.TAG;
 
@@ -27,15 +24,11 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.os.Build.VERSION_CODES;
-import android.os.IBinder;
 import android.os.IIdmap2;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.Slog;
 
-import com.android.internal.os.BackgroundThread;
 import com.android.server.om.OverlayManagerServiceImpl.PackageManagerHelper;
 import com.android.server.pm.Installer;
 
@@ -51,11 +44,6 @@
  */
 class IdmapManager {
     private static final boolean FEATURE_FLAG_IDMAP2 = true;
-
-    private final Installer mInstaller;
-    private final PackageManagerHelper mPackageManager;
-    private IIdmap2 mIdmap2Service;
-
     private static final boolean VENDOR_IS_Q_OR_LATER;
     static {
         final String value = SystemProperties.get("ro.vndk.version", "29");
@@ -70,12 +58,14 @@
         VENDOR_IS_Q_OR_LATER = isQOrLater;
     }
 
+    private final Installer mInstaller;
+    private final PackageManagerHelper mPackageManager;
+    private final IdmapDaemon mIdmapDaemon;
+
     IdmapManager(final Installer installer, final PackageManagerHelper packageManager) {
         mInstaller = installer;
         mPackageManager = packageManager;
-        if (FEATURE_FLAG_IDMAP2) {
-            connectToIdmap2d();
-        }
+        mIdmapDaemon = IdmapDaemon.getInstance();
     }
 
     boolean createIdmap(@NonNull final PackageInfo targetPackage,
@@ -91,11 +81,11 @@
             if (FEATURE_FLAG_IDMAP2) {
                 int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId);
                 boolean enforce = enforceOverlayable(overlayPackage);
-                if (mIdmap2Service.verifyIdmap(overlayPath, policies, enforce, userId)) {
+                if (mIdmapDaemon.verifyIdmap(overlayPath, policies, enforce, userId)) {
                     return true;
                 }
-                return mIdmap2Service.createIdmap(targetPath, overlayPath, policies, enforce,
-                    userId) != null;
+                return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies,
+                        enforce, userId) != null;
             } else {
                 mInstaller.idmap(targetPath, overlayPath, sharedGid);
                 return true;
@@ -113,7 +103,7 @@
         }
         try {
             if (FEATURE_FLAG_IDMAP2) {
-                return mIdmap2Service.removeIdmap(oi.baseCodePath, userId);
+                return mIdmapDaemon.removeIdmap(oi.baseCodePath, userId);
             } else {
                 mInstaller.removeIdmap(oi.baseCodePath);
                 return true;
@@ -137,7 +127,7 @@
             final int userId) {
         if (FEATURE_FLAG_IDMAP2) {
             try {
-                return mIdmap2Service.getIdmapPath(overlayPackagePath, userId);
+                return mIdmapDaemon.getIdmapPath(overlayPackagePath, userId);
             } catch (Exception e) {
                 Slog.w(TAG, "failed to get idmap path for " + overlayPackagePath + ": "
                         + e.getMessage());
@@ -151,35 +141,6 @@
         }
     }
 
-    private void connectToIdmap2d() {
-        IBinder binder = ServiceManager.getService(IDMAP_SERVICE);
-        if (binder != null) {
-            try {
-                binder.linkToDeath(new IBinder.DeathRecipient() {
-                    @Override
-                    public void binderDied() {
-                        Slog.w(TAG, "service '" + IDMAP_SERVICE + "' died; reconnecting...");
-                        connectToIdmap2d();
-                    }
-
-                }, 0);
-            } catch (RemoteException e) {
-                binder = null;
-            }
-        }
-        if (binder != null) {
-            mIdmap2Service = IIdmap2.Stub.asInterface(binder);
-            if (DEBUG) {
-                Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected");
-            }
-        } else {
-            Slog.w(TAG, "service '" + IDMAP_SERVICE + "' not found; trying again...");
-            BackgroundThread.getHandler().postDelayed(() -> {
-                connectToIdmap2d();
-            }, SECOND_IN_MILLIS);
-        }
-    }
-
     /**
      * Checks if overlayable and policies should be enforced on the specified overlay for backwards
      * compatibility with pre-Q overlays.
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index da69986..ce95181 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -262,6 +262,7 @@
 
             initIfNeeded();
             onSwitchUser(UserHandle.USER_SYSTEM);
+            IdmapDaemon.stopIdmapService();
 
             publishBinderService(Context.OVERLAY_SERVICE, mService);
             publishLocalService(OverlayManagerService.class, this);
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index c98a79a..714bbb9 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -297,19 +297,5 @@
             }
             mDs.asBinder().unlinkToDeath(this, 0);
         }
-
-        // Old methods; unused in the API flow.
-        @Override
-        public void onProgressUpdated(int progress) throws RemoteException {
-        }
-
-        @Override
-        public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
-        }
-
-        @Override
-        public void onSectionComplete(String title, int status, int size, int durationMs)
-                throws RemoteException {
-        }
     }
 }
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 8f38026..5eaddf9 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -686,7 +686,7 @@
 
         // Prune first installed instant apps
         synchronized (mService.mLock) {
-            allUsers = PackageManagerService.sUserManager.getUserIds();
+            allUsers = mService.mUserManager.getUserIds();
 
             final int packageCount = mService.mPackages.size();
             for (int i = 0; i < packageCount; i++) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2b99221..3f6d4df 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -118,7 +118,6 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
 import android.app.IActivityManager;
@@ -768,6 +767,26 @@
             T produce(Injector injector, PackageManagerService packageManager);
         }
 
+        static class LocalServicesProducer<T> implements Producer<T> {
+            private final Class<T> mProducingClass;
+            LocalServicesProducer(Class<T> clazz) {
+                this.mProducingClass = clazz;
+            }
+            public T produce(Injector injector, PackageManagerService packageManager) {
+                return LocalServices.getService(mProducingClass);
+            }
+        }
+
+        static class SystemServiceProducer<T> implements Producer<T> {
+            private final Class<T> mProducingClass;
+            SystemServiceProducer(Class<T> clazz) {
+                this.mProducingClass = clazz;
+            }
+            public T produce(Injector injector, PackageManagerService packageManager) {
+                return packageManager.mContext.getSystemService(mProducingClass);
+            }
+        }
+
         @VisibleForTesting(visibility = Visibility.PRIVATE)
         static class Singleton<T> {
             private final Producer<T> mProducer;
@@ -783,6 +802,8 @@
             }
         }
 
+        private PackageManagerService mPackageManager;
+
         private final PackageAbiHelper mAbiHelper;
         private final Context mContext;
         private final Object mLock;
@@ -790,19 +811,35 @@
         private final Object mInstallLock;
 
         // ----- producers -----
-
         private final Singleton<ComponentResolver> mComponentResolverProducer;
         private final Singleton<PermissionManagerServiceInternal> mPermissionManagerProducer;
         private final Singleton<UserManagerService> mUserManagerProducer;
         private final Singleton<Settings> mSettingsProducer;
-        private PackageManagerService mPackageManager;
+        private final Singleton<ActivityTaskManagerInternal> mActivityTaskManagerProducer;
+        private final Singleton<DeviceIdleController.LocalService> mLocalDeviceIdleController;
+        private final Singleton<StorageManagerInternal> mStorageManagerInternalProducer;
+        private final Singleton<NetworkPolicyManagerInternal> mNetworkPolicyManagerProducer;
+        private final Singleton<PermissionPolicyInternal> mPermissionPolicyProducer;
+        private final Singleton<DeviceStorageMonitorInternal> mDeviceStorageMonitorProducer;
+        private final Singleton<DisplayManager> mDisplayManagerProducer;
+        private final Singleton<StorageManager> mStorageManagerProducer;
+        private final Singleton<AppOpsManager> mAppOpsManagerProducer;
 
         Injector(Context context, Object lock, Installer installer,
                 Object installLock, PackageAbiHelper abiHelper,
                 Producer<ComponentResolver> componentResolverProducer,
                 Producer<PermissionManagerServiceInternal> permissionManagerProducer,
                 Producer<UserManagerService> userManagerProducer,
-                Producer<Settings> settingsProducer) {
+                Producer<Settings> settingsProducer,
+                Producer<ActivityTaskManagerInternal> activityTaskManagerProducer,
+                Producer<DeviceIdleController.LocalService> deviceIdleControllerProducer,
+                Producer<StorageManagerInternal> storageManagerInternalProducer,
+                Producer<NetworkPolicyManagerInternal> networkPolicyManagerProducer,
+                Producer<PermissionPolicyInternal> permissionPolicyProvider,
+                Producer<DeviceStorageMonitorInternal> deviceStorageMonitorProducer,
+                Producer<DisplayManager> displayManagerProducer,
+                Producer<StorageManager> storageManagerProducer,
+                Producer<AppOpsManager> appOpsManagerProducer) {
             mContext = context;
             mLock = lock;
             mInstaller = installer;
@@ -812,6 +849,15 @@
             mPermissionManagerProducer = new Singleton<>(permissionManagerProducer);
             mUserManagerProducer = new Singleton<>(userManagerProducer);
             mSettingsProducer = new Singleton<>(settingsProducer);
+            mActivityTaskManagerProducer = new Singleton<>(activityTaskManagerProducer);
+            mLocalDeviceIdleController = new Singleton<>(deviceIdleControllerProducer);
+            mStorageManagerInternalProducer = new Singleton<>(storageManagerInternalProducer);
+            mNetworkPolicyManagerProducer = new Singleton<>(networkPolicyManagerProducer);
+            mPermissionPolicyProducer = new Singleton<>(permissionPolicyProvider);
+            mDeviceStorageMonitorProducer = new Singleton<>(deviceStorageMonitorProducer);
+            mDisplayManagerProducer = new Singleton<>(displayManagerProducer);
+            mStorageManagerProducer = new Singleton<>(storageManagerProducer);
+            mAppOpsManagerProducer = new Singleton<>(appOpsManagerProducer);
         }
 
         /**
@@ -822,7 +868,7 @@
             this.mPackageManager = pm;
         }
 
-        public UserManagerInternal getUserManager() {
+        public UserManagerInternal getUserManagerInternal() {
             return getUserManagerService().getInternalForInjectorOnly();
         }
 
@@ -861,6 +907,42 @@
         public Settings getSettings() {
             return mSettingsProducer.get(this, mPackageManager);
         }
+
+        public ActivityTaskManagerInternal getActivityTaskManagerInternal() {
+            return mActivityTaskManagerProducer.get(this, mPackageManager);
+        }
+
+        public DeviceIdleController.LocalService getLocalDeviceIdleController() {
+            return mLocalDeviceIdleController.get(this, mPackageManager);
+        }
+
+        public StorageManagerInternal getStorageManagerInternal() {
+            return mStorageManagerInternalProducer.get(this, mPackageManager);
+        }
+
+        public NetworkPolicyManagerInternal getNetworkPolicyManagerInternal() {
+            return mNetworkPolicyManagerProducer.get(this, mPackageManager);
+        }
+
+        public PermissionPolicyInternal getPermissionPolicyInternal() {
+            return mPermissionPolicyProducer.get(this, mPackageManager);
+        }
+
+        public DeviceStorageMonitorInternal getDeviceStorageMonitorInternal() {
+            return mDeviceStorageMonitorProducer.get(this, mPackageManager);
+        }
+
+        public DisplayManager getDisplayManager() {
+            return mDisplayManagerProducer.get(this, mPackageManager);
+        }
+
+        public StorageManager getStorageManager() {
+            return mStorageManagerProducer.get(this, mPackageManager);
+        }
+
+        public AppOpsManager getAppOpsManager() {
+            return mAppOpsManagerProducer.get(this, mPackageManager);
+        }
     }
 
     private final AppsFilter mAppsFilter;
@@ -1077,12 +1159,6 @@
     // List of packages names to keep cached, even if they are uninstalled for all users
     private List<String> mKeepUninstalledPackages;
 
-    private ActivityManagerInternal mActivityManagerInternal;
-    private ActivityTaskManagerInternal mActivityTaskManagerInternal;
-    private StorageManagerInternal mStorageManagerInternal;
-
-    private DeviceIdleController.LocalService mDeviceIdleController;
-
     private File mCacheDir;
 
     private Future<?> mPrepareAppDataFuture;
@@ -1173,7 +1249,8 @@
             final BroadcastOptions options = BroadcastOptions.makeBasic();
             options.setTemporaryAppWhitelistDuration(whitelistTimeout);
 
-            DeviceIdleController.LocalService idleController = getDeviceIdleController();
+            DeviceIdleController.LocalService idleController =
+                    mInjector.getLocalDeviceIdleController();
             idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                     mIntentFilterVerifierComponent.getPackageName(), whitelistTimeout,
                     UserHandle.USER_SYSTEM, true, "intent filter verifier");
@@ -1440,7 +1517,7 @@
     private static final long DEFAULT_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD =
             2 * 60 * 60 * 1000L; /* two hours */
 
-    static UserManagerService sUserManager;
+    UserManagerService mUserManager;
 
     // Stores a list of users whose package restrictions file needs to be updated
     private ArraySet<Integer> mDirtyUsers = new ArraySet<>();
@@ -2037,8 +2114,7 @@
                 // Send broadcast package appeared if external for all users
                 if (isExternal(res.pkg)) {
                     if (!update) {
-                        final StorageManager storage =
-                                mContext.getSystemService(StorageManager.class);
+                        final StorageManager storage = mInjector.getStorageManager();
                         VolumeInfo volume =
                                 storage.findVolumeByUuid(
                                         res.pkg.applicationInfo.storageUuid.toString());
@@ -2229,7 +2305,7 @@
 
                     // Clean up any users or apps that were removed or recreated
                     // while this volume was missing
-                    sUserManager.reconcileUsers(volumeUuid);
+                    mUserManager.reconcileUsers(volumeUuid);
                     reconcileApps(volumeUuid);
 
                     // Clean up any install sessions that expired or were
@@ -2314,9 +2390,9 @@
 
     void scheduleWritePackageRestrictionsLocked(int userId) {
         final int[] userIds = (userId == UserHandle.USER_ALL)
-                ? sUserManager.getUserIds() : new int[]{userId};
+                ? mUserManager.getUserIds() : new int[]{userId};
         for (int nextUserId : userIds) {
-            if (!sUserManager.exists(nextUserId)) return;
+            if (!mUserManager.exists(nextUserId)) return;
             mDirtyUsers.add(nextUserId);
             if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
                 mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY);
@@ -2334,8 +2410,8 @@
         final Object lock = new Object();
         final Object installLock = new Object();
 
-        Injector injector = new Injector(context, lock, installer, installLock,
-                new PackageAbiHelperImpl(),
+        Injector injector = new Injector(
+                context, lock, installer, installLock, new PackageAbiHelperImpl(),
                 (i, pm) ->
                         new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
                 (i, pm) ->
@@ -2347,7 +2423,16 @@
                 (i, pm) ->
                         new Settings(Environment.getDataDirectory(),
                                 i.getPermissionManagerServiceInternal().getPermissionSettings(),
-                                lock));
+                                lock),
+                new Injector.LocalServicesProducer<>(ActivityTaskManagerInternal.class),
+                new Injector.LocalServicesProducer<>(DeviceIdleController.LocalService.class),
+                new Injector.LocalServicesProducer<>(StorageManagerInternal.class),
+                new Injector.LocalServicesProducer<>(NetworkPolicyManagerInternal.class),
+                new Injector.LocalServicesProducer<>(PermissionPolicyInternal.class),
+                new Injector.LocalServicesProducer<>(DeviceStorageMonitorInternal.class),
+                new Injector.SystemServiceProducer<>(DisplayManager.class),
+                new Injector.SystemServiceProducer<>(StorageManager.class),
+                new Injector.SystemServiceProducer<>(AppOpsManager.class));
 
         PackageManagerService m = new PackageManagerService(injector, factoryTest, onlyCore);
         t.traceEnd(); // "create package manager"
@@ -2403,9 +2488,8 @@
         }
     }
 
-    private static void getDefaultDisplayMetrics(Context context, DisplayMetrics metrics) {
-        DisplayManager displayManager = (DisplayManager) context.getSystemService(
-                Context.DISPLAY_SERVICE);
+    private static void getDefaultDisplayMetrics(
+            DisplayManager displayManager, DisplayMetrics metrics) {
         displayManager.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(metrics);
     }
 
@@ -2469,13 +2553,12 @@
         // Expose private service for system components to use.
         mPmInternal = new PackageManagerInternalImpl();
         LocalServices.addService(PackageManagerInternal.class, mPmInternal);
-        sUserManager = injector.getUserManagerService();
+        mUserManager = injector.getUserManagerService();
         mComponentResolver = injector.getComponentResolver();
         mPermissionManager = injector.getPermissionManagerServiceInternal();
         mSettings = injector.getSettings();
         mPermissionManagerService = (IPermissionManager) ServiceManager.getService("permissionmgr");
 
-
         // CHECKSTYLE:ON IndentationCheck
         t.traceEnd();
 
@@ -2524,7 +2607,7 @@
 
         mViewCompiler = new ViewCompiler(mInstallLock, mInstaller);
 
-        getDefaultDisplayMetrics(mContext, mMetrics);
+        getDefaultDisplayMetrics(mInjector.getDisplayManager(), mMetrics);
 
         t.traceBegin("get system config");
         SystemConfig systemConfig = SystemConfig.getInstance();
@@ -2580,7 +2663,7 @@
             t.traceEnd();
 
             t.traceBegin("read user settings");
-            mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
+            mFirstBoot = !mSettings.readLPw(mUserManager.getUsers(false));
             t.traceEnd();
 
             // Clean up orphaned packages for which the code path doesn't exist
@@ -3235,7 +3318,7 @@
             // boot, then we need to initialize the default preferred apps across
             // all defined users.
             if (!mOnlyCore && (mPromoteSystemApps || mFirstBoot)) {
-                for (UserInfo user : sUserManager.getUsers(true)) {
+                for (UserInfo user : mUserManager.getUsers(true)) {
                     mSettings.applyDefaultPreferredAppsLPw(user.id);
                     primeDomainVerificationsLPw(user.id);
                 }
@@ -4121,7 +4204,7 @@
     }
 
     private PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         if (ps == null) {
             return null;
         }
@@ -4224,7 +4307,7 @@
 
     @Override
     public boolean isPackageAvailable(String packageName, int userId) {
-        if (!sUserManager.exists(userId)) return false;
+        if (!mUserManager.exists(userId)) return false;
         final int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/, "is package available");
@@ -4267,7 +4350,7 @@
      */
     private PackageInfo getPackageInfoInternal(String packageName, long versionCode,
             int flags, int filterCallingUid, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForPackage(flags, userId, packageName);
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 false /* requireFullPermission */, false /* checkShell */, "get package info");
@@ -4568,7 +4651,7 @@
 
     @Override
     public int getPackageUid(String packageName, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return -1;
+        if (!mUserManager.exists(userId)) return -1;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForPackage(flags, userId, packageName);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -4598,7 +4681,7 @@
 
     @Override
     public int[] getPackageGids(String packageName, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForPackage(flags, userId, packageName);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -4642,7 +4725,7 @@
     @GuardedBy("mLock")
     private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
             int filterCallingUid, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         PackageSetting ps = mSettings.mPackages.get(packageName);
         if (ps != null) {
             if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
@@ -4681,7 +4764,7 @@
      */
     private ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
             int filterCallingUid, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForApplication(flags, userId, packageName);
 
         if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
@@ -4795,7 +4878,7 @@
      * until the requested bytes are available.
      */
     public void freeStorage(String volumeUuid, long bytes, int storageFlags) throws IOException {
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         final File file = storage.findPathForUuid(volumeUuid);
         if (file.getUsableSpace() >= bytes) return;
 
@@ -4878,14 +4961,14 @@
 
     private boolean pruneUnusedStaticSharedLibraries(long neededSpace, long maxCachePeriod)
             throws IOException {
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         final File volume = storage.findPathForUuid(StorageManager.UUID_PRIVATE_INTERNAL);
 
         List<VersionedPackage> packagesToDelete = null;
         final long now = System.currentTimeMillis();
 
         synchronized (mLock) {
-            final int[] allUsers = sUserManager.getUserIds();
+            final int[] allUsers = mUserManager.getUserIds();
             final int libCount = mSharedLibraries.size();
             for (int i = 0; i < libCount; i++) {
                 final LongSparseArray<SharedLibraryInfo> versionedLib
@@ -4957,7 +5040,7 @@
             // give them what they want
         } else {
             // Caller expressed no opinion, so match based on user state
-            if (mInjector.getUserManager().isUserUnlockingOrUnlocked(userId)) {
+            if (mUserManager.isUserUnlockingOrUnlocked(userId)) {
                 flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
             } else {
                 flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -4966,36 +5049,6 @@
         return flags;
     }
 
-    private ActivityManagerInternal getActivityManagerInternal() {
-        if (mActivityManagerInternal == null) {
-            mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
-        }
-        return mActivityManagerInternal;
-    }
-
-    private ActivityTaskManagerInternal getActivityTaskManagerInternal() {
-        if (mActivityTaskManagerInternal == null) {
-            mActivityTaskManagerInternal =
-                    LocalServices.getService(ActivityTaskManagerInternal.class);
-        }
-        return mActivityTaskManagerInternal;
-    }
-
-    private DeviceIdleController.LocalService getDeviceIdleController() {
-        if (mDeviceIdleController == null) {
-            mDeviceIdleController =
-                    LocalServices.getService(DeviceIdleController.LocalService.class);
-        }
-        return mDeviceIdleController;
-    }
-
-    private StorageManagerInternal getStorageManagerInternal() {
-        if (mStorageManagerInternal == null) {
-            mStorageManagerInternal = LocalServices.getService(StorageManagerInternal.class);
-        }
-        return mStorageManagerInternal;
-    }
-
     /**
      * Update given flags when being used to request {@link PackageInfo}.
      */
@@ -5010,7 +5063,7 @@
                     "MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission at "
                     + Debug.getCallers(5));
         } else if ((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0 && isCallerSystemUser
-                && sUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) {
+                && mUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) {
             // If the caller wants all packages and has a restricted profile associated with it,
             // then match all users. This is to make sure that launchers that need to access work
             // profile apps don't start breaking. TODO: Remove this hack when launchers stop using
@@ -5107,7 +5160,7 @@
      */
     private ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
             int filterCallingUid, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, component);
 
         if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
@@ -5138,7 +5191,7 @@
     }
 
     private boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId) {
-        if (!getActivityTaskManagerInternal().isCallerRecents(callingUid)) {
+        if (!mInjector.getActivityTaskManagerInternal().isCallerRecents(callingUid)) {
             return false;
         }
         final long token = Binder.clearCallingIdentity();
@@ -5147,7 +5200,7 @@
             if (ActivityManager.getCurrentUser() != callingUserId) {
                 return false;
             }
-            return sUserManager.isSameProfileGroup(callingUserId, targetUserId);
+            return mUserManager.isSameProfileGroup(callingUserId, targetUserId);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -5187,7 +5240,7 @@
 
     @Override
     public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForComponent(flags, userId, component);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -5213,7 +5266,7 @@
     @Override
     public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(String packageName,
             int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0");
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return null;
@@ -5295,7 +5348,7 @@
 
         Preconditions.checkNotNull(packageName, "packageName cannot be null");
         Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0");
-        if (!sUserManager.exists(userId)) {
+        if (!mUserManager.exists(userId)) {
             return null;
         }
 
@@ -5402,7 +5455,7 @@
 
     @Override
     public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForComponent(flags, userId, component);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -5427,7 +5480,7 @@
 
     @Override
     public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForComponent(flags, userId, component);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -6127,7 +6180,7 @@
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
 
-            if (!sUserManager.exists(userId)) return null;
+            if (!mUserManager.exists(userId)) return null;
             final int callingUid = Binder.getCallingUid();
             flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart);
             mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -6152,7 +6205,7 @@
             throw new SecurityException(
                     "findPersistentPreferredActivity can only be run by the system");
         }
-        if (!sUserManager.exists(userId)) {
+        if (!mUserManager.exists(userId)) {
             return null;
         }
         final int callingUid = Binder.getCallingUid();
@@ -6465,7 +6518,7 @@
             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
                     + " is holding mPackages", new Throwable());
         }
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         final int callingUid = Binder.getCallingUid();
         // Do NOT hold the packages lock; this calls up into the settings provider which
         // could cause a deadlock.
@@ -6694,7 +6747,7 @@
     private UserInfo getProfileParent(int userId) {
         final long identity = Binder.clearCallingIdentity();
         try {
-            return sUserManager.getProfileParent(userId);
+            return mUserManager.getProfileParent(userId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -6753,7 +6806,7 @@
     private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
             String resolvedType, int flags, int filterCallingUid, int userId,
             boolean resolveForStart, boolean allowDynamicSplits) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         final String instantAppPkgName = getInstantAppPackageName(filterCallingUid);
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 false /* requireFullPermission */, false /* checkShell */,
@@ -7027,7 +7080,7 @@
 
     private CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
             String resolvedType, int flags, int sourceUserId, int parentUserId) {
-        if (!sUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
+        if (!mUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
                 sourceUserId)) {
             return null;
         }
@@ -7088,7 +7141,7 @@
     private boolean isUserEnabled(int userId) {
         long callingId = Binder.clearCallingIdentity();
         try {
-            UserInfo userInfo = sUserManager.getUserInfo(userId);
+            UserInfo userInfo = mUserManager.getUserInfo(userId);
             return userInfo != null && userInfo.isEnabled();
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -7493,7 +7546,7 @@
         long ident = Binder.clearCallingIdentity();
         boolean targetIsProfile;
         try {
-            targetIsProfile = sUserManager.getUserInfo(targetUserId).isManagedProfile();
+            targetIsProfile = mUserManager.getUserInfo(targetUserId).isManagedProfile();
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -7532,7 +7585,7 @@
     private @NonNull List<ResolveInfo> queryIntentActivityOptionsInternal(ComponentName caller,
             Intent[] specifics, String[] specificTypes, Intent intent,
             String resolvedType, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         final int callingUid = Binder.getCallingUid();
         flags = updateFlagsForResolve(flags, userId, intent, callingUid,
                 false /*includeInstantApps*/);
@@ -7715,7 +7768,7 @@
 
     private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
             String resolvedType, int flags, int userId, boolean allowDynamicSplits) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         final int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/,
@@ -7805,7 +7858,7 @@
 
     private ResolveInfo resolveServiceInternal(Intent intent, String resolvedType, int flags,
             int userId, int callingUid) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForResolve(
                 flags, userId, intent, callingUid, false /*includeInstantApps*/);
         List<ResolveInfo> query = queryIntentServicesInternal(
@@ -7831,7 +7884,7 @@
     private @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
             String resolvedType, int flags, int userId, int callingUid,
             boolean includeInstantApps) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/,
                 "query intent receivers");
@@ -7950,7 +8003,7 @@
 
     private @NonNull List<ResolveInfo> queryIntentContentProvidersInternal(
             Intent intent, String resolvedType, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         final int callingUid = Binder.getCallingUid();
         final String instantAppPkgName = getInstantAppPackageName(callingUid);
         flags = updateFlagsForResolve(flags, userId, intent, callingUid,
@@ -8065,7 +8118,7 @@
         if (getInstantAppPackageName(callingUid) != null) {
             return ParceledListSlice.emptyList();
         }
-        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForPackage(flags, userId, null);
         final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
         final boolean listApex = (flags & MATCH_APEX) != 0;
@@ -8165,7 +8218,7 @@
     @Override
     public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
             String[] permissions, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForPackage(flags, userId, permissions);
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 true /* requireFullPermission */, false /* checkShell */,
@@ -8207,7 +8260,7 @@
         if (getInstantAppPackageName(callingUid) != null) {
             return Collections.emptyList();
         }
-        if (!sUserManager.exists(userId)) return Collections.emptyList();
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
         flags = updateFlagsForApplication(flags, userId, null);
         final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
 
@@ -8437,7 +8490,7 @@
     }
 
     private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!mUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, name);
         final int callingUid = Binder.getCallingUid();
         final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId);
@@ -8476,7 +8529,7 @@
         final int callingUid = Binder.getCallingUid();
         final int userId = processName != null ? UserHandle.getUserId(uid)
                 : UserHandle.getCallingUserId();
-        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForComponent(flags, userId, processName);
         ArrayList<ProviderInfo> finalList = null;
         final List<ProviderInfo> matchList =
@@ -9852,7 +9905,7 @@
     }
 
     private int[] resolveUserIds(int userId) {
-        return (userId == UserHandle.USER_ALL) ? sUserManager.getUserIds() : new int[] { userId };
+        return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
     }
 
     private void clearAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
@@ -10248,7 +10301,7 @@
                     if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) {
                         final int flags = pkg.isUpdatedSystemApp()
                                 ? PackageManager.DELETE_KEEP_DATA : 0;
-                        deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(),
+                        deletePackageLIF(pkg.packageName, null, true, mUserManager.getUserIds(),
                                 flags , null, true, null);
                     }
                     Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
@@ -10588,14 +10641,15 @@
         final String realPkgName = request.realPkgName;
         final List<String> changedAbiCodePath = result.changedAbiCodePath;
         final PackageSetting pkgSetting;
+        if (request.pkgSetting != null && request.pkgSetting.sharedUser != null
+                && request.pkgSetting.sharedUser != result.pkgSetting.sharedUser) {
+            // shared user changed, remove from old shared user
+            request.pkgSetting.sharedUser.removePackage(request.pkgSetting);
+        }
         if (result.existingSettingCopied) {
             pkgSetting = request.pkgSetting;
             pkgSetting.updateFrom(result.pkgSetting);
             pkg.mExtras = pkgSetting;
-            if (pkgSetting.sharedUser != null
-                    && pkgSetting.sharedUser.removePackage(result.pkgSetting)) {
-                pkgSetting.sharedUser.addPackage(pkgSetting);
-            }
         } else {
             pkgSetting = result.pkgSetting;
             if (originalPkgSetting != null) {
@@ -10605,6 +10659,9 @@
                 mTransferedPackages.add(originalPkgSetting.name);
             }
         }
+        if (pkgSetting.sharedUser != null) {
+            pkgSetting.sharedUser.addPackage(pkgSetting);
+        }
         // TODO(toddke): Consider a method specifically for modifying the Package object
         // post scan; or, moving this stuff out of the Package object since it has nothing
         // to do with the package on disk.
@@ -10817,7 +10874,7 @@
             boolean isUnderFactoryTest, long currentTime)
             throws PackageManagerException {
         final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
-        final UserManagerInternal userManager = injector.getUserManager();
+        final UserManagerInternal userManager = injector.getUserManagerInternal();
         final PackageParser.Package pkg = request.pkg;
         PackageSetting pkgSetting = request.pkgSetting;
         final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
@@ -12385,10 +12442,10 @@
      * automatically without needing an explicit launch.
      * Send it a LOCKED_BOOT_COMPLETED/BOOT_COMPLETED if it would ordinarily have gotten ones.
      */
-    private void sendBootCompletedBroadcastToSystemApp(String packageName, boolean includeStopped,
-            int userId) {
+    private void sendBootCompletedBroadcastToSystemApp(
+            String packageName, boolean includeStopped, int userId) {
         // If user is not running, the app didn't miss any broadcast
-        if (!mInjector.getUserManager().isUserRunning(userId)) {
+        if (!mUserManager.isUserRunning(userId)) {
             return;
         }
         final IActivityManager am = ActivityManager.getService();
@@ -12404,7 +12461,7 @@
                     android.app.AppOpsManager.OP_NONE, null, false, false, userId);
 
             // Deliver BOOT_COMPLETED only if user is unlocked
-            if (mInjector.getUserManager().isUserUnlockingOrUnlocked(userId)) {
+            if (mUserManager.isUserUnlockingOrUnlocked(userId)) {
                 Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED).setPackage(packageName);
                 if (includeStopped) {
                     bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
@@ -12682,7 +12739,7 @@
                     // only allow the existing package to be used if it's installed as a full
                     // application for at least one user
                     boolean installAllowed = false;
-                    for (int checkUserId : sUserManager.getUserIds()) {
+                    for (int checkUserId : mUserManager.getUserIds()) {
                         installAllowed = !pkgSetting.getInstantApp(checkUserId);
                         if (installAllowed) {
                             break;
@@ -12764,7 +12821,7 @@
                 pkgSetting.setInstantApp(false /*instantApp*/, userId);
             }
         } else {
-            for (int currentUserId : injector.getUserManager().getUserIds()) {
+            for (int currentUserId : injector.getUserManagerInternal().getUserIds()) {
                 if (instantApp && !pkgSetting.getInstantApp(currentUserId)) {
                     pkgSetting.setInstantApp(true /*instantApp*/, currentUserId);
                 } else if (fullApp && pkgSetting.getInstantApp(currentUserId)) {
@@ -12775,7 +12832,7 @@
     }
 
     boolean isUserRestricted(int userId, String restrictionKey) {
-        Bundle restrictions = sUserManager.getUserRestrictions(userId);
+        Bundle restrictions = mUserManager.getUserRestrictions(userId);
         if (restrictions.getBoolean(restrictionKey, false)) {
             Log.w(TAG, "User is restricted: " + restrictionKey);
             return true;
@@ -13013,7 +13070,7 @@
      * @param affectedUser The user for which the changes are taking place.
      */
     void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
-        final int[] userIds = (affectedUser == UserHandle.USER_ALL) ? sUserManager.getUserIds()
+        final int[] userIds = (affectedUser == UserHandle.USER_ALL) ? mUserManager.getUserIds()
                 : new int[] {affectedUser};
         for (int userId : userIds) {
             unsuspendForSuspendingPackages(packageName::equals, userId);
@@ -13369,7 +13426,7 @@
      * @return default verification response code
      */
     private int getDefaultVerificationResponse(UserHandle user) {
-        if (sUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) {
+        if (mUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) {
             return PackageManager.VERIFICATION_REJECT;
         }
         return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
@@ -13415,7 +13472,7 @@
                         && mInstantAppInstallerActivity.packageName.equals(
                                 mRequiredVerifierPackage)) {
                     try {
-                        mContext.getSystemService(AppOpsManager.class)
+                        mInjector.getAppOpsManager()
                                 .checkPackage(installerUid, mRequiredVerifierPackage);
                         if (DEBUG_VERIFY) {
                             Slog.i(TAG, "disable verification for instant app");
@@ -13636,7 +13693,7 @@
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             throw new SecurityException("Instant applications don't have access to this method");
         }
-        mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
+        mInjector.getAppOpsManager().checkPackage(Binder.getCallingUid(),
                 callerPackageName);
         synchronized (mLock) {
             PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -13781,7 +13838,7 @@
 
             final String packageName = res.pkg.applicationInfo.packageName;
             final String seInfo = res.pkg.applicationInfo.seInfo;
-            final int[] allUsers = sUserManager.getUserIds();
+            final int[] allUsers = mUserManager.getUserIds();
             final int[] installedUsers;
 
             final PackageSetting ps;
@@ -14454,7 +14511,8 @@
                     final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
                             receivers, verificationState);
 
-                    DeviceIdleController.LocalService idleController = getDeviceIdleController();
+                    DeviceIdleController.LocalService idleController =
+                            mInjector.getLocalDeviceIdleController();
                     final long idleDuration = getVerificationTimeout();
 
                     /*
@@ -14526,7 +14584,7 @@
                     synchronized (mLock) {
                         PackageSetting ps = mSettings.getPackageLPr(pkgLite.packageName);
                         if (ps != null) {
-                            installedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(),
+                            installedUsers = ps.queryInstalledUsers(mUserManager.getUserIds(),
                                     true);
                         } else {
                             installedUsers = new int[0];
@@ -15046,7 +15104,7 @@
             final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid),
                     move.dataAppName);
             Slog.d(TAG, "Cleaning up " + move.packageName + " on " + volumeUuid);
-            final int[] userIds = sUserManager.getUserIds();
+            final int[] userIds = mUserManager.getUserIds();
             synchronized (mInstallLock) {
                 // Clean up both app data and code
                 // All package moves are frozen until finished
@@ -15327,7 +15385,7 @@
 
                 // Set install reason for users that are having the package newly installed.
                 if (userId == UserHandle.USER_ALL) {
-                    for (int currentUserId : sUserManager.getUserIds()) {
+                    for (int currentUserId : mUserManager.getUserIds()) {
                         if (!previousUserIds.contains(currentUserId)) {
                             ps.setInstallReason(installReason, currentUserId);
                         }
@@ -15960,7 +16018,7 @@
 
             final PackageSetting ps = mSettings.mPackages.get(packageName);
             if (ps != null) {
-                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+                res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
                 ps.setUpdateAvailable(false /*updateAvailable*/);
             }
             final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
@@ -15971,7 +16029,7 @@
                 PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                 if (childPs != null) {
                     childRes.newUsers = childPs.queryInstalledUsers(
-                            sUserManager.getUserIds(), true);
+                            mUserManager.getUserIds(), true);
                 }
             }
             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
@@ -16091,7 +16149,7 @@
                 try {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
                     commitRequest = new CommitRequest(reconciledPackages,
-                            sUserManager.getUserIds());
+                            mUserManager.getUserIds());
                     commitPackagesLocked(commitRequest);
                     success = true;
                 } finally {
@@ -16387,7 +16445,7 @@
                     PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                     if (childPs != null) {
                         childRes.origUsers = childPs.queryInstalledUsers(
-                                sUserManager.getUserIds(), true);
+                                mUserManager.getUserIds(), true);
                     }
                     if ((mPackages.containsKey(childPkg.packageName))) {
                         childRes.removedInfo = new PackageRemovedInfo(this);
@@ -16552,7 +16610,7 @@
                     systemApp = (ps.pkg.applicationInfo.flags &
                             ApplicationInfo.FLAG_SYSTEM) != 0;
                 }
-                res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+                res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
             }
 
 
@@ -16811,7 +16869,7 @@
                     }
 
                     // In case of rollback, remember per-user/profile install state
-                    allUsers = sUserManager.getUserIds();
+                    allUsers = mUserManager.getUserIds();
                     installedUsers = ps.queryInstalledUsers(allUsers, true);
 
 
@@ -17322,7 +17380,7 @@
             return;
         }
         final boolean deleteAllUsers = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0;
-        final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{userId};
+        final int[] users = deleteAllUsers ? mUserManager.getUserIds() : new int[]{userId};
         if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
@@ -17572,7 +17630,7 @@
                 // Does it contain a device admin for any user?
                 int[] users;
                 if (userId == UserHandle.USER_ALL) {
-                    users = sUserManager.getUserIds();
+                    users = mUserManager.getUserIds();
                 } else {
                     users = new int[]{userId};
                 }
@@ -17649,7 +17707,7 @@
             // allow removing a package if it provides a lib others depend on.
             pkg = mPackages.get(packageName);
 
-            allUsers = sUserManager.getUserIds();
+            allUsers = mUserManager.getUserIds();
 
             if (pkg != null && pkg.staticSharedLibName != null) {
                 SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(pkg.staticSharedLibName,
@@ -17899,7 +17957,7 @@
             outInfo.isStaticSharedLib = deletedPkg != null
                     && deletedPkg.staticSharedLibName != null;
             outInfo.populateUsers(deletedPs == null ? null
-                    : deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true), deletedPs);
+                    : deletedPs.queryInstalledUsers(mUserManager.getUserIds(), true), deletedPs);
         }
 
         removePackageLI(deletedPs.name, (flags & PackageManager.DELETE_CHATTY) != 0);
@@ -17998,7 +18056,8 @@
         if (removedAppId != -1) {
             // A user ID was deleted here. Go through all users and remove it
             // from KeyStore.
-            removeKeystoreDataIfNeeded(UserHandle.USER_ALL, removedAppId);
+            removeKeystoreDataIfNeeded(
+                    mInjector.getUserManagerInternal(), UserHandle.USER_ALL, removedAppId);
         }
     }
 
@@ -18505,7 +18564,7 @@
                 if (!systemApp) {
                     // Do not uninstall the APK if an app should be cached
                     boolean keepUninstalledPackage = shouldKeepUninstalledPackageLPr(packageName);
-                    if (ps.isAnyInstalled(sUserManager.getUserIds()) || keepUninstalledPackage) {
+                    if (ps.isAnyInstalled(mUserManager.getUserIds()) || keepUninstalledPackage) {
                         // Other users still have this package installed, so all
                         // we need to do is clear this user's data and save that
                         // it is uninstalled.
@@ -18619,7 +18678,7 @@
     @GuardedBy("mLock")
     private void markPackageUninstalledForUserLPw(PackageSetting ps, UserHandle user) {
         final int[] userIds = (user == null || user.getIdentifier() == UserHandle.USER_ALL)
-                ? sUserManager.getUserIds() : new int[] {user.getIdentifier()};
+                ? mUserManager.getUserIds() : new int[] {user.getIdentifier()};
         for (int nextUserId : userIds) {
             if (DEBUG_REMOVE) {
                 Slog.d(TAG, "Marking package:" + ps.name + " uninstalled for user:" + nextUserId);
@@ -18656,7 +18715,7 @@
 
         destroyAppProfilesLIF(pkg);
 
-        final int[] userIds = (userId == UserHandle.USER_ALL) ? sUserManager.getUserIds()
+        final int[] userIds = (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds()
                 : new int[] {userId};
         for (int nextUserId : userIds) {
             if (DEBUG_REMOVE) {
@@ -18667,7 +18726,7 @@
             destroyAppDataLIF(pkg, nextUserId,
                     FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
             clearDefaultBrowserIfNeededForUser(ps.name, nextUserId);
-            removeKeystoreDataIfNeeded(nextUserId, ps.appId);
+            removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), nextUserId, ps.appId);
             final SparseBooleanArray changedUsers = new SparseBooleanArray();
             clearPackagePreferredActivitiesLPw(ps.name, changedUsers, nextUserId);
             if (changedUsers.size() > 0) {
@@ -18800,9 +18859,9 @@
                 FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
 
         final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
-        removeKeystoreDataIfNeeded(userId, appId);
+        removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), userId, appId);
 
-        UserManagerInternal umInternal = mInjector.getUserManager();
+        UserManagerInternal umInternal = mInjector.getUserManagerInternal();
         final int flags;
         if (umInternal.isUserUnlockingOrUnlocked(userId)) {
             flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
@@ -18817,14 +18876,14 @@
     }
 
     private void resetNetworkPolicies(int userId) {
-        LocalServices.getService(NetworkPolicyManagerInternal.class).resetUserState(userId);
+        mInjector.getNetworkPolicyManagerInternal().resetUserState(userId);
     }
 
     /**
      * Remove entries from the keystore daemon. Will only remove it if the
      * {@code appId} is valid.
      */
-    private static void removeKeystoreDataIfNeeded(int userId, int appId) {
+    private static void removeKeystoreDataIfNeeded(UserManagerInternal um, int userId, int appId) {
         if (appId < 0) {
             return;
         }
@@ -18832,7 +18891,7 @@
         final KeyStore keyStore = KeyStore.getInstance();
         if (keyStore != null) {
             if (userId == UserHandle.USER_ALL) {
-                for (final int individual : sUserManager.getUserIds()) {
+                for (final int individual : um.getUserIds()) {
                     keyStore.clearUid(UserHandle.getUid(individual, appId));
                 }
             } else {
@@ -19233,8 +19292,8 @@
     void clearIntentFilterVerificationsLPw(String packageName, int userId) {
         if (userId == UserHandle.USER_ALL) {
             if (mSettings.removeIntentFilterVerificationLPw(packageName,
-                    sUserManager.getUserIds())) {
-                for (int oneUserId : sUserManager.getUserIds()) {
+                    mUserManager.getUserIds())) {
+                for (int oneUserId : mUserManager.getUserIds()) {
                     scheduleWritePackageRestrictionsLocked(oneUserId);
                 }
             }
@@ -19247,7 +19306,7 @@
 
     /** Clears state for all users, and touches intent filter verification policy */
     void clearDefaultBrowserIfNeeded(String packageName) {
-        for (int oneUserId : sUserManager.getUserIds()) {
+        for (int oneUserId : mUserManager.getUserIds()) {
             clearDefaultBrowserIfNeededForUser(packageName, oneUserId);
         }
     }
@@ -19614,7 +19673,7 @@
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
         int callingUid = Binder.getCallingUid();
         enforceOwnerRights(ownerPackage, callingUid);
-        PackageManagerServiceUtils.enforceShellRestriction(
+        PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
                 UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
         if (intentFilter.countActions() == 0) {
             Slog.w(TAG, "Cannot set a crossProfile intent filter with no filter actions");
@@ -19646,7 +19705,7 @@
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
         final int callingUid = Binder.getCallingUid();
         enforceOwnerRights(ownerPackage, callingUid);
-        PackageManagerServiceUtils.enforceShellRestriction(
+        PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
                 UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
         synchronized (mLock) {
             CrossProfileIntentResolver resolver =
@@ -19995,7 +20054,7 @@
     @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId, String callingPackage) {
-        if (!sUserManager.exists(userId)) return;
+        if (!mUserManager.exists(userId)) return;
         if (callingPackage == null) {
             callingPackage = Integer.toString(Binder.getCallingUid());
         }
@@ -20016,7 +20075,7 @@
     @Override
     public void setComponentEnabledSetting(ComponentName componentName,
             int newState, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return;
+        if (!mUserManager.exists(userId)) return;
         setEnabledSetting(componentName.getPackageName(),
                 componentName.getClassName(), newState, flags, userId, null);
     }
@@ -20243,7 +20302,7 @@
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return;
         }
-        if (!sUserManager.exists(userId)) {
+        if (!mUserManager.exists(userId)) {
             return;
         }
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/,
@@ -20284,7 +20343,7 @@
 
     @Override
     public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
-        if (!sUserManager.exists(userId)) return;
+        if (!mUserManager.exists(userId)) return;
         final int callingUid = Binder.getCallingUid();
         if (getInstantAppPackageName(callingUid) != null) {
             return;
@@ -20334,7 +20393,7 @@
 
     @Override
     public int getApplicationEnabledSetting(String packageName, int userId) {
-        if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
+        if (!mUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
         int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /* requireFullPermission */, false /* checkShell */, "get enabled");
@@ -20351,7 +20410,7 @@
     @Override
     public int getComponentEnabledSetting(@NonNull ComponentName component, int userId) {
         if (component == null) return COMPONENT_ENABLED_STATE_DEFAULT;
-        if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
+        if (!mUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
         int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/, "getComponentEnabled");
@@ -20449,7 +20508,7 @@
             }
         }
 
-        sUserManager.systemReady();
+        mUserManager.systemReady();
 
         // Now that we've scanned all packages, and granted any default
         // permissions, ensure permissions are updated. Beware of dragons if you
@@ -20458,7 +20517,7 @@
             mPermissionManager.updateAllPermissions(StorageManager.UUID_PRIVATE_INTERNAL, false);
 
             final PermissionPolicyInternal permissionPolicyInternal =
-                    LocalServices.getService(PermissionPolicyInternal.class);
+                    mInjector.getPermissionPolicyInternal();
             permissionPolicyInternal.setOnInitializedCallback(userId -> {
                 // The SDK updated case is already handled when we run during the ctor.
                 synchronized (mPackages) {
@@ -20469,14 +20528,14 @@
         }
 
         // Watch for external volumes that come and go over time
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         storage.registerListener(mStorageListener);
 
         mInstallerService.systemReady();
         mApexManager.systemReady();
         mPackageDexOptimizer.systemReady();
 
-        getStorageManagerInternal().addExternalStoragePolicy(
+        mInjector.getStorageManagerInternal().addExternalStoragePolicy(
                 new StorageManagerInternal.ExternalStorageMountPolicy() {
             @Override
             public int getMountMode(int uid, String packageName) {
@@ -20499,7 +20558,7 @@
         });
 
         // Now that we're mostly running, clean up stale users and apps
-        sUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
+        mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
         reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
 
         mPermissionManager.systemReady();
@@ -20977,7 +21036,7 @@
                             pw.println(prefix + "No app verification established.");
                             pw.println();
                         }
-                        for (int userId : sUserManager.getUserIds()) {
+                        for (int userId : mUserManager.getUserIds()) {
                             pw.println("App linkages for user " + userId + ":");
                             pw.println();
                             count = 0;
@@ -21142,7 +21201,7 @@
         }
         for (String packageName : apkList) {
             setSystemAppHiddenUntilInstalled(packageName, true);
-            for (UserInfo user : sUserManager.getUsers(false)) {
+            for (UserInfo user : mUserManager.getUsers(false)) {
                 setSystemAppInstallState(packageName, false, user.id);
             }
         }
@@ -21428,10 +21487,9 @@
         }
 
         // Reconcile app data for all started/unlocked users
-        final StorageManager sm = mContext.getSystemService(StorageManager.class);
-        final UserManager um = mContext.getSystemService(UserManager.class);
-        UserManagerInternal umInternal = mInjector.getUserManager();
-        for (UserInfo user : um.getUsers()) {
+        final StorageManager sm = mInjector.getStorageManager();
+        UserManagerInternal umInternal = mInjector.getUserManagerInternal();
+        for (UserInfo user : mUserManager.getUsers(false /* includeDying */)) {
             final int flags;
             if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
                 flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
@@ -21621,7 +21679,7 @@
      * correct for all installed apps on all mounted volumes.
      */
     void reconcileAppsData(int userId, int flags, boolean migrateAppsData) {
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
             final String volumeUuid = vol.getFsUuid();
             synchronized (mInstallLock) {
@@ -21750,9 +21808,8 @@
             mSettings.writeKernelMappingLPr(ps);
         }
 
-        final UserManager um = mContext.getSystemService(UserManager.class);
-        UserManagerInternal umInternal = mInjector.getUserManager();
-        for (UserInfo user : um.getUsers()) {
+        UserManagerInternal umInternal = mInjector.getUserManagerInternal();
+        for (UserInfo user : mUserManager.getUsers(false /*excludeDying*/)) {
             final int flags;
             if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
                 flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
@@ -22083,7 +22140,7 @@
     private void movePackageInternal(final String packageName, final String volumeUuid,
             final int moveId, final int callingUid, UserHandle user)
                     throws PackageManagerException {
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         final PackageManager pm = mContext.getPackageManager();
 
         final String currentVolumeUuid;
@@ -22152,7 +22209,7 @@
             label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo));
             targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
             freezer = freezePackage(packageName, "movePackageInternal");
-            installedUserIds = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+            installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
         }
 
         final Bundle extras = new Bundle();
@@ -22319,7 +22376,7 @@
             return;
         }
 
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         VolumeInfo volume = storage.findVolumeByUuid(pkg.applicationInfo.storageUuid.toString());
         int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(pkg));
 
@@ -22357,7 +22414,7 @@
             }
         };
 
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        final StorageManager storage = mInjector.getStorageManager();
         storage.setPrimaryStorageUuid(volumeUuid, callback);
         return realMoveId;
     }
@@ -22503,7 +22560,7 @@
         final long token = Binder.clearCallingIdentity();
         try {
             final DeviceStorageMonitorInternal
-                    dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+                    dsm = mInjector.getDeviceStorageMonitorInternal();
             if (dsm != null) {
                 return dsm.isMemoryLow();
             } else {
@@ -22533,7 +22590,7 @@
             final UserInfo userInfo;
             final long token = Binder.clearCallingIdentity();
             try {
-                userInfo = sUserManager.getUserInfo(userId);
+                userInfo = mUserManager.getUserInfo(userId);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -22658,7 +22715,7 @@
         if (ps == null) {
             return;
         }
-        if (!ps.isAnyInstalled(sUserManager.getUserIds())) {
+        if (!ps.isAnyInstalled(mUserManager.getUserIds())) {
             // TODO Implement atomic delete if package is unused
             // It is currently possible that the package will be deleted even if it is installed
             // after this method returns.
@@ -23941,8 +23998,8 @@
                 return false;
             }
         }
-        if (sUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId)
-                  || sUserManager.hasUserRestriction(
+        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId)
+                  || mUserManager.hasUserRestriction(
                         UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, userId)) {
             return false;
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 4c7db9a..ef47410 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -47,6 +47,7 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManagerInternal;
 import android.service.pm.PackageServiceDumpProto;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -375,10 +376,12 @@
         }
     }
 
-    public static void enforceShellRestriction(String restriction, int callingUid, int userHandle) {
+    /** Enforces that if the caller is shell, it does not have the provided user restriction. */
+    public static void enforceShellRestriction(
+            UserManagerInternal userManager, String restriction, int callingUid, int userHandle) {
         if (callingUid == Process.SHELL_UID) {
             if (userHandle >= 0
-                    && PackageManagerService.sUserManager.hasUserRestriction(
+                    && userManager.hasUserRestriction(
                             restriction, userHandle)) {
                 throw new SecurityException("Shell does not have permission to access user "
                         + userHandle);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 2f30863..a707aa8 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1557,11 +1557,7 @@
     /** @return a specific user restriction that's in effect currently. */
     @Override
     public boolean hasUserRestriction(String restrictionKey, int userId) {
-        if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) {
-            return false;
-        }
-        Bundle restrictions = getEffectiveUserRestrictions(userId);
-        return restrictions != null && restrictions.getBoolean(restrictionKey);
+        return mLocalService.hasUserRestriction(restrictionKey, userId);
     }
 
     /** @return if any user has the given restriction. */
@@ -4128,6 +4124,15 @@
             return UserRestrictionsUtils.isSettingRestrictedForUser(mContext, setting, userId,
                     value, callingUid);
         }
+
+        @Override
+        public boolean hasUserRestriction(String restrictionKey, int userId) {
+            if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) {
+                return false;
+            }
+            Bundle restrictions = getEffectiveUserRestrictions(userId);
+            return restrictions != null && restrictions.getBoolean(restrictionKey);
+        }
     }
 
     /* Remove all the users except of the system one. */
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 2e58af7..e2644ff 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3930,7 +3930,7 @@
             throw new IllegalArgumentException("Invalid userId " + userId);
         }
         if (checkShell) {
-            PackageManagerServiceUtils.enforceShellRestriction(
+            PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
                     UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
         }
         if (!requirePermissionWhenSameUser && userId == UserHandle.getUserId(callingUid)) return;
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 6375b48..d33c10c 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -121,8 +121,6 @@
      */
     public int getVersion() {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             return mVersion;
         }
     }
@@ -134,8 +132,6 @@
      */
     public void setVersion(int version) {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             if (mVersion == version) {
                 return;
             }
@@ -163,8 +159,6 @@
      */
     public void setPackagesHash(@Nullable String packagesHash) {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             if (Objects.equals(mPackagesHash, packagesHash)) {
                 return;
             }
@@ -182,8 +176,6 @@
      */
     public boolean isRoleAvailable(@NonNull String roleName) {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             return mRoles.containsKey(roleName);
         }
     }
@@ -198,8 +190,6 @@
     @Nullable
     public ArraySet<String> getRoleHolders(@NonNull String roleName) {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             ArraySet<String> packageNames = mRoles.get(roleName);
             if (packageNames == null) {
                 return null;
@@ -217,8 +207,6 @@
      */
     public boolean addRoleName(@NonNull String roleName) {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             if (!mRoles.containsKey(roleName)) {
                 mRoles.put(roleName, new ArraySet<>());
                 Slog.i(LOG_TAG, "Added new role: " + roleName);
@@ -237,8 +225,6 @@
      */
     public void setRoleNames(@NonNull List<String> roleNames) {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             boolean changed = false;
 
             for (int i = mRoles.size() - 1; i >= 0; i--) {
@@ -279,8 +265,6 @@
         boolean changed;
 
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             ArraySet<String> roleHolders = mRoles.get(roleName);
             if (roleHolders == null) {
                 Slog.e(LOG_TAG, "Cannot add role holder for unknown role, role: " + roleName
@@ -312,8 +296,6 @@
         boolean changed;
 
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             ArraySet<String> roleHolders = mRoles.get(roleName);
             if (roleHolders == null) {
                 Slog.e(LOG_TAG, "Cannot remove role holder for unknown role, role: " + roleName
@@ -338,14 +320,16 @@
      */
     @NonNull
     public List<String> getHeldRoles(@NonNull String packageName) {
-        ArrayList<String> result = new ArrayList<>();
-        int size = mRoles.size();
-        for (int i = 0; i < size; i++) {
-            if (mRoles.valueAt(i).contains(packageName)) {
-                result.add(mRoles.keyAt(i));
+        synchronized (mLock) {
+            List<String> roleNames = new ArrayList<>();
+            int size = mRoles.size();
+            for (int i = 0; i < size; i++) {
+                if (mRoles.valueAt(i).contains(packageName)) {
+                    roleNames.add(mRoles.keyAt(i));
+                }
             }
+            return roleNames;
         }
-        return result;
     }
 
     /**
@@ -353,7 +337,9 @@
      */
     @GuardedBy("mLock")
     private void scheduleWriteFileLocked() {
-        throwIfDestroyedLocked();
+        if (mDestroyed) {
+            return;
+        }
 
         if (!mWriteScheduled) {
             mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeFile,
@@ -537,8 +523,6 @@
         String packagesHash;
         ArrayMap<String, ArraySet<String>> roles;
         synchronized (mLock) {
-            throwIfDestroyedLocked();
-
             version = mVersion;
             packagesHash = mPackagesHash;
             roles = snapshotRolesLocked();
@@ -602,20 +586,15 @@
      */
     public void destroy() {
         synchronized (mLock) {
-            throwIfDestroyedLocked();
+            if (mDestroyed) {
+                throw new IllegalStateException("This RoleUserState has already been destroyed");
+            }
             mWriteHandler.removeCallbacksAndMessages(null);
             getFile(mUserId).delete();
             mDestroyed = true;
         }
     }
 
-    @GuardedBy("mLock")
-    private void throwIfDestroyedLocked() {
-        if (mDestroyed) {
-            throw new IllegalStateException("This RoleUserState has already been destroyed");
-        }
-    }
-
     @NonNull
     private static File getFile(@UserIdInt int userId) {
         return new File(Environment.getUserSystemDirectory(userId), ROLES_FILE_NAME);
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index cfa370b..f0cf9cf 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -388,7 +388,7 @@
 
         // Get a context for the caller to use to install the downgraded
         // version of the package.
-        Context context = null;
+        final Context context;
         try {
             context = mContext.createPackageContext(callerPackageName, 0);
         } catch (PackageManager.NameNotFoundException e) {
@@ -434,7 +434,6 @@
                 }
                 int sessionId = packageInstaller.createSession(params);
                 PackageInstaller.Session session = packageInstaller.openSession(sessionId);
-
                 File[] packageCodePaths = RollbackStore.getPackageCodePaths(
                         data, info.getPackageName());
                 if (packageCodePaths == null) {
@@ -504,8 +503,10 @@
 
                             Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
 
-                            mContext.sendBroadcastAsUser(broadcast, UserHandle.SYSTEM,
-                                    Manifest.permission.MANAGE_ROLLBACKS);
+                            for (UserInfo userInfo : UserManager.get(mContext).getUsers(true)) {
+                                mContext.sendBroadcastAsUser(broadcast, userInfo.getUserHandle(),
+                                        Manifest.permission.MANAGE_ROLLBACKS);
+                            }
                         });
                     }
             );
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index f08e585..6ea274d 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -403,6 +403,10 @@
                     || checkUidChangedLocked(connection, callingUid, resolvedUserId)) {
                 return;
             }
+            ITvInputHardwareCallback callback = connection.getCallbackLocked();
+            if (callback != null) {
+                callback.asBinder().unlinkToDeath(connection, 0);
+            }
             connection.resetLocked(null, null, null, null, null);
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 20ccfa8..a3ab27e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1458,16 +1458,18 @@
             @Nullable IRecentsAnimationRunner recentsAnimationRunner) {
         enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()");
         final int callingPid = Binder.getCallingPid();
+        final int callingUid = Binder.getCallingUid();
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
                 final ComponentName recentsComponent = mRecentTasks.getRecentsComponent();
                 final int recentsUid = mRecentTasks.getRecentsComponentUid();
+                final WindowProcessController caller = getProcessController(callingPid, callingUid);
 
                 // Start a new recents animation
                 final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor,
                         getActivityStartController(), mWindowManager, intent, recentsComponent,
-                        recentsUid, callingPid);
+                        recentsUid, caller);
                 if (recentsAnimationRunner == null) {
                     anim.preloadRecentsActivity();
                 } else {
@@ -4581,7 +4583,7 @@
     public void registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition) {
         mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
                 "registerRemoteAnimations");
-        definition.setCallingPid(Binder.getCallingPid());
+        definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
@@ -4601,7 +4603,7 @@
             RemoteAnimationAdapter adapter) {
         mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
                 "registerRemoteAnimationForNextActivityStart");
-        adapter.setCallingPid(Binder.getCallingPid());
+        adapter.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
         synchronized (mGlobalLock) {
             final long origId = Binder.clearCallingIdentity();
             try {
@@ -4618,7 +4620,7 @@
             RemoteAnimationDefinition definition) {
         mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
                 "registerRemoteAnimations");
-        definition.setCallingPid(Binder.getCallingPid());
+        definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
         synchronized (mGlobalLock) {
             final ActivityDisplay display = mRootActivityContainer.getActivityDisplay(displayId);
             if (display == null) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4f4da4c..c8e806e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -67,6 +67,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
@@ -136,6 +137,8 @@
 import static com.android.server.wm.WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
 import static com.android.server.wm.WindowManagerService.logSurface;
+import static com.android.server.wm.WindowState.EXCLUSION_LEFT;
+import static com.android.server.wm.WindowState.EXCLUSION_RIGHT;
 import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
 import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
 import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
@@ -328,6 +331,8 @@
     private final RemoteCallbackList<ISystemGestureExclusionListener>
             mSystemGestureExclusionListeners = new RemoteCallbackList<>();
     private final Region mSystemGestureExclusion = new Region();
+    private boolean mSystemGestureExclusionWasRestricted = false;
+    private final Region mSystemGestureExclusionUnrestricted = new Region();
     private int mSystemGestureExclusionLimit;
 
     /**
@@ -5165,16 +5170,21 @@
             return false;
         }
 
-        final Region systemGestureExclusion = calculateSystemGestureExclusion();
+        final Region systemGestureExclusion = Region.obtain();
+        mSystemGestureExclusionWasRestricted = calculateSystemGestureExclusion(
+                systemGestureExclusion, mSystemGestureExclusionUnrestricted);
         try {
             if (mSystemGestureExclusion.equals(systemGestureExclusion)) {
                 return false;
             }
             mSystemGestureExclusion.set(systemGestureExclusion);
+            final Region unrestrictedOrNull = mSystemGestureExclusionWasRestricted
+                    ? mSystemGestureExclusionUnrestricted : null;
             for (int i = mSystemGestureExclusionListeners.beginBroadcast() - 1; i >= 0; --i) {
                 try {
                     mSystemGestureExclusionListeners.getBroadcastItem(i)
-                            .onSystemGestureExclusionChanged(mDisplayId, systemGestureExclusion);
+                            .onSystemGestureExclusionChanged(mDisplayId, systemGestureExclusion,
+                                    unrestrictedOrNull);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Failed to notify SystemGestureExclusionListener", e);
                 }
@@ -5186,8 +5196,22 @@
         }
     }
 
+    /**
+     * Calculates the system gesture exclusion.
+     *
+     * @param outExclusion will be set to the gesture exclusion region
+     * @param outExclusionUnrestricted will be set to the gesture exclusion region without
+     *                                 any restrictions applied.
+     * @return whether any restrictions were applied, i.e. outExclusion and outExclusionUnrestricted
+     *         differ.
+     */
     @VisibleForTesting
-    Region calculateSystemGestureExclusion() {
+    boolean calculateSystemGestureExclusion(Region outExclusion, @Nullable
+            Region outExclusionUnrestricted) {
+        outExclusion.setEmpty();
+        if (outExclusionUnrestricted != null) {
+            outExclusionUnrestricted.setEmpty();
+        }
         final Region unhandled = Region.obtain();
         unhandled.set(0, 0, mDisplayFrames.mDisplayWidth, mDisplayFrames.mDisplayHeight);
 
@@ -5196,7 +5220,6 @@
         final Rect rightEdge = mInsetsStateController.getSourceProvider(TYPE_RIGHT_GESTURES)
                 .getSource().getFrame();
 
-        final Region global = Region.obtain();
         final Region touchableRegion = Region.obtain();
         final Region local = Region.obtain();
         final int[] remainingLeftRight =
@@ -5234,28 +5257,39 @@
             if (needsGestureExclusionRestrictions(w, mLastDispatchedSystemUiVisibility)) {
 
                 // Processes the region along the left edge.
-                remainingLeftRight[0] = addToGlobalAndConsumeLimit(local, global, leftEdge,
-                        remainingLeftRight[0]);
+                remainingLeftRight[0] = addToGlobalAndConsumeLimit(local, outExclusion, leftEdge,
+                        remainingLeftRight[0], w, EXCLUSION_LEFT);
 
                 // Processes the region along the right edge.
-                remainingLeftRight[1] = addToGlobalAndConsumeLimit(local, global, rightEdge,
-                        remainingLeftRight[1]);
+                remainingLeftRight[1] = addToGlobalAndConsumeLimit(local, outExclusion, rightEdge,
+                        remainingLeftRight[1], w, EXCLUSION_RIGHT);
 
                 // Adds the middle (unrestricted area)
                 final Region middle = Region.obtain(local);
                 middle.op(leftEdge, Op.DIFFERENCE);
                 middle.op(rightEdge, Op.DIFFERENCE);
-                global.op(middle, Op.UNION);
+                outExclusion.op(middle, Op.UNION);
                 middle.recycle();
             } else {
-                global.op(local, Op.UNION);
+                boolean loggable = needsGestureExclusionRestrictions(w, 0 /* lastSysUiVis */);
+                if (loggable) {
+                    addToGlobalAndConsumeLimit(local, outExclusion, leftEdge,
+                            Integer.MAX_VALUE, w, EXCLUSION_LEFT);
+                    addToGlobalAndConsumeLimit(local, outExclusion, rightEdge,
+                            Integer.MAX_VALUE, w, EXCLUSION_RIGHT);
+                }
+                outExclusion.op(local, Op.UNION);
+            }
+            if (outExclusionUnrestricted != null) {
+                outExclusionUnrestricted.op(local, Op.UNION);
             }
             unhandled.op(touchableRegion, Op.DIFFERENCE);
         }, true /* topToBottom */);
         local.recycle();
         touchableRegion.recycle();
         unhandled.recycle();
-        return global;
+        return remainingLeftRight[0] < mSystemGestureExclusionLimit
+                || remainingLeftRight[1] < mSystemGestureExclusionLimit;
     }
 
     /**
@@ -5273,31 +5307,57 @@
     }
 
     /**
+     * @return Whether gesture exclusion area should be logged for the given window
+     */
+    static boolean logsGestureExclusionRestrictions(WindowState win) {
+        if (win.mWmService.mSystemGestureExclusionLogDebounceTimeoutMillis <= 0) {
+            return false;
+        }
+        final WindowManager.LayoutParams attrs = win.getAttrs();
+        final int type = attrs.type;
+        return type != TYPE_WALLPAPER
+                && type != TYPE_APPLICATION_STARTING
+                && type != TYPE_NAVIGATION_BAR
+                && (attrs.flags & FLAG_NOT_TOUCHABLE) == 0
+                && needsGestureExclusionRestrictions(win, 0 /* sysUiVisibility */)
+                && win.getDisplayContent().mDisplayPolicy.hasSideGestures();
+    }
+
+    /**
      * Adds a local gesture exclusion area to the global area while applying a limit per edge.
      *
      * @param local The gesture exclusion area to add.
      * @param global The destination.
      * @param edge Only processes the part in that region.
      * @param limit How much limit in pixels we have.
-     * @return How much of the limit are remaining.
+     * @param win The WindowState that is being processed
+     * @param side The side that is being processed, either {@link WindowState#EXCLUSION_LEFT} or
+     *             {@link WindowState#EXCLUSION_RIGHT}
+     * @return How much of the limit is remaining.
      */
     private static int addToGlobalAndConsumeLimit(Region local, Region global, Rect edge,
-            int limit) {
+            int limit, WindowState win, int side) {
         final Region r = Region.obtain(local);
         r.op(edge, Op.INTERSECT);
 
         final int[] remaining = {limit};
+        final int[] requestedExclusion = {0};
         forEachRectReverse(r, rect -> {
             if (remaining[0] <= 0) {
                 return;
             }
             final int height = rect.height();
+            requestedExclusion[0] += height;
             if (height > remaining[0]) {
                 rect.top = rect.bottom - remaining[0];
             }
             remaining[0] -= height;
             global.op(rect, Op.UNION);
         });
+
+        final int grantedExclusion = limit - remaining[0];
+        win.setLastExclusionHeights(side, requestedExclusion[0], grantedExclusion);
+
         r.recycle();
         return remaining[0];
     }
@@ -5312,10 +5372,13 @@
         }
 
         if (!changed) {
+            final Region unrestrictedOrNull = mSystemGestureExclusionWasRestricted
+                    ? mSystemGestureExclusionUnrestricted : null;
             // If updateSystemGestureExclusion changed the exclusion, it will already have
             // notified the listener. Otherwise, we'll do it here.
             try {
-                listener.onSystemGestureExclusionChanged(mDisplayId, mSystemGestureExclusion);
+                listener.onSystemGestureExclusionChanged(mDisplayId, mSystemGestureExclusion,
+                        unrestrictedOrNull);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to notify SystemGestureExclusionListener during register", e);
             }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 1576873..e35ef25 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -480,9 +480,10 @@
 
                     @Override
                     public void onSwipeFromRight() {
-                        final Region excludedRegion;
+                        final Region excludedRegion = Region.obtain();
                         synchronized (mLock) {
-                            excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
+                            mDisplayContent.calculateSystemGestureExclusion(
+                                    excludedRegion, null /* outUnrestricted */);
                         }
                         final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
                                 || mNavigationBarPosition == NAV_BAR_RIGHT;
@@ -490,13 +491,15 @@
                                 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
                             requestTransientBars(mNavigationBar);
                         }
+                        excludedRegion.recycle();
                     }
 
                     @Override
                     public void onSwipeFromLeft() {
-                        final Region excludedRegion;
+                        final Region excludedRegion = Region.obtain();
                         synchronized (mLock) {
-                            excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
+                            mDisplayContent.calculateSystemGestureExclusion(
+                                    excludedRegion, null /* outUnrestricted */);
                         }
                         final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
                                 || mNavigationBarPosition == NAV_BAR_LEFT;
@@ -504,6 +507,7 @@
                                 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
                             requestTransientBars(mNavigationBar);
                         }
+                        excludedRegion.recycle();
                     }
 
                     @Override
@@ -676,6 +680,10 @@
         return mHasStatusBar;
     }
 
+    boolean hasSideGestures() {
+        return mHasNavigationBar && mSideGestureInset > 0;
+    }
+
     public boolean navigationBarCanMove() {
         return mNavigationBarCanMove;
     }
@@ -2830,7 +2838,11 @@
         mHandler.post(() -> {
             final int displayId = getDisplayId();
             getStatusBarManagerInternal().onDisplayReady(displayId);
-            LocalServices.getService(WallpaperManagerInternal.class).onDisplayReady(displayId);
+            final WallpaperManagerInternal wpMgr = LocalServices
+                    .getService(WallpaperManagerInternal.class);
+            if (wpMgr != null) {
+                wpMgr.onDisplayReady(displayId);
+            }
         });
     }
 
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 85ba95f..422b6e5 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -90,11 +90,24 @@
     }
 
     /**
-     * @return true if either 1) AOD is showing, or 2) Keyguard is showing, not going away, and not
-     *         being occluded on the given display, false otherwise.
+     * @return true if either Keyguard or AOD are showing, not going away, and not being occluded
+     *         on the given display, false otherwise.
      */
     boolean isKeyguardOrAodShowing(int displayId) {
-        return mAodShowing || isKeyguardShowing(displayId);
+        return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway
+                && !isDisplayOccluded(displayId);
+    }
+
+    /**
+     * @return {@code true} for default display when AOD is showing. Otherwise, same as
+     *         {@link #isKeyguardOrAodShowing(int)}
+     * TODO(b/125198167): Replace isKeyguardOrAodShowing() by this logic.
+     */
+    boolean isKeyguardUnoccludedOrAodShowing(int displayId) {
+        if (displayId == DEFAULT_DISPLAY && mAodShowing) {
+            return true;
+        }
+        return isKeyguardOrAodShowing(displayId);
     }
 
     /**
@@ -102,7 +115,7 @@
      *         display, false otherwise
      */
     boolean isKeyguardShowing(int displayId) {
-        return mKeyguardShowing && !mKeyguardGoingAway && !isKeyguardOccluded(displayId);
+        return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId);
     }
 
     /**
@@ -315,7 +328,7 @@
             return;
         }
 
-        mWindowManager.onKeyguardOccludedChanged(isKeyguardOccluded(DEFAULT_DISPLAY));
+        mWindowManager.onKeyguardOccludedChanged(isDisplayOccluded(DEFAULT_DISPLAY));
         if (isKeyguardLocked()) {
             mWindowManager.deferSurfaceLayout();
             try {
@@ -360,7 +373,7 @@
         }
     }
 
-    private boolean isKeyguardOccluded(int displayId) {
+    private boolean isDisplayOccluded(int displayId) {
         return getDisplay(displayId).mOccluded;
     }
 
@@ -378,13 +391,13 @@
         if (mBeforeUnoccludeTransit != TRANSIT_UNSET
                 && dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
                 // TODO(b/113840485): Handle app transition for individual display.
-                && isKeyguardOccluded(DEFAULT_DISPLAY)) {
+                && isDisplayOccluded(DEFAULT_DISPLAY)) {
 
             // Reuse old transit in case we are occluding Keyguard again, meaning that we never
             // actually occclude/unocclude Keyguard, but just run a normal transition.
             return mBeforeUnoccludeTransit;
             // TODO(b/113840485): Handle app transition for individual display.
-        } else if (!isKeyguardOccluded(DEFAULT_DISPLAY)) {
+        } else if (!isDisplayOccluded(DEFAULT_DISPLAY)) {
 
             // Save transit in case we dismiss/occlude Keyguard shortly after.
             mBeforeUnoccludeTransit = dc.mAppTransition.getAppTransition();
@@ -396,7 +409,7 @@
 
     private void dismissDockedStackIfNeeded() {
         // TODO(b/113840485): Handle docked stack for individual display.
-        if (mKeyguardShowing && isKeyguardOccluded(DEFAULT_DISPLAY)) {
+        if (mKeyguardShowing && isDisplayOccluded(DEFAULT_DISPLAY)) {
             // The lock screen is currently showing, but is occluded by a window that can
             // show on top of the lock screen. In this can we want to dismiss the docked
             // stack since it will be complicated/risky to try to put the activity on top
@@ -421,9 +434,9 @@
 
     private void updateKeyguardSleepToken(int displayId) {
         final KeyguardDisplayState state = getDisplay(displayId);
-        if (isKeyguardOrAodShowing(displayId) && state.mSleepToken == null) {
+        if (isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken == null) {
             state.acquiredSleepToken();
-        } else if (!isKeyguardOrAodShowing(displayId) && state.mSleepToken != null) {
+        } else if (!isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken != null) {
             state.releaseSleepToken();
         }
     }
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 541a8bb..fb6b5da 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -126,6 +126,7 @@
     // iterating through the recents list
     private static final ActivityInfo NO_ACTIVITY_INFO_TOKEN = new ActivityInfo();
     private static final ApplicationInfo NO_APPLICATION_INFO_TOKEN = new ApplicationInfo();
+    private TaskChangeNotificationController mTaskNotificationController;
 
     /**
      * Callbacks made when manipulating the list.
@@ -228,6 +229,7 @@
         mTaskPersister = taskPersister;
         mGlobalMaxNumTasks = ActivityTaskManager.getMaxRecentTasksStatic();
         mHasVisibleRecentTasks = true;
+        mTaskNotificationController = service.getTaskChangeNotificationController();
     }
 
     RecentTasks(ActivityTaskManagerService service, ActivityStackSupervisor stackSupervisor) {
@@ -238,6 +240,7 @@
         mTaskPersister = new TaskPersister(systemDir, stackSupervisor, service, this,
                 stackSupervisor.mPersisterQueue);
         mGlobalMaxNumTasks = ActivityTaskManager.getMaxRecentTasksStatic();
+        mTaskNotificationController = service.getTaskChangeNotificationController();
         mHasVisibleRecentTasks = res.getBoolean(com.android.internal.R.bool.config_hasRecents);
         loadParametersFromResources(res);
     }
@@ -298,7 +301,7 @@
         // Resume trimming tasks
         trimInactiveRecentTasks();
 
-        mService.getTaskChangeNotificationController().notifyTaskStackChanged();
+        mTaskNotificationController.notifyTaskStackChanged();
     }
 
     /**
@@ -427,12 +430,14 @@
         for (int i = 0; i < mCallbacks.size(); i++) {
             mCallbacks.get(i).onRecentTaskAdded(task);
         }
+        mTaskNotificationController.notifyTaskListUpdated();
     }
 
     private void notifyTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess) {
         for (int i = 0; i < mCallbacks.size(); i++) {
             mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed, killProcess);
         }
+        mTaskNotificationController.notifyTaskListUpdated();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 0a3e7a4..4f0332c 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -33,6 +33,7 @@
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
 
+import android.annotation.Nullable;
 import android.app.ActivityOptions;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -60,7 +61,7 @@
     private final Intent mTargetIntent;
     private final ComponentName mRecentsComponent;
     private final int mRecentsUid;
-    private final int mCallingPid;
+    private final @Nullable WindowProcessController mCaller;
     private final int mUserId;
     private final int mTargetActivityType;
 
@@ -76,7 +77,8 @@
 
     RecentsAnimation(ActivityTaskManagerService atm, ActivityStackSupervisor stackSupervisor,
             ActivityStartController activityStartController, WindowManagerService wm,
-            Intent targetIntent, ComponentName recentsComponent, int recentsUid, int callingPid) {
+            Intent targetIntent, ComponentName recentsComponent, int recentsUid,
+            @Nullable WindowProcessController caller) {
         mService = atm;
         mStackSupervisor = stackSupervisor;
         mDefaultDisplay = mService.mRootActivityContainer.getDefaultDisplay();
@@ -85,7 +87,7 @@
         mTargetIntent = targetIntent;
         mRecentsComponent = recentsComponent;
         mRecentsUid = recentsUid;
-        mCallingPid = callingPid;
+        mCaller = caller;
         mUserId = atm.getCurrentUserId();
         mTargetActivityType = targetIntent.getComponent() != null
                 && recentsComponent.equals(targetIntent.getComponent())
@@ -190,7 +192,9 @@
 
         mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mTargetIntent);
 
-        mService.mH.post(() -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true));
+        if (mCaller != null) {
+            mCaller.setRunningRecentsAnimation(true);
+        }
 
         mWindowManager.deferSurfaceLayout();
         try {
@@ -286,8 +290,9 @@
                 mService.stopAppSwitches();
             }
 
-            mService.mH.post(
-                    () -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, false));
+            if (mCaller != null) {
+                mCaller.setRunningRecentsAnimation(false);
+            }
 
             mWindowManager.inSurfaceTransaction(() -> {
                 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER,
@@ -453,9 +458,9 @@
     /**
      * Called only when the animation should be canceled prior to starting.
      */
-    private void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) {
+    static void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) {
         try {
-            recentsAnimationRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
+            recentsAnimationRunner.onAnimationCanceled(null /* taskSnapshot */);
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to cancel recents animation before start", e);
         }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 6ea4d58..724a72e 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -23,8 +23,8 @@
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
-
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
@@ -525,18 +525,23 @@
                 // Screen shot previous task when next task starts transition and notify the runner.
                 // We will actually finish the animation once the runner calls cleanUpScreenshot().
                 final Task task = mPendingAnimations.get(0).mTask;
-                screenshotRecentTask(task, reorderMode, runSynchronously);
+                final TaskSnapshot taskSnapshot = screenshotRecentTask(task, reorderMode,
+                        runSynchronously);
                 try {
-                    mRunner.onAnimationCanceled(true /* deferredWithScreenshot */);
+                    mRunner.onAnimationCanceled(taskSnapshot);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Failed to cancel recents animation", e);
                 }
+                if (taskSnapshot == null) {
+                    mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
+                            false /* sendUserLeaveHint */);
+                }
             } else {
                 // Otherwise, notify the runner and clean up the animation immediately
                 // Note: In the fallback case, this can trigger multiple onAnimationCancel() calls
                 // to the runner if we this actually triggers cancel twice on the caller
                 try {
-                    mRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
+                    mRunner.onAnimationCanceled(null /* taskSnapshot */);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Failed to cancel recents animation", e);
                 }
@@ -587,20 +592,32 @@
         return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
     }
 
-    void screenshotRecentTask(Task task, @ReorderMode int reorderMode, boolean runSynchronously) {
-        final TaskScreenshotAnimatable animatable = TaskScreenshotAnimatable.create(task);
-        if (animatable != null) {
-            mRecentScreenshotAnimator = new SurfaceAnimator(
-                    animatable,
-                    () -> {
-                        if (DEBUG_RECENTS_ANIMATIONS) {
-                            Slog.d(TAG, "mRecentScreenshotAnimator finish");
-                        }
-                        mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
-                                false /* sendUserLeaveHint */);
-                    }, mService);
-            mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
+    TaskSnapshot screenshotRecentTask(Task task, @ReorderMode int reorderMode,
+            boolean runSynchronously) {
+        final TaskSnapshotController snapshotController = mService.mTaskSnapshotController;
+        final ArraySet<Task> tasks = Sets.newArraySet(task);
+        snapshotController.snapshotTasks(tasks);
+        snapshotController.addSkipClosingAppSnapshotTasks(tasks);
+        final TaskSnapshot taskSnapshot = snapshotController.getSnapshot(task.mTaskId,
+                task.mUserId, false /* restoreFromDisk */, false /* reducedResolution */);
+        if (taskSnapshot == null) {
+            return null;
         }
+
+        final TaskScreenshotAnimatable animatable = new TaskScreenshotAnimatable(task,
+                new SurfaceControl.ScreenshotGraphicBuffer(taskSnapshot.getSnapshot(),
+                        taskSnapshot.getColorSpace(), false /* containsSecureLayers */));
+        mRecentScreenshotAnimator = new SurfaceAnimator(
+                animatable,
+                () -> {
+                    if (DEBUG_RECENTS_ANIMATIONS) {
+                        Slog.d(TAG, "mRecentScreenshotAnimator finish");
+                    }
+                    mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
+                            false /* sendUserLeaveHint */);
+                }, mService);
+        mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
+        return taskSnapshot;
     }
 
     void cleanupAnimation(@ReorderMode int reorderMode) {
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index b4bfedd..a1bc406 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -129,7 +129,7 @@
                 writeStartDebugStatement();
             }
         });
-        sendRunningRemoteAnimation(true);
+        setRunningRemoteAnimation(true);
     }
 
     void cancelAnimation(String reason) {
@@ -216,7 +216,7 @@
                 mService.closeSurfaceTransaction("RemoteAnimationController#finished");
             }
         }
-        sendRunningRemoteAnimation(false);
+        setRunningRemoteAnimation(false);
         if (DEBUG_REMOTE_ANIMATIONS) Slog.i(TAG, "Finishing remote animation");
     }
 
@@ -235,12 +235,18 @@
         }
     }
 
-    private void sendRunningRemoteAnimation(boolean running) {
+    private void setRunningRemoteAnimation(boolean running) {
         final int pid = mRemoteAnimationAdapter.getCallingPid();
+        final int uid = mRemoteAnimationAdapter.getCallingUid();
         if (pid == 0) {
             throw new RuntimeException("Calling pid of remote animation was null");
         }
-        mService.sendSetRunningRemoteAnimation(pid, running);
+        final WindowProcessController wpc = mService.mAtmService.getProcessController(pid, uid);
+        if (wpc == null) {
+            Slog.w(TAG, "Unable to find process with pid=" + pid + " uid=" + uid);
+            return;
+        }
+        wpc.setRunningRemoteAnimation(running);
     }
 
     private void linkToDeathOfRunner() throws RemoteException {
@@ -417,7 +423,7 @@
                 mHandler.removeCallbacks(mTimeoutRunnable);
                 releaseFinishedCallback();
                 invokeAnimationCancelled();
-                sendRunningRemoteAnimation(false);
+                setRunningRemoteAnimation(false);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index ac90283..a7b5368 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -122,17 +122,20 @@
         if (mOriginalOptions != null) {
             checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions,
                     mOriginalCallingPid, mOriginalCallingUid);
-            setCallingPidForRemoteAnimationAdapter(mOriginalOptions, mOriginalCallingPid);
+            setCallingPidUidForRemoteAnimationAdapter(mOriginalOptions, mOriginalCallingPid,
+                    mOriginalCallingUid);
         }
         if (mCallerOptions != null) {
             checkPermissions(intent, aInfo, callerApp, supervisor, mCallerOptions,
                     mRealCallingPid, mRealCallingUid);
-            setCallingPidForRemoteAnimationAdapter(mCallerOptions, mRealCallingPid);
+            setCallingPidUidForRemoteAnimationAdapter(mCallerOptions, mRealCallingPid,
+                    mRealCallingUid);
         }
         return mergeActivityOptions(mOriginalOptions, mCallerOptions);
     }
 
-    private void setCallingPidForRemoteAnimationAdapter(ActivityOptions options, int callingPid) {
+    private void setCallingPidUidForRemoteAnimationAdapter(ActivityOptions options,
+            int callingPid, int callingUid) {
         final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter();
         if (adapter == null) {
             return;
@@ -141,7 +144,7 @@
             Slog.wtf(TAG, "Safe activity options constructed after clearing calling id");
             return;
         }
-        adapter.setCallingPid(callingPid);
+        adapter.setCallingPidUid(callingPid, callingUid);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index f776062..c2c4767 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -56,6 +56,7 @@
     private static final int NOTIFY_BACK_PRESSED_ON_TASK_ROOT = 21;
     private static final int NOTIFY_SINGLE_TASK_DISPLAY_DRAWN = 22;
     private static final int NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG = 23;
+    private static final int NOTIFY_TASK_LIST_UPDATED_LISTENERS_MSG = 24;
 
     // Delay in notifying task stack change listeners (in millis)
     private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -164,6 +165,10 @@
         l.onTaskDisplayChanged(m.arg1, m.arg2);
     };
 
+    private final TaskStackConsumer mNotifyTaskListUpdated = (l, m) -> {
+        l.onRecentTaskListUpdated();
+    };
+
     @FunctionalInterface
     public interface TaskStackConsumer {
         void accept(ITaskStackListener t, Message m) throws RemoteException;
@@ -249,6 +254,9 @@
                 case NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG:
                     forAllRemoteListeners(mNotifyTaskDisplayChanged, msg);
                     break;
+                case NOTIFY_TASK_LIST_UPDATED_LISTENERS_MSG:
+                    forAllRemoteListeners(mNotifyTaskListUpdated, msg);
+                    break;
             }
         }
     }
@@ -513,4 +521,13 @@
         forAllLocalListeners(mNotifyTaskStackChanged, msg);
         msg.sendToTarget();
     }
+
+    /**
+     * Called when any additions or deletions to the recent tasks list have been made.
+     */
+    void notifyTaskListUpdated() {
+        final Message msg = mHandler.obtainMessage(NOTIFY_TASK_LIST_UPDATED_LISTENERS_MSG);
+        forAllLocalListeners(mNotifyTaskListUpdated, msg);
+        msg.sendToTarget();
+    }
 }
diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
index 143543e..d6c2f66 100644
--- a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
+++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
@@ -18,7 +18,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
 
 import android.graphics.GraphicBuffer;
-import android.graphics.Rect;
 import android.util.Slog;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -37,20 +36,7 @@
     private int mWidth;
     private int mHeight;
 
-    public static TaskScreenshotAnimatable create(Task task) {
-        return new TaskScreenshotAnimatable(task, getBufferFromTask(task));
-    }
-
-    private static SurfaceControl.ScreenshotGraphicBuffer getBufferFromTask(Task task) {
-        if (task == null) {
-            return null;
-        }
-        final Rect tmpRect = task.getBounds();
-        tmpRect.offset(0, 0);
-        return SurfaceControl.captureLayers(task.getSurfaceControl(), tmpRect, 1f);
-    }
-
-    private TaskScreenshotAnimatable(Task task,
+    TaskScreenshotAnimatable(Task task,
             SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer) {
         GraphicBuffer buffer = screenshotBuffer == null
                 ? null : screenshotBuffer.getGraphicBuffer();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8fb23a4..3221aef 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -34,6 +34,7 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE;
 import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP;
+import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
@@ -848,6 +849,16 @@
     int mSystemGestureExclusionLimitDp;
     boolean mSystemGestureExcludedByPreQStickyImmersive;
 
+    /**
+     * The minimum duration between gesture exclusion logging for a given window in
+     * milliseconds.
+     *
+     * Events that happen in-between will be silently dropped.
+     *
+     * A non-positive value disables logging.
+     */
+    public long mSystemGestureExclusionLogDebounceTimeoutMillis;
+
     public interface WindowChangeListener {
         public void windowsChanged();
         public void focusChanged();
@@ -1147,6 +1158,9 @@
         mSystemGestureExclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP,
                 DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                         KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
+        mSystemGestureExclusionLogDebounceTimeoutMillis =
+                DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                        KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0);
         mSystemGestureExcludedByPreQStickyImmersive =
                 DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                         KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
@@ -1164,6 +1178,10 @@
                             mSystemGestureExcludedByPreQStickyImmersive = excludedByPreQSticky;
                             mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit);
                         }
+
+                        mSystemGestureExclusionLogDebounceTimeoutMillis =
+                                DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                                        KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0);
                     }
                 });
 
@@ -4531,7 +4549,6 @@
         public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
         public static final int RESTORE_POINTER_ICON = 55;
         public static final int SET_HAS_OVERLAY_UI = 58;
-        public static final int SET_RUNNING_REMOTE_ANIMATION = 59;
         public static final int ANIMATION_FAILSAFE = 60;
         public static final int RECOMPUTE_FOCUS = 61;
         public static final int ON_POINTER_DOWN_OUTSIDE_FOCUS = 62;
@@ -4888,10 +4905,6 @@
                     mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1);
                     break;
                 }
-                case SET_RUNNING_REMOTE_ANIMATION: {
-                    mAmInternal.setRunningRemoteAnimation(msg.arg1, msg.arg2 == 1);
-                    break;
-                }
                 case ANIMATION_FAILSAFE: {
                     synchronized (mGlobalLock) {
                         if (mRecentsAnimationController != null) {
@@ -7576,11 +7589,6 @@
         return mSurfaceBuilderFactory.make(s);
     }
 
-    void sendSetRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) {
-        mH.obtainMessage(H.SET_RUNNING_REMOTE_ANIMATION, pid, runningRemoteAnimation ? 1 : 0)
-                .sendToTarget();
-    }
-
     void startSeamlessRotation() {
         // We are careful to reset this in case a window was removed before it finished
         // seamless rotation.
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index d7a519c..cf8e1e8 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -58,6 +58,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
+import android.view.IRemoteAnimationRunner;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.HeavyWeightSwitcherActivity;
@@ -180,6 +181,12 @@
     // Registered display id as a listener to override config change
     private int mDisplayId;
 
+    /** Whether our process is currently running a {@link RecentsAnimation} */
+    private boolean mRunningRecentsAnimation;
+
+    /** Whether our process is currently running a {@link IRemoteAnimationRunner} */
+    private boolean mRunningRemoteAnimation;
+
     public WindowProcessController(ActivityTaskManagerService atm, ApplicationInfo info,
             String name, int uid, int userId, Object owner, WindowProcessListener listener) {
         mInfo = info;
@@ -1098,6 +1105,30 @@
         }
     }
 
+    void setRunningRecentsAnimation(boolean running) {
+        if (mRunningRecentsAnimation == running) {
+            return;
+        }
+        mRunningRecentsAnimation = running;
+        updateRunningRemoteOrRecentsAnimation();
+    }
+
+    void setRunningRemoteAnimation(boolean running) {
+        if (mRunningRemoteAnimation == running) {
+            return;
+        }
+        mRunningRemoteAnimation = running;
+        updateRunningRemoteOrRecentsAnimation();
+    }
+
+    private void updateRunningRemoteOrRecentsAnimation() {
+
+        // Posting on handler so WM lock isn't held when we call into AM.
+        mAtm.mH.sendMessage(PooledLambda.obtainMessage(
+                WindowProcessListener::setRunningRemoteAnimation, mListener,
+                mRunningRecentsAnimation || mRunningRemoteAnimation));
+    }
+
     @Override
     public String toString() {
         return mOwner != null ? mOwner.toString() : null;
diff --git a/services/core/java/com/android/server/wm/WindowProcessListener.java b/services/core/java/com/android/server/wm/WindowProcessListener.java
index 527d54a..23d7a6a 100644
--- a/services/core/java/com/android/server/wm/WindowProcessListener.java
+++ b/services/core/java/com/android/server/wm/WindowProcessListener.java
@@ -17,6 +17,8 @@
 package com.android.server.wm;
 
 import android.util.proto.ProtoOutputStream;
+import android.view.IRemoteAnimationRunner;
+import android.view.RemoteAnimationAdapter;
 
 /**
  * Interface used by the owner/creator of a process that owns windows to listen to changes from the
@@ -60,4 +62,14 @@
     /** App died :(...oh well */
     void appDied();
     void writeToProto(ProtoOutputStream proto, long fieldId);
+
+    /**
+     * Sets if the process is currently running a remote animation, which is taken a signal for
+     * determining oom adjustment and scheduling behavior.
+     *
+     * @param runningRemoteAnimation True if the process is running a remote animation, false
+     *                               otherwise.
+     * @see RemoteAnimationAdapter
+     */
+    void setRunningRemoteAnimation(boolean runningRemoteAnimation);
 }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 9f9ef24..e14514b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -20,6 +20,8 @@
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_DEFAULT;
 import static android.app.AppOpsManager.OP_NONE;
+import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.os.PowerManager.DRAW_WAKE_LOCK;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.SurfaceControl.Transaction;
@@ -79,6 +81,7 @@
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
 import static com.android.server.wm.AnimationSpecProto.MOVE;
+import static com.android.server.wm.DisplayContent.logsGestureExclusionRestrictions;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
@@ -173,6 +176,7 @@
 import android.util.DisplayMetrics;
 import android.util.MergedConfiguration;
 import android.util.Slog;
+import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
@@ -226,6 +230,9 @@
     // to capture touch events in that area.
     static final int RESIZE_HANDLE_WIDTH_IN_DP = 30;
 
+    static final int EXCLUSION_LEFT = 0;
+    static final int EXCLUSION_RIGHT = 1;
+
     final WindowManagerPolicy mPolicy;
     final Context mContext;
     final Session mSession;
@@ -396,6 +403,13 @@
      */
     private final List<Rect> mExclusionRects = new ArrayList<>();
 
+    // 0 = left, 1 = right
+    private final int[] mLastRequestedExclusionHeight = {0, 0};
+    private final int[] mLastGrantedExclusionHeight = {0, 0};
+    private final long[] mLastExclusionLogUptimeMillis = {0, 0};
+
+    private boolean mLastShownChangedReported;
+
     // If a window showing a wallpaper: the requested offset for the
     // wallpaper; if a wallpaper window: the currently applied offset.
     float mWallpaperX = -1;
@@ -678,6 +692,20 @@
                 && mAppToken != null && mAppToken.mTargetSdk < Build.VERSION_CODES.Q;
     }
 
+    void setLastExclusionHeights(int side, int requested, int granted) {
+        boolean changed = mLastGrantedExclusionHeight[side] != granted
+                || mLastRequestedExclusionHeight[side] != requested;
+
+        if (changed) {
+            if (mLastShownChangedReported) {
+                logExclusionRestrictions(side);
+            }
+
+            mLastGrantedExclusionHeight[side] = granted;
+            mLastRequestedExclusionHeight[side] = requested;
+        }
+    }
+
     interface PowerManagerWrapper {
         void wakeUp(long time, @WakeReason int reason, String details);
 
@@ -2961,6 +2989,49 @@
         mAnimatingExit = false;
     }
 
+    void onSurfaceShownChanged(boolean shown) {
+        if (mLastShownChangedReported == shown) {
+            return;
+        }
+        mLastShownChangedReported = shown;
+
+        if (shown) {
+            initExclusionRestrictions();
+        } else {
+            logExclusionRestrictions(EXCLUSION_LEFT);
+            logExclusionRestrictions(EXCLUSION_RIGHT);
+        }
+    }
+
+    private void logExclusionRestrictions(int side) {
+        if (!logsGestureExclusionRestrictions(this)
+                || SystemClock.uptimeMillis() < mLastExclusionLogUptimeMillis[side]
+                + mWmService.mSystemGestureExclusionLogDebounceTimeoutMillis) {
+            // Drop the log if we have just logged; this is okay, because what we would have logged
+            // was true only for a short duration.
+            return;
+        }
+
+        final long now = SystemClock.uptimeMillis();
+        final long duration = now - mLastExclusionLogUptimeMillis[side];
+        mLastExclusionLogUptimeMillis[side] = now;
+
+        final int requested = mLastRequestedExclusionHeight[side];
+        final int granted = mLastGrantedExclusionHeight[side];
+
+        StatsLog.write(StatsLog.EXCLUSION_RECT_STATE_CHANGED,
+                mAttrs.packageName, requested, requested - granted /* rejected */,
+                side + 1 /* Sides are 1-indexed in atoms.proto */,
+                (getConfiguration().orientation == ORIENTATION_LANDSCAPE),
+                isSplitScreenWindowingMode(getWindowingMode()), (int) duration);
+    }
+
+    private void initExclusionRestrictions() {
+        final long now = SystemClock.uptimeMillis();
+        mLastExclusionLogUptimeMillis[EXCLUSION_LEFT] = now;
+        mLastExclusionLogUptimeMillis[EXCLUSION_RIGHT] = now;
+    }
+
     @Override
     public boolean isDefaultDisplay() {
         final DisplayContent displayContent = getDisplayContent();
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index a616e06..bcefa8f 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -499,6 +499,8 @@
 
         mService.updateNonSystemOverlayWindowsVisibilityIfNeeded(mAnimator.mWin, surfaceShown);
 
+        mAnimator.mWin.onSurfaceShownChanged(surfaceShown);
+
         if (mWindowSession != null) {
             mWindowSession.onWindowSurfaceVisibilityChanged(this, mSurfaceShown, mWindowType);
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index cfa9944..59996cc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -16,6 +16,7 @@
 package com.android.server.devicepolicy;
 
 import android.app.admin.IDevicePolicyManager;
+import android.content.ComponentName;
 
 import com.android.server.SystemService;
 
@@ -56,4 +57,9 @@
 
     public void clearSystemUpdatePolicyFreezePeriodRecord() {
     }
+
+    public boolean setKeyGrantForApp(ComponentName admin, String callerPackage, String alias,
+            String packageName, boolean hasGrant) {
+        return false;
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ba06369..f800cca 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5727,6 +5727,59 @@
         return false;
     }
 
+    @Override
+    public boolean setKeyGrantForApp(
+            ComponentName who, String callerPackage, String alias, String packageName,
+            boolean hasGrant) {
+        enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+                DELEGATION_CERT_SELECTION);
+
+        if (TextUtils.isEmpty(alias)) {
+            throw new IllegalArgumentException("Alias to grant cannot be empty.");
+        }
+
+        if (TextUtils.isEmpty(packageName)) {
+            throw new IllegalArgumentException("Package to grant to cannot be empty.");
+        }
+
+        final int userId = mInjector.userHandleGetCallingUserId();
+        final int granteeUid;
+        try {
+            ApplicationInfo ai = mInjector.getIPackageManager().getApplicationInfo(
+                    packageName, 0, userId);
+            if (ai == null) {
+                throw new IllegalArgumentException(
+                        String.format("Provided package %s is not installed", packageName));
+            }
+            granteeUid = ai.uid;
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failure getting grantee uid", e);
+        }
+
+        final int callingUid = mInjector.binderGetCallingUid();
+        final long id = mInjector.binderClearCallingIdentity();
+        try {
+            final KeyChainConnection keyChainConnection =
+                    KeyChain.bindAsUser(mContext, UserHandle.getUserHandleForUid(callingUid));
+            try {
+                IKeyChainService keyChain = keyChainConnection.getService();
+                keyChain.setGrant(granteeUid, alias, hasGrant);
+                return true;
+            } catch (RemoteException e) {
+                Log.e(LOG_TAG, "Setting grant for package.", e);
+                return  false;
+            } finally {
+                keyChainConnection.close();
+            }
+        } catch (InterruptedException e) {
+            Log.w(LOG_TAG, "Interrupted while setting key grant", e);
+            Thread.currentThread().interrupt();
+        } finally {
+            mInjector.binderRestoreCallingIdentity(id);
+        }
+        return false;
+    }
+
     /**
      * Enforce one the following conditions are met:
      * (1) The device has a Device Owner, and one of the following holds:
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6e0d834..83b3194 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1476,6 +1476,8 @@
                 t.traceBegin("StartWallpaperManagerService");
                 mSystemServiceManager.startService(WALLPAPER_SERVICE_CLASS);
                 t.traceEnd();
+            } else {
+                Slog.i(TAG, "Wallpaper service disabled by config");
             }
 
             t.traceBegin("StartAudioService");
diff --git a/services/net/java/android/net/dhcp/DhcpServerCallbacks.java b/services/net/java/android/net/dhcp/DhcpServerCallbacks.java
index bb56876..7c413779 100644
--- a/services/net/java/android/net/dhcp/DhcpServerCallbacks.java
+++ b/services/net/java/android/net/dhcp/DhcpServerCallbacks.java
@@ -21,13 +21,11 @@
  * @hide
  */
 public abstract class DhcpServerCallbacks extends IDhcpServerCallbacks.Stub {
-    // TODO: add @Override here once the API is versioned
-
     /**
      * Get the version of the aidl interface implemented by the callbacks.
      */
+    @Override
     public int getInterfaceVersion() {
-        // TODO: return IDhcpServerCallbacks.VERSION;
-        return 0;
+        return IDhcpServerCallbacks.VERSION;
     }
 }
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
index be93d6ba..0d99561 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -26,12 +26,18 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.robolectric.Shadows.shadowOf;
 import static org.testng.Assert.expectThrows;
 
+import static java.util.Collections.emptySet;
+
 import android.annotation.UserIdInt;
 import android.app.Application;
 import android.app.backup.IBackupManagerMonitor;
@@ -49,6 +55,7 @@
 import com.android.server.backup.testing.TransportData;
 import com.android.server.testing.shadows.ShadowApplicationPackageManager;
 import com.android.server.testing.shadows.ShadowBinder;
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
 
 import org.junit.After;
 import org.junit.Before;
@@ -69,7 +76,12 @@
 
 /** Tests for the user-aware backup/restore system service {@link BackupManagerService}. */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowApplicationPackageManager.class, ShadowBinder.class})
+@Config(
+        shadows = {
+            ShadowApplicationPackageManager.class,
+            ShadowBinder.class,
+            ShadowSystemServiceRegistry.class
+        })
 @Presubmit
 public class BackupManagerServiceTest {
     private static final String TEST_PACKAGE = "package";
@@ -121,7 +133,7 @@
     public void testConstructor_doesNotRegisterUsers() throws Exception {
         BackupManagerService backupManagerService = createService();
 
-        assertThat(backupManagerService.getServiceUsers().size()).isEqualTo(0);
+        assertThat(backupManagerService.getUserServices().size()).isEqualTo(0);
     }
 
     /** Test that the constructor handles {@code null} parameters. */
@@ -150,9 +162,9 @@
     public void testStartServiceForUser_registersUser() throws Exception {
         BackupManagerService backupManagerService = createService();
 
-        backupManagerService.startServiceForUser(mUserOneId);
+        backupManagerService.startServiceForUser(mUserOneId, emptySet());
 
-        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers();
+        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices();
         assertThat(serviceUsers.size()).isEqualTo(1);
         assertThat(serviceUsers.get(mUserOneId)).isNotNull();
     }
@@ -164,7 +176,7 @@
 
         backupManagerService.startServiceForUser(mUserOneId, mUserOneService);
 
-        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers();
+        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices();
         assertThat(serviceUsers.size()).isEqualTo(1);
         assertThat(serviceUsers.get(mUserOneId)).isEqualTo(mUserOneService);
     }
@@ -178,7 +190,7 @@
 
         backupManagerService.stopServiceForUser(mUserOneId);
 
-        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers();
+        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices();
         assertThat(serviceUsers.size()).isEqualTo(1);
         assertThat(serviceUsers.get(mUserOneId)).isNull();
         assertThat(serviceUsers.get(mUserTwoId)).isEqualTo(mUserTwoService);
@@ -204,7 +216,7 @@
 
         backupManagerService.stopServiceForUser(mUserOneId);
 
-        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers();
+        SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices();
         assertThat(serviceUsers.size()).isEqualTo(0);
     }
 
@@ -1500,6 +1512,48 @@
     }
 
     // ---------------------------------------------
+    //  Lifecycle tests
+    // ---------------------------------------------
+
+
+    /** testOnStart_publishesService */
+    @Test
+    public void testOnStart_publishesService() {
+        Trampoline trampoline = mock(Trampoline.class);
+        BackupManagerService.Lifecycle lifecycle =
+                spy(new BackupManagerService.Lifecycle(mContext, trampoline));
+        doNothing().when(lifecycle).publishService(anyString(), any());
+
+        lifecycle.onStart();
+
+        verify(lifecycle).publishService(Context.BACKUP_SERVICE, trampoline);
+    }
+
+    /** testOnUnlockUser_forwards */
+    @Test
+    public void testOnUnlockUser_forwards() {
+        Trampoline trampoline = mock(Trampoline.class);
+        BackupManagerService.Lifecycle lifecycle =
+                new BackupManagerService.Lifecycle(mContext, trampoline);
+
+        lifecycle.onUnlockUser(UserHandle.USER_SYSTEM);
+
+        verify(trampoline).onUnlockUser(UserHandle.USER_SYSTEM);
+    }
+
+    /** testOnStopUser_forwards */
+    @Test
+    public void testOnStopUser_forwards() {
+        Trampoline trampoline = mock(Trampoline.class);
+        BackupManagerService.Lifecycle lifecycle =
+                new BackupManagerService.Lifecycle(mContext, trampoline);
+
+        lifecycle.onStopUser(UserHandle.USER_SYSTEM);
+
+        verify(trampoline).onStopUser(UserHandle.USER_SYSTEM);
+    }
+
+    // ---------------------------------------------
     //  Service tests
     // ---------------------------------------------
 
diff --git a/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java b/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java
index 9a78d0b3..dbc0da7 100644
--- a/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java
@@ -25,6 +25,8 @@
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -36,7 +38,7 @@
 import org.robolectric.shadows.ShadowJobScheduler;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowJobScheduler.class})
+@Config(shadows = {ShadowJobScheduler.class, ShadowSystemServiceRegistry.class})
 @Presubmit
 public class FullBackupJobTest {
     private Context mContext;
diff --git a/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java b/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
index 8d9e44f..1c5fac2 100644
--- a/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
@@ -24,14 +24,18 @@
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowSystemServiceRegistry.class})
 @Presubmit
 public class KeyValueBackupJobTest {
     private Context mContext;
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 74fe81c..84e810d 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -63,6 +63,7 @@
 import com.android.server.testing.shadows.ShadowBinder;
 import com.android.server.testing.shadows.ShadowKeyValueBackupJob;
 import com.android.server.testing.shadows.ShadowKeyValueBackupTask;
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
 
 import org.junit.After;
 import org.junit.Before;
@@ -88,7 +89,12 @@
  * UserBackupManagerService} that performs operations for its target user.
  */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowAppBackupUtils.class, ShadowApplicationPackageManager.class})
+@Config(
+        shadows = {
+            ShadowAppBackupUtils.class,
+            ShadowApplicationPackageManager.class,
+            ShadowSystemServiceRegistry.class
+        })
 @Presubmit
 public class UserBackupManagerServiceTest {
     private static final String TAG = "BMSTest";
diff --git a/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java b/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
index 44e9e6a..e49425b 100644
--- a/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
@@ -32,6 +32,7 @@
 import com.android.server.backup.UserBackupManagerService;
 import com.android.server.backup.testing.BackupManagerServiceTestUtils;
 import com.android.server.testing.shadows.ShadowApplicationPackageManager;
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -51,7 +52,12 @@
  * UserBackupManagerService}.
  */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowApplicationPackageManager.class, ShadowJobScheduler.class})
+@Config(
+        shadows = {
+            ShadowApplicationPackageManager.class,
+            ShadowJobScheduler.class,
+            ShadowSystemServiceRegistry.class
+        })
 @Presubmit
 public class SetupObserverTest {
     private static final String TAG = "SetupObserverTest";
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 43691e0..6a90d0b 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -94,7 +94,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 import android.util.Pair;
@@ -121,6 +120,7 @@
 import com.android.server.testing.shadows.ShadowBackupDataInput;
 import com.android.server.testing.shadows.ShadowBackupDataOutput;
 import com.android.server.testing.shadows.ShadowEventLog;
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
 
 import com.google.common.truth.IterableSubject;
 
@@ -164,10 +164,11 @@
             ShadowBackupDataInput.class,
             ShadowBackupDataOutput.class,
             ShadowEventLog.class,
-            ShadowQueuedWork.class
+            ShadowQueuedWork.class,
+            ShadowSystemServiceRegistry.class
         })
 @Presubmit
-public class KeyValueBackupTaskTest {
+public class KeyValueBackupTaskTest  {
     private static final PackageData PACKAGE_1 = keyValuePackage(1);
     private static final PackageData PACKAGE_2 = keyValuePackage(2);
     private static final String BACKUP_AGENT_SHARED_PREFS_SYNCHRONIZER_CLASS =
@@ -184,7 +185,7 @@
     private TransportData mTransport;
     private ShadowLooper mShadowBackupLooper;
     private Handler mBackupHandler;
-    private PowerManager.WakeLock mWakeLock;
+    private UserBackupManagerService.BackupWakeLock mWakeLock;
     private KeyValueBackupReporter mReporter;
     private PackageManager mPackageManager;
     private ShadowPackageManager mShadowPackageManager;
diff --git a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
index f4cea7a..3fc421d 100644
--- a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
@@ -18,7 +18,7 @@
 
 import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createBackupWakeLock;
 import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBackupManagerServiceBasics;
-import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThreadAndGetLooper;
+import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThread;
 import static com.android.server.backup.testing.TestUtils.assertEventLogged;
 import static com.android.server.backup.testing.TestUtils.assertEventNotLogged;
 import static com.android.server.backup.testing.TransportData.backupTransport;
@@ -44,8 +44,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.Looper;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 
@@ -98,7 +98,7 @@
     @Mock private IBackupManagerMonitor mMonitor;
     private ShadowLooper mShadowBackupLooper;
     private ShadowApplication mShadowApplication;
-    private PowerManager.WakeLock mWakeLock;
+    private UserBackupManagerService.BackupWakeLock mWakeLock;
     private TransportData mTransport;
     private RestoreSet mRestoreSet1;
     private RestoreSet mRestoreSet2;
@@ -118,7 +118,8 @@
 
         mShadowPackageManager = shadowOf(application.getPackageManager());
 
-        Looper backupLooper = startBackupThreadAndGetLooper();
+        HandlerThread handlerThread = startBackupThread(null);
+        Looper backupLooper = handlerThread.getLooper();
         mShadowBackupLooper = shadowOf(backupLooper);
 
         Handler mainHandler = new Handler(Looper.getMainLooper());
@@ -129,7 +130,7 @@
         // We need to mock BMS timeout parameters before initializing the BackupHandler since
         // the constructor of BackupHandler relies on it.
         when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters);
-        BackupHandler backupHandler = new BackupHandler(mBackupManagerService, backupLooper);
+        BackupHandler backupHandler = new BackupHandler(mBackupManagerService, handlerThread);
 
         mWakeLock = createBackupWakeLock(application);
 
diff --git a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
index 47abcc5..392d182 100644
--- a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
+++ b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
@@ -113,7 +113,7 @@
             TransportManager transportManager,
             PackageManager packageManager,
             Handler backupHandler,
-            PowerManager.WakeLock wakeLock,
+            UserBackupManagerService.BackupWakeLock wakeLock,
             BackupAgentTimeoutParameters agentTimeoutParameters) {
 
         when(backupManagerService.getContext()).thenReturn(application);
@@ -161,10 +161,12 @@
                 });
     }
 
-    public static PowerManager.WakeLock createBackupWakeLock(Application application) {
+    public static UserBackupManagerService.BackupWakeLock createBackupWakeLock(
+            Application application) {
         PowerManager powerManager =
                 (PowerManager) application.getSystemService(Context.POWER_SERVICE);
-        return powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
+        return new UserBackupManagerService.BackupWakeLock(
+                powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*"));
     }
 
     /**
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowSystemServiceRegistry.java b/services/robotests/src/com/android/server/testing/shadows/ShadowSystemServiceRegistry.java
new file mode 100644
index 0000000..c59798fc92
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowSystemServiceRegistry.java
@@ -0,0 +1,48 @@
+/*
+ * 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.testing.shadows;
+
+import android.app.SystemServiceRegistry;
+import android.app.job.JobSchedulerFrameworkInitializer;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.util.ReflectionHelpers;
+
+/**
+ * Shadow of {@link SystemServiceRegistry}
+ *
+ * <p>JobSchedulerFrameworkInitializer contains a static initializer registering JobScheduler as a
+ * system service. We need to make sure the initializer is run before the tests that use
+ * JobScheduler. And we're putting this on the static initializer of SystemServiceRegistry since
+ * other services are registered here.
+ */
+@Implements(className = "android.app.SystemServiceRegistry")
+public class ShadowSystemServiceRegistry {
+    @Implementation
+    protected static void __staticInitializer__() {
+        // Make sure the static init in the real class is still executed.
+        ReflectionHelpers.callStaticMethod(SystemServiceRegistry.class, "__staticInitializer__");
+        try {
+            Class.forName(JobSchedulerFrameworkInitializer.class.getCanonicalName());
+        } catch (ClassNotFoundException e) {
+            // Rethrowing as an unchecked exception because checked exceptions are not allowed in
+            // static blocks.
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
index 4a33739..48e459f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
@@ -21,12 +21,17 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.content.Context;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Process;
 import android.platform.test.annotations.Presubmit;
 import android.provider.DeviceConfig;
 import android.text.TextUtils;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.ServiceThread;
 import com.android.server.appop.AppOpsService;
 import com.android.server.testables.TestableDeviceConfig;
 
@@ -54,6 +59,8 @@
 @RunWith(MockitoJUnitRunner.class)
 public final class AppCompactorTest {
 
+    private ServiceThread mThread;
+
     @Mock
     private AppOpsService mAppOpsService;
     private AppCompactor mCompactorUnderTest;
@@ -70,7 +77,14 @@
         mHandlerThread = new HandlerThread("");
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
-        ActivityManagerService ams = new ActivityManagerService(new TestInjector());
+
+        mThread = new ServiceThread("TestServiceThread", Process.THREAD_PRIORITY_DEFAULT,
+                true /* allowIo */);
+        mThread.start();
+
+        ActivityManagerService ams = new ActivityManagerService(
+                new TestInjector(InstrumentationRegistry.getInstrumentation().getContext()),
+                mThread);
         mCompactorUnderTest = new AppCompactor(ams,
                 new AppCompactor.PropertyChangedCallbackForTest() {
                     @Override
@@ -85,6 +99,7 @@
     @After
     public void tearDown() {
         mHandlerThread.quit();
+        mThread.quit();
         mCountDown = null;
     }
 
@@ -647,6 +662,11 @@
     }
 
     private class TestInjector extends Injector {
+
+        TestInjector(Context context) {
+            super(context);
+        }
+
         @Override
         public AppOpsService getAppOpsService(File file, Handler handler) {
             return mAppOpsService;
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
new file mode 100644
index 0000000..9670899
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -0,0 +1,1615 @@
+/*
+ * 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.am;
+
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_RECENT;
+import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION;
+import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
+import static android.app.ActivityManager.PROCESS_STATE_HOME;
+import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
+import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
+import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_TOP;
+import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING;
+import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.server.am.ProcessList.BACKUP_APP_ADJ;
+import static com.android.server.am.ProcessList.CACHED_APP_MAX_ADJ;
+import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ;
+import static com.android.server.am.ProcessList.FOREGROUND_APP_ADJ;
+import static com.android.server.am.ProcessList.HEAVY_WEIGHT_APP_ADJ;
+import static com.android.server.am.ProcessList.HOME_APP_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_APP_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
+import static com.android.server.am.ProcessList.PERSISTENT_PROC_ADJ;
+import static com.android.server.am.ProcessList.PERSISTENT_SERVICE_ADJ;
+import static com.android.server.am.ProcessList.PREVIOUS_APP_ADJ;
+import static com.android.server.am.ProcessList.SCHED_GROUP_BACKGROUND;
+import static com.android.server.am.ProcessList.SCHED_GROUP_DEFAULT;
+import static com.android.server.am.ProcessList.SCHED_GROUP_RESTRICTED;
+import static com.android.server.am.ProcessList.SCHED_GROUP_TOP_APP;
+import static com.android.server.am.ProcessList.SCHED_GROUP_TOP_APP_BOUND;
+import static com.android.server.am.ProcessList.SERVICE_ADJ;
+import static com.android.server.am.ProcessList.SERVICE_B_ADJ;
+import static com.android.server.am.ProcessList.UNKNOWN_ADJ;
+import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.AdditionalAnswers.answer;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Build;
+import android.os.IBinder;
+import android.os.PowerManagerInternal;
+import android.os.SystemClock;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.android.server.wm.ActivityServiceConnectionsHolder;
+import com.android.server.wm.ActivityTaskManagerService;
+import com.android.server.wm.WindowProcessController;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+
+/**
+ * Test class for {@link OomAdjuster}.
+ *
+ * Build/Install/Run:
+ * atest MockingOomAdjusterTests
+ */
+public class MockingOomAdjusterTests {
+    private static final int MOCKAPP_PID = 12345;
+    private static final int MOCKAPP_UID = 12345;
+    private static final String MOCKAPP_PROCESSNAME = "test #1";
+    private static final String MOCKAPP_PACKAGENAME = "com.android.test.test1";
+    private static final int MOCKAPP2_PID = MOCKAPP_PID + 1;
+    private static final int MOCKAPP2_UID = MOCKAPP_UID + 1;
+    private static final String MOCKAPP2_PROCESSNAME = "test #2";
+    private static final String MOCKAPP2_PACKAGENAME = "com.android.test.test2";
+    private static final int MOCKAPP3_PID = MOCKAPP_PID + 2;
+    private static final int MOCKAPP3_UID = MOCKAPP_UID + 2;
+    private static final String MOCKAPP3_PROCESSNAME = "test #3";
+    private static final String MOCKAPP3_PACKAGENAME = "com.android.test.test3";
+    private static final int MOCKAPP4_PID = MOCKAPP_PID + 3;
+    private static final int MOCKAPP4_UID = MOCKAPP_UID + 3;
+    private static final String MOCKAPP4_PROCESSNAME = "test #4";
+    private static final String MOCKAPP4_PACKAGENAME = "com.android.test.test4";
+    private static final int MOCKAPP5_PID = MOCKAPP_PID + 4;
+    private static final int MOCKAPP5_UID = MOCKAPP_UID + 4;
+    private static final String MOCKAPP5_PROCESSNAME = "test #5";
+    private static final String MOCKAPP5_PACKAGENAME = "com.android.test.test5";
+    private static Context sContext;
+    private static ActivityManagerService sService;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        sContext = getInstrumentation().getTargetContext();
+        System.setProperty("dexmaker.share_classloader", "true");
+
+        sService = mock(ActivityManagerService.class);
+        sService.mActivityTaskManager = new ActivityTaskManagerService(sContext);
+        sService.mActivityTaskManager.initialize(null, null, sContext.getMainLooper());
+        sService.mAtmInternal = spy(sService.mActivityTaskManager.getAtmInternal());
+
+        sService.mConstants = new ActivityManagerConstants(sContext, sService,
+                sContext.getMainThreadHandler());
+        setFieldValue(ActivityManagerService.class, sService, "mProcessList",
+                new ProcessList());
+        setFieldValue(ActivityManagerService.class, sService, "mHandler",
+                mock(ActivityManagerService.MainHandler.class));
+        setFieldValue(ActivityManagerService.class, sService, "mProcessStats",
+                mock(ProcessStatsService.class));
+        setFieldValue(ActivityManagerService.class, sService, "mBackupTargets",
+                mock(SparseArray.class));
+        setFieldValue(ActivityManagerService.class, sService, "mOomAdjProfiler",
+                mock(OomAdjProfiler.class));
+        doReturn(new ActivityManagerService.ProcessChangeItem()).when(sService)
+                .enqueueProcessChangeItemLocked(anyInt(), anyInt());
+        sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList,
+                mock(ActiveUids.class));
+        sService.mOomAdjuster.mAdjSeq = 10000;
+    }
+
+    private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
+        try {
+            Field field = clazz.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            Field mfield = Field.class.getDeclaredField("accessFlags");
+            mfield.setAccessible(true);
+            mfield.setInt(field, mfield.getInt(field) & ~(Modifier.FINAL | Modifier.PRIVATE));
+            field.set(obj, val);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+        }
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Persistent_TopUi_Sleeping() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        app.maxAdj = PERSISTENT_PROC_ADJ;
+        app.setHasTopUi(true);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_ASLEEP;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+
+        assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERSISTENT_PROC_ADJ,
+                SCHED_GROUP_RESTRICTED);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Persistent_TopUi_Awake() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        app.maxAdj = PERSISTENT_PROC_ADJ;
+        app.setHasTopUi(true);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_PERSISTENT_UI, PERSISTENT_PROC_ADJ,
+                SCHED_GROUP_TOP_APP);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Persistent_TopApp() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        app.maxAdj = PERSISTENT_PROC_ADJ;
+        doReturn(app).when(sService).getTopAppLocked();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doReturn(null).when(sService).getTopAppLocked();
+
+        assertProcStates(app, PROCESS_STATE_PERSISTENT_UI, PERSISTENT_PROC_ADJ,
+                SCHED_GROUP_TOP_APP);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_TopApp_Awake() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
+        doReturn(app).when(sService).getTopAppLocked();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doReturn(null).when(sService).getTopAppLocked();
+
+        assertProcStates(app, PROCESS_STATE_TOP, FOREGROUND_APP_ADJ, SCHED_GROUP_TOP_APP);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_RunningAnimations() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        doReturn(PROCESS_STATE_TOP_SLEEPING).when(sService.mAtmInternal).getTopProcessState();
+        app.runningRemoteAnimation = true;
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
+
+        assertProcStates(app, PROCESS_STATE_TOP_SLEEPING, VISIBLE_APP_ADJ, SCHED_GROUP_TOP_APP);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_RunningInstrumentation() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        doReturn(mock(ActiveInstrumentation.class)).when(app).getActiveInstrumentation();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doCallRealMethod().when(app).getActiveInstrumentation();
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, FOREGROUND_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_ReceivingBroadcast() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        doReturn(true).when(sService).isReceivingBroadcastLocked(any(ProcessRecord.class),
+                any(ArraySet.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doReturn(false).when(sService).isReceivingBroadcastLocked(any(ProcessRecord.class),
+                any(ArraySet.class));
+
+        assertProcStates(app, PROCESS_STATE_RECEIVER, FOREGROUND_APP_ADJ, SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_ExecutingService() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        app.executingServices.add(mock(ServiceRecord.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_SERVICE, FOREGROUND_APP_ADJ, SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_TopApp_Sleeping() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        doReturn(PROCESS_STATE_TOP_SLEEPING).when(sService.mAtmInternal).getTopProcessState();
+        doReturn(app).when(sService).getTopAppLocked();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_ASLEEP;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doReturn(null).when(sService).getTopAppLocked();
+        doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+
+        assertProcStates(app, PROCESS_STATE_TOP_SLEEPING, FOREGROUND_APP_ADJ,
+                SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_CachedEmpty() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        app.setCurRawAdj(CACHED_APP_MIN_ADJ);
+        doReturn(null).when(sService).getTopAppLocked();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, CACHED_APP_MIN_ADJ,
+                SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_VisibleActivities() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController();
+        WindowProcessController wpc = app.getWindowProcessController();
+        doReturn(true).when(wpc).hasActivities();
+        doAnswer(answer((minTaskLayer, callback) -> {
+            Field field = callback.getClass().getDeclaredField("adj");
+            field.set(callback, VISIBLE_APP_ADJ);
+            field = callback.getClass().getDeclaredField("foregroundActivities");
+            field.set(callback, true);
+            field = callback.getClass().getDeclaredField("procState");
+            field.set(callback, PROCESS_STATE_TOP);
+            field = callback.getClass().getDeclaredField("schedGroup");
+            field.set(callback, SCHED_GROUP_TOP_APP);
+            return 0;
+        })).when(wpc).computeOomAdjFromActivities(anyInt(),
+                any(WindowProcessController.ComputeOomAdjCallback.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doCallRealMethod().when(app).getWindowProcessController();
+
+        assertProcStates(app, PROCESS_STATE_TOP, VISIBLE_APP_ADJ, SCHED_GROUP_TOP_APP);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_RecentTasks() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        doReturn(true).when(app).hasRecentTasks();
+        app.lastTopTime = SystemClock.uptimeMillis();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doCallRealMethod().when(app).hasRecentTasks();
+
+        assertEquals(PROCESS_STATE_CACHED_RECENT, app.setProcState);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_FgServiceLocation() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        app.setHasForegroundServices(true, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_FgService() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        app.setHasForegroundServices(true, 0);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_OverlayUi() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        app.setHasOverlayUi(true);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_PerceptibleRecent() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        app.setHasForegroundServices(true, 0);
+        app.lastTopTime = SystemClock.uptimeMillis();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE,
+                PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Toast() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        app.forcingToImportant = new Object();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_HeavyWeight() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        doReturn(true).when(sService.mAtmInternal).isHeavyWeightProcess(any(
+                WindowProcessController.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doReturn(false).when(sService.mAtmInternal).isHeavyWeightProcess(any(
+                WindowProcessController.class));
+
+        assertProcStates(app, PROCESS_STATE_HEAVY_WEIGHT, HEAVY_WEIGHT_APP_ADJ,
+                SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_HomeApp() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController();
+        WindowProcessController wpc = app.getWindowProcessController();
+        doReturn(true).when(wpc).isHomeProcess();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_HOME, HOME_APP_ADJ, SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_PreviousApp() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController();
+        WindowProcessController wpc = app.getWindowProcessController();
+        doReturn(true).when(wpc).isPreviousProcess();
+        doReturn(true).when(app).hasActivities();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
+                SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Backup() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        BackupRecord backupTarget = new BackupRecord(null, 0, 0);
+        backupTarget.app = app;
+        doReturn(backupTarget).when(sService.mBackupTargets).get(anyInt());
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doReturn(null).when(sService.mBackupTargets).get(anyInt());
+
+        assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, BACKUP_APP_ADJ,
+                SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_ClientActivities() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        doReturn(true).when(app).hasClientActivities();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(PROCESS_STATE_CACHED_ACTIVITY_CLIENT, app.setProcState);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_TreatLikeActivity() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        app.treatLikeActivity = true;
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.setProcState);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_ServiceB() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        app.serviceb = true;
+        ServiceRecord s = mock(ServiceRecord.class);
+        doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
+        s.startRequested = true;
+        s.lastActivity = SystemClock.uptimeMillis();
+        app.services.add(s);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_B_ADJ, SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_MaxAdj() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        app.maxAdj = PERCEPTIBLE_LOW_APP_ADJ;
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, PERCEPTIBLE_LOW_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Started() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ServiceRecord s = mock(ServiceRecord.class);
+        doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
+        s.startRequested = true;
+        s.lastActivity = SystemClock.uptimeMillis();
+        app.services.add(s);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Started_WaivePriority() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        ServiceRecord s = bindService(app, client, null, Context.BIND_WAIVE_PRIORITY,
+                mock(IBinder.class));
+        s.startRequested = true;
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
+        doReturn(client).when(sService).getTopAppLocked();
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doReturn(null).when(sService).getTopAppLocked();
+
+        assertProcStates(app, PROCESS_STATE_SERVICE, UNKNOWN_ADJ, SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Started_WaivePriority_TreatLikeActivity() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, Context.BIND_WAIVE_PRIORITY
+                | Context.BIND_TREAT_LIKE_ACTIVITY, mock(IBinder.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.setProcState);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Started_WaivePriority_AdjustWithActivity() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        IBinder binder = mock(IBinder.class);
+        ServiceRecord s = bindService(app, client, null, Context.BIND_WAIVE_PRIORITY
+                | Context.BIND_ADJUST_WITH_ACTIVITY | Context.BIND_IMPORTANT, binder);
+        ConnectionRecord cr = s.getConnections().get(binder).get(0);
+        setFieldValue(ConnectionRecord.class, cr, "activity",
+                mock(ActivityServiceConnectionsHolder.class));
+        doReturn(true).when(cr.activity).isActivityVisible();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(FOREGROUND_APP_ADJ, app.setAdj);
+        assertEquals(SCHED_GROUP_TOP_APP_BOUND, app.setSchedGroup);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Self() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        bindService(app, app, null, 0, mock(IBinder.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, UNKNOWN_ADJ, SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_CachedActivity() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        client.treatLikeActivity = true;
+        bindService(app, client, null, 0, mock(IBinder.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(PROCESS_STATE_CACHED_EMPTY, app.setProcState);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_AllowOomManagement() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController();
+        WindowProcessController wpc = app.getWindowProcessController();
+        doReturn(false).when(wpc).isHomeProcess();
+        doReturn(true).when(wpc).isPreviousProcess();
+        doReturn(true).when(app).hasActivities();
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, Context.BIND_ALLOW_OOM_MANAGEMENT, mock(IBinder.class));
+        doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
+        doReturn(client).when(sService).getTopAppLocked();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doReturn(null).when(sService).getTopAppLocked();
+
+        assertEquals(PREVIOUS_APP_ADJ, app.setAdj);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_BoundByPersistentService() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
+        client.maxAdj = PERSISTENT_PROC_ADJ;
+        client.setHasTopUi(true);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Bound_ImportantFg() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, Context.BIND_IMPORTANT, mock(IBinder.class));
+        client.executingServices.add(mock(ServiceRecord.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(FOREGROUND_APP_ADJ, app.setAdj);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_BoundByTop() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
+        doReturn(client).when(sService).getTopAppLocked();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doReturn(null).when(sService).getTopAppLocked();
+
+        assertProcStates(app, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ, SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_BoundFgService() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
+        client.maxAdj = PERSISTENT_PROC_ADJ;
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(PROCESS_STATE_BOUND_FOREGROUND_SERVICE, app.setProcState);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_BoundNotForeground() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, Context.BIND_NOT_FOREGROUND, mock(IBinder.class));
+        client.maxAdj = PERSISTENT_PROC_ADJ;
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, app.setProcState);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_ImportantFgService() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        client.setHasForegroundServices(true, 0);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(PROCESS_STATE_FOREGROUND_SERVICE, app.setProcState);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_BoundByBackup_AboveClient() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
+        BackupRecord backupTarget = new BackupRecord(null, 0, 0);
+        backupTarget.app = client;
+        doReturn(backupTarget).when(sService.mBackupTargets).get(anyInt());
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doReturn(null).when(sService.mBackupTargets).get(anyInt());
+
+        assertEquals(BACKUP_APP_ADJ, app.setAdj);
+
+        client.maxAdj = PERSISTENT_PROC_ADJ;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(PERSISTENT_SERVICE_ADJ, app.setAdj);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_NotPerceptible() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
+        client.runningRemoteAnimation = true;
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(PERCEPTIBLE_LOW_APP_ADJ, app.setAdj);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_NotVisible() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, Context.BIND_NOT_VISIBLE, mock(IBinder.class));
+        client.runningRemoteAnimation = true;
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(PERCEPTIBLE_APP_ADJ, app.setAdj);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Perceptible() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        client.setHasOverlayUi(true);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(PERCEPTIBLE_APP_ADJ, app.setAdj);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Other() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        client.runningRemoteAnimation = true;
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(VISIBLE_APP_ADJ, app.setAdj);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Bind_ImportantBg() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, Context.BIND_IMPORTANT_BACKGROUND, mock(IBinder.class));
+        client.setHasOverlayUi(true);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertEquals(PROCESS_STATE_IMPORTANT_BACKGROUND, app.setProcState);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Provider_Self() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        bindProvider(app, app, null, null, false);
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, UNKNOWN_ADJ, SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Provider_Cached_Activity() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindProvider(app, client, null, null, false);
+        client.treatLikeActivity = true;
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, UNKNOWN_ADJ, SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Provider_TopApp() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindProvider(app, client, null, null, false);
+        doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
+        doReturn(client).when(sService).getTopAppLocked();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doReturn(null).when(sService).getTopAppLocked();
+
+        assertProcStates(app, PROCESS_STATE_BOUND_TOP, FOREGROUND_APP_ADJ, SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Provider_FgService() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        client.setHasForegroundServices(true, 0);
+        bindProvider(app, client, null, null, false);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Provider_ExternalProcessHandles() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindProvider(app, client, null, null, true);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND, FOREGROUND_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Provider_Retention() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        app.lastProviderTime = SystemClock.uptimeMillis();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
+                SCHED_GROUP_BACKGROUND);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Chain_BoundByTop() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(client, client2, null, 0, mock(IBinder.class));
+        doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
+        doReturn(client2).when(sService).getTopAppLocked();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doReturn(null).when(sService).getTopAppLocked();
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_BoundByFgService_Branch() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(app, client2, null, 0, mock(IBinder.class));
+        client2.setHasForegroundServices(true, 0);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Chain_BoundByFgService() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(client, client2, null, 0, mock(IBinder.class));
+        client2.setHasForegroundServices(true, 0);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Chain_BoundByFgService_Cycle() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(client, client2, null, 0, mock(IBinder.class));
+        client2.setHasForegroundServices(true, 0);
+        bindService(client2, app, null, 0, mock(IBinder.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Chain_BoundByFgService_Cycle_Branch() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(client, client2, null, 0, mock(IBinder.class));
+        client2.setHasForegroundServices(true, 0);
+        bindService(client2, app, null, 0, mock(IBinder.class));
+        ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
+                MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
+        client3.forcingToImportant = new Object();
+        bindService(app, client3, null, 0, mock(IBinder.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Chain_Perceptible_Cycle_Branch() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(client, client2, null, 0, mock(IBinder.class));
+        bindService(client2, app, null, 0, mock(IBinder.class));
+        doReturn(mock(WindowProcessController.class)).when(client2).getWindowProcessController();
+        WindowProcessController wpc = client2.getWindowProcessController();
+        doReturn(true).when(wpc).isHomeProcess();
+        ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
+                MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
+        client3.forcingToImportant = new Object();
+        bindService(app, client3, null, 0, mock(IBinder.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Chain_Perceptible_Cycle_2() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(client, client2, null, 0, mock(IBinder.class));
+        bindService(client2, app, null, 0, mock(IBinder.class));
+        doReturn(mock(WindowProcessController.class)).when(client2).getWindowProcessController();
+        WindowProcessController wpc = client2.getWindowProcessController();
+        doReturn(true).when(wpc).isHomeProcess();
+        ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
+                MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
+        ProcessRecord client4 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
+                MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
+        client4.forcingToImportant = new Object();
+        bindService(app, client4, null, 0, mock(IBinder.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Chain_BoundByFgService_Cycle_Branch_2() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(client, client2, null, 0, mock(IBinder.class));
+        bindService(client2, app, null, 0, mock(IBinder.class));
+        doReturn(mock(WindowProcessController.class)).when(client2).getWindowProcessController();
+        WindowProcessController wpc = client2.getWindowProcessController();
+        doReturn(true).when(wpc).isHomeProcess();
+        ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
+                MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
+        client3.forcingToImportant = new Object();
+        bindService(app, client3, null, 0, mock(IBinder.class));
+        ProcessRecord client4 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
+                MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
+        client4.setHasForegroundServices(true, 0);
+        bindService(app, client4, null, 0, mock(IBinder.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Chain_BoundByFgService_Branch_3() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        doReturn(mock(WindowProcessController.class)).when(client).getWindowProcessController();
+        WindowProcessController wpc = client.getWindowProcessController();
+        doReturn(true).when(wpc).isHomeProcess();
+        bindService(app, client, null, 0, mock(IBinder.class));
+        ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(app, client2, null, 0, mock(IBinder.class));
+        client2.setHasForegroundServices(true, 0);
+        ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
+                MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
+        client3.forcingToImportant = new Object();
+        bindService(app, client3, null, 0, mock(IBinder.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Provider() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindProvider(client, client2, null, null, false);
+        client2.setHasForegroundServices(true, 0);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Service_Provider_Cycle() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindProvider(client, client2, null, null, false);
+        client2.setHasForegroundServices(true, 0);
+        bindService(client2, app, null, 0, mock(IBinder.class));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Provider_Chain_BoundByFgService() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindProvider(app, client, null, null, false);
+        ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindProvider(client, client2, null, null, false);
+        client2.setHasForegroundServices(true, 0);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_Provider_Chain_BoundByFgService_Cycle() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindProvider(app, client, null, null, false);
+        ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindProvider(client, client2, null, null, false);
+        client2.setHasForegroundServices(true, 0);
+        bindProvider(client2, app, null, null, false);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoAll_Unbound() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        app.forcingToImportant = new Object();
+        ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        app2.setHasForegroundServices(true, 0);
+        ArrayList<ProcessRecord> lru = sService.mProcessList.mLruProcesses;
+        lru.clear();
+        lru.add(app);
+        lru.add(app2);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+        lru.clear();
+
+        assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoAll_BoundFgService() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        app.forcingToImportant = new Object();
+        ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        app2.setHasForegroundServices(true, 0);
+        bindService(app, app2, null, 0, mock(IBinder.class));
+        ArrayList<ProcessRecord> lru = sService.mProcessList.mLruProcesses;
+        lru.clear();
+        lru.add(app);
+        lru.add(app2);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+        lru.clear();
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoAll_BoundFgService_Cycle() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, app2, null, 0, mock(IBinder.class));
+        ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(app2, app3, null, 0, mock(IBinder.class));
+        app3.setHasForegroundServices(true, 0);
+        bindService(app3, app, null, 0, mock(IBinder.class));
+        ArrayList<ProcessRecord> lru = sService.mProcessList.mLruProcesses;
+        lru.clear();
+        lru.add(app);
+        lru.add(app2);
+        lru.add(app3);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+        lru.clear();
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app3, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoAll_BoundFgService_Cycle_Branch_2() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class));
+        ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(app2, app3, null, 0, mock(IBinder.class));
+        bindService(app3, app, null, 0, mock(IBinder.class));
+        doReturn(mock(WindowProcessController.class)).when(app3).getWindowProcessController();
+        WindowProcessController wpc = app3.getWindowProcessController();
+        doReturn(true).when(wpc).isHomeProcess();
+        ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
+                MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
+        app4.setHasOverlayUi(true);
+        bindService(app, app4, s, 0, mock(IBinder.class));
+        ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
+                MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
+        app5.setHasForegroundServices(true, 0);
+        bindService(app, app5, s, 0, mock(IBinder.class));
+        ArrayList<ProcessRecord> lru = sService.mProcessList.mLruProcesses;
+        lru.clear();
+        lru.add(app);
+        lru.add(app2);
+        lru.add(app3);
+        lru.add(app4);
+        lru.add(app5);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+        lru.clear();
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app3, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app4, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app5, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoAll_BoundFgService_Cycle_Branch_3() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class));
+        ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(app2, app3, null, 0, mock(IBinder.class));
+        bindService(app3, app, null, 0, mock(IBinder.class));
+        doReturn(mock(WindowProcessController.class)).when(app3).getWindowProcessController();
+        WindowProcessController wpc = app3.getWindowProcessController();
+        doReturn(true).when(wpc).isHomeProcess();
+        ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
+                MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
+        app4.setHasOverlayUi(true);
+        bindService(app, app4, s, 0, mock(IBinder.class));
+        ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
+                MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
+        app5.setHasForegroundServices(true, 0);
+        bindService(app, app5, s, 0, mock(IBinder.class));
+        ArrayList<ProcessRecord> lru = sService.mProcessList.mLruProcesses;
+        lru.clear();
+        lru.add(app5);
+        lru.add(app4);
+        lru.add(app3);
+        lru.add(app2);
+        lru.add(app);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+        lru.clear();
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app3, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app4, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app5, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoAll_BoundFgService_Cycle_Branch_4() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class));
+        ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(app2, app3, null, 0, mock(IBinder.class));
+        bindService(app3, app, null, 0, mock(IBinder.class));
+        doReturn(mock(WindowProcessController.class)).when(app3).getWindowProcessController();
+        WindowProcessController wpc = app3.getWindowProcessController();
+        doReturn(true).when(wpc).isHomeProcess();
+        ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
+                MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
+        app4.setHasOverlayUi(true);
+        bindService(app, app4, s, 0, mock(IBinder.class));
+        ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
+                MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
+        app5.setHasForegroundServices(true, 0);
+        bindService(app, app5, s, 0, mock(IBinder.class));
+        ArrayList<ProcessRecord> lru = sService.mProcessList.mLruProcesses;
+        lru.clear();
+        lru.add(app3);
+        lru.add(app4);
+        lru.add(app2);
+        lru.add(app);
+        lru.add(app5);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+        lru.clear();
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app3, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app4, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app5, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoAll_Provider_Cycle_Branch_2() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        ContentProviderRecord cr = bindProvider(app, app2, null, null, false);
+        ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindProvider(app2, app3, null, null, false);
+        bindProvider(app3, app, null, null, false);
+        doReturn(mock(WindowProcessController.class)).when(app3).getWindowProcessController();
+        WindowProcessController wpc = app3.getWindowProcessController();
+        doReturn(true).when(wpc).isHomeProcess();
+        ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
+                MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
+        app4.setHasOverlayUi(true);
+        bindProvider(app, app4, cr, null, false);
+        ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
+                MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
+        app5.setHasForegroundServices(true, 0);
+        bindProvider(app, app5, cr, null, false);
+        ArrayList<ProcessRecord> lru = sService.mProcessList.mLruProcesses;
+        lru.clear();
+        lru.add(app);
+        lru.add(app2);
+        lru.add(app3);
+        lru.add(app4);
+        lru.add(app5);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+        lru.clear();
+
+        assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app2, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app3, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app4, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(app5, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
+            String packageName, boolean hasShownUi) {
+        long now = SystemClock.uptimeMillis();
+        return makeProcessRecord(sService, pid, uid, processName,
+                packageName, 12345, Build.VERSION_CODES.CUR_DEVELOPMENT,
+                now, now, now, 12345, UNKNOWN_ADJ, UNKNOWN_ADJ,
+                UNKNOWN_ADJ, CACHED_APP_MAX_ADJ,
+                SCHED_GROUP_DEFAULT, SCHED_GROUP_DEFAULT,
+                PROCESS_STATE_NONEXISTENT, PROCESS_STATE_NONEXISTENT,
+                PROCESS_STATE_NONEXISTENT, PROCESS_STATE_NONEXISTENT,
+                0, 0, false, false, false, ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE,
+                false, false, false, hasShownUi, false, false, false, false, false, false, null,
+                0, 0, 0, true, 0, null, false);
+    }
+
+    private ProcessRecord makeProcessRecord(ActivityManagerService service, int pid, int uid,
+            String processName, String packageName, long versionCode, int targetSdkVersion,
+            long lastActivityTime, long lastPssTime, long nextPssTime, long lastPss, int maxAdj,
+            int setRawAdj, int curAdj, int setAdj, int curSchedGroup, int setSchedGroup,
+            int curProcState, int repProcState, int curRawProcState, int setProcState,
+            int connectionGroup, int connectionImportance, boolean serviceb,
+            boolean hasClientActivities, boolean hasForegroundServices, int fgServiceTypes,
+            boolean hasForegroundActivities, boolean repForegroundActivities, boolean systemNoUi,
+            boolean hasShownUi, boolean hasTopUi, boolean hasOverlayUi,
+            boolean runningRemoteAnimation, boolean hasAboveClient, boolean treatLikeActivity,
+            boolean killedByAm, Object forcingToImportant, int numOfCurReceivers,
+            long lastProviderTime, long lastTopTime, boolean cached, int numOfExecutingServices,
+            String isolatedEntryPoint, boolean execServicesFg) {
+        ApplicationInfo ai = spy(new ApplicationInfo());
+        ai.uid = uid;
+        ai.packageName = packageName;
+        ai.longVersionCode = versionCode;
+        ai.targetSdkVersion = targetSdkVersion;
+        ProcessRecord app = new ProcessRecord(service, ai, processName, uid);
+        app.thread = mock(IApplicationThread.class);
+        app.lastActivityTime = lastActivityTime;
+        app.lastPssTime = lastPssTime;
+        app.nextPssTime = nextPssTime;
+        app.lastPss = lastPss;
+        app.maxAdj = maxAdj;
+        app.setRawAdj = setRawAdj;
+        app.curAdj = curAdj;
+        app.setAdj = setAdj;
+        app.setCurrentSchedulingGroup(curSchedGroup);
+        app.setSchedGroup = setSchedGroup;
+        app.setCurProcState(curProcState);
+        app.setReportedProcState(repProcState);
+        app.setCurRawProcState(curRawProcState);
+        app.setProcState = setProcState;
+        app.connectionGroup = connectionGroup;
+        app.connectionImportance = connectionImportance;
+        app.serviceb = serviceb;
+        app.setHasClientActivities(hasClientActivities);
+        app.setHasForegroundServices(hasForegroundServices, fgServiceTypes);
+        app.setHasClientActivities(hasForegroundActivities);
+        app.repForegroundActivities = repForegroundActivities;
+        app.systemNoUi = systemNoUi;
+        app.hasShownUi = hasShownUi;
+        app.setHasTopUi(hasTopUi);
+        app.setHasOverlayUi(hasOverlayUi);
+        app.runningRemoteAnimation = runningRemoteAnimation;
+        app.hasAboveClient = hasAboveClient;
+        app.treatLikeActivity = treatLikeActivity;
+        app.killedByAm = killedByAm;
+        app.forcingToImportant = forcingToImportant;
+        for (int i = 0; i < numOfCurReceivers; i++) {
+            app.curReceivers.add(mock(BroadcastRecord.class));
+        }
+        app.lastProviderTime = lastProviderTime;
+        app.lastTopTime = lastTopTime;
+        app.cached = cached;
+        for (int i = 0; i < numOfExecutingServices; i++) {
+            app.executingServices.add(mock(ServiceRecord.class));
+        }
+        app.isolatedEntryPoint = isolatedEntryPoint;
+        app.execServicesFg = execServicesFg;
+        return app;
+    }
+
+    private ServiceRecord bindService(ProcessRecord service, ProcessRecord client,
+            ServiceRecord record, int bindFlags, IBinder binder) {
+        if (record == null) {
+            record = mock(ServiceRecord.class);
+            record.app = service;
+            setFieldValue(ServiceRecord.class, record, "connections",
+                    new ArrayMap<IBinder, ArrayList<ConnectionRecord>>());
+            service.services.add(record);
+            doCallRealMethod().when(record).getConnections();
+        }
+        AppBindRecord binding = new AppBindRecord(record, null, client);
+        ConnectionRecord cr = spy(new ConnectionRecord(binding,
+                mock(ActivityServiceConnectionsHolder.class),
+                mock(IServiceConnection.class), bindFlags,
+                0, null, client.uid, client.processName, client.info.packageName));
+        doCallRealMethod().when(record).addConnection(any(IBinder.class),
+                any(ConnectionRecord.class));
+        record.addConnection(binder, cr);
+        client.connections.add(cr);
+        binding.connections.add(cr);
+        doNothing().when(cr).trackProcState(anyInt(), anyInt(), anyLong());
+        return record;
+    }
+
+    private ContentProviderRecord bindProvider(ProcessRecord publisher, ProcessRecord client,
+            ContentProviderRecord record, String name, boolean hasExternalProviders) {
+        if (record == null) {
+            record = mock(ContentProviderRecord.class);
+            publisher.pubProviders.put(name, record);
+            record.proc = publisher;
+            setFieldValue(ContentProviderRecord.class, record, "connections",
+                    new ArrayList<ContentProviderConnection>());
+            doReturn(hasExternalProviders).when(record).hasExternalProcessHandles();
+        }
+        ContentProviderConnection conn = spy(new ContentProviderConnection(record, client,
+                client.info.packageName));
+        record.connections.add(conn);
+        client.conProviders.add(conn);
+        return record;
+    }
+
+    private void assertProcStates(ProcessRecord app, int expectedProcState, int expectedAdj,
+            int expectedSchedGroup) {
+        assertEquals(expectedProcState, app.setProcState);
+        assertEquals(expectedAdj, app.setAdj);
+        assertEquals(expectedSchedGroup, app.setSchedGroup);
+    }
+}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index b37e460..83e20fb 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -83,6 +83,8 @@
     optimize: {
         enabled: false,
     },
+
+    data: [":JobTestApp"],
 }
 
 java_library {
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
index 5dafe07..d57fd4b 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
@@ -18,13 +18,17 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
 
 import android.app.ActivityManagerInternal;
 import android.os.SystemClock;
 
 import androidx.test.filters.MediumTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -43,6 +47,8 @@
     private static final long TEST_PROC_STATE_SEQ2 = 1112;
     private static final long TEST_PROC_STATE_SEQ3 = 1113;
 
+    @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+
     @Mock private ActivityManagerService.Injector mMockInjector;
 
     private ActivityManagerService mAms;
@@ -52,7 +58,11 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mAms = new ActivityManagerService(mMockInjector);
+        doReturn(InstrumentationRegistry.getInstrumentation().getContext()).when(mMockInjector)
+                .getContext();
+        doReturn(mServiceThreadRule.getThread().getThreadHandler()).when(mMockInjector)
+                .getUiHandler(any());
+        mAms = new ActivityManagerService(mMockInjector, mServiceThreadRule.getThread());
         mAmi = mAms.new LocalService();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 3df6976..29244f0 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -70,13 +70,14 @@
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
-import com.android.server.appop.AppOpsService;
 import com.android.server.am.ProcessList.IsolatedUidRange;
 import com.android.server.am.ProcessList.IsolatedUidRangeAllocator;
+import com.android.server.appop.AppOpsService;
 import com.android.server.wm.ActivityTaskManagerService;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.Mockito;
@@ -114,6 +115,8 @@
         UidRecord.CHANGE_ACTIVE
     };
 
+    @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+
     private Context mContext = getInstrumentation().getTargetContext();
     @Mock private AppOpsService mAppOpsService;
     @Mock private PackageManager mPackageManager;
@@ -130,8 +133,8 @@
         mHandlerThread = new HandlerThread(TAG);
         mHandlerThread.start();
         mHandler = new TestHandler(mHandlerThread.getLooper());
-        mInjector = new TestInjector();
-        mAms = new ActivityManagerService(mInjector);
+        mInjector = new TestInjector(mContext);
+        mAms = new ActivityManagerService(mInjector, mServiceThreadRule.getThread());
         mAms.mWaitForNetworkTimeoutMs = 2000;
         mAms.mActivityTaskManager = new ActivityTaskManagerService(mContext);
         mAms.mActivityTaskManager.initialize(null, null, mHandler.getLooper());
@@ -917,9 +920,8 @@
     private class TestInjector extends Injector {
         private boolean mRestricted = true;
 
-        @Override
-        public Context getContext() {
-            return mContext;
+        TestInjector(Context context) {
+            super(context);
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
index 1dfce51..377bfd1 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
@@ -29,6 +29,7 @@
 import com.android.server.wm.ActivityTaskManagerService;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.io.File;
@@ -41,13 +42,16 @@
 @FlakyTest(bugId = 113616538)
 public class AppErrorDialogTest {
 
+    @Rule
+    public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+
     private Context mContext;
     private ActivityManagerService mService;
 
     @Before
     public void setUp() throws Exception {
         mContext = getInstrumentation().getTargetContext();
-        mService = new ActivityManagerService(new ActivityManagerService.Injector() {
+        mService = new ActivityManagerService(new ActivityManagerService.Injector(mContext) {
             @Override
             public AppOpsService getAppOpsService(File file, Handler handler) {
                 return null;
@@ -55,14 +59,14 @@
 
             @Override
             public Handler getUiHandler(ActivityManagerService service) {
-                return null;
+                return mServiceThreadRule.getThread().getThreadHandler();
             }
 
             @Override
             public boolean isNetworkRestrictedForUid(int uid) {
                 return false;
             }
-        });
+        }, mServiceThreadRule.getThread());
         mService.mActivityTaskManager = new ActivityTaskManagerService(mContext);
         mService.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
     }
diff --git a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
index cbdc6c3..4221575 100644
--- a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
@@ -23,9 +23,11 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.Handler;
 import android.provider.Settings;
@@ -39,6 +41,7 @@
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -61,6 +64,8 @@
     private static final float TEST_FLOAT = 3.14f;
     private static final String TEST_STRING = "testString";
 
+    @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+
     private ActivityManagerService mAms;
     @Mock private Context mContext;
 
@@ -89,8 +94,10 @@
         mContentResolver = new MockContentResolver(mContext);
         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
         when(mContext.getContentResolver()).thenReturn(mContentResolver);
+        when(mContext.getResources()).thenReturn(mock(Resources.class));
 
-        mAms = new ActivityManagerService(new TestInjector());
+        mAms = new ActivityManagerService(new TestInjector(mContext),
+                mServiceThreadRule.getThread());
         mCoreSettingsObserver = new CoreSettingsObserver(mAms);
     }
 
@@ -155,9 +162,9 @@
     }
 
     private class TestInjector extends Injector {
-        @Override
-        public Context getContext() {
-            return mContext;
+
+        TestInjector(Context context) {
+            super(context);
         }
 
         @Override
@@ -167,7 +174,7 @@
 
         @Override
         public Handler getUiHandler(ActivityManagerService service) {
-            return null;
+            return mServiceThreadRule.getThread().getThreadHandler();
         }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ServiceThreadRule.java b/services/tests/servicestests/src/com/android/server/am/ServiceThreadRule.java
new file mode 100644
index 0000000..e86ce7e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ServiceThreadRule.java
@@ -0,0 +1,51 @@
+/*
+ * 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.am;
+
+import android.os.Process;
+
+import com.android.server.ServiceThread;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+class ServiceThreadRule implements TestRule {
+
+    private ServiceThread mThread;
+
+    ServiceThread getThread() {
+        return mThread;
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                mThread = new ServiceThread("TestServiceThread", Process.THREAD_PRIORITY_DEFAULT,
+                        true /* allowIo */);
+                mThread.start();
+                try {
+                    base.evaluate();
+                } finally {
+                    mThread.getThreadHandler().runWithScissors(mThread::quit, 0 /* timeout */);
+                }
+            }
+        };
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index 29cbf98..8668a3c 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -18,11 +18,11 @@
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -44,6 +44,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.os.ConditionVariable;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
@@ -70,7 +71,8 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.util.concurrent.LinkedBlockingQueue;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 
 @SmallTest
@@ -136,7 +138,7 @@
         SparseArray<UserBackupManagerService> serviceUsers = new SparseArray<>();
         serviceUsers.append(UserHandle.USER_SYSTEM, mUserBackupManagerService);
         serviceUsers.append(NON_USER_SYSTEM, mUserBackupManagerService);
-        when(mBackupManagerServiceMock.getServiceUsers()).thenReturn(serviceUsers);
+        when(mBackupManagerServiceMock.getUserServices()).thenReturn(serviceUsers);
 
         when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock);
         when(mUserManagerMock.getUserInfo(NON_USER_SYSTEM)).thenReturn(mUserInfoMock);
@@ -182,37 +184,78 @@
     }
 
     @Test
-    public void initializeService_successfullyInitializesBackupService() {
-        mTrampoline.initializeService();
-
+    public void testIsBackupServiceActive_whenBackupsNotDisabledAndSuppressFileDoesNotExist() {
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
-    public void initializeService_globallyDisabled_nonInitialized() {
+    public void testOnUnlockUser_forNonSystemUserWhenBackupsDisabled_doesNotStartUser() {
+        when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>());
         TrampolineTestable.sBackupDisabled = true;
         TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
+        ConditionVariable unlocked = new ConditionVariable(false);
 
-        trampoline.initializeService();
+        trampoline.onUnlockUser(NON_USER_SYSTEM);
+
+        trampoline.getBackupHandler().post(unlocked::open);
+        unlocked.block();
+        assertNull(trampoline.getUserService(NON_USER_SYSTEM));
+    }
+
+    @Test
+    public void testOnUnlockUser_forSystemUserWhenBackupsDisabled_doesNotStartUser() {
+        when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>());
+        TrampolineTestable.sBackupDisabled = true;
+        TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
+        ConditionVariable unlocked = new ConditionVariable(false);
+
+        trampoline.onUnlockUser(UserHandle.USER_SYSTEM);
+
+        trampoline.getBackupHandler().post(unlocked::open);
+        unlocked.block();
+        assertNull(trampoline.getUserService(UserHandle.USER_SYSTEM));
+    }
+
+    @Test
+    public void testOnUnlockUser_whenBackupNotActivated_doesNotStartUser() {
+        when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>());
+        TrampolineTestable.sBackupDisabled = false;
+        TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
+        trampoline.setBackupServiceActive(NON_USER_SYSTEM, false);
+        ConditionVariable unlocked = new ConditionVariable(false);
+
+        trampoline.onUnlockUser(NON_USER_SYSTEM);
+
+        trampoline.getBackupHandler().post(unlocked::open);
+        unlocked.block();
+        assertNull(trampoline.getUserService(NON_USER_SYSTEM));
+        //noinspection unchecked
+        verify(mBackupManagerServiceMock, never()).startServiceForUser(
+                eq(NON_USER_SYSTEM), any(Set.class));
+    }
+
+    @Test
+    public void testIsBackupServiceActive_forSystemUserWhenBackupDisabled_returnsTrue()
+            throws Exception {
+        TrampolineTestable.sBackupDisabled = true;
+        Trampoline trampoline = new TrampolineTestable(mContextMock);
+        trampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
         assertFalse(trampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
     @Test
-    public void initializeService_doesNotStartServiceForUsers() {
-        mTrampoline.initializeService();
+    public void testIsBackupServiceActive_forNonSystemUserWhenBackupDisabled_returnsTrue()
+            throws Exception {
+        TrampolineTestable.sBackupDisabled = true;
+        Trampoline trampoline = new TrampolineTestable(mContextMock);
+        trampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
 
-        verify(mBackupManagerServiceMock, never()).startServiceForUser(anyInt());
-    }
-
-    @Test
-    public void isBackupServiceActive_calledBeforeInitialize_returnsFalse() {
-        assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+        assertFalse(trampoline.isBackupServiceActive(NON_USER_SYSTEM));
     }
 
     @Test
     public void isBackupServiceActive_forSystemUser_returnsTrueWhenActivated() throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
@@ -220,7 +263,6 @@
 
     @Test
     public void isBackupServiceActive_forSystemUser_returnsFalseWhenDeactivated() throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
 
         assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
@@ -229,7 +271,6 @@
     @Test
     public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenSystemUserDeactivated()
             throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
 
@@ -239,7 +280,6 @@
     @Test
     public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenNonSystemUserDeactivated()
             throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
         // Don't activate non-system user.
 
@@ -250,7 +290,6 @@
     public void
             isBackupServiceActive_forNonSystemUser_returnsTrueWhenSystemAndNonSystemUserActivated()
                 throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
 
@@ -261,7 +300,6 @@
     public void
             isBackupServiceActive_forUnstartedNonSystemUser_returnsTrueWhenSystemAndUserActivated()
             throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UNSTARTED_NON_USER_SYSTEM, true);
 
         assertTrue(mTrampoline.isBackupServiceActive(UNSTARTED_NON_USER_SYSTEM));
@@ -269,7 +307,6 @@
 
     @Test
     public void setBackupServiceActive_forSystemUserAndCallerSystemUid_serviceCreated() {
-        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
 
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -279,7 +316,6 @@
 
     @Test
     public void setBackupServiceActive_forSystemUserAndCallerRootUid_serviceCreated() {
-        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.ROOT_UID;
 
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -289,7 +325,6 @@
 
     @Test
     public void setBackupServiceActive_forSystemUserAndCallerNonRootNonSystem_throws() {
-        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
 
         try {
@@ -302,7 +337,6 @@
     @Test
     public void setBackupServiceActive_forManagedProfileAndCallerSystemUid_serviceCreated() {
         when(mUserInfoMock.isManagedProfile()).thenReturn(true);
-        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
 
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
@@ -313,7 +347,6 @@
     @Test
     public void setBackupServiceActive_forManagedProfileAndCallerRootUid_serviceCreated() {
         when(mUserInfoMock.isManagedProfile()).thenReturn(true);
-        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.ROOT_UID;
 
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
@@ -324,7 +357,6 @@
     @Test
     public void setBackupServiceActive_forManagedProfileAndCallerNonRootNonSystem_throws() {
         when(mUserInfoMock.isManagedProfile()).thenReturn(true);
-        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
 
         try {
@@ -339,7 +371,6 @@
         doThrow(new SecurityException())
                 .when(mContextMock)
                 .enforceCallingOrSelfPermission(eq(Manifest.permission.BACKUP), anyString());
-        mTrampoline.initializeService();
 
         try {
             mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
@@ -354,7 +385,6 @@
                 .when(mContextMock)
                 .enforceCallingOrSelfPermission(
                         eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL), anyString());
-        mTrampoline.initializeService();
 
         try {
             mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
@@ -367,7 +397,6 @@
     public void setBackupServiceActive_backupDisabled_ignored() {
         TrampolineTestable.sBackupDisabled = true;
         TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
-        trampoline.initializeService();
 
         trampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
@@ -376,19 +405,15 @@
 
     @Test
     public void setBackupServiceActive_alreadyActive_ignored() {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
-        assertEquals(1, mTrampoline.getCreateServiceCallsCount());
 
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
-        assertEquals(1, mTrampoline.getCreateServiceCallsCount());
     }
 
     @Test
     public void setBackupServiceActive_makeNonActive_alreadyNonActive_ignored() {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
 
@@ -397,7 +422,6 @@
 
     @Test
     public void setBackupServiceActive_makeActive_serviceCreatedAndSuppressFileDeleted() {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
@@ -406,7 +430,6 @@
     @Test
     public void setBackupServiceActive_makeNonActive_serviceDeletedAndSuppressFileCreated()
             throws IOException {
-        mTrampoline.initializeService();
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
 
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
@@ -416,7 +439,6 @@
 
     @Test
     public void setBackupActive_nonSystemUser_disabledForSystemUser_ignored() {
-        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
 
@@ -425,7 +447,6 @@
 
     @Test
     public void setBackupServiceActive_forOneNonSystemUser_doesNotActivateForAllNonSystemUsers() {
-        mTrampoline.initializeService();
         int otherUser = NON_USER_SYSTEM + 1;
         File activateFile = new File(mTestDir, "activate-" + otherUser);
         TrampolineTestable.sActivatedFiles.append(otherUser, activateFile);
@@ -440,7 +461,6 @@
 
     @Test
     public void setBackupServiceActive_forNonSystemUser_remembersActivated() {
-        mTrampoline.initializeService();
 
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
 
@@ -450,7 +470,6 @@
 
     @Test
     public void setBackupServiceActiveFalse_forNonSystemUser_remembersActivated() {
-        mTrampoline.initializeService();
 
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, false);
 
@@ -460,8 +479,6 @@
 
     @Test
     public void setBackupServiceActiveTwice_forNonSystemUser_remembersLastActivated() {
-        mTrampoline.initializeService();
-
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
         mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, false);
 
@@ -470,15 +487,7 @@
     }
 
     @Test
-    public void dataChanged_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.dataChanged(PACKAGE_NAME);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void dataChangedForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
-
         mTrampoline.dataChangedForUser(mUserId, PACKAGE_NAME);
 
         verify(mBackupManagerServiceMock).dataChanged(mUserId, PACKAGE_NAME);
@@ -487,7 +496,6 @@
     @Test
     public void dataChanged_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.dataChanged(PACKAGE_NAME);
 
@@ -495,14 +503,7 @@
     }
 
     @Test
-    public void clearBackupData_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.clearBackupData(TRANSPORT_NAME, PACKAGE_NAME);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void clearBackupDataForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.clearBackupDataForUser(mUserId, TRANSPORT_NAME, PACKAGE_NAME);
 
@@ -512,7 +513,6 @@
     @Test
     public void clearBackupData_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.clearBackupData(TRANSPORT_NAME, PACKAGE_NAME);
 
@@ -520,14 +520,7 @@
     }
 
     @Test
-    public void agentConnected_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.agentConnected(PACKAGE_NAME, mAgentMock);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void agentConnectedForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.agentConnectedForUser(mUserId, PACKAGE_NAME, mAgentMock);
 
@@ -537,7 +530,6 @@
     @Test
     public void agentConnected_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.agentConnected(PACKAGE_NAME, mAgentMock);
 
@@ -545,14 +537,7 @@
     }
 
     @Test
-    public void agentDisconnected_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.agentDisconnected(PACKAGE_NAME);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void agentDisconnectedForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.agentDisconnectedForUser(mUserId, PACKAGE_NAME);
 
@@ -562,7 +547,6 @@
     @Test
     public void agentDisconnected_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.agentDisconnected(PACKAGE_NAME);
 
@@ -570,14 +554,7 @@
     }
 
     @Test
-    public void restoreAtInstall_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.restoreAtInstall(PACKAGE_NAME, 123);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void restoreAtInstallForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.restoreAtInstallForUser(mUserId, PACKAGE_NAME, 123);
 
@@ -587,7 +564,6 @@
     @Test
     public void restoreAtInstall_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.restoreAtInstall(PACKAGE_NAME, 123);
 
@@ -595,14 +571,7 @@
     }
 
     @Test
-    public void setBackupEnabled_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.setBackupEnabled(true);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void setBackupEnabledForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.setBackupEnabledForUser(mUserId, true);
 
@@ -612,7 +581,6 @@
     @Test
     public void setBackupEnabled_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.setBackupEnabled(true);
 
@@ -620,14 +588,7 @@
     }
 
     @Test
-    public void setAutoRestore_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.setAutoRestore(true);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void setAutoRestoreForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.setAutoRestoreForUser(mUserId, true);
 
@@ -637,7 +598,6 @@
     @Test
     public void setAutoRestore_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.setAutoRestore(true);
 
@@ -645,14 +605,7 @@
     }
 
     @Test
-    public void isBackupEnabled_calledBeforeInitialize_ignored() throws Exception {
-        assertFalse(mTrampoline.isBackupEnabled());
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void isBackupEnabledForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.isBackupEnabledForUser(mUserId);
 
@@ -662,7 +615,6 @@
     @Test
     public void isBackupEnabled_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.isBackupEnabled();
 
@@ -670,40 +622,19 @@
     }
 
     @Test
-    public void setBackupPassword_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void setBackupPassword_forwarded() throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD);
         verify(mBackupManagerServiceMock).setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD);
     }
 
     @Test
-    public void hasBackupPassword_calledBeforeInitialize_ignored() throws Exception {
-        assertFalse(mTrampoline.hasBackupPassword());
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void hasBackupPassword_forwarded() throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.hasBackupPassword();
         verify(mBackupManagerServiceMock).hasBackupPassword();
     }
 
     @Test
-    public void backupNow_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.backupNow();
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void backupNowForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.backupNowForUser(mUserId);
 
@@ -713,7 +644,6 @@
     @Test
     public void backupNow_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.backupNow();
 
@@ -721,16 +651,7 @@
     }
 
     @Test
-    public void adbBackup_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.adbBackup(mUserId, mParcelFileDescriptorMock, true, true,
-                true, true, true, true, true, true,
-                PACKAGE_NAMES);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void adbBackup_forwarded() throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.adbBackup(mUserId, mParcelFileDescriptorMock, true, true,
                 true, true, true, true, true, true,
                 PACKAGE_NAMES);
@@ -739,14 +660,7 @@
     }
 
     @Test
-    public void fullTransportBackup_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.fullTransportBackupForUser(mUserId, PACKAGE_NAMES);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void fullTransportBackupForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.fullTransportBackupForUser(mUserId, PACKAGE_NAMES);
 
@@ -754,29 +668,13 @@
     }
 
     @Test
-    public void adbRestore_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.adbRestore(mUserId, mParcelFileDescriptorMock);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void adbRestore_forwarded() throws Exception {
-        mTrampoline.initializeService();
         mTrampoline.adbRestore(mUserId, mParcelFileDescriptorMock);
         verify(mBackupManagerServiceMock).adbRestore(mUserId, mParcelFileDescriptorMock);
     }
 
     @Test
-    public void acknowledgeFullBackupOrRestore_calledBeforeInitialize_ignored()
-            throws Exception {
-        mTrampoline.acknowledgeFullBackupOrRestore(123, true, CURRENT_PASSWORD, ENCRYPTION_PASSWORD,
-                mFullBackupRestoreObserverMock);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void acknowledgeFullBackupOrRestoreForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.acknowledgeFullBackupOrRestoreForUser(
                 mUserId,
@@ -799,7 +697,6 @@
     @Test
     public void acknowledgeFullBackupOrRestore_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.acknowledgeFullBackupOrRestore(123, true, CURRENT_PASSWORD, ENCRYPTION_PASSWORD,
                 mFullBackupRestoreObserverMock);
@@ -815,15 +712,8 @@
     }
 
     @Test
-    public void getCurrentTransport_calledBeforeInitialize_ignored() throws Exception {
-        assertNull(mTrampoline.getCurrentTransport());
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void getCurrentTransportForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.getCurrentTransport(mUserId)).thenReturn(TRANSPORT_NAME);
-        mTrampoline.initializeService();
 
         assertEquals(TRANSPORT_NAME, mTrampoline.getCurrentTransportForUser(mUserId));
         verify(mBackupManagerServiceMock).getCurrentTransport(mUserId);
@@ -833,22 +723,14 @@
     public void getCurrentTransport_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         when(mBackupManagerServiceMock.getCurrentTransport(mUserId)).thenReturn(TRANSPORT_NAME);
-        mTrampoline.initializeService();
 
         assertEquals(TRANSPORT_NAME, mTrampoline.getCurrentTransport());
         verify(mBackupManagerServiceMock).getCurrentTransport(mUserId);
     }
 
     @Test
-    public void listAllTransports_calledBeforeInitialize_ignored() throws Exception {
-        assertNull(mTrampoline.listAllTransports());
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void listAllTransportsForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.listAllTransports(mUserId)).thenReturn(TRANSPORTS);
-        mTrampoline.initializeService();
 
         assertEquals(TRANSPORTS, mTrampoline.listAllTransportsForUser(mUserId));
         verify(mBackupManagerServiceMock).listAllTransports(mUserId);
@@ -859,63 +741,22 @@
     public void listAllTransports_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         when(mBackupManagerServiceMock.listAllTransports(mUserId)).thenReturn(TRANSPORTS);
-        mTrampoline.initializeService();
 
         assertEquals(TRANSPORTS, mTrampoline.listAllTransports());
         verify(mBackupManagerServiceMock).listAllTransports(mUserId);
     }
 
     @Test
-    public void listAllTransportComponentsForUser_calledBeforeInitialize_ignored()
-            throws Exception {
-        assertNull(mTrampoline.listAllTransportComponentsForUser(mUserId));
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void listAllTransportComponentsForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.listAllTransportComponents(mUserId)).thenReturn(
                 TRANSPORT_COMPONENTS);
-        mTrampoline.initializeService();
 
         assertEquals(TRANSPORT_COMPONENTS, mTrampoline.listAllTransportComponentsForUser(mUserId));
         verify(mBackupManagerServiceMock).listAllTransportComponents(mUserId);
     }
 
     @Test
-    public void getTransportWhitelist_calledBeforeInitialize_ignored() throws Exception {
-        assertNull(mTrampoline.getTransportWhitelist());
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
-    public void getTransportWhitelist_forwarded() {
-        when(mBackupManagerServiceMock.getTransportWhitelist()).thenReturn(TRANSPORTS);
-        mTrampoline.initializeService();
-
-        assertEquals(TRANSPORTS, mTrampoline.getTransportWhitelist());
-        verify(mBackupManagerServiceMock).getTransportWhitelist();
-    }
-
-    @Test
-    public void updateTransportAttributesForUser_calledBeforeInitialize_ignored() {
-        mTrampoline.updateTransportAttributesForUser(
-                mUserId,
-                TRANSPORT_COMPONENT_NAME,
-                TRANSPORT_NAME,
-                null,
-                "Transport Destination",
-                null,
-                "Data Management");
-
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void updateTransportAttributesForUser_forwarded() {
-        when(mBackupManagerServiceMock.getTransportWhitelist()).thenReturn(TRANSPORTS);
-        mTrampoline.initializeService();
-
         mTrampoline.updateTransportAttributesForUser(
                 mUserId,
                 TRANSPORT_COMPONENT_NAME,
@@ -937,14 +778,7 @@
     }
 
     @Test
-    public void selectBackupTransport_calledBeforeInitialize_ignored() throws RemoteException {
-        mTrampoline.selectBackupTransport(TRANSPORT_NAME);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void selectBackupTransportForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.selectBackupTransportForUser(mUserId, TRANSPORT_NAME);
 
@@ -954,7 +788,6 @@
     @Test
     public void selectBackupTransport_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.selectBackupTransport(TRANSPORT_NAME);
 
@@ -962,75 +795,56 @@
     }
 
     @Test
-    public void selectBackupTransportAsyncForUser_calledBeforeInitialize_ignored()
+    public void selectBackupTransportAsyncForUser_beforeUserUnlocked_notifiesBackupNotAllowed()
             throws Exception {
-        LinkedBlockingQueue<Integer> q = new LinkedBlockingQueue();
-
-        mTrampoline.selectBackupTransportAsyncForUser(
-                mUserId,
-                TRANSPORT_COMPONENT_NAME,
-                new ISelectBackupTransportCallback() {
+        when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>());
+        CompletableFuture<Integer> future = new CompletableFuture<>();
+        ISelectBackupTransportCallback listener =
+                new ISelectBackupTransportCallback.Stub() {
                     @Override
-                    public void onSuccess(String transportName) throws RemoteException {
-
+                    public void onSuccess(String transportName) {
+                        future.completeExceptionally(new AssertionError());
                     }
-
                     @Override
-                    public void onFailure(int reason) throws RemoteException {
-                        q.offer(reason);
+                    public void onFailure(int reason) {
+                        future.complete(reason);
                     }
+                };
 
-                    @Override
-                    public IBinder asBinder() {
-                        return null;
-                    }
-                });
+        mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener);
 
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-        Integer errorCode = q.poll(5, TimeUnit.SECONDS);
-        assertNotNull(errorCode);
-        assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, (int) errorCode);
+        assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, (int) future.get(5, TimeUnit.SECONDS));
     }
 
     @Test
-    public void selectBackupTransportAsyncForUser_calledBeforeInitialize_ignored_nullListener()
+    public void selectBackupTransportAsyncForUser_beforeUserUnlockedWithNullListener_doesNotThrow()
             throws Exception {
         mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null);
 
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
         // No crash.
     }
 
     @Test
-    public void selectBackupTransportAsyncForUser_calledBeforeInitialize_ignored_listenerThrows()
+    public void
+            selectBackupTransportAsyncForUser_beforeUserUnlockedWithThrowingListener_doesNotThrow()
             throws Exception {
-        mTrampoline.selectBackupTransportAsyncForUser(
-                mUserId,
-                TRANSPORT_COMPONENT_NAME,
-                new ISelectBackupTransportCallback() {
+        ISelectBackupTransportCallback.Stub listener =
+                new ISelectBackupTransportCallback.Stub() {
                     @Override
-                    public void onSuccess(String transportName) throws RemoteException {
-
-                    }
-
+                    public void onSuccess(String transportName) {}
                     @Override
                     public void onFailure(int reason) throws RemoteException {
-                        throw new RemoteException("Crash");
+                        throw new RemoteException();
                     }
+                };
 
-                    @Override
-                    public IBinder asBinder() {
-                        return null;
-                    }
-                });
+        mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener);
 
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
         // No crash.
     }
 
     @Test
     public void selectBackupTransportAsyncForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null);
 
@@ -1039,17 +853,10 @@
     }
 
     @Test
-    public void getConfigurationIntent_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.getConfigurationIntent(TRANSPORT_NAME);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void getConfigurationIntentForUser_forwarded() throws Exception {
         Intent configurationIntentStub = new Intent();
         when(mBackupManagerServiceMock.getConfigurationIntent(mUserId, TRANSPORT_NAME)).thenReturn(
                 configurationIntentStub);
-        mTrampoline.initializeService();
 
         assertEquals(
                 configurationIntentStub,
@@ -1063,23 +870,15 @@
         Intent configurationIntentStub = new Intent();
         when(mBackupManagerServiceMock.getConfigurationIntent(mUserId, TRANSPORT_NAME)).thenReturn(
                 configurationIntentStub);
-        mTrampoline.initializeService();
 
         assertEquals(configurationIntentStub, mTrampoline.getConfigurationIntent(TRANSPORT_NAME));
         verify(mBackupManagerServiceMock).getConfigurationIntent(mUserId, TRANSPORT_NAME);
     }
 
     @Test
-    public void getDestinationString_calledBeforeInitialize_ignored() throws Exception {
-        assertNull(mTrampoline.getDestinationString(TRANSPORT_NAME));
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void getDestinationStringForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.getDestinationString(mUserId, TRANSPORT_NAME)).thenReturn(
                 DESTINATION_STRING);
-        mTrampoline.initializeService();
 
         assertEquals(
                 DESTINATION_STRING,
@@ -1093,23 +892,15 @@
         when(mBackupManagerServiceMock.getDestinationString(mUserId, TRANSPORT_NAME)).thenReturn(
                 DESTINATION_STRING);
 
-        mTrampoline.initializeService();
         assertEquals(DESTINATION_STRING, mTrampoline.getDestinationString(TRANSPORT_NAME));
         verify(mBackupManagerServiceMock).getDestinationString(mUserId, TRANSPORT_NAME);
     }
 
     @Test
-    public void getDataManagementIntent_calledBeforeInitialize_ignored() throws Exception {
-        assertNull(mTrampoline.getDataManagementIntent(TRANSPORT_NAME));
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void getDataManagementIntentForUser_forwarded() throws Exception {
         Intent dataManagementIntent = new Intent();
         when(mBackupManagerServiceMock.getDataManagementIntent(mUserId, TRANSPORT_NAME)).thenReturn(
                 dataManagementIntent);
-        mTrampoline.initializeService();
 
         assertEquals(
                 dataManagementIntent,
@@ -1123,23 +914,15 @@
         Intent dataManagementIntent = new Intent();
         when(mBackupManagerServiceMock.getDataManagementIntent(mUserId, TRANSPORT_NAME)).thenReturn(
                 dataManagementIntent);
-        mTrampoline.initializeService();
 
         assertEquals(dataManagementIntent, mTrampoline.getDataManagementIntent(TRANSPORT_NAME));
         verify(mBackupManagerServiceMock).getDataManagementIntent(mUserId, TRANSPORT_NAME);
     }
 
     @Test
-    public void getDataManagementLabelForUser_calledBeforeInitialize_ignored() throws Exception {
-        assertNull(mTrampoline.getDataManagementLabelForUser(mUserId, TRANSPORT_NAME));
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void getDataManagementLabelForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.getDataManagementLabel(mUserId, TRANSPORT_NAME)).thenReturn(
                 DATA_MANAGEMENT_LABEL);
-        mTrampoline.initializeService();
 
         assertEquals(
                 DATA_MANAGEMENT_LABEL,
@@ -1148,14 +931,7 @@
     }
 
     @Test
-    public void beginRestoreSession_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.beginRestoreSessionForUser(mUserId, PACKAGE_NAME, TRANSPORT_NAME);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void beginRestoreSessionForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.beginRestoreSessionForUser(mUserId, PACKAGE_NAME, TRANSPORT_NAME);
 
@@ -1164,15 +940,8 @@
     }
 
     @Test
-    public void opComplete_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.opComplete(1, 2);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void opComplete_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.opComplete(1, 2);
 
@@ -1180,49 +949,27 @@
     }
 
     @Test
-    public void getAvailableRestoreTokenForUser_calledBeforeInitialize_ignored() {
-        assertEquals(0, mTrampoline.getAvailableRestoreTokenForUser(mUserId, PACKAGE_NAME));
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void getAvailableRestoreTokenForUser_forwarded() {
         when(mBackupManagerServiceMock.getAvailableRestoreToken(mUserId, PACKAGE_NAME))
                 .thenReturn(123L);
-        mTrampoline.initializeService();
 
         assertEquals(123, mTrampoline.getAvailableRestoreTokenForUser(mUserId, PACKAGE_NAME));
         verify(mBackupManagerServiceMock).getAvailableRestoreToken(mUserId, PACKAGE_NAME);
     }
 
     @Test
-    public void isAppEligibleForBackupForUser_calledBeforeInitialize_ignored() {
-        assertFalse(mTrampoline.isAppEligibleForBackupForUser(mUserId, PACKAGE_NAME));
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void isAppEligibleForBackupForUser_forwarded() {
         when(mBackupManagerServiceMock.isAppEligibleForBackup(mUserId, PACKAGE_NAME))
                 .thenReturn(true);
-        mTrampoline.initializeService();
 
         assertTrue(mTrampoline.isAppEligibleForBackupForUser(mUserId, PACKAGE_NAME));
         verify(mBackupManagerServiceMock).isAppEligibleForBackup(mUserId, PACKAGE_NAME);
     }
 
     @Test
-    public void requestBackup_calledBeforeInitialize_ignored() throws RemoteException {
-        assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, mTrampoline.requestBackup(
-                PACKAGE_NAMES, mBackupObserverMock, mBackupManagerMonitorMock, 123));
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void requestBackupForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.requestBackup(mUserId, PACKAGE_NAMES,
                 mBackupObserverMock, mBackupManagerMonitorMock, 123)).thenReturn(456);
-        mTrampoline.initializeService();
 
         assertEquals(456, mTrampoline.requestBackupForUser(mUserId, PACKAGE_NAMES,
                 mBackupObserverMock, mBackupManagerMonitorMock, 123));
@@ -1235,7 +982,6 @@
         TrampolineTestable.sCallingUserId = mUserId;
         when(mBackupManagerServiceMock.requestBackup(mUserId, PACKAGE_NAMES,
                 mBackupObserverMock, mBackupManagerMonitorMock, 123)).thenReturn(456);
-        mTrampoline.initializeService();
 
         assertEquals(456, mTrampoline.requestBackup(PACKAGE_NAMES,
                 mBackupObserverMock, mBackupManagerMonitorMock, 123));
@@ -1244,14 +990,7 @@
     }
 
     @Test
-    public void cancelBackups_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.cancelBackups();
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void cancelBackupsForUser_forwarded() throws Exception {
-        mTrampoline.initializeService();
 
         mTrampoline.cancelBackupsForUser(mUserId);
 
@@ -1261,7 +1000,6 @@
     @Test
     public void cancelBackups_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        mTrampoline.initializeService();
 
         mTrampoline.cancelBackups();
 
@@ -1269,30 +1007,16 @@
     }
 
     @Test
-    public void beginFullBackup_calledBeforeInitialize_ignored() throws Exception {
-        mTrampoline.beginFullBackup(mUserId, new FullBackupJob());
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void beginFullBackup_forwarded() throws Exception {
         FullBackupJob fullBackupJob = new FullBackupJob();
         when(mBackupManagerServiceMock.beginFullBackup(mUserId, fullBackupJob)).thenReturn(true);
 
-        mTrampoline.initializeService();
         assertTrue(mTrampoline.beginFullBackup(mUserId, fullBackupJob));
         verify(mBackupManagerServiceMock).beginFullBackup(mUserId, fullBackupJob);
     }
 
     @Test
-    public void endFullBackup_calledBeforeInitialize_ignored() {
-        mTrampoline.endFullBackup(mUserId);
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
     public void endFullBackup_forwarded() {
-        mTrampoline.initializeService();
         mTrampoline.endFullBackup(mUserId);
         verify(mBackupManagerServiceMock).endFullBackup(mUserId);
     }
@@ -1302,18 +1026,6 @@
         when(mContextMock.checkCallingOrSelfPermission(
                 android.Manifest.permission.DUMP)).thenReturn(
                 PackageManager.PERMISSION_DENIED);
-        mTrampoline.initializeService();
-
-        mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]);
-
-        verifyNoMoreInteractions(mBackupManagerServiceMock);
-    }
-
-    @Test
-    public void dump_calledBeforeInitialize_ignored() {
-        when(mContextMock.checkCallingOrSelfPermission(
-                android.Manifest.permission.DUMP)).thenReturn(
-                PackageManager.PERMISSION_GRANTED);
 
         mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]);
 
@@ -1325,13 +1037,28 @@
         when(mContextMock.checkCallingOrSelfPermission(
                 android.Manifest.permission.DUMP)).thenReturn(
                 PackageManager.PERMISSION_GRANTED);
-        mTrampoline.initializeService();
 
         mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, null);
 
         verify(mBackupManagerServiceMock).dump(mFileDescriptorStub, mPrintWriterMock, null);
     }
 
+    public void testGetUserForAncestralSerialNumber() {
+        TrampolineTestable.sBackupDisabled = false;
+        Trampoline trampoline = new TrampolineTestable(mContextMock);
+
+        trampoline.getUserForAncestralSerialNumber(0L);
+        verify(mBackupManagerServiceMock).getUserForAncestralSerialNumber(anyInt());
+    }
+
+    public void testGetUserForAncestralSerialNumber_whenDisabled() {
+        TrampolineTestable.sBackupDisabled = true;
+        Trampoline trampoline = new TrampolineTestable(mContextMock);
+
+        trampoline.getUserForAncestralSerialNumber(0L);
+        verify(mBackupManagerServiceMock, never()).getUserForAncestralSerialNumber(anyInt());
+    }
+
     private static class TrampolineTestable extends Trampoline {
         static boolean sBackupDisabled = false;
         static int sCallingUserId = -1;
@@ -1341,10 +1068,10 @@
         static SparseArray<File> sActivatedFiles = new SparseArray<>();
         static SparseArray<File> sRememberActivatedFiles = new SparseArray<>();
         static UserManager sUserManagerMock = null;
-        private int mCreateServiceCallsCount = 0;
 
         TrampolineTestable(Context context) {
             super(context);
+            mService = sBackupManagerServiceMock;
         }
 
         @Override
@@ -1353,7 +1080,7 @@
         }
 
         @Override
-        public boolean isBackupDisabled() {
+        protected boolean isBackupDisabled() {
             return sBackupDisabled;
         }
 
@@ -1382,18 +1109,8 @@
         }
 
         @Override
-        protected BackupManagerService createBackupManagerService() {
-            mCreateServiceCallsCount++;
-            return sBackupManagerServiceMock;
-        }
-
-        @Override
         protected void postToHandler(Runnable runnable) {
             runnable.run();
         }
-
-        int getCreateServiceCallsCount() {
-            return mCreateServiceCallsCount;
-        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
index f9e4c34..8e0d7be 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -311,8 +311,6 @@
     public void testFileLocation_Owner() {
         LockSettingsStorage storage = new LockSettingsStorage(getContext());
 
-        assertEquals("/data/system/gesture.key", storage.getLegacyLockPatternFilename(0));
-        assertEquals("/data/system/password.key", storage.getLegacyLockPasswordFilename(0));
         assertEquals("/data/system/gatekeeper.pattern.key", storage.getLockPatternFilename(0));
         assertEquals("/data/system/gatekeeper.password.key", storage.getLockPasswordFilename(0));
     }
@@ -436,10 +434,8 @@
                 PAYLOAD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD).toBytes();
         CredentialHash deserialized = CredentialHash.fromBytes(serialized);
 
-        assertEquals(CredentialHash.VERSION_GATEKEEPER, deserialized.version);
         assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, deserialized.type);
         assertArrayEquals(PAYLOAD, deserialized.hash);
-        assertFalse(deserialized.isBaseZeroPattern);
     }
 
     public void testCredentialHash_unserialize_versionGatekeeper() {
@@ -453,10 +449,8 @@
         };
         CredentialHash deserialized = CredentialHash.fromBytes(serialized);
 
-        assertEquals(CredentialHash.VERSION_GATEKEEPER, deserialized.version);
         assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, deserialized.type);
         assertArrayEquals(PAYLOAD, deserialized.hash);
-        assertFalse(deserialized.isBaseZeroPattern);
 
         // Make sure the constants we use on the wire do not change.
         assertEquals(-1, LockPatternUtils.CREDENTIAL_TYPE_NONE);
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index 87afdfb..05905d9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -76,7 +76,7 @@
     @Before
     public void setupInjector() {
         when(mMockInjector.getAbiHelper()).thenReturn(mMockPackageAbiHelper);
-        when(mMockInjector.getUserManager()).thenReturn(mMockUserManager);
+        when(mMockInjector.getUserManagerInternal()).thenReturn(mMockUserManager);
     }
 
     @Before
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index f4a6231..4ffcf8f 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -39,6 +39,7 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.doReturn;
@@ -297,9 +298,6 @@
         mInjector.setDisplayOn(true);
         setChargingState(controller, false);
         controller.checkIdleStates(USER_ID);
-        assertEquals(STANDBY_BUCKET_EXEMPTED,
-                controller.getAppStandbyBucket(PACKAGE_EXEMPTED_1, USER_ID,
-                        mInjector.mElapsedRealtime, false));
         assertNotEquals(STANDBY_BUCKET_EXEMPTED,
                 controller.getAppStandbyBucket(PACKAGE_1, USER_ID,
                         mInjector.mElapsedRealtime, false));
@@ -378,6 +376,14 @@
     }
 
     @Test
+    public void testBoundWidgetPackageExempt() throws Exception {
+        assumeTrue(mInjector.getContext().getSystemService(AppWidgetManager.class) != null);
+        assertEquals(STANDBY_BUCKET_EXEMPTED,
+                mController.getAppStandbyBucket(PACKAGE_EXEMPTED_1, USER_ID,
+                        mInjector.mElapsedRealtime, false));
+    }
+
+    @Test
     public void testCharging() throws Exception {
         long startTime;
         TestParoleListener paroleListener = new TestParoleListener();
diff --git a/services/tests/servicestests/test-apps/JobTestApp/Android.bp b/services/tests/servicestests/test-apps/JobTestApp/Android.bp
index ae1eca7..b29e187 100644
--- a/services/tests/servicestests/test-apps/JobTestApp/Android.bp
+++ b/services/tests/servicestests/test-apps/JobTestApp/Android.bp
@@ -17,8 +17,6 @@
 
     sdk_version: "current",
 
-    test_suites: ["device-tests"],
-
     srcs: ["**/*.java"],
 
     dex_preopt: {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index ecf3acd..ab2da2b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -98,7 +98,7 @@
             new DexmakerShareClassLoaderRule();
 
     final Context mContext = getInstrumentation().getTargetContext();
-    final TestInjector mTestInjector = new TestInjector();
+    final TestInjector mTestInjector = new TestInjector(mContext);
 
     ActivityTaskManagerService mService;
     RootActivityContainer mRootActivityContainer;
@@ -467,6 +467,7 @@
 
             spyOn(getLifecycleManager());
             spyOn(getLockTaskController());
+            spyOn(getTaskChangeNotificationController());
             doReturn(mock(IPackageManager.class)).when(this).getPackageManager();
             // allow background activity starts by default
             doReturn(true).when(this).isBackgroundActivityStartsEnabled();
@@ -567,9 +568,8 @@
     private static class TestInjector extends ActivityManagerService.Injector {
         private ServiceThread mHandlerThread;
 
-        @Override
-        public Context getContext() {
-            return getInstrumentation().getTargetContext();
+        TestInjector(Context context) {
+            super(context);
         }
 
         @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index f602418..d1dc382 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -207,7 +207,7 @@
         final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
                 runner, 100, 50, true /* changeNeedsSnapshot */);
         // RemoteAnimationController will tracking RemoteAnimationAdapter's caller with calling pid.
-        adapter.setCallingPid(123);
+        adapter.setCallingPidUid(123, 456);
 
         // Simulate activity finish flows to prepare app transition & set visibility,
         // make sure transition is set as expected.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index c5e7c47..388658d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -756,7 +756,8 @@
         final ISystemGestureExclusionListener.Stub verifier =
                 new ISystemGestureExclusionListener.Stub() {
             @Override
-            public void onSystemGestureExclusionChanged(int displayId, Region actual) {
+            public void onSystemGestureExclusionChanged(int displayId, Region actual,
+                    Region unrestricted) {
                 Region expected = Region.obtain();
                 expected.set(10, 20, 30, 40);
                 assertEquals(expected, actual);
@@ -790,7 +791,14 @@
 
         final Region expected = Region.obtain();
         expected.set(20, 30, 40, 50);
-        assertEquals(expected, dc.calculateSystemGestureExclusion());
+        assertEquals(expected, calculateSystemGestureExclusion(dc));
+    }
+
+    private Region calculateSystemGestureExclusion(DisplayContent dc) {
+        Region out = Region.obtain();
+        Region unrestricted = Region.obtain();
+        dc.calculateSystemGestureExclusion(out, unrestricted);
+        return out;
     }
 
     @Test
@@ -814,7 +822,7 @@
         win2.setHasSurface(true);
 
         final Region expected = Region.obtain();
-        assertEquals(expected, dc.calculateSystemGestureExclusion());
+        assertEquals(expected, calculateSystemGestureExclusion(dc));
     }
 
     @Test
@@ -839,7 +847,7 @@
 
             final Region expected = Region.obtain();
             expected.set(dc.getBounds());
-            assertEquals(expected, dc.calculateSystemGestureExclusion());
+            assertEquals(expected, calculateSystemGestureExclusion(dc));
 
             win.setHasSurface(false);
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index a1999c90..b7a85d7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -43,6 +43,8 @@
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import static java.lang.Integer.MAX_VALUE;
 
@@ -900,6 +902,46 @@
                         true /* showRecents */));
     }
 
+    @Test
+    public void addTask_callsTaskNotificationController() {
+        final TaskRecord task = createTaskBuilder(".Task").build();
+
+        mRecentTasks.add(task);
+        mRecentTasks.remove(task);
+
+        TaskChangeNotificationController controller =
+                mTestService.getTaskChangeNotificationController();
+        verify(controller, times(2)).notifyTaskListUpdated();
+    }
+
+    @Test
+    public void removeTask_callsTaskNotificationController() {
+        final TaskRecord task = createTaskBuilder(".Task").build();
+
+        mRecentTasks.add(task);
+        mRecentTasks.remove(task);
+
+        // 2 calls - Once for add and once for remove
+        TaskChangeNotificationController controller =
+                mTestService.getTaskChangeNotificationController();
+        verify(controller, times(2)).notifyTaskListUpdated();
+    }
+
+    @Test
+    public void removeALlVisibleTask_callsTaskNotificationController_twice() {
+        final TaskRecord task1 = createTaskBuilder(".Task").build();
+        final TaskRecord task2 = createTaskBuilder(".Task2").build();
+
+        mRecentTasks.add(task1);
+        mRecentTasks.add(task2);
+        mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID);
+
+        // 4 calls - Twice for add and twice for remove
+        TaskChangeNotificationController controller =
+                mTestService.getTaskChangeNotificationController();
+        verify(controller, times(4)).notifyTaskListUpdated();
+    }
+
     /**
      * Ensures that the raw recent tasks list is in the provided order. Note that the expected tasks
      * should be ordered from least to most recent.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index cd292b2..f5a1d75 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -44,6 +44,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 
+import android.app.ActivityManager.TaskSnapshot;
 import android.os.Binder;
 import android.os.IInterface;
 import android.platform.test.annotations.Presubmit;
@@ -73,6 +74,7 @@
     @Mock OnAnimationFinishedCallback mFinishedCallback;
     @Mock IRecentsAnimationRunner mMockRunner;
     @Mock RecentsAnimationController.RecentsAnimationCallbacks mAnimationCallbacks;
+    @Mock TaskSnapshot mMockTaskSnapshot;
     private RecentsAnimationController mController;
 
     @Before
@@ -104,7 +106,7 @@
         // Verify that the finish callback to reparent the leash is called
         verify(mFinishedCallback).onAnimationFinished(eq(adapter));
         // Verify the animation canceled callback to the app was made
-        verify(mMockRunner).onAnimationCanceled(false);
+        verify(mMockRunner).onAnimationCanceled(null /* taskSnapshot */);
         verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
     }
 
@@ -162,7 +164,7 @@
 
         mController.setDeferredCancel(true /* deferred */, false /* screenshot */);
         mController.cancelAnimationWithScreenshot(false /* screenshot */);
-        verify(mMockRunner).onAnimationCanceled(false /* deferredWithScreenshot */);
+        verify(mMockRunner).onAnimationCanceled(null /* taskSnapshot */);
         assertNull(mController.mRecentScreenshotAnimator);
 
         // Simulate the app transition finishing
@@ -183,9 +185,14 @@
         mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
         assertTrue(mController.isAnimatingTask(appWindow.getTask()));
 
+        spyOn(mWm.mTaskSnapshotController);
+        doNothing().when(mWm.mTaskSnapshotController).notifyAppVisibilityChanged(any(),
+                anyBoolean());
+        doReturn(mMockTaskSnapshot).when(mWm.mTaskSnapshotController).getSnapshot(anyInt(),
+                anyInt(), eq(false) /* restoreFromDisk */, eq(false) /* reducedResolution */);
         mController.setDeferredCancel(true /* deferred */, true /* screenshot */);
         mController.cancelAnimationWithScreenshot(true /* screenshot */);
-        verify(mMockRunner).onAnimationCanceled(true /* deferredWithScreenshot */);
+        verify(mMockRunner).onAnimationCanceled(mMockTaskSnapshot /* taskSnapshot */);
         assertNotNull(mController.mRecentScreenshotAnimator);
         assertTrue(mController.mRecentScreenshotAnimator.isAnimating());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index cb74c3e..74791e2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -79,7 +79,7 @@
 
         when(mMockRunner.asBinder()).thenReturn(new Binder());
         mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50, true /* changeNeedsSnapshot */);
-        mAdapter.setCallingPid(123);
+        mAdapter.setCallingPidUid(123, 456);
         mWm.mH.runWithScissors(() -> mHandler = new TestHandler(null, mClock), 0);
         mController = new RemoteAnimationController(mWm, mAdapter, mHandler);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index a7c84a1..8c56ffa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -23,12 +23,18 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.content.pm.ApplicationInfo;
 import android.platform.test.annotations.Presubmit;
 
+import org.junit.Before;
 import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
 
 /**
  * Tests for the {@link WindowProcessController} class.
@@ -39,43 +45,89 @@
 @Presubmit
 public class WindowProcessControllerTests extends ActivityTestsBase {
 
+    WindowProcessController mWpc;
+    WindowProcessListener mMockListener;
+
+    @Before
+    public void setUp() {
+        mMockListener = mock(WindowProcessListener.class);
+        mWpc = new WindowProcessController(
+                mService, mock(ApplicationInfo.class), null, 0, -1, null, mMockListener);
+    }
+
     @Test
     public void testDisplayConfigurationListener() {
-        final WindowProcessController wpc = new WindowProcessController(
-                        mService, mock(ApplicationInfo.class), null, 0, -1, null, null);
+
         //By default, the process should not listen to any display.
-        assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
+        assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
 
         // Register to display 1 as a listener.
         TestActivityDisplay testActivityDisplay1 = createTestActivityDisplayInContainer();
-        wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
-        assertTrue(testActivityDisplay1.containsListener(wpc));
-        assertEquals(testActivityDisplay1.mDisplayId, wpc.getDisplayId());
+        mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
+        assertTrue(testActivityDisplay1.containsListener(mWpc));
+        assertEquals(testActivityDisplay1.mDisplayId, mWpc.getDisplayId());
 
         // Move to display 2.
         TestActivityDisplay testActivityDisplay2 = createTestActivityDisplayInContainer();
-        wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay2);
-        assertFalse(testActivityDisplay1.containsListener(wpc));
-        assertTrue(testActivityDisplay2.containsListener(wpc));
-        assertEquals(testActivityDisplay2.mDisplayId, wpc.getDisplayId());
+        mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay2);
+        assertFalse(testActivityDisplay1.containsListener(mWpc));
+        assertTrue(testActivityDisplay2.containsListener(mWpc));
+        assertEquals(testActivityDisplay2.mDisplayId, mWpc.getDisplayId());
 
         // Null ActivityDisplay will not change anything.
-        wpc.registerDisplayConfigurationListenerLocked(null);
-        assertTrue(testActivityDisplay2.containsListener(wpc));
-        assertEquals(testActivityDisplay2.mDisplayId, wpc.getDisplayId());
+        mWpc.registerDisplayConfigurationListenerLocked(null);
+        assertTrue(testActivityDisplay2.containsListener(mWpc));
+        assertEquals(testActivityDisplay2.mDisplayId, mWpc.getDisplayId());
 
         // Unregister listener will remove the wpc from registered displays.
-        wpc.unregisterDisplayConfigurationListenerLocked();
-        assertFalse(testActivityDisplay1.containsListener(wpc));
-        assertFalse(testActivityDisplay2.containsListener(wpc));
-        assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
+        mWpc.unregisterDisplayConfigurationListenerLocked();
+        assertFalse(testActivityDisplay1.containsListener(mWpc));
+        assertFalse(testActivityDisplay2.containsListener(mWpc));
+        assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
 
         // Unregistration still work even if the display was removed.
-        wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
-        assertEquals(testActivityDisplay1.mDisplayId, wpc.getDisplayId());
+        mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
+        assertEquals(testActivityDisplay1.mDisplayId, mWpc.getDisplayId());
         mRootActivityContainer.removeChild(testActivityDisplay1);
-        wpc.unregisterDisplayConfigurationListenerLocked();
-        assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
+        mWpc.unregisterDisplayConfigurationListenerLocked();
+        assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
+    }
+
+    @Test
+    public void testSetRunningRecentsAnimation() {
+        mWpc.setRunningRecentsAnimation(true);
+        mWpc.setRunningRecentsAnimation(false);
+        mService.mH.runWithScissors(() -> {}, 0);
+
+        InOrder orderVerifier = Mockito.inOrder(mMockListener);
+        orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true));
+        orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(false));
+    }
+
+    @Test
+    public void testSetRunningRemoteAnimation() {
+        mWpc.setRunningRemoteAnimation(true);
+        mWpc.setRunningRemoteAnimation(false);
+        mService.mH.runWithScissors(() -> {}, 0);
+
+        InOrder orderVerifier = Mockito.inOrder(mMockListener);
+        orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true));
+        orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(false));
+    }
+
+    @Test
+    public void testSetRunningBothAnimations() {
+        mWpc.setRunningRemoteAnimation(true);
+        mWpc.setRunningRecentsAnimation(true);
+
+        mWpc.setRunningRecentsAnimation(false);
+        mWpc.setRunningRemoteAnimation(false);
+        mService.mH.runWithScissors(() -> {}, 0);
+
+        InOrder orderVerifier = Mockito.inOrder(mMockListener);
+        orderVerifier.verify(mMockListener, times(3)).setRunningRemoteAnimation(eq(true));
+        orderVerifier.verify(mMockListener, times(1)).setRunningRemoteAnimation(eq(false));
+        orderVerifier.verifyNoMoreInteractions();
     }
 
     private TestActivityDisplay createTestActivityDisplayInContainer() {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 2298aa1..2bdeddf 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -830,6 +830,9 @@
                             mUserState.get(user).dumpDatabaseInfo(ipw);
                         }
                         return;
+                    } else if ("appstandby".equals(arg)) {
+                        mAppStandby.dumpState(args, pw);
+                        return;
                     } else if (arg != null && !arg.startsWith("-")) {
                         // Anything else that doesn't start with '-' is a pkg to filter
                         pkg = arg;
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index 92ea872..4f6524e 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -77,7 +77,6 @@
     name: "view-compiler-tests",
     defaults: ["viewcompiler_defaults"],
     srcs: [
-        "dex_builder_test.cc",
         "layout_validation_test.cc",
         "util_test.cc",
     ],
diff --git a/startop/view_compiler/dex_builder_test.cc b/startop/view_compiler/dex_builder_test.cc
deleted file mode 100644
index 90c256f..0000000
--- a/startop/view_compiler/dex_builder_test.cc
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_builder.h"
-
-#include "dex/art_dex_file_loader.h"
-#include "dex/dex_file.h"
-#include "gtest/gtest.h"
-
-using namespace startop::dex;
-
-// Takes a DexBuilder, encodes it into an in-memory DEX file, verifies the resulting DEX file and
-// returns whether the verification was successful.
-bool EncodeAndVerify(DexBuilder* dex_file) {
-  slicer::MemView image{dex_file->CreateImage()};
-
-  art::ArtDexFileLoader loader;
-  std::string error_msg;
-  std::unique_ptr<const art::DexFile> loaded_dex_file{loader.Open(image.ptr<const uint8_t>(),
-                                                                  image.size(),
-                                                                  /*location=*/"",
-                                                                  /*location_checksum=*/0,
-                                                                  /*oat_dex_file=*/nullptr,
-                                                                  /*verify=*/true,
-                                                                  /*verify_checksum=*/false,
-                                                                  &error_msg)};
-  return loaded_dex_file != nullptr;
-}
-
-// Write out and verify a DEX file that corresponds to:
-//
-// package dextest;
-// public class DexTest {
-//     public static void foo() {}
-// }
-TEST(DexBuilderTest, VerifyDexWithClassMethod) {
-  DexBuilder dex_file;
-
-  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
-
-  auto method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Void()})};
-  method.BuildReturn();
-  method.Encode();
-
-  EXPECT_TRUE(EncodeAndVerify(&dex_file));
-}
-
-// Makes sure a bad DEX class fails to verify.
-TEST(DexBuilderTest, VerifyBadDexWithClassMethod) {
-  DexBuilder dex_file;
-
-  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
-
-  // This method has the error, because methods cannot take Void() as a parameter.
-  auto method{
-      cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Void(), TypeDescriptor::Void()})};
-  method.BuildReturn();
-  method.Encode();
-
-  EXPECT_FALSE(EncodeAndVerify(&dex_file));
-}
-
-// Write out and verify a DEX file that corresponds to:
-//
-// package dextest;
-// public class DexTest {
-//     public static int foo() { return 5; }
-// }
-TEST(DexBuilderTest, VerifyDexReturn5) {
-  DexBuilder dex_file;
-
-  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
-
-  auto method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int()})};
-  auto r = method.MakeRegister();
-  method.BuildConst4(r, 5);
-  method.BuildReturn(r);
-  method.Encode();
-
-  EXPECT_TRUE(EncodeAndVerify(&dex_file));
-}
-
-// Write out and verify a DEX file that corresponds to:
-//
-// package dextest;
-// public class DexTest {
-//     public static int foo(int x) { return x; }
-// }
-TEST(DexBuilderTest, VerifyDexReturnIntParam) {
-  DexBuilder dex_file;
-
-  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
-
-  auto method{
-      cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), TypeDescriptor::Int()})};
-  method.BuildReturn(Value::Parameter(0));
-  method.Encode();
-
-  EXPECT_TRUE(EncodeAndVerify(&dex_file));
-}
-
-// Write out and verify a DEX file that corresponds to:
-//
-// package dextest;
-// public class DexTest {
-//     public static int foo(String s) { return s.length(); }
-// }
-TEST(DexBuilderTest, VerifyDexCallStringLength) {
-  DexBuilder dex_file;
-
-  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
-
-  MethodBuilder method{cbuilder.CreateMethod(
-      "foo", Prototype{TypeDescriptor::Int(), TypeDescriptor::FromClassname("java.lang.String")})};
-
-  Value result = method.MakeRegister();
-
-  MethodDeclData string_length =
-      dex_file.GetOrDeclareMethod(TypeDescriptor::FromClassname("java.lang.String"),
-                                  "length",
-                                  Prototype{TypeDescriptor::Int()});
-
-  method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0)));
-  method.BuildReturn(result);
-
-  method.Encode();
-
-  EXPECT_TRUE(EncodeAndVerify(&dex_file));
-}
-
-// Write out and verify a DEX file that corresponds to:
-//
-// package dextest;
-// public class DexTest {
-//     public static int foo(String s) { return s.length(); }
-// }
-TEST(DexBuilderTest, VerifyDexCallManyRegisters) {
-  DexBuilder dex_file;
-
-  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
-
-  MethodBuilder method{cbuilder.CreateMethod(
-      "foo", Prototype{TypeDescriptor::Int()})};
-
-  Value result = method.MakeRegister();
-
-  // Make a bunch of registers
-  for (size_t i = 0; i < 25; ++i) {
-    method.MakeRegister();
-  }
-
-  // Now load a string literal into a register
-  Value string_val = method.MakeRegister();
-  method.BuildConstString(string_val, "foo");
-
-  MethodDeclData string_length =
-      dex_file.GetOrDeclareMethod(TypeDescriptor::FromClassname("java.lang.String"),
-                                  "length",
-                                  Prototype{TypeDescriptor::Int()});
-
-  method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, string_val));
-  method.BuildReturn(result);
-
-  method.Encode();
-
-  EXPECT_TRUE(EncodeAndVerify(&dex_file));
-}
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 17d725e..c4a9ee9 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -24,7 +24,6 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
-import android.app.job.JobService;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -4102,9 +4101,11 @@
          * ServiceState provider.
          * <p>
          * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
-         * {@link ServiceState} while your app is running.  You can also use a {@link JobService} to
+         * {@link ServiceState} while your app is running.
+         * You can also use a {@link android.app.job.JobService} to
          * ensure your app is notified of changes to the {@link Uri} even when it is not running.
-         * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+         * Note, however, that using a {@link android.app.job.JobService}
+         * does not guarantee timely delivery of
          * updates to the {@link Uri}.
          *
          * @param subscriptionId the subscriptionId to receive updates on
@@ -4121,9 +4122,11 @@
          * ServiceState provider.
          * <p>
          * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
-         * {@link ServiceState} while your app is running.  You can also use a {@link JobService} to
+         * {@link ServiceState} while your app is running.  You can also use a
+         * {@link android.app.job.JobService} to
          * ensure your app is notified of changes to the {@link Uri} even when it is not running.
-         * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+         * Note, however, that using a {@link android.app.job.JobService}
+         * does not guarantee timely delivery of
          * updates to the {@link Uri}.
          *
          * @param subscriptionId the subscriptionId to receive updates on
@@ -4378,10 +4381,11 @@
          * <p>
          * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
          * carrier identity {@link TelephonyManager#getSimCarrierId()}
-         * while your app is running. You can also use a {@link JobService} to ensure your app
+         * while your app is running. You can also use a {@link android.app.job.JobService}
+         * to ensure your app
          * is notified of changes to the {@link Uri} even when it is not running.
-         * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-         * updates to the {@link Uri}.
+         * Note, however, that using a {@link android.app.job.JobService} does not guarantee
+         * timely delivery of updates to the {@link Uri}.
          *
          * @param subscriptionId the subscriptionId to receive updates on
          * @return the Uri used to observe carrier identity changes
@@ -4399,10 +4403,11 @@
          * <p>
          * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
          * specific carrier identity {@link TelephonyManager#getSimSpecificCarrierId()}
-         * while your app is running. You can also use a {@link JobService} to ensure your app
+         * while your app is running. You can also use a {@link android.app.job.JobService}
+         * to ensure your app
          * is notified of changes to the {@link Uri} even when it is not running.
-         * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-         * updates to the {@link Uri}.
+         * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+         * delivery of updates to the {@link Uri}.
          *
          * @param subscriptionId the subscriptionId to receive updates on
          * @return the Uri used to observe specific carrier identity changes
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 292a294..66cc6eb 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -468,6 +468,14 @@
             "notify_handover_video_from_wifi_to_lte_bool";
 
     /**
+     * Flag specifying whether the carrier supports merging a RTT call with a voice call,
+     * downgrading the call in the process.
+     * @hide
+     */
+    public static final String KEY_ALLOW_MERGING_RTT_CALLS_BOOL =
+             "allow_merging_rtt_calls_bool";
+
+    /**
      * Flag specifying whether the carrier wants to notify the user when a VT call has been handed
      * over from LTE to WIFI.
      * <p>
@@ -2718,12 +2726,20 @@
 
     /**
      * Controls hysteresis time in milli seconds for which OpportunisticNetworkService
-     * will wait before switching data to a network.
+     * will wait before switching data to an opportunistic network.
      */
     public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG =
             "opportunistic_network_data_switch_hysteresis_time_long";
 
     /**
+     * Controls hysteresis time in milli seconds for which OpportunisticNetworkService
+     * will wait before switching data from opportunistic network to primary network.
+     * @hide
+     */
+    public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG =
+            "opportunistic_network_data_switch_exit_hysteresis_time_long";
+
+    /**
      * Indicates zero or more emergency number prefix(es), because some carrier requires
      * if users dial an emergency number address with a specific prefix, the combination of the
      * prefix and the address is also a valid emergency number to dial. For example, an emergency
@@ -2923,10 +2939,10 @@
 
     /**
      * Wi-Fi configs used in Carrier Wi-Fi application.
-     * TODO(b/132059890): Expose it in a future release as systemapi.
      *
      * @hide
      */
+    @SystemApi
     public static final class Wifi {
         /** Prefix of all Wifi.KEY_* constants. */
         public static final String KEY_PREFIX = "wifi.";
@@ -3113,6 +3129,7 @@
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VT_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL, false);
+        sDefaults.putBoolean(KEY_ALLOW_MERGING_RTT_CALLS_BOOL, false);
         sDefaults.putBoolean(KEY_NOTIFY_HANDOVER_VIDEO_FROM_LTE_TO_WIFI_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_DOWNGRADE_VT_TO_AUDIO_BOOL, true);
         sDefaults.putString(KEY_DEFAULT_VM_NUMBER_STRING, "");
@@ -3484,6 +3501,8 @@
         sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_ENTRY_OR_EXIT_HYSTERESIS_TIME_LONG, 10000);
         /* Default value is 10 seconds. */
         sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG, 10000);
+        /* Default value is 3 seconds. */
+        sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 3000);
         sDefaults.putAll(Gps.getDefaults());
         sDefaults.putAll(Wifi.getDefaults());
         sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 2822fcc..8c53c51 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -34,7 +34,6 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.BroadcastOptions;
 import android.app.PendingIntent;
-import android.app.job.JobService;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
@@ -147,10 +146,11 @@
      * <p>
      * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
      * subscription wfc enabled {@link ImsMmTelManager#isVoWiFiSettingEnabled()}
-     * while your app is running. You can also use a {@link JobService} to ensure your app
+     * while your app is running. You can also use a {@link android.app.job.JobService}
+     * to ensure your app
      * is notified of changes to the {@link Uri} even when it is not running.
-     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-     * updates to the {@link Uri}.
+     * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+     * delivery of updates to the {@link Uri}.
      * To be notified of changes to a specific subId, append subId to the URI
      * {@link Uri#withAppendedPath(Uri, String)}.
      * @hide
@@ -166,10 +166,10 @@
      * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
      * subscription advanced calling enabled
      * {@link ImsMmTelManager#isAdvancedCallingSettingEnabled()} while your app is running.
-     * You can also use a {@link JobService} to ensure your app is notified of changes to the
-     * {@link Uri} even when it is not running.
-     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-     * updates to the {@link Uri}.
+     * You can also use a {@link android.app.job.JobService} to ensure your app is notified of
+     * changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+     * delivery of updates to the {@link Uri}.
      * To be notified of changes to a specific subId, append subId to the URI
      * {@link Uri#withAppendedPath(Uri, String)}.
      * @hide
@@ -184,10 +184,10 @@
      * <p>
      * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
      * subscription wfc mode {@link ImsMmTelManager#getVoWiFiModeSetting()}
-     * while your app is running. You can also use a {@link JobService} to ensure your app
-     * is notified of changes to the {@link Uri} even when it is not running.
-     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-     * updates to the {@link Uri}.
+     * while your app is running. You can also use a {@link android.app.job.JobService} to ensure
+     * your app is notified of changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+     * delivery of updates to the {@link Uri}.
      * To be notified of changes to a specific subId, append subId to the URI
      * {@link Uri#withAppendedPath(Uri, String)}.
      * @hide
@@ -201,10 +201,10 @@
      * <p>
      * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
      * subscription wfc roaming mode {@link ImsMmTelManager#getVoWiFiRoamingModeSetting()}
-     * while your app is running. You can also use a {@link JobService} to ensure your app
-     * is notified of changes to the {@link Uri} even when it is not running.
-     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-     * updates to the {@link Uri}.
+     * while your app is running. You can also use a {@link android.app.job.JobService}
+     * to ensure your app is notified of changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+     * delivery of updates to the {@link Uri}.
      * To be notified of changes to a specific subId, append subId to the URI
      * {@link Uri#withAppendedPath(Uri, String)}.
      * @hide
@@ -220,10 +220,10 @@
      * <p>
      * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
      * subscription vt enabled {@link ImsMmTelManager#isVtSettingEnabled()}
-     * while your app is running. You can also use a {@link JobService} to ensure your app
-     * is notified of changes to the {@link Uri} even when it is not running.
-     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-     * updates to the {@link Uri}.
+     * while your app is running. You can also use a {@link android.app.job.JobService} to ensure
+     * your app is notified of changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+     * delivery of updates to the {@link Uri}.
      * To be notified of changes to a specific subId, append subId to the URI
      * {@link Uri#withAppendedPath(Uri, String)}.
      * @hide
@@ -238,10 +238,10 @@
      * <p>
      * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
      * subscription wfc roaming enabled {@link ImsMmTelManager#isVoWiFiRoamingSettingEnabled()}
-     * while your app is running. You can also use a {@link JobService} to ensure your app
-     * is notified of changes to the {@link Uri} even when it is not running.
-     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-     * updates to the {@link Uri}.
+     * while your app is running. You can also use a {@link android.app.job.JobService} to ensure
+     * your app is notified of changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+     * delivery of updates to the {@link Uri}.
      * To be notified of changes to a specific subId, append subId to the URI
      * {@link Uri#withAppendedPath(Uri, String)}.
      * @hide
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index 511adf6..19d0724 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -22,6 +22,7 @@
 import android.hardware.radio.V1_4.EmergencyServiceCategory;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.Rlog;
 
@@ -301,6 +302,9 @@
      * The character in the number string is only the dial pad
      * character('0'-'9', '*', '+', or '#'). For example: 911.
      *
+     * If the number starts with carrier prefix, the carrier prefix is configured in
+     * {@link CarrierConfigManager#KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY}.
+     *
      * @return the dialing number.
      */
     public @NonNull String getNumber() {
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 3bec8b0..8f89899 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -34,7 +34,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.Set;
 import java.util.WeakHashMap;
 
@@ -106,6 +108,16 @@
     public static final int FEATURE_MAX = 3;
 
     /**
+     * Used for logging purposes.
+     * @hide
+     */
+    public static final Map<Integer, String> FEATURE_LOG_MAP = new HashMap<Integer, String>() {{
+            put(FEATURE_EMERGENCY_MMTEL, "EMERGENCY_MMTEL");
+            put(FEATURE_MMTEL, "MMTEL");
+            put(FEATURE_RCS, "RCS");
+        }};
+
+    /**
      * Integer values defining IMS features that are supported in ImsFeature.
      * @hide
      */
@@ -150,6 +162,16 @@
     public static final int STATE_READY = 2;
 
     /**
+     * Used for logging purposes.
+     * @hide
+     */
+    public static final Map<Integer, String> STATE_LOG_MAP = new HashMap<Integer, String>() {{
+            put(STATE_UNAVAILABLE, "UNAVAILABLE");
+            put(STATE_INITIALIZING, "INITIALIZING");
+            put(STATE_READY, "READY");
+        }};
+
+    /**
      * Integer values defining the result codes that should be returned from
      * {@link #changeEnabledCapabilities} when the framework tries to set a feature's capability.
      * @hide
diff --git a/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java b/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java
index 6ab9465..3b298bb 100644
--- a/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java
+++ b/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java
@@ -21,7 +21,6 @@
 import android.os.Parcelable;
 import android.telephony.ims.feature.ImsFeature;
 import android.util.ArraySet;
-import android.util.Pair;
 
 import java.util.Set;
 
@@ -80,7 +79,7 @@
 
         @Override
         public String toString() {
-            return "{s=" + slotId + ", f=" + featureType + "}";
+            return "{s=" + slotId + ", f=" + ImsFeature.FEATURE_LOG_MAP.get(featureType) + "}";
         }
     }
 
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index af993be..e9a177d 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -115,7 +115,7 @@
             final Context otherContext;
             try {
                 otherContext = context.createPackageContextAsUser(context.getPackageName(),
-                        /* flags =*/ 0, new UserHandle(currentUser));
+                        /* flags =*/ 0, UserHandle.of(currentUser));
                 return otherContext.getContentResolver();
             } catch (NameNotFoundException e) {
                 Rlog.e(LOG_TAG, "Can't find self package", e);
diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
index 6498e49..0d4fd0f 100644
--- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
@@ -21,6 +21,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.os.RemoteException;
 import android.permission.IPermissionManager;
 import android.provider.Settings;
@@ -29,7 +30,9 @@
 import android.util.ArraySet;
 import android.util.Slog;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.SystemConfig;
 
 import java.util.ArrayList;
@@ -143,9 +146,12 @@
         try {
             for (ApplicationInfo ai : candidates) {
                 String packageName = ai.packageName;
-                boolean hasPrivileges = telephonyManager != null &&
-                        telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
-                                TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+                String[] restrictedCarrierApps = Resources.getSystem().getStringArray(
+                        R.array.config_restrictedPreinstalledCarrierApps);
+                boolean hasPrivileges = telephonyManager != null
+                        && telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName)
+                                == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
+                        && !ArrayUtils.contains(restrictedCarrierApps, packageName);
 
                 // add hiddenUntilInstalled flag for carrier apps and associated apps
                 packageManager.setSystemAppHiddenUntilInstalled(packageName, true);
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index 6df5457..62d3536 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -300,7 +300,7 @@
                 Uri.fromParts(SCHEME_SMSTO, "", null));
         List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent,
                 PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                UserHandle.getUserHandleForUid(userId));
+                UserHandle.of(userId));
         for (ResolveInfo resolveInfo : respondServices) {
             final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
             if (serviceInfo == null) {
@@ -806,7 +806,7 @@
             if (userId != UserHandle.USER_SYSTEM) {
                 try {
                     userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
-                            new UserHandle(userId));
+                        UserHandle.of(userId));
                 } catch (NameNotFoundException nnfe) {
                     if (DEBUG_MULTIUSER) {
                         Log.w(LOG_TAG, "Unable to create package context for user " + userId);
diff --git a/tests/Codegen/runTest.sh b/tests/Codegen/runTest.sh
index bc1aae0..614cbb7 100755
--- a/tests/Codegen/runTest.sh
+++ b/tests/Codegen/runTest.sh
@@ -12,6 +12,7 @@
 
     header_and_eval m -j16 codegen_cli && \
         header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java && \
+        header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java && \
         cd $ANDROID_BUILD_TOP &&
         header_and_eval mmma -j16 frameworks/base/tests/Codegen && \
         header_and_eval adb install -r -t $ANDROID_PRODUCT_OUT/testcases/CodegenTests/arm64/CodegenTests.apk && \
diff --git a/tests/Codegen/src/com/android/codegentest/DateParcelling.java b/tests/Codegen/src/com/android/codegentest/MyDateParcelling.java
similarity index 94%
rename from tests/Codegen/src/com/android/codegentest/DateParcelling.java
rename to tests/Codegen/src/com/android/codegentest/MyDateParcelling.java
index b0b00d0..4faeb8e 100644
--- a/tests/Codegen/src/com/android/codegentest/DateParcelling.java
+++ b/tests/Codegen/src/com/android/codegentest/MyDateParcelling.java
@@ -31,11 +31,11 @@
  *
  * Ignore {@link #sInstanceCount} - used for testing.
  */
-public class DateParcelling implements Parcelling<Date> {
+public class MyDateParcelling implements Parcelling<Date> {
 
     static AtomicInteger sInstanceCount = new AtomicInteger(0);
 
-    public DateParcelling() {
+    public MyDateParcelling() {
         sInstanceCount.getAndIncrement();
     }
 
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index f69a092..30bb3ef 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -53,11 +53,13 @@
 //        genAidl = true,       // implied by `implements Parcelable`
 //        genGetters = true,    // on by default
 //        genConstDefs = true,  // implied by presence of constants with common prefix
+        genBuilder = true,      // on by default if optional fields present, but suppressed by
+                                // genConstructor
+        genConstructor = true,  // on by default but normally suppressed by genBuilder
         genEqualsHashCode = true,
-        genBuilder = true,
         genToString = true,
         genForEachField = true,
-        genConstructor = true   // on by default but normally suppressed by genBuilder
+        genSetters = true
 )
 public final class SampleDataClass implements Parcelable {
 
@@ -136,48 +138,53 @@
     private int mNum4;
 
     /**
-     * {@link Nullable} fields are considered optional and will not throw an exception if omitted
-     * (or set to null) when creating an instance either via a {@link Builder} or constructor.
+     * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
      */
     private @Nullable String mName;
     /**
-     * Fields with default value expressions ("mFoo = ...") are also optional, and are automatically
+     * Fields with default value expressions ("mFoo = ...") are optional, and are automatically
      * initialized to the provided default expression, unless explicitly set.
-     */
-    private String mName2 = "Bob";
-    /**
-     * Fields without {@link Nullable} annotation or default value are considered required.
      *
-     * {@link NonNull} annotation is recommended on such non-primitive fields for documentation.
+     * When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter}
+     * while mandatory fields are passed via {@link Builder#Builder constructor}.
+     */
+    private @NonNull String mName2 = "Bob";
+    /**
+     * Alternatively, when default value computation is expensive,
+     * {@link #defaultName4 defaultFieldName()} can be defined to compute the default value.
      */
     private @NonNull String mName4;
+    private static String defaultName4() {
+        // Expensive computation
+        return "Bob4";
+    }
 
     /**
      * For parcelling, any field type supported by {@link Parcel} is supported out of the box.
      * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
      */
-    private AccessibilityNodeInfo mOtherParcelable = null;
+    private @Nullable AccessibilityNodeInfo mOtherParcelable = null;
     /**
      * Additionally, support for parcelling other types can be added by implementing a
      * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation.
      *
-     * @see DateParcelling an example {@link Parcelling} implementation
+     * @see MyDateParcelling an example {@link Parcelling} implementation
      */
-    @DataClass.ParcelWith(DateParcelling.class)
-    private Date mDate = new Date(42 * 42);
+    @DataClass.ParcelWith(MyDateParcelling.class)
+    private @NonNull Date mDate = new Date(42 * 42);
     /**
      * If a {@link Parcelling} is fairly common, consider putting it in {@link Parcelling.BuiltIn}
      * to encourage its reuse.
      */
     @DataClass.ParcelWith(Parcelling.BuiltIn.ForPattern.class)
-    private Pattern mPattern = Pattern.compile("");
+    private @NonNull Pattern mPattern = Pattern.compile("");
 
     /**
      * For lists, when using a {@link Builder}, other than a regular
      * {@link Builder#setLinkAddresses2(List) setter}, and additional
      * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience.
      */
-    private List<LinkAddress> mLinkAddresses2 = new ArrayList<>();
+    private @NonNull List<LinkAddress> mLinkAddresses2 = new ArrayList<>();
     /**
      * For aesthetics, you may want to consider providing a singular version of the plural field
      * name, which would be used for the {@link #mLinkAddresses2 above mentioned} "add" method.
@@ -185,7 +192,7 @@
      * @see Builder#addLinkAddress(LinkAddress)
      */
     @DataClass.PluralOf("linkAddress")
-    private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
+    private @NonNull ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
     /**
      * For array fields, when using a {@link Builder}, vararg argument format is used for
      * convenience.
@@ -193,11 +200,6 @@
      * @see Builder#setLinkAddresses4(LinkAddress...)
      */
     private @Nullable LinkAddress[] mLinkAddresses4 = null;
-    /**
-     * For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods
-     * like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated.
-     */
-    private boolean mActive = true;
 
     /**
      * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to
@@ -206,7 +208,7 @@
      * @see #getStateName
      * @see Builder#setStateName
      */
-    private @StateName String mStateName = STATE_NAME_UNDEFINED;
+    private @StateName @NonNull String mStateName = STATE_NAME_UNDEFINED;
     /**
      * Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value.
      */
@@ -220,11 +222,11 @@
     /**
      * Making a field public will suppress getter generation in favor of accessing it directly.
      */
-    public CharSequence charSeq = "";
+    public @NonNull CharSequence charSeq = "";
     /**
      * Final fields suppress generating a setter (when setters are requested).
      */
-    private final LinkAddress[] mLinkAddresses5;
+    private final @Nullable LinkAddress[] mLinkAddresses5;
     /**
      * Transient fields are completely ignored and can be used for caching.
      */
@@ -261,7 +263,7 @@
      *
      * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int)
      */
-    private @android.annotation.IntRange(from = 0, to = 4) int mLimited = 3;
+    private @android.annotation.IntRange(from = 0, to = 6) int mDayOfWeek = 3;
     /**
      * Unnamed validation annotation parameter gets supplied to the validating method named as
      * "value".
@@ -272,6 +274,7 @@
      * @see AnnotationValidations#validate(Class, Size, int, String, int)
      */
     @Size(2)
+    @NonNull
     @Each @FloatRange(from = 0f)
     private float[] mCoords = new float[] {0f, 0f};
 
@@ -340,7 +343,6 @@
 
 
     // Code below generated by codegen v1.0.0.
-    //   on Jul 29, 2019, 2:50:21 PM PDT
     //
     // DO NOT MODIFY!
     //
@@ -408,13 +410,9 @@
     @DataClass.Generated.Member
     public @interface StateName {}
 
-    @DataClass.Generated(
-            time = 1564437021513L,
-            codegenVersion = "1.0.0",
-            sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
-            inputSignatures = "public static final  java.lang.String STATE_NAME_UNDEFINED\npublic static final  java.lang.String STATE_NAME_ON\npublic static final  java.lang.String STATE_NAME_OFF\npublic static final  int STATE_UNDEFINED\npublic static final  int STATE_ON\npublic static final  int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate  int mNum\nprivate  int mNum2\nprivate  int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate  java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate  android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.DateParcelling.class) java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) java.util.regex.Pattern mPattern\nprivate  java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate  boolean mActive\nprivate @com.android.codegentest.SampleDataClass.StateName java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic  java.lang.CharSequence charSeq\nprivate final  android.net.LinkAddress[] mLinkAddresses5\nprivate transient  android.net.LinkAddress[] mLinkAddresses6\ntransient  int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=4L) int mLimited\nprivate @android.annotation.Size(2L) @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate  int[] lazyInitTmpStorage()\npublic  android.net.LinkAddress[] getLinkAddresses4()\nprivate  boolean patternEquals(java.util.regex.Pattern)\nprivate  int patternHashCode()\nprivate  void onConstructed()\npublic  void dump(java.io.PrintWriter)")
-
-/**
+    /**
+     * Creates a new SampleDataClass.
+     *
      * @param num
      *   Any property javadoc should go onto the field, and will be copied where appropriate,
      *   including getters, constructor parameters, builder setters, etc.
@@ -429,15 +427,16 @@
      *   {@code @hide} javadoc annotation is also propagated, which can be used to adjust the
      *   desired public API surface.
      * @param name
-     *   {@link Nullable} fields are considered optional and will not throw an exception if omitted
-     *   (or set to null) when creating an instance either via a {@link Builder} or constructor.
+     *   {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
      * @param name2
-     *   Fields with default value expressions ("mFoo = ...") are also optional, and are automatically
+     *   Fields with default value expressions ("mFoo = ...") are optional, and are automatically
      *   initialized to the provided default expression, unless explicitly set.
-     * @param name4
-     *   Fields without {@link Nullable} annotation or default value are considered required.
      *
-     *   {@link NonNull} annotation is recommended on such non-primitive fields for documentation.
+     *   When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter}
+     *   while mandatory fields are passed via {@link Builder#Builder constructor}.
+     * @param name4
+     *   Alternatively, when default value computation is expensive,
+     *   {@link #defaultName4 defaultFieldName()} can be defined to compute the default value.
      * @param otherParcelable
      *   For parcelling, any field type supported by {@link Parcel} is supported out of the box.
      *   E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
@@ -457,9 +456,6 @@
      * @param linkAddresses4
      *   For array fields, when using a {@link Builder}, vararg argument format is used for
      *   convenience.
-     * @param active
-     *   For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods
-     *   like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated.
      * @param stateName
      *   {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to
      *   getter/constructor/setter/builder parameters, making for a nicer api.
@@ -480,7 +476,7 @@
      *   You can also extend support to your custom annotations by creating another corresponding
      *   overloads like
      *   {@link AnnotationValidations#validate(Class, UserIdInt, int)}.
-     * @param limited
+     * @param dayOfWeek
      *   Validation annotations may also have parameters.
      *
      *   Parameter values will be supplied to validation method as name-value pairs.
@@ -497,50 +493,49 @@
             int num2,
             int num4,
             @Nullable String name,
-            String name2,
+            @NonNull String name2,
             @NonNull String name4,
-            AccessibilityNodeInfo otherParcelable,
-            Date date,
-            Pattern pattern,
-            List<LinkAddress> linkAddresses2,
-            ArrayList<LinkAddress> linkAddresses,
+            @Nullable AccessibilityNodeInfo otherParcelable,
+            @NonNull Date date,
+            @NonNull Pattern pattern,
+            @NonNull List<LinkAddress> linkAddresses2,
+            @NonNull ArrayList<LinkAddress> linkAddresses,
             @Nullable LinkAddress[] linkAddresses4,
-            boolean active,
-            @StateName String stateName,
+            @StateName @NonNull String stateName,
             @RequestFlags int flags,
             @State int state,
-            CharSequence charSeq,
-            LinkAddress[] linkAddresses5,
+            @NonNull CharSequence charSeq,
+            @Nullable LinkAddress[] linkAddresses5,
             @StringRes int stringRes,
-            @android.annotation.IntRange(from = 0, to = 4) int limited,
-            @Size(2) @FloatRange(from = 0f) float[] coords) {
+            @android.annotation.IntRange(from = 0, to = 6) int dayOfWeek,
+            @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] coords) {
         this.mNum = num;
         this.mNum2 = num2;
         this.mNum4 = num4;
         this.mName = name;
         this.mName2 = name2;
-        this.mName4 = Preconditions.checkNotNull(name4);
-        this.mOtherParcelable = otherParcelable;
-        this.mDate = date;
-        this.mPattern = pattern;
-        this.mLinkAddresses2 = linkAddresses2;
-        this.mLinkAddresses = linkAddresses;
-        this.mLinkAddresses4 = linkAddresses4;
-        this.mActive = active;
-        this.mStateName = stateName;
-        this.mFlags = flags;
-        this.mState = state;
-        this.charSeq = charSeq;
-        this.mLinkAddresses5 = linkAddresses5;
-        this.mStringRes = stringRes;
-        this.mLimited = limited;
-        this.mCoords = coords;
+        AnnotationValidations.validate(
+                NonNull.class, null, mName2);
+        this.mName4 = name4;
         AnnotationValidations.validate(
                 NonNull.class, null, mName4);
+        this.mOtherParcelable = otherParcelable;
+        this.mDate = date;
+        AnnotationValidations.validate(
+                NonNull.class, null, mDate);
+        this.mPattern = pattern;
+        AnnotationValidations.validate(
+                NonNull.class, null, mPattern);
+        this.mLinkAddresses2 = linkAddresses2;
+        AnnotationValidations.validate(
+                NonNull.class, null, mLinkAddresses2);
+        this.mLinkAddresses = linkAddresses;
+        AnnotationValidations.validate(
+                NonNull.class, null, mLinkAddresses);
+        this.mLinkAddresses4 = linkAddresses4;
+        this.mStateName = stateName;
 
-        //noinspection PointlessBooleanExpression
-        if (true
-                && !(Objects.equals(mStateName, STATE_NAME_UNDEFINED))
+        if (!(Objects.equals(mStateName, STATE_NAME_UNDEFINED))
                 && !(Objects.equals(mStateName, STATE_NAME_ON))
                 && !(Objects.equals(mStateName, STATE_NAME_OFF))) {
             throw new java.lang.IllegalArgumentException(
@@ -550,17 +545,18 @@
                             + "STATE_NAME_OFF(" + STATE_NAME_OFF + ")");
         }
 
+        AnnotationValidations.validate(
+                NonNull.class, null, mStateName);
+        this.mFlags = flags;
 
-        //noinspection PointlessBitwiseExpression
         Preconditions.checkFlagsArgument(
-                mFlags, 0
-                        | FLAG_MANUAL_REQUEST
+                mFlags,
+                FLAG_MANUAL_REQUEST
                         | FLAG_COMPATIBILITY_MODE_REQUEST
                         | FLAG_AUGMENTED_REQUEST);
+        this.mState = state;
 
-        //noinspection PointlessBooleanExpression
-        if (true
-                && !(mState == STATE_UNDEFINED)
+        if (!(mState == STATE_UNDEFINED)
                 && !(mState == STATE_ON)
                 && !(mState == STATE_OFF)) {
             throw new java.lang.IllegalArgumentException(
@@ -570,15 +566,24 @@
                             + "STATE_OFF(" + STATE_OFF + ")");
         }
 
+        this.charSeq = charSeq;
+        AnnotationValidations.validate(
+                NonNull.class, null, charSeq);
+        this.mLinkAddresses5 = linkAddresses5;
+        this.mStringRes = stringRes;
         AnnotationValidations.validate(
                 StringRes.class, null, mStringRes);
+        this.mDayOfWeek = dayOfWeek;
         AnnotationValidations.validate(
-                android.annotation.IntRange.class, null, mLimited,
+                android.annotation.IntRange.class, null, mDayOfWeek,
                 "from", 0,
-                "to", 4);
+                "to", 6);
+        this.mCoords = coords;
         AnnotationValidations.validate(
                 Size.class, null, mCoords.length,
                 "value", 2);
+        AnnotationValidations.validate(
+                NonNull.class, null, mCoords);
         int coordsSize = mCoords.length;
         for (int i = 0; i < coordsSize; i++) {
             AnnotationValidations.validate(
@@ -628,8 +633,7 @@
     }
 
     /**
-     * {@link Nullable} fields are considered optional and will not throw an exception if omitted
-     * (or set to null) when creating an instance either via a {@link Builder} or constructor.
+     * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
      */
     @DataClass.Generated.Member
     public @Nullable String getName() {
@@ -637,18 +641,20 @@
     }
 
     /**
-     * Fields with default value expressions ("mFoo = ...") are also optional, and are automatically
+     * Fields with default value expressions ("mFoo = ...") are optional, and are automatically
      * initialized to the provided default expression, unless explicitly set.
+     *
+     * When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter}
+     * while mandatory fields are passed via {@link Builder#Builder constructor}.
      */
     @DataClass.Generated.Member
-    public String getName2() {
+    public @NonNull String getName2() {
         return mName2;
     }
 
     /**
-     * Fields without {@link Nullable} annotation or default value are considered required.
-     *
-     * {@link NonNull} annotation is recommended on such non-primitive fields for documentation.
+     * Alternatively, when default value computation is expensive,
+     * {@link #defaultName4 defaultFieldName()} can be defined to compute the default value.
      */
     @DataClass.Generated.Member
     public @NonNull String getName4() {
@@ -660,7 +666,7 @@
      * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
      */
     @DataClass.Generated.Member
-    public AccessibilityNodeInfo getOtherParcelable() {
+    public @Nullable AccessibilityNodeInfo getOtherParcelable() {
         return mOtherParcelable;
     }
 
@@ -668,10 +674,10 @@
      * Additionally, support for parcelling other types can be added by implementing a
      * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation.
      *
-     * @see DateParcelling an example {@link Parcelling} implementation
+     * @see MyDateParcelling an example {@link Parcelling} implementation
      */
     @DataClass.Generated.Member
-    public Date getDate() {
+    public @NonNull Date getDate() {
         return mDate;
     }
 
@@ -680,7 +686,7 @@
      * to encourage its reuse.
      */
     @DataClass.Generated.Member
-    public Pattern getPattern() {
+    public @NonNull Pattern getPattern() {
         return mPattern;
     }
 
@@ -690,7 +696,7 @@
      * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience.
      */
     @DataClass.Generated.Member
-    public List<LinkAddress> getLinkAddresses2() {
+    public @NonNull List<LinkAddress> getLinkAddresses2() {
         return mLinkAddresses2;
     }
 
@@ -701,20 +707,11 @@
      * @see Builder#addLinkAddress(LinkAddress)
      */
     @DataClass.Generated.Member
-    public ArrayList<LinkAddress> getLinkAddresses() {
+    public @NonNull ArrayList<LinkAddress> getLinkAddresses() {
         return mLinkAddresses;
     }
 
     /**
-     * For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods
-     * like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated.
-     */
-    @DataClass.Generated.Member
-    public boolean isActive() {
-        return mActive;
-    }
-
-    /**
      * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to
      * getter/constructor/setter/builder parameters, making for a nicer api.
      *
@@ -722,7 +719,7 @@
      * @see Builder#setStateName
      */
     @DataClass.Generated.Member
-    public @StateName String getStateName() {
+    public @StateName @NonNull String getStateName() {
         return mStateName;
     }
 
@@ -746,7 +743,7 @@
      * Final fields suppress generating a setter (when setters are requested).
      */
     @DataClass.Generated.Member
-    public LinkAddress[] getLinkAddresses5() {
+    public @Nullable LinkAddress[] getLinkAddresses5() {
         return mLinkAddresses5;
     }
 
@@ -775,8 +772,8 @@
      * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int)
      */
     @DataClass.Generated.Member
-    public @android.annotation.IntRange(from = 0, to = 4) int getLimited() {
-        return mLimited;
+    public @android.annotation.IntRange(from = 0, to = 6) int getDayOfWeek() {
+        return mDayOfWeek;
     }
 
     /**
@@ -789,7 +786,7 @@
      * @see AnnotationValidations#validate(Class, Size, int, String, int)
      */
     @DataClass.Generated.Member
-    public @Size(2) @FloatRange(from = 0f) float[] getCoords() {
+    public @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] getCoords() {
         return mCoords;
     }
 
@@ -810,6 +807,282 @@
         return tmpStorage;
     }
 
+    /**
+     * Any property javadoc should go onto the field, and will be copied where appropriate,
+     * including getters, constructor parameters, builder setters, etc.
+     *
+     * <p>
+     * This allows to avoid the burden of maintaining copies of the same documentation
+     * pieces in multiple places for each field.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setNum(int value) {
+        mNum = value;
+        return this;
+    }
+
+    /**
+     * Various javadoc features should work as expected when copied, e.g {@code code},
+     * {@link #mName links}, <a href="https://google.com">html links</a>, etc.
+     *
+     * @see #mNum2 ..and so should blocks at the bottom, e.g. {@code @see} blocks.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setNum2(int value) {
+        mNum2 = value;
+        return this;
+    }
+
+    /**
+     * {@code @hide} javadoc annotation is also propagated, which can be used to adjust the
+     * desired public API surface.
+     *
+     * @see #getNum4() is hidden
+     * @see Builder#setNum4(int) also hidden
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setNum4(int value) {
+        mNum4 = value;
+        return this;
+    }
+
+    /**
+     * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setName(@Nullable String value) {
+        mName = value;
+        return this;
+    }
+
+    /**
+     * Fields with default value expressions ("mFoo = ...") are optional, and are automatically
+     * initialized to the provided default expression, unless explicitly set.
+     *
+     * When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter}
+     * while mandatory fields are passed via {@link Builder#Builder constructor}.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setName2(@NonNull String value) {
+        mName2 = value;
+        AnnotationValidations.validate(
+                NonNull.class, null, mName2);
+        return this;
+    }
+
+    /**
+     * Alternatively, when default value computation is expensive,
+     * {@link #defaultName4 defaultFieldName()} can be defined to compute the default value.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setName4(@NonNull String value) {
+        mName4 = value;
+        AnnotationValidations.validate(
+                NonNull.class, null, mName4);
+        return this;
+    }
+
+    /**
+     * For parcelling, any field type supported by {@link Parcel} is supported out of the box.
+     * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setOtherParcelable(@Nullable AccessibilityNodeInfo value) {
+        mOtherParcelable = value;
+        return this;
+    }
+
+    /**
+     * Additionally, support for parcelling other types can be added by implementing a
+     * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation.
+     *
+     * @see MyDateParcelling an example {@link Parcelling} implementation
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setDate(@NonNull Date value) {
+        mDate = value;
+        AnnotationValidations.validate(
+                NonNull.class, null, mDate);
+        return this;
+    }
+
+    /**
+     * If a {@link Parcelling} is fairly common, consider putting it in {@link Parcelling.BuiltIn}
+     * to encourage its reuse.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setPattern(@NonNull Pattern value) {
+        mPattern = value;
+        AnnotationValidations.validate(
+                NonNull.class, null, mPattern);
+        return this;
+    }
+
+    /**
+     * For lists, when using a {@link Builder}, other than a regular
+     * {@link Builder#setLinkAddresses2(List) setter}, and additional
+     * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setLinkAddresses2(@NonNull List<LinkAddress> value) {
+        mLinkAddresses2 = value;
+        AnnotationValidations.validate(
+                NonNull.class, null, mLinkAddresses2);
+        return this;
+    }
+
+    /**
+     * For aesthetics, you may want to consider providing a singular version of the plural field
+     * name, which would be used for the {@link #mLinkAddresses2 above mentioned} "add" method.
+     *
+     * @see Builder#addLinkAddress(LinkAddress)
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setLinkAddresses(@NonNull ArrayList<LinkAddress> value) {
+        mLinkAddresses = value;
+        AnnotationValidations.validate(
+                NonNull.class, null, mLinkAddresses);
+        return this;
+    }
+
+    /**
+     * For array fields, when using a {@link Builder}, vararg argument format is used for
+     * convenience.
+     *
+     * @see Builder#setLinkAddresses4(LinkAddress...)
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setLinkAddresses4(@Nullable LinkAddress... value) {
+        mLinkAddresses4 = value;
+        return this;
+    }
+
+    /**
+     * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to
+     * getter/constructor/setter/builder parameters, making for a nicer api.
+     *
+     * @see #getStateName
+     * @see Builder#setStateName
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setStateName(@StateName @NonNull String value) {
+        mStateName = value;
+
+        if (!(Objects.equals(mStateName, STATE_NAME_UNDEFINED))
+                && !(Objects.equals(mStateName, STATE_NAME_ON))
+                && !(Objects.equals(mStateName, STATE_NAME_OFF))) {
+            throw new java.lang.IllegalArgumentException(
+                    "stateName was " + mStateName + " but must be one of: "
+                            + "STATE_NAME_UNDEFINED(" + STATE_NAME_UNDEFINED + "), "
+                            + "STATE_NAME_ON(" + STATE_NAME_ON + "), "
+                            + "STATE_NAME_OFF(" + STATE_NAME_OFF + ")");
+        }
+
+        AnnotationValidations.validate(
+                NonNull.class, null, mStateName);
+        return this;
+    }
+
+    /**
+     * Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setFlags(@RequestFlags int value) {
+        mFlags = value;
+
+        Preconditions.checkFlagsArgument(
+                mFlags,
+                FLAG_MANUAL_REQUEST
+                        | FLAG_COMPATIBILITY_MODE_REQUEST
+                        | FLAG_AUGMENTED_REQUEST);
+        return this;
+    }
+
+    /**
+     * Above is true for both {@link IntDef#flag flags} and enum-like {@link IntDef}s
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setState(@State int value) {
+        mState = value;
+
+        if (!(mState == STATE_UNDEFINED)
+                && !(mState == STATE_ON)
+                && !(mState == STATE_OFF)) {
+            throw new java.lang.IllegalArgumentException(
+                    "state was " + mState + " but must be one of: "
+                            + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), "
+                            + "STATE_ON(" + STATE_ON + "), "
+                            + "STATE_OFF(" + STATE_OFF + ")");
+        }
+
+        return this;
+    }
+
+    /**
+     * Fields with certain annotations are automatically validated in constructor
+     *
+     * You can see overloads in {@link AnnotationValidations} for a list of currently
+     * supported ones.
+     *
+     * You can also extend support to your custom annotations by creating another corresponding
+     * overloads like
+     * {@link AnnotationValidations#validate(Class, UserIdInt, int)}.
+     *
+     * @see #SampleDataClass
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setStringRes(@StringRes int value) {
+        mStringRes = value;
+        AnnotationValidations.validate(
+                StringRes.class, null, mStringRes);
+        return this;
+    }
+
+    /**
+     * Validation annotations may also have parameters.
+     *
+     * Parameter values will be supplied to validation method as name-value pairs.
+     *
+     * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int)
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setDayOfWeek(@android.annotation.IntRange(from = 0, to = 6) int value) {
+        mDayOfWeek = value;
+        AnnotationValidations.validate(
+                android.annotation.IntRange.class, null, mDayOfWeek,
+                "from", 0,
+                "to", 6);
+        return this;
+    }
+
+    /**
+     * Unnamed validation annotation parameter gets supplied to the validating method named as
+     * "value".
+     *
+     * Validation annotations following {@link Each} annotation, will be applied for each
+     * array/collection element instead.
+     *
+     * @see AnnotationValidations#validate(Class, Size, int, String, int)
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass setCoords(@Size(2) @NonNull @Each @FloatRange(from = 0f) float... value) {
+        mCoords = value;
+        AnnotationValidations.validate(
+                Size.class, null, mCoords.length,
+                "value", 2);
+        AnnotationValidations.validate(
+                NonNull.class, null, mCoords);
+        int coordsSize = mCoords.length;
+        for (int i = 0; i < coordsSize; i++) {
+            AnnotationValidations.validate(
+                    FloatRange.class, null, mCoords[i],
+                    "from", 0f);
+        }
+
+        return this;
+    }
+
     @Override
     @DataClass.Generated.Member
     public String toString() {
@@ -829,14 +1102,13 @@
                 "linkAddresses2 = " + mLinkAddresses2 + ", " +
                 "linkAddresses = " + mLinkAddresses + ", " +
                 "linkAddresses4 = " + java.util.Arrays.toString(mLinkAddresses4) + ", " +
-                "active = " + mActive + ", " +
                 "stateName = " + mStateName + ", " +
                 "flags = " + requestFlagsToString(mFlags) + ", " +
                 "state = " + stateToString(mState) + ", " +
                 "charSeq = " + charSeq + ", " +
                 "linkAddresses5 = " + java.util.Arrays.toString(mLinkAddresses5) + ", " +
                 "stringRes = " + mStringRes + ", " +
-                "limited = " + mLimited + ", " +
+                "dayOfWeek = " + mDayOfWeek + ", " +
                 "coords = " + java.util.Arrays.toString(mCoords) +
         " }";
     }
@@ -866,14 +1138,13 @@
                 && Objects.equals(mLinkAddresses2, that.mLinkAddresses2)
                 && Objects.equals(mLinkAddresses, that.mLinkAddresses)
                 && java.util.Arrays.equals(mLinkAddresses4, that.mLinkAddresses4)
-                && mActive == that.mActive
                 && Objects.equals(mStateName, that.mStateName)
                 && mFlags == that.mFlags
                 && mState == that.mState
                 && Objects.equals(charSeq, that.charSeq)
                 && java.util.Arrays.equals(mLinkAddresses5, that.mLinkAddresses5)
                 && mStringRes == that.mStringRes
-                && mLimited == that.mLimited
+                && mDayOfWeek == that.mDayOfWeek
                 && java.util.Arrays.equals(mCoords, that.mCoords);
     }
 
@@ -896,14 +1167,13 @@
         _hash = 31 * _hash + Objects.hashCode(mLinkAddresses2);
         _hash = 31 * _hash + Objects.hashCode(mLinkAddresses);
         _hash = 31 * _hash + java.util.Arrays.hashCode(mLinkAddresses4);
-        _hash = 31 * _hash + Boolean.hashCode(mActive);
         _hash = 31 * _hash + Objects.hashCode(mStateName);
         _hash = 31 * _hash + mFlags;
         _hash = 31 * _hash + mState;
         _hash = 31 * _hash + Objects.hashCode(charSeq);
         _hash = 31 * _hash + java.util.Arrays.hashCode(mLinkAddresses5);
         _hash = 31 * _hash + mStringRes;
-        _hash = 31 * _hash + mLimited;
+        _hash = 31 * _hash + mDayOfWeek;
         _hash = 31 * _hash + java.util.Arrays.hashCode(mCoords);
         return _hash;
     }
@@ -924,14 +1194,13 @@
         actionObject.acceptObject(this, "linkAddresses2", mLinkAddresses2);
         actionObject.acceptObject(this, "linkAddresses", mLinkAddresses);
         actionObject.acceptObject(this, "linkAddresses4", mLinkAddresses4);
-        actionObject.acceptObject(this, "active", mActive);
         actionObject.acceptObject(this, "stateName", mStateName);
         actionInt.acceptInt(this, "flags", mFlags);
         actionInt.acceptInt(this, "state", mState);
         actionObject.acceptObject(this, "charSeq", charSeq);
         actionObject.acceptObject(this, "linkAddresses5", mLinkAddresses5);
         actionInt.acceptInt(this, "stringRes", mStringRes);
-        actionInt.acceptInt(this, "limited", mLimited);
+        actionInt.acceptInt(this, "dayOfWeek", mDayOfWeek);
         actionObject.acceptObject(this, "coords", mCoords);
     }
 
@@ -951,25 +1220,24 @@
         action.acceptObject(this, "linkAddresses2", mLinkAddresses2);
         action.acceptObject(this, "linkAddresses", mLinkAddresses);
         action.acceptObject(this, "linkAddresses4", mLinkAddresses4);
-        action.acceptObject(this, "active", mActive);
         action.acceptObject(this, "stateName", mStateName);
         action.acceptObject(this, "flags", mFlags);
         action.acceptObject(this, "state", mState);
         action.acceptObject(this, "charSeq", charSeq);
         action.acceptObject(this, "linkAddresses5", mLinkAddresses5);
         action.acceptObject(this, "stringRes", mStringRes);
-        action.acceptObject(this, "limited", mLimited);
+        action.acceptObject(this, "dayOfWeek", mDayOfWeek);
         action.acceptObject(this, "coords", mCoords);
     }
 
     @DataClass.Generated.Member
     static Parcelling<Date> sParcellingForDate =
             Parcelling.Cache.get(
-                    DateParcelling.class);
+                    MyDateParcelling.class);
     static {
         if (sParcellingForDate == null) {
             sParcellingForDate = Parcelling.Cache.put(
-                    new DateParcelling());
+                    new MyDateParcelling());
         }
     }
 
@@ -991,40 +1259,31 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         long flg = 0;
-        if (mActive) flg |= 0x1000;
         if (mName != null) flg |= 0x8;
-        if (mName2 != null) flg |= 0x10;
         if (mOtherParcelable != null) flg |= 0x40;
-        if (mDate != null) flg |= 0x80;
-        if (mPattern != null) flg |= 0x100;
-        if (mLinkAddresses2 != null) flg |= 0x200;
-        if (mLinkAddresses != null) flg |= 0x400;
         if (mLinkAddresses4 != null) flg |= 0x800;
-        if (mStateName != null) flg |= 0x2000;
-        if (charSeq != null) flg |= 0x10000;
-        if (mLinkAddresses5 != null) flg |= 0x20000;
-        if (mCoords != null) flg |= 0x100000;
+        if (mLinkAddresses5 != null) flg |= 0x10000;
         dest.writeLong(flg);
         dest.writeInt(mNum);
         dest.writeInt(mNum2);
         dest.writeInt(mNum4);
         if (mName != null) dest.writeString(mName);
-        if (mName2 != null) dest.writeString(mName2);
+        dest.writeString(mName2);
         dest.writeString(mName4);
         if (mOtherParcelable != null) dest.writeTypedObject(mOtherParcelable, flags);
         sParcellingForDate.parcel(mDate, dest, flags);
         sParcellingForPattern.parcel(mPattern, dest, flags);
-        if (mLinkAddresses2 != null) dest.writeParcelableList(mLinkAddresses2, flags);
-        if (mLinkAddresses != null) dest.writeParcelableList(mLinkAddresses, flags);
+        dest.writeParcelableList(mLinkAddresses2, flags);
+        dest.writeParcelableList(mLinkAddresses, flags);
         if (mLinkAddresses4 != null) dest.writeTypedArray(mLinkAddresses4, flags);
-        if (mStateName != null) dest.writeString(mStateName);
+        dest.writeString(mStateName);
         dest.writeInt(mFlags);
         dest.writeInt(mState);
-        if (charSeq != null) dest.writeCharSequence(charSeq);
+        dest.writeCharSequence(charSeq);
         if (mLinkAddresses5 != null) dest.writeTypedArray(mLinkAddresses5, flags);
         dest.writeInt(mStringRes);
-        dest.writeInt(mLimited);
-        if (mCoords != null) dest.writeFloatArray(mCoords);
+        dest.writeInt(mDayOfWeek);
+        dest.writeFloatArray(mCoords);
     }
 
     @Override
@@ -1046,35 +1305,28 @@
             // static FieldType unparcelFieldName(Parcel in) { ... }
 
             long flg = in.readLong();
-            boolean active = (flg & 0x1000) != 0;
             int num = in.readInt();
             int num2 = in.readInt();
             int num4 = in.readInt();
             String name = (flg & 0x8) == 0 ? null : in.readString();
-            String name2 = (flg & 0x10) == 0 ? null : in.readString();
+            String name2 = in.readString();
             String name4 = in.readString();
             AccessibilityNodeInfo otherParcelable = (flg & 0x40) == 0 ? null : (AccessibilityNodeInfo) in.readTypedObject(AccessibilityNodeInfo.CREATOR);
             Date date = sParcellingForDate.unparcel(in);
             Pattern pattern = sParcellingForPattern.unparcel(in);
-            List<LinkAddress> linkAddresses2 = null;
-            if ((flg & 0x200) != 0) {
-                linkAddresses2 = new ArrayList<>();
-                in.readParcelableList(linkAddresses2, LinkAddress.class.getClassLoader());
-            }
-            ArrayList<LinkAddress> linkAddresses = null;
-            if ((flg & 0x400) != 0) {
-                linkAddresses = new ArrayList<>();
-                in.readParcelableList(linkAddresses, LinkAddress.class.getClassLoader());
-            }
+            List<LinkAddress> linkAddresses2 = new ArrayList<>();
+            in.readParcelableList(linkAddresses2, LinkAddress.class.getClassLoader());
+            ArrayList<LinkAddress> linkAddresses = new ArrayList<>();
+            in.readParcelableList(linkAddresses, LinkAddress.class.getClassLoader());
             LinkAddress[] linkAddresses4 = (flg & 0x800) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR);
-            String stateName = (flg & 0x2000) == 0 ? null : in.readString();
+            String stateName = in.readString();
             int flags = in.readInt();
             int state = in.readInt();
-            CharSequence _charSeq = (flg & 0x10000) == 0 ? null : (CharSequence) in.readCharSequence();
-            LinkAddress[] linkAddresses5 = (flg & 0x20000) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR);
+            CharSequence _charSeq = (CharSequence) in.readCharSequence();
+            LinkAddress[] linkAddresses5 = (flg & 0x10000) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR);
             int stringRes = in.readInt();
-            int limited = in.readInt();
-            float[] coords = (flg & 0x100000) == 0 ? null : in.createFloatArray();
+            int dayOfWeek = in.readInt();
+            float[] coords = in.createFloatArray();
             return new SampleDataClass(
                     num,
                     num2,
@@ -1088,14 +1340,13 @@
                     linkAddresses2,
                     linkAddresses,
                     linkAddresses4,
-                    active,
                     stateName,
                     flags,
                     state,
                     _charSeq,
                     linkAddresses5,
                     stringRes,
-                    limited,
+                    dayOfWeek,
                     coords);
         }
     };
@@ -1105,34 +1356,74 @@
      */
     @SuppressWarnings("WeakerAccess")
     @DataClass.Generated.Member
-    public static class Builder
-            extends android.provider.OneTimeUseBuilder<SampleDataClass> {
+    public static class Builder {
 
-        protected int mNum;
-        protected int mNum2;
-        protected int mNum4;
-        protected @Nullable String mName;
-        protected String mName2;
-        protected @NonNull String mName4;
-        protected AccessibilityNodeInfo mOtherParcelable;
-        protected Date mDate;
-        protected Pattern mPattern;
-        protected List<LinkAddress> mLinkAddresses2;
-        protected ArrayList<LinkAddress> mLinkAddresses;
-        protected @Nullable LinkAddress[] mLinkAddresses4;
-        protected boolean mActive;
-        protected @StateName String mStateName;
-        protected @RequestFlags int mFlags;
-        protected @State int mState;
-        protected CharSequence charSeq;
-        protected LinkAddress[] mLinkAddresses5;
-        protected @StringRes int mStringRes;
-        protected @android.annotation.IntRange(from = 0, to = 4) int mLimited;
-        protected @Size(2) @FloatRange(from = 0f) float[] mCoords;
+        private int mNum;
+        private int mNum2;
+        private int mNum4;
+        private @Nullable String mName;
+        private @NonNull String mName2;
+        private @NonNull String mName4;
+        private @Nullable AccessibilityNodeInfo mOtherParcelable;
+        private @NonNull Date mDate;
+        private @NonNull Pattern mPattern;
+        private @NonNull List<LinkAddress> mLinkAddresses2;
+        private @NonNull ArrayList<LinkAddress> mLinkAddresses;
+        private @Nullable LinkAddress[] mLinkAddresses4;
+        private @StateName @NonNull String mStateName;
+        private @RequestFlags int mFlags;
+        private @State int mState;
+        private @NonNull CharSequence charSeq;
+        private @Nullable LinkAddress[] mLinkAddresses5;
+        private @StringRes int mStringRes;
+        private @android.annotation.IntRange(from = 0, to = 6) int mDayOfWeek;
+        private @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] mCoords;
 
-        protected long mBuilderFieldsSet = 0L;
+        private long mBuilderFieldsSet = 0L;
 
-        public Builder() {};
+        /**
+         * Creates a new Builder.
+         *
+         * @param num
+         *   Any property javadoc should go onto the field, and will be copied where appropriate,
+         *   including getters, constructor parameters, builder setters, etc.
+         *
+         *   <p>
+         *   This allows to avoid the burden of maintaining copies of the same documentation
+         *   pieces in multiple places for each field.
+         * @param num2
+         *   Various javadoc features should work as expected when copied, e.g {@code code},
+         *   {@link #mName links}, <a href="https://google.com">html links</a>, etc.
+         * @param num4
+         *   {@code @hide} javadoc annotation is also propagated, which can be used to adjust the
+         *   desired public API surface.
+         * @param name
+         *   {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
+         * @param flags
+         *   Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value.
+         * @param linkAddresses5
+         *   Final fields suppress generating a setter (when setters are requested).
+         */
+        public Builder(
+                int num,
+                int num2,
+                int num4,
+                @Nullable String name,
+                @RequestFlags int flags,
+                @Nullable LinkAddress[] linkAddresses5) {
+            mNum = num;
+            mNum2 = num2;
+            mNum4 = num4;
+            mName = name;
+            mFlags = flags;
+
+            Preconditions.checkFlagsArgument(
+                    mFlags,
+                    FLAG_MANUAL_REQUEST
+                            | FLAG_COMPATIBILITY_MODE_REQUEST
+                            | FLAG_AUGMENTED_REQUEST);
+            mLinkAddresses5 = linkAddresses5;
+        }
 
         /**
          * Any property javadoc should go onto the field, and will be copied where appropriate,
@@ -1143,7 +1434,7 @@
          * pieces in multiple places for each field.
          */
         @DataClass.Generated.Member
-        public Builder setNum(int value) {
+        public @NonNull Builder setNum(int value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x1;
             mNum = value;
@@ -1157,7 +1448,7 @@
          * @see #mNum2 ..and so should blocks at the bottom, e.g. {@code @see} blocks.
          */
         @DataClass.Generated.Member
-        public Builder setNum2(int value) {
+        public @NonNull Builder setNum2(int value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x2;
             mNum2 = value;
@@ -1173,7 +1464,7 @@
          * @hide
          */
         @DataClass.Generated.Member
-        public Builder setNum4(int value) {
+        public @NonNull Builder setNum4(int value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x4;
             mNum4 = value;
@@ -1181,11 +1472,10 @@
         }
 
         /**
-         * {@link Nullable} fields are considered optional and will not throw an exception if omitted
-         * (or set to null) when creating an instance either via a {@link Builder} or constructor.
+         * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
          */
         @DataClass.Generated.Member
-        public Builder setName(@Nullable String value) {
+        public @NonNull Builder setName(@Nullable String value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x8;
             mName = value;
@@ -1193,11 +1483,14 @@
         }
 
         /**
-         * Fields with default value expressions ("mFoo = ...") are also optional, and are automatically
+         * Fields with default value expressions ("mFoo = ...") are optional, and are automatically
          * initialized to the provided default expression, unless explicitly set.
+         *
+         * When using a {@link Builder} optional fields are passed via a {@link Builder#setName2 setter}
+         * while mandatory fields are passed via {@link Builder#Builder constructor}.
          */
         @DataClass.Generated.Member
-        public Builder setName2(String value) {
+        public @NonNull Builder setName2(@NonNull String value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x10;
             mName2 = value;
@@ -1205,12 +1498,11 @@
         }
 
         /**
-         * Fields without {@link Nullable} annotation or default value are considered required.
-         *
-         * {@link NonNull} annotation is recommended on such non-primitive fields for documentation.
+         * Alternatively, when default value computation is expensive,
+         * {@link #defaultName4 defaultFieldName()} can be defined to compute the default value.
          */
         @DataClass.Generated.Member
-        public Builder setName4(@NonNull String value) {
+        public @NonNull Builder setName4(@NonNull String value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x20;
             mName4 = value;
@@ -1222,7 +1514,7 @@
          * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
          */
         @DataClass.Generated.Member
-        public Builder setOtherParcelable(AccessibilityNodeInfo value) {
+        public @NonNull Builder setOtherParcelable(@Nullable AccessibilityNodeInfo value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x40;
             mOtherParcelable = value;
@@ -1233,10 +1525,10 @@
          * Additionally, support for parcelling other types can be added by implementing a
          * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation.
          *
-         * @see DateParcelling an example {@link Parcelling} implementation
+         * @see MyDateParcelling an example {@link Parcelling} implementation
          */
         @DataClass.Generated.Member
-        public Builder setDate(Date value) {
+        public @NonNull Builder setDate(@NonNull Date value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x80;
             mDate = value;
@@ -1248,7 +1540,7 @@
          * to encourage its reuse.
          */
         @DataClass.Generated.Member
-        public Builder setPattern(Pattern value) {
+        public @NonNull Builder setPattern(@NonNull Pattern value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x100;
             mPattern = value;
@@ -1261,7 +1553,7 @@
          * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience.
          */
         @DataClass.Generated.Member
-        public Builder setLinkAddresses2(List<LinkAddress> value) {
+        public @NonNull Builder setLinkAddresses2(@NonNull List<LinkAddress> value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x200;
             mLinkAddresses2 = value;
@@ -1270,7 +1562,7 @@
 
         /** @see #setLinkAddresses2 */
         @DataClass.Generated.Member
-        public Builder addLinkAddresses2(@NonNull LinkAddress value) {
+        public @NonNull Builder addLinkAddresses2(LinkAddress value) {
             // You can refine this method's name by providing item's singular name, e.g.:
             // @DataClass.PluralOf("item")) mItems = ...
 
@@ -1286,7 +1578,7 @@
          * @see Builder#addLinkAddress(LinkAddress)
          */
         @DataClass.Generated.Member
-        public Builder setLinkAddresses(ArrayList<LinkAddress> value) {
+        public @NonNull Builder setLinkAddresses(@NonNull ArrayList<LinkAddress> value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x400;
             mLinkAddresses = value;
@@ -1295,7 +1587,7 @@
 
         /** @see #setLinkAddresses */
         @DataClass.Generated.Member
-        public Builder addLinkAddress(@NonNull LinkAddress value) {
+        public @NonNull Builder addLinkAddress(LinkAddress value) {
             if (mLinkAddresses == null) setLinkAddresses(new ArrayList<>());
             mLinkAddresses.add(value);
             return this;
@@ -1308,7 +1600,7 @@
          * @see Builder#setLinkAddresses4(LinkAddress...)
          */
         @DataClass.Generated.Member
-        public Builder setLinkAddresses4(@Nullable LinkAddress... value) {
+        public @NonNull Builder setLinkAddresses4(@Nullable LinkAddress... value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x800;
             mLinkAddresses4 = value;
@@ -1316,30 +1608,6 @@
         }
 
         /**
-         * For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods
-         * like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated.
-         */
-        @DataClass.Generated.Member
-        public Builder setActive(boolean value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x1000;
-            mActive = value;
-            return this;
-        }
-
-        /** @see #setActive */
-        @DataClass.Generated.Member
-        public Builder markActive() {
-            return setActive(true);
-        }
-
-        /** @see #setActive */
-        @DataClass.Generated.Member
-        public Builder markNotActive() {
-            return setActive(false);
-        }
-
-        /**
          * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to
          * getter/constructor/setter/builder parameters, making for a nicer api.
          *
@@ -1347,9 +1615,9 @@
          * @see Builder#setStateName
          */
         @DataClass.Generated.Member
-        public Builder setStateName(@StateName String value) {
+        public @NonNull Builder setStateName(@StateName @NonNull String value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x2000;
+            mBuilderFieldsSet |= 0x1000;
             mStateName = value;
             return this;
         }
@@ -1358,9 +1626,9 @@
          * Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value.
          */
         @DataClass.Generated.Member
-        public Builder setFlags(@RequestFlags int value) {
+        public @NonNull Builder setFlags(@RequestFlags int value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x4000;
+            mBuilderFieldsSet |= 0x2000;
             mFlags = value;
             return this;
         }
@@ -1369,9 +1637,9 @@
          * Above is true for both {@link IntDef#flag flags} and enum-like {@link IntDef}s
          */
         @DataClass.Generated.Member
-        public Builder setState(@State int value) {
+        public @NonNull Builder setState(@State int value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x8000;
+            mBuilderFieldsSet |= 0x4000;
             mState = value;
             return this;
         }
@@ -1380,9 +1648,9 @@
          * Making a field public will suppress getter generation in favor of accessing it directly.
          */
         @DataClass.Generated.Member
-        public Builder setCharSeq(CharSequence value) {
+        public @NonNull Builder setCharSeq(@NonNull CharSequence value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x10000;
+            mBuilderFieldsSet |= 0x8000;
             charSeq = value;
             return this;
         }
@@ -1391,9 +1659,9 @@
          * Final fields suppress generating a setter (when setters are requested).
          */
         @DataClass.Generated.Member
-        public Builder setLinkAddresses5(LinkAddress... value) {
+        public @NonNull Builder setLinkAddresses5(@Nullable LinkAddress... value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x20000;
+            mBuilderFieldsSet |= 0x10000;
             mLinkAddresses5 = value;
             return this;
         }
@@ -1411,9 +1679,9 @@
          * @see #SampleDataClass
          */
         @DataClass.Generated.Member
-        public Builder setStringRes(@StringRes int value) {
+        public @NonNull Builder setStringRes(@StringRes int value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x40000;
+            mBuilderFieldsSet |= 0x20000;
             mStringRes = value;
             return this;
         }
@@ -1426,10 +1694,10 @@
          * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int)
          */
         @DataClass.Generated.Member
-        public Builder setLimited(@android.annotation.IntRange(from = 0, to = 4) int value) {
+        public @NonNull Builder setDayOfWeek(@android.annotation.IntRange(from = 0, to = 6) int value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x80000;
-            mLimited = value;
+            mBuilderFieldsSet |= 0x40000;
+            mDayOfWeek = value;
             return this;
         }
 
@@ -1443,30 +1711,23 @@
          * @see AnnotationValidations#validate(Class, Size, int, String, int)
          */
         @DataClass.Generated.Member
-        public Builder setCoords(@Size(2) @FloatRange(from = 0f) float... value) {
+        public @NonNull Builder setCoords(@Size(2) @NonNull @Each @FloatRange(from = 0f) float... value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x100000;
+            mBuilderFieldsSet |= 0x80000;
             mCoords = value;
             return this;
         }
 
         /** Builds the instance. This builder should not be touched after calling this! */
         public SampleDataClass build() {
-            markUsed();
-            if ((mBuilderFieldsSet & 0x1) == 0) {
-                throw new IllegalStateException("Required field not set: num");
-            }
-            if ((mBuilderFieldsSet & 0x2) == 0) {
-                throw new IllegalStateException("Required field not set: num2");
-            }
-            if ((mBuilderFieldsSet & 0x4) == 0) {
-                throw new IllegalStateException("Required field not set: num4");
-            }
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x100000; // Mark builder used
+
             if ((mBuilderFieldsSet & 0x10) == 0) {
                 mName2 = "Bob";
             }
             if ((mBuilderFieldsSet & 0x20) == 0) {
-                throw new IllegalStateException("Required field not set: name4");
+                mName4 = defaultName4();
             }
             if ((mBuilderFieldsSet & 0x40) == 0) {
                 mOtherParcelable = null;
@@ -1487,30 +1748,21 @@
                 mLinkAddresses4 = null;
             }
             if ((mBuilderFieldsSet & 0x1000) == 0) {
-                mActive = true;
-            }
-            if ((mBuilderFieldsSet & 0x2000) == 0) {
                 mStateName = STATE_NAME_UNDEFINED;
             }
             if ((mBuilderFieldsSet & 0x4000) == 0) {
-                throw new IllegalStateException("Required field not set: flags");
-            }
-            if ((mBuilderFieldsSet & 0x8000) == 0) {
                 mState = STATE_UNDEFINED;
             }
-            if ((mBuilderFieldsSet & 0x10000) == 0) {
+            if ((mBuilderFieldsSet & 0x8000) == 0) {
                 charSeq = "";
             }
             if ((mBuilderFieldsSet & 0x20000) == 0) {
-                throw new IllegalStateException("Required field not set: linkAddresses5");
-            }
-            if ((mBuilderFieldsSet & 0x40000) == 0) {
                 mStringRes = 0;
             }
-            if ((mBuilderFieldsSet & 0x80000) == 0) {
-                mLimited = 3;
+            if ((mBuilderFieldsSet & 0x40000) == 0) {
+                mDayOfWeek = 3;
             }
-            if ((mBuilderFieldsSet & 0x100000) == 0) {
+            if ((mBuilderFieldsSet & 0x80000) == 0) {
                 mCoords = new float[] { 0f, 0f };
             }
             SampleDataClass o = new SampleDataClass(
@@ -1526,17 +1778,31 @@
                     mLinkAddresses2,
                     mLinkAddresses,
                     mLinkAddresses4,
-                    mActive,
                     mStateName,
                     mFlags,
                     mState,
                     charSeq,
                     mLinkAddresses5,
                     mStringRes,
-                    mLimited,
+                    mDayOfWeek,
                     mCoords);
             return o;
         }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x100000) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
     }
 
+    @DataClass.Generated(
+            time = 1565126122525L,
+            codegenVersion = "1.0.0",
+            sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
+            inputSignatures = "public static final  java.lang.String STATE_NAME_UNDEFINED\npublic static final  java.lang.String STATE_NAME_ON\npublic static final  java.lang.String STATE_NAME_OFF\npublic static final  int STATE_UNDEFINED\npublic static final  int STATE_ON\npublic static final  int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate  int mNum\nprivate  int mNum2\nprivate  int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient  android.net.LinkAddress[] mLinkAddresses6\ntransient  int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static  java.lang.String defaultName4()\nprivate  int[] lazyInitTmpStorage()\npublic  android.net.LinkAddress[] getLinkAddresses4()\nprivate  boolean patternEquals(java.util.regex.Pattern)\nprivate  int patternHashCode()\nprivate  void onConstructed()\npublic  void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
+    @Deprecated
+    private void __metadata() {}
+
 }
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java b/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java
index 71e85ab..6636207 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java
@@ -49,7 +49,7 @@
     private SampleDataClass mSpecimen = newBuilder().build();
 
     private static SampleDataClass.Builder newBuilder() {
-        return newIncompleteBuilder()
+        return newInvalidBuilder()
                 .setNum(42)
                 .setNum2(42)
                 .setNum4(42)
@@ -57,9 +57,8 @@
                 .setLinkAddresses5();
     }
 
-    private static SampleDataClass.Builder newIncompleteBuilder() {
-        return new SampleDataClass.Builder()
-                .markActive()
+    private static SampleDataClass.Builder newInvalidBuilder() {
+        return new SampleDataClass.Builder(1, 2, 3, "a", 0, null)
                 .setName("some parcelable")
                 .setFlags(SampleDataClass.FLAG_MANUAL_REQUEST);
     }
@@ -91,7 +90,7 @@
     public void testCustomParcelling_instanceIsCached() {
         parcelAndUnparcel(mSpecimen, SampleDataClass.CREATOR);
         parcelAndUnparcel(mSpecimen, SampleDataClass.CREATOR);
-        assertEquals(1, DateParcelling.sInstanceCount.get());
+        assertEquals(1, MyDateParcelling.sInstanceCount.get());
     }
 
     @Test
@@ -149,8 +148,8 @@
     }
 
     @Test(expected = IllegalStateException.class)
-    public void testBuilder_throwsWhenRequiredFieldMissing() {
-        newIncompleteBuilder().build();
+    public void testBuilder_performsValidation() {
+        newInvalidBuilder().build();
     }
 
     @Test
@@ -205,6 +204,11 @@
         assertSame(tmpStorage, tmpStorageAgain);
     }
 
+    @Test(expected = IllegalStateException.class)
+    public void testCustomAnnotationValidation_isRun() {
+        newBuilder().setDayOfWeek(42).build();
+    }
+
     private static <T extends Parcelable> T parcelAndUnparcel(
             T original, Parcelable.Creator<T> creator) {
         Parcel p = Parcel.obtain();
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
new file mode 100644
index 0000000..11f03a7
--- /dev/null
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
@@ -0,0 +1,186 @@
+/*
+ * 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.codegentest;
+
+import android.annotation.NonNull;
+import android.os.SystemClock;
+
+import com.android.internal.util.DataClass;
+
+import java.util.concurrent.TimeUnit;
+
+@DataClass(genBuilder = true)
+public class SampleWithCustomBuilder {
+
+    long delayAmount = 0;
+    @NonNull
+    TimeUnit delayUnit = TimeUnit.MILLISECONDS;
+
+    long creationTimestamp = SystemClock.uptimeMillis();
+
+    /**
+     * You can declare a class named {@code BaseBuilder} to have the generated builder extend from
+     * it instead.
+     *
+     * Same rules apply where defining a non-abstract method will suppress the generation of a
+     * method with the same signature.
+     *
+     * For abstract generatable methods, implementations are generated as normal, but original
+     * visibility is used, allowing you to hide methods.
+     *
+     * Here for example, we hide {@link #setDelayUnit} and {@link #setDelayAmount} from public API,
+     * replacing it with {@link #setDelay} instead.
+     */
+    // Suppress setter generation for a field that is not supposed to come from user input.
+    @DataClass.Suppress("setCreationTimestamp")
+    static abstract class BaseBuilder {
+
+        /**
+         * Hide methods by declaring them with reduced (package-private) visibility.
+         */
+        abstract Builder setDelayAmount(long value);
+
+        /**
+         * Alternatively, hide methods by using @hide, to hide them from public API only.
+         *
+         * @hide
+         */
+        public abstract Builder setDelayUnit(TimeUnit value);
+
+        /**
+         * Can provide additional method on the builder, e.g. as a replacement for the ones we've
+         * just hidden.
+         */
+        public Builder setDelay(long amount, TimeUnit unit) {
+            setDelayAmount(amount);
+            setDelayUnit(unit);
+            return (Builder) this;
+        }
+    }
+
+
+
+    // Code below generated by codegen v1.0.0.
+    //
+    // DO NOT MODIFY!
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
+    //
+    // CHECKSTYLE:OFF Generated code
+
+    @DataClass.Generated.Member
+    /* package-private */ SampleWithCustomBuilder(
+            long delayAmount,
+            @NonNull TimeUnit delayUnit,
+            long creationTimestamp) {
+        this.delayAmount = delayAmount;
+        this.delayUnit = delayUnit;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, delayUnit);
+        this.creationTimestamp = creationTimestamp;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public long getDelayAmount() {
+        return delayAmount;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull TimeUnit getDelayUnit() {
+        return delayUnit;
+    }
+
+    @DataClass.Generated.Member
+    public long getCreationTimestamp() {
+        return creationTimestamp;
+    }
+
+    /**
+     * A builder for {@link SampleWithCustomBuilder}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static class Builder extends BaseBuilder {
+
+        private long delayAmount;
+        private @NonNull TimeUnit delayUnit;
+        private long creationTimestamp;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder() {
+        }
+
+        @DataClass.Generated.Member
+        @Override
+        @NonNull Builder setDelayAmount(long value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            delayAmount = value;
+            return this;
+        }
+
+        @DataClass.Generated.Member
+        @Override
+        public @NonNull Builder setDelayUnit(@NonNull TimeUnit value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            delayUnit = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public SampleWithCustomBuilder build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x1) == 0) {
+                delayAmount = 0;
+            }
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                delayUnit = TimeUnit.MILLISECONDS;
+            }
+            if ((mBuilderFieldsSet & 0x4) == 0) {
+                creationTimestamp = SystemClock.uptimeMillis();
+            }
+            SampleWithCustomBuilder o = new SampleWithCustomBuilder(
+                    delayAmount,
+                    delayUnit,
+                    creationTimestamp);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x8) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    @DataClass.Generated(
+            time = 1565126123496L,
+            codegenVersion = "1.0.0",
+            sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java",
+            inputSignatures = "  long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n  long creationTimestamp\nclass SampleWithCustomBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true)\nabstract  com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract  com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic  com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
+    @Deprecated
+    private void __metadata() {}
+
+}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index a27df47..2c0432a 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -154,15 +154,8 @@
             // TODO: Race condition between the timeout and when the broadcast is
             // received could lead to test flakiness.
             Intent broadcast = broadcastReceiver.poll(5, TimeUnit.SECONDS);
-            if (context.getUser().isSystem()) {
-                // Only system user should receive those broadcasts.
-                assertThat(broadcast).isNotNull();
-                assertThat(broadcastReceiver.poll(0, TimeUnit.SECONDS)).isNull();
-            } else {
-                // This is in case the test was running under a secondary user, in which case
-                // the broadcast won't be received here.
-                assertThat(broadcast).isNull();
-            }
+            assertThat(broadcast).isNotNull();
+            assertThat(broadcastReceiver.poll(0, TimeUnit.SECONDS)).isNull();
 
             // Verify the recent rollback has been recorded.
             RollbackInfo committed = getUniqueRollbackInfoForPackage(
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 5260b30..502aa97 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -56,6 +56,7 @@
         "androidx.test.rules",
         "FrameworksNetCommonTests",
         "frameworks-base-testutils",
+        "frameworks-net-integration-testutils",
         "framework-protos",
         "mockito-target-minus-junit4",
         "net-tests-utils",
diff --git a/tests/net/integration/Android.bp b/tests/net/integration/Android.bp
new file mode 100644
index 0000000..16a68d7
--- /dev/null
+++ b/tests/net/integration/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Utilities for testing framework code both in integration and unit tests.
+java_library {
+    name: "frameworks-net-integration-testutils",
+    srcs: ["util/**/*.java", "util/**/*.kt"],
+    static_libs: [
+        "androidx.annotation_annotation",
+        "androidx.test.rules",
+        "junit",
+        "net-tests-utils",
+    ],
+    libs: [
+        "services.core",
+        "services.net",
+    ],
+}
diff --git a/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt b/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt
new file mode 100644
index 0000000..fa2b99c
--- /dev/null
+++ b/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server
+
+import android.net.ConnectivityManager.TYPE_BLUETOOTH
+import android.net.ConnectivityManager.TYPE_ETHERNET
+import android.net.ConnectivityManager.TYPE_MOBILE
+import android.net.ConnectivityManager.TYPE_NONE
+import android.net.ConnectivityManager.TYPE_TEST
+import android.net.ConnectivityManager.TYPE_VPN
+import android.net.ConnectivityManager.TYPE_WIFI
+import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
+import android.net.NetworkCapabilities.TRANSPORT_TEST
+import android.net.NetworkCapabilities.TRANSPORT_VPN
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+
+fun transportToLegacyType(transport: Int) = when (transport) {
+    TRANSPORT_BLUETOOTH -> TYPE_BLUETOOTH
+    TRANSPORT_CELLULAR -> TYPE_MOBILE
+    TRANSPORT_ETHERNET -> TYPE_ETHERNET
+    TRANSPORT_TEST -> TYPE_TEST
+    TRANSPORT_VPN -> TYPE_VPN
+    TRANSPORT_WIFI -> TYPE_WIFI
+    else -> TYPE_NONE
+}
\ No newline at end of file
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
new file mode 100644
index 0000000..1e8d83c
--- /dev/null
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -0,0 +1,267 @@
+/*
+ * 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;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
+
+import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkAgent;
+import android.net.NetworkCapabilities;
+import android.net.NetworkFactory;
+import android.net.NetworkInfo;
+import android.net.NetworkMisc;
+import android.net.NetworkSpecifier;
+import android.net.SocketKeepalive;
+import android.net.UidRange;
+import android.os.ConditionVariable;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.util.Log;
+
+import com.android.server.connectivity.ConnectivityConstants;
+import com.android.testutils.HandlerUtilsKt;
+import com.android.testutils.TestableNetworkCallback;
+
+import java.util.Set;
+
+public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
+    private final NetworkInfo mNetworkInfo;
+    private final NetworkCapabilities mNetworkCapabilities;
+    private final HandlerThread mHandlerThread;
+    private final Context mContext;
+    private final String mLogTag;
+
+    private final ConditionVariable mDisconnected = new ConditionVariable();
+    private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
+    private int mScore;
+    private NetworkAgent mNetworkAgent;
+    private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
+    private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
+    private Integer mExpectedKeepaliveSlot = null;
+
+    public NetworkAgentWrapper(int transport, LinkProperties linkProperties, Context context)
+            throws Exception {
+        final int type = transportToLegacyType(transport);
+        final String typeName = ConnectivityManager.getNetworkTypeName(type);
+        mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
+        mNetworkCapabilities = new NetworkCapabilities();
+        mNetworkCapabilities.addTransportType(transport);
+        switch (transport) {
+            case TRANSPORT_ETHERNET:
+                mScore = 70;
+                break;
+            case TRANSPORT_WIFI:
+                mScore = 60;
+                break;
+            case TRANSPORT_CELLULAR:
+                mScore = 50;
+                break;
+            case TRANSPORT_WIFI_AWARE:
+                mScore = 20;
+                break;
+            case TRANSPORT_VPN:
+                mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
+                mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
+                break;
+            default:
+                throw new UnsupportedOperationException("unimplemented network type");
+        }
+        mContext = context;
+        mLogTag = "Mock-" + typeName;
+        mHandlerThread = new HandlerThread(mLogTag);
+        mHandlerThread.start();
+
+        mNetworkAgent = makeNetworkAgent(linkProperties);
+    }
+
+    protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties)
+            throws Exception {
+        return new InstrumentedNetworkAgent(this, linkProperties);
+    }
+
+    public static class InstrumentedNetworkAgent extends NetworkAgent {
+        private final NetworkAgentWrapper mWrapper;
+
+        public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp) {
+            super(wrapper.mHandlerThread.getLooper(), wrapper.mContext, wrapper.mLogTag,
+                    wrapper.mNetworkInfo, wrapper.mNetworkCapabilities, lp, wrapper.mScore,
+                    new NetworkMisc(), NetworkFactory.SerialNumber.NONE);
+            mWrapper = wrapper;
+        }
+
+        @Override
+        public void unwanted() {
+            mWrapper.mDisconnected.open();
+        }
+
+        @Override
+        public void startSocketKeepalive(Message msg) {
+            int slot = msg.arg1;
+            if (mWrapper.mExpectedKeepaliveSlot != null) {
+                assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot);
+            }
+            onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError);
+        }
+
+        @Override
+        public void stopSocketKeepalive(Message msg) {
+            onSocketKeepaliveEvent(msg.arg1, mWrapper.mStopKeepaliveError);
+        }
+
+        @Override
+        protected void preventAutomaticReconnect() {
+            mWrapper.mPreventReconnectReceived.open();
+        }
+
+        @Override
+        protected void addKeepalivePacketFilter(Message msg) {
+            Log.i(mWrapper.mLogTag, "Add keepalive packet filter.");
+        }
+
+        @Override
+        protected void removeKeepalivePacketFilter(Message msg) {
+            Log.i(mWrapper.mLogTag, "Remove keepalive packet filter.");
+        }
+    }
+
+    public void adjustScore(int change) {
+        mScore += change;
+        mNetworkAgent.sendNetworkScore(mScore);
+    }
+
+    public int getScore() {
+        return mScore;
+    }
+
+    public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
+        mNetworkAgent.explicitlySelected(explicitlySelected, acceptUnvalidated);
+    }
+
+    public void addCapability(int capability) {
+        mNetworkCapabilities.addCapability(capability);
+        mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+    }
+
+    public void removeCapability(int capability) {
+        mNetworkCapabilities.removeCapability(capability);
+        mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+    }
+
+    public void setUids(Set<UidRange> uids) {
+        mNetworkCapabilities.setUids(uids);
+        mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+    }
+
+    public void setSignalStrength(int signalStrength) {
+        mNetworkCapabilities.setSignalStrength(signalStrength);
+        mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+    }
+
+    public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
+        mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
+        mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+    }
+
+    public void setNetworkCapabilities(NetworkCapabilities nc, boolean sendToConnectivityService) {
+        mNetworkCapabilities.set(nc);
+        if (sendToConnectivityService) {
+            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+        }
+    }
+
+    public void connect() {
+        assertNotEquals("MockNetworkAgents can only be connected once",
+                getNetworkInfo().getDetailedState(), NetworkInfo.DetailedState.CONNECTED);
+        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
+        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+    }
+
+    public void suspend() {
+        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, null, null);
+        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+    }
+
+    public void resume() {
+        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
+        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+    }
+
+    public void disconnect() {
+        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
+        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+    }
+
+    @Override
+    public Network getNetwork() {
+        return new Network(mNetworkAgent.netId);
+    }
+
+    public void expectPreventReconnectReceived(long timeoutMs) {
+        assertTrue(mPreventReconnectReceived.block(timeoutMs));
+    }
+
+    public void expectDisconnected(long timeoutMs) {
+        assertTrue(mDisconnected.block(timeoutMs));
+    }
+
+    public void sendLinkProperties(LinkProperties lp) {
+        mNetworkAgent.sendLinkProperties(lp);
+    }
+
+    public void setStartKeepaliveEvent(int reason) {
+        mStartKeepaliveError = reason;
+    }
+
+    public void setStopKeepaliveEvent(int reason) {
+        mStopKeepaliveError = reason;
+    }
+
+    public void setExpectedKeepaliveSlot(Integer slot) {
+        mExpectedKeepaliveSlot = slot;
+    }
+
+    public NetworkAgent getNetworkAgent() {
+        return mNetworkAgent;
+    }
+
+    public NetworkInfo getNetworkInfo() {
+        return mNetworkInfo;
+    }
+
+    public NetworkCapabilities getNetworkCapabilities() {
+        return mNetworkCapabilities;
+    }
+
+    public void waitForIdle(long timeoutMs) {
+        HandlerUtilsKt.waitForIdle(mHandlerThread, timeoutMs);
+    }
+}
diff --git a/tests/net/integration/util/com/android/server/TestNetIdManager.kt b/tests/net/integration/util/com/android/server/TestNetIdManager.kt
new file mode 100644
index 0000000..eb290dc
--- /dev/null
+++ b/tests/net/integration/util/com/android/server/TestNetIdManager.kt
@@ -0,0 +1,38 @@
+/*
+ * 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
+
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * A [NetIdManager] that generates ID starting from [NetIdManager.MAX_NET_ID] and decreasing, rather
+ * than starting from [NetIdManager.MIN_NET_ID] and increasing.
+ *
+ * Useful for testing ConnectivityService, to minimize the risk of test ConnectivityService netIDs
+ * overlapping with netIDs used by the real ConnectivityService on the device.
+ *
+ * IDs may still overlap if many networks have been used on the device (so the "real" netIDs
+ * are close to MAX_NET_ID), but this is typically not the case when running unit tests. Also, there
+ * is no way to fully solve the overlap issue without altering ID allocation in non-test code, as
+ * the real ConnectivityService could start using netIds that have been used by the test in the
+ * past.
+ */
+class TestNetIdManager : NetIdManager() {
+    private val nextId = AtomicInteger(MAX_NET_ID)
+    override fun reserveNetId() = nextId.decrementAndGet()
+    override fun releaseNetId(id: Int) = Unit
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 5cc95d9..f3c735c 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -28,8 +28,6 @@
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
 import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
-import static android.net.ConnectivityManager.TYPE_NONE;
-import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
@@ -69,6 +67,7 @@
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
 
+import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType;
 import static com.android.testutils.ConcurrentUtilsKt.await;
 import static com.android.testutils.ConcurrentUtilsKt.durationOf;
 import static com.android.testutils.ExceptionUtils.ignoreExceptions;
@@ -86,6 +85,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.anyInt;
@@ -93,6 +93,7 @@
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -105,6 +106,7 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
+import android.app.AlarmManager;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -125,6 +127,7 @@
 import android.net.ConnectivityManager.TooManyRequestsException;
 import android.net.ConnectivityThread;
 import android.net.IDnsResolver;
+import android.net.IIpConnectivityMetrics;
 import android.net.INetd;
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
@@ -139,12 +142,8 @@
 import android.net.LinkProperties;
 import android.net.MatchAllNetworkSpecifier;
 import android.net.Network;
-import android.net.NetworkAgent;
 import android.net.NetworkCapabilities;
 import android.net.NetworkFactory;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkMisc;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
 import android.net.NetworkStack;
@@ -168,7 +167,6 @@
 import android.os.HandlerThread;
 import android.os.INetworkManagementService;
 import android.os.Looper;
-import android.os.Message;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
@@ -265,10 +263,12 @@
     // timeout. For this, our assertions should run fast enough to leave less than
     // (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are
     // supposedly fired, and the time we call expectCallback.
-    private final static int TEST_CALLBACK_TIMEOUT_MS = 200;
+    private static final int TEST_CALLBACK_TIMEOUT_MS = 200;
     // Chosen to be less than TEST_CALLBACK_TIMEOUT_MS. This ensures that requests have time to
     // complete before callbacks are verified.
-    private final static int TEST_REQUEST_TIMEOUT_MS = 150;
+    private static final int TEST_REQUEST_TIMEOUT_MS = 150;
+
+    private static final int UNREASONABLY_LONG_ALARM_WAIT_MS = 1000;
 
     private static final String CLAT_PREFIX = "v4-";
     private static final String MOBILE_IFNAME = "test_rmnet_data0";
@@ -276,15 +276,19 @@
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
 
     private MockContext mServiceContext;
-    private WrappedConnectivityService mService;
+    private HandlerThread mCsHandlerThread;
+    private ConnectivityService mService;
     private WrappedConnectivityManager mCm;
-    private MockNetworkAgent mWiFiNetworkAgent;
-    private MockNetworkAgent mCellNetworkAgent;
-    private MockNetworkAgent mEthernetNetworkAgent;
+    private TestNetworkAgentWrapper mWiFiNetworkAgent;
+    private TestNetworkAgentWrapper mCellNetworkAgent;
+    private TestNetworkAgentWrapper mEthernetNetworkAgent;
     private MockVpn mMockVpn;
     private Context mContext;
     private INetworkPolicyListener mPolicyListener;
+    private WrappedMultinetworkPolicyTracker mPolicyTracker;
+    private HandlerThread mAlarmManagerThread;
 
+    @Mock IIpConnectivityMetrics mIpConnectivityMetrics;
     @Mock IpConnectivityMetrics.Logger mMetricsService;
     @Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
     @Mock INetworkManagementService mNetworkManagementService;
@@ -296,6 +300,7 @@
     @Mock PackageManager mPackageManager;
     @Mock UserManager mUserManager;
     @Mock NotificationManager mNotificationManager;
+    @Mock AlarmManager mAlarmManager;
 
     private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
             ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -368,6 +373,7 @@
             if (Context.NOTIFICATION_SERVICE.equals(name)) return mNotificationManager;
             if (Context.NETWORK_STACK_SERVICE.equals(name)) return mNetworkStack;
             if (Context.USER_SERVICE.equals(name)) return mUserManager;
+            if (Context.ALARM_SERVICE.equals(name)) return mAlarmManager;
             return super.getSystemService(name);
         }
 
@@ -397,25 +403,20 @@
         }
     }
 
-    public void waitForIdle(int timeoutMsAsInt) {
-        long timeoutMs = timeoutMsAsInt;
-        HandlerUtilsKt.waitForIdle(mService.mHandlerThread, timeoutMs);
-        waitForIdle(mCellNetworkAgent, timeoutMs);
-        waitForIdle(mWiFiNetworkAgent, timeoutMs);
-        waitForIdle(mEthernetNetworkAgent, timeoutMs);
-        HandlerUtilsKt.waitForIdle(mService.mHandlerThread, timeoutMs);
-        HandlerUtilsKt.waitForIdle(ConnectivityThread.get(), timeoutMs);
+    private void waitForIdle() {
+        HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
+        waitForIdle(mCellNetworkAgent, TIMEOUT_MS);
+        waitForIdle(mWiFiNetworkAgent, TIMEOUT_MS);
+        waitForIdle(mEthernetNetworkAgent, TIMEOUT_MS);
+        HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
+        HandlerUtilsKt.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS);
     }
 
-    public void waitForIdle(MockNetworkAgent agent, long timeoutMs) {
+    private void waitForIdle(TestNetworkAgentWrapper agent, long timeoutMs) {
         if (agent == null) {
             return;
         }
-        HandlerUtilsKt.waitForIdle(agent.mHandlerThread, timeoutMs);
-    }
-
-    private void waitForIdle() {
-        waitForIdle(TIMEOUT_MS);
+        agent.waitForIdle(timeoutMs);
     }
 
     @Test
@@ -429,7 +430,7 @@
 
         // Bring up a network that we can use to send messages to ConnectivityService.
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
         Network n = mWiFiNetworkAgent.getNetwork();
@@ -449,7 +450,7 @@
     public void verifyThatNotWaitingForIdleCausesRaceConditions() throws Exception {
         // Bring up a network that we can use to send messages to ConnectivityService.
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
         Network n = mWiFiNetworkAgent.getNetwork();
@@ -469,7 +470,7 @@
         fail("expected race condition at least once in " + attempts + " attempts");
     }
 
-    private class MockNetworkAgent implements TestableNetworkCallback.HasNetwork {
+    private class TestNetworkAgentWrapper extends NetworkAgentWrapper {
         private static final int VALIDATION_RESULT_BASE = NETWORK_VALIDATION_PROBE_DNS
                 | NETWORK_VALIDATION_PROBE_HTTP
                 | NETWORK_VALIDATION_PROBE_HTTPS;
@@ -480,86 +481,35 @@
                 | NETWORK_VALIDATION_RESULT_PARTIAL;
         private static final int VALIDATION_RESULT_INVALID = 0;
 
-        private final INetworkMonitor mNetworkMonitor;
-        private final NetworkInfo mNetworkInfo;
-        private final NetworkCapabilities mNetworkCapabilities;
-        private final HandlerThread mHandlerThread;
-        private final ConditionVariable mDisconnected = new ConditionVariable();
-        private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
-        private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
-        private int mScore;
-        private NetworkAgent mNetworkAgent;
-        private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
-        private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
-        private Integer mExpectedKeepaliveSlot = null;
-        // Contains the redirectUrl from networkStatus(). Before reading, wait for
-        // mNetworkStatusReceived.
-        private String mRedirectUrl;
-
+        private INetworkMonitor mNetworkMonitor;
         private INetworkMonitorCallbacks mNmCallbacks;
         private int mNmValidationResult = VALIDATION_RESULT_BASE;
         private String mNmValidationRedirectUrl = null;
         private boolean mNmProvNotificationRequested = false;
 
-        void setNetworkValid() {
-            mNmValidationResult = VALIDATION_RESULT_VALID;
-            mNmValidationRedirectUrl = null;
-        }
+        private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
+        // Contains the redirectUrl from networkStatus(). Before reading, wait for
+        // mNetworkStatusReceived.
+        private String mRedirectUrl;
 
-        void setNetworkInvalid() {
-            mNmValidationResult = VALIDATION_RESULT_INVALID;
-            mNmValidationRedirectUrl = null;
-        }
-
-        void setNetworkPortal(String redirectUrl) {
-            setNetworkInvalid();
-            mNmValidationRedirectUrl = redirectUrl;
-        }
-
-        void setNetworkPartial() {
-            mNmValidationResult = VALIDATION_RESULT_PARTIAL;
-            mNmValidationRedirectUrl = null;
-        }
-
-        void setNetworkPartialValid() {
-            mNmValidationResult = VALIDATION_RESULT_PARTIAL | VALIDATION_RESULT_VALID;
-            mNmValidationRedirectUrl = null;
-        }
-
-        MockNetworkAgent(int transport) throws Exception {
+        TestNetworkAgentWrapper(int transport) throws Exception {
             this(transport, new LinkProperties());
         }
 
-        MockNetworkAgent(int transport, LinkProperties linkProperties) throws Exception {
-            final int type = transportToLegacyType(transport);
-            final String typeName = ConnectivityManager.getNetworkTypeName(type);
-            mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
-            mNetworkCapabilities = new NetworkCapabilities();
-            mNetworkCapabilities.addTransportType(transport);
-            switch (transport) {
-                case TRANSPORT_ETHERNET:
-                    mScore = 70;
-                    break;
-                case TRANSPORT_WIFI:
-                    mScore = 60;
-                    break;
-                case TRANSPORT_CELLULAR:
-                    mScore = 50;
-                    break;
-                case TRANSPORT_WIFI_AWARE:
-                    mScore = 20;
-                    break;
-                case TRANSPORT_VPN:
-                    mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
-                    mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
-                    break;
-                default:
-                    throw new UnsupportedOperationException("unimplemented network type");
-            }
-            mHandlerThread = new HandlerThread("Mock-" + typeName);
-            mHandlerThread.start();
+        TestNetworkAgentWrapper(int transport, LinkProperties linkProperties)
+                throws Exception {
+            super(transport, linkProperties, mServiceContext);
 
+            // Waits for the NetworkAgent to be registered, which includes the creation of the
+            // NetworkMonitor.
+            waitForIdle(TIMEOUT_MS);
+        }
+
+        @Override
+        protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties)
+                throws Exception {
             mNetworkMonitor = mock(INetworkMonitor.class);
+
             final Answer validateAnswer = inv -> {
                 new Thread(ignoreExceptions(this::onValidationRequested)).start();
                 return null;
@@ -576,56 +526,20 @@
                     any() /* name */,
                     nmCbCaptor.capture());
 
-            mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext,
-                    "Mock-" + typeName, mNetworkInfo, mNetworkCapabilities,
-                    linkProperties, mScore, new NetworkMisc(), NetworkFactory.SerialNumber.NONE) {
-                @Override
-                public void unwanted() { mDisconnected.open(); }
-
-                @Override
-                public void startSocketKeepalive(Message msg) {
-                    int slot = msg.arg1;
-                    if (mExpectedKeepaliveSlot != null) {
-                        assertEquals((int) mExpectedKeepaliveSlot, slot);
-                    }
-                    onSocketKeepaliveEvent(slot, mStartKeepaliveError);
-                }
-
-                @Override
-                public void stopSocketKeepalive(Message msg) {
-                    onSocketKeepaliveEvent(msg.arg1, mStopKeepaliveError);
-                }
-
+            final InstrumentedNetworkAgent na = new InstrumentedNetworkAgent(this, linkProperties) {
                 @Override
                 public void networkStatus(int status, String redirectUrl) {
                     mRedirectUrl = redirectUrl;
                     mNetworkStatusReceived.open();
                 }
-
-                @Override
-                protected void preventAutomaticReconnect() {
-                    mPreventReconnectReceived.open();
-                }
-
-                @Override
-                protected void addKeepalivePacketFilter(Message msg) {
-                    Log.i(TAG, "Add keepalive packet filter.");
-                }
-
-                @Override
-                protected void removeKeepalivePacketFilter(Message msg) {
-                    Log.i(TAG, "Remove keepalive packet filter.");
-                }
             };
 
-            assertEquals(mNetworkAgent.netId, nmNetworkCaptor.getValue().netId);
+            assertEquals(na.netId, nmNetworkCaptor.getValue().netId);
             mNmCallbacks = nmCbCaptor.getValue();
 
             mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor);
 
-            // Waits for the NetworkAgent to be registered, which includes the creation of the
-            // NetworkMonitor.
-            waitForIdle();
+            return na;
         }
 
         private void onValidationRequested() throws Exception {
@@ -645,55 +559,11 @@
             }
         }
 
-        public void adjustScore(int change) {
-            mScore += change;
-            mNetworkAgent.sendNetworkScore(mScore);
-        }
-
-        public int getScore() {
-            return mScore;
-        }
-
-        public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
-            mNetworkAgent.explicitlySelected(explicitlySelected, acceptUnvalidated);
-        }
-
-        public void addCapability(int capability) {
-            mNetworkCapabilities.addCapability(capability);
-            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
-        }
-
-        public void removeCapability(int capability) {
-            mNetworkCapabilities.removeCapability(capability);
-            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
-        }
-
-        public void setUids(Set<UidRange> uids) {
-            mNetworkCapabilities.setUids(uids);
-            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
-        }
-
-        public void setSignalStrength(int signalStrength) {
-            mNetworkCapabilities.setSignalStrength(signalStrength);
-            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
-        }
-
-        public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
-            mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
-            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
-        }
-
-        public void setNetworkCapabilities(NetworkCapabilities nc,
-                boolean sendToConnectivityService) {
-            mNetworkCapabilities.set(nc);
-            if (sendToConnectivityService) {
-                mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
-            }
-        }
-
+        /**
+         * Connect without adding any internet capability.
+         */
         public void connectWithoutInternet() {
-            mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
-            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+            super.connect();
         }
 
         /**
@@ -710,23 +580,21 @@
          * @param hasInternet Indicate if network should pretend to have NET_CAPABILITY_INTERNET.
          */
         public void connect(boolean validated, boolean hasInternet) {
-            assertEquals("MockNetworkAgents can only be connected once",
-                    mNetworkInfo.getDetailedState(), DetailedState.IDLE);
-            assertFalse(mNetworkCapabilities.hasCapability(NET_CAPABILITY_INTERNET));
+            assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_INTERNET));
 
-            NetworkCallback callback = null;
+            ConnectivityManager.NetworkCallback callback = null;
             final ConditionVariable validatedCv = new ConditionVariable();
             if (validated) {
                 setNetworkValid();
                 NetworkRequest request = new NetworkRequest.Builder()
-                        .addTransportType(mNetworkCapabilities.getTransportTypes()[0])
+                        .addTransportType(getNetworkCapabilities().getTransportTypes()[0])
                         .clearCapabilities()
                         .build();
-                callback = new NetworkCallback() {
+                callback = new ConnectivityManager.NetworkCallback() {
                     public void onCapabilitiesChanged(Network network,
                             NetworkCapabilities networkCapabilities) {
                         if (network.equals(getNetwork()) &&
-                            networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
+                                networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
                             validatedCv.open();
                         }
                     }
@@ -763,47 +631,29 @@
             connect(false);
         }
 
-        public void suspend() {
-            mNetworkInfo.setDetailedState(DetailedState.SUSPENDED, null, null);
-            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+        void setNetworkValid() {
+            mNmValidationResult = VALIDATION_RESULT_VALID;
+            mNmValidationRedirectUrl = null;
         }
 
-        public void resume() {
-            mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
-            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+        void setNetworkInvalid() {
+            mNmValidationResult = VALIDATION_RESULT_INVALID;
+            mNmValidationRedirectUrl = null;
         }
 
-        public void disconnect() {
-            mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
-            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+        void setNetworkPortal(String redirectUrl) {
+            setNetworkInvalid();
+            mNmValidationRedirectUrl = redirectUrl;
         }
 
-        public Network getNetwork() {
-            return new Network(mNetworkAgent.netId);
+        void setNetworkPartial() {
+            mNmValidationResult = VALIDATION_RESULT_PARTIAL;
+            mNmValidationRedirectUrl = null;
         }
 
-        public ConditionVariable getPreventReconnectReceived() {
-            return mPreventReconnectReceived;
-        }
-
-        public ConditionVariable getDisconnectedCV() {
-            return mDisconnected;
-        }
-
-        public void sendLinkProperties(LinkProperties lp) {
-            mNetworkAgent.sendLinkProperties(lp);
-        }
-
-        public void setStartKeepaliveError(int error) {
-            mStartKeepaliveError = error;
-        }
-
-        public void setStopKeepaliveError(int error) {
-            mStopKeepaliveError = error;
-        }
-
-        public void setExpectedKeepaliveSlot(Integer slot) {
-            mExpectedKeepaliveSlot = slot;
+        void setNetworkPartialValid() {
+            mNmValidationResult = VALIDATION_RESULT_PARTIAL | VALIDATION_RESULT_VALID;
+            mNmValidationRedirectUrl = null;
         }
 
         public String waitForRedirectUrl() {
@@ -811,12 +661,12 @@
             return mRedirectUrl;
         }
 
-        public NetworkAgent getNetworkAgent() {
-            return mNetworkAgent;
+        public void expectDisconnected() {
+            expectDisconnected(TIMEOUT_MS);
         }
 
-        public NetworkCapabilities getNetworkCapabilities() {
-            return mNetworkCapabilities;
+        public void expectPreventReconnectReceived() {
+            expectPreventReconnectReceived(TIMEOUT_MS);
         }
     }
 
@@ -995,15 +845,15 @@
         private boolean mConnected = false;
         // Careful ! This is different from mNetworkAgent, because MockNetworkAgent does
         // not inherit from NetworkAgent.
-        private MockNetworkAgent mMockNetworkAgent;
+        private TestNetworkAgentWrapper mMockNetworkAgent;
 
         public MockVpn(int userId) {
             super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService,
                     userId);
         }
 
-        public void setNetworkAgent(MockNetworkAgent agent) {
-            waitForIdle(agent, TIMEOUT_MS);
+        public void setNetworkAgent(TestNetworkAgentWrapper agent) {
+            agent.waitForIdle(TIMEOUT_MS);
             mMockNetworkAgent = agent;
             mNetworkAgent = agent.getNetworkAgent();
             mNetworkCapabilities.set(agent.getNetworkCapabilities());
@@ -1070,187 +920,45 @@
         }
     }
 
-    private class FakeWakeupMessage extends WakeupMessage {
-        private static final int UNREASONABLY_LONG_WAIT = 1000;
-
-        public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
-            super(context, handler, cmdName, cmd);
-        }
-
-        public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd,
-                int arg1, int arg2, Object obj) {
-            super(context, handler, cmdName, cmd, arg1, arg2, obj);
-        }
-
-        @Override
-        public void schedule(long when) {
-            long delayMs = when - SystemClock.elapsedRealtime();
-            if (delayMs < 0) delayMs = 0;
-            if (delayMs > UNREASONABLY_LONG_WAIT) {
-                fail("Attempting to send msg more than " + UNREASONABLY_LONG_WAIT +
-                        "ms into the future: " + delayMs);
-            }
-            Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
-            mHandler.sendMessageDelayed(msg, delayMs);
-        }
-
-        @Override
-        public void cancel() {
-            mHandler.removeMessages(mCmd, mObj);
-        }
-
-        @Override
-        public void onAlarm() {
-            throw new AssertionError("Should never happen. Update this fake.");
+    private void mockVpn(int uid) {
+        synchronized (mService.mVpns) {
+            int userId = UserHandle.getUserId(uid);
+            mMockVpn = new MockVpn(userId);
+            // This has no effect unless the VPN is actually connected, because things like
+            // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN
+            // netId, and check if that network is actually connected.
+            mService.mVpns.put(userId, mMockVpn);
         }
     }
 
-    private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
-        public volatile boolean configRestrictsAvoidBadWifi;
-        public volatile int configMeteredMultipathPreference;
+    private void setUidRulesChanged(int uidRules) throws RemoteException {
+        mPolicyListener.onUidRulesChanged(Process.myUid(), uidRules);
+    }
 
-        public WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
+    private void setRestrictBackgroundChanged(boolean restrictBackground) throws RemoteException {
+        mPolicyListener.onRestrictBackgroundChanged(restrictBackground);
+    }
+
+    private Nat464Xlat getNat464Xlat(NetworkAgentWrapper mna) {
+        return mService.getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
+    }
+
+    private static class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
+        volatile boolean mConfigRestrictsAvoidBadWifi;
+        volatile int mConfigMeteredMultipathPreference;
+
+        WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
             super(c, h, r);
         }
 
         @Override
         public boolean configRestrictsAvoidBadWifi() {
-            return configRestrictsAvoidBadWifi;
+            return mConfigRestrictsAvoidBadWifi;
         }
 
         @Override
         public int configMeteredMultipathPreference() {
-            return configMeteredMultipathPreference;
-        }
-    }
-
-    private class WrappedConnectivityService extends ConnectivityService {
-        public WrappedMultinetworkPolicyTracker wrappedMultinetworkPolicyTracker;
-        private MockableSystemProperties mSystemProperties;
-
-        public WrappedConnectivityService(Context context, INetworkManagementService netManager,
-                INetworkStatsService statsService, INetworkPolicyManager policyManager,
-                IpConnectivityLog log, INetd netd, IDnsResolver dnsResolver) {
-            super(context, netManager, statsService, policyManager, dnsResolver, log, netd);
-            mNetd = netd;
-            mLingerDelayMs = TEST_LINGER_DELAY_MS;
-        }
-
-        @Override
-        protected MockableSystemProperties getSystemProperties() {
-            // Minimal approach to overriding system properties: let most calls fall through to real
-            // device values, and only override ones values that are important to this test.
-            mSystemProperties = spy(new MockableSystemProperties());
-            when(mSystemProperties.getInt("net.tcp.default_init_rwnd", 0)).thenReturn(0);
-            when(mSystemProperties.getBoolean("ro.radio.noril", false)).thenReturn(false);
-            return mSystemProperties;
-        }
-
-        @Override
-        protected Tethering makeTethering() {
-            return mock(Tethering.class);
-        }
-
-        @Override
-        protected ProxyTracker makeProxyTracker() {
-            return mock(ProxyTracker.class);
-        }
-
-        @Override
-        protected int reserveNetId() {
-            while (true) {
-                final int netId = super.reserveNetId();
-
-                // Don't overlap test NetIDs with real NetIDs as binding sockets to real networks
-                // can have odd side-effects, like network validations succeeding.
-                Context context = InstrumentationRegistry.getContext();
-                final Network[] networks = ConnectivityManager.from(context).getAllNetworks();
-                boolean overlaps = false;
-                for (Network network : networks) {
-                    if (netId == network.netId) {
-                        overlaps = true;
-                        break;
-                    }
-                }
-                if (overlaps) continue;
-
-                return netId;
-            }
-        }
-
-        @Override
-        protected boolean queryUserAccess(int uid, int netId) {
-            return true;
-        }
-
-        public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) {
-            return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
-        }
-
-        @Override
-        public MultinetworkPolicyTracker createMultinetworkPolicyTracker(
-                Context c, Handler h, Runnable r) {
-            final WrappedMultinetworkPolicyTracker tracker = new WrappedMultinetworkPolicyTracker(c, h, r);
-            return tracker;
-        }
-
-        public WrappedMultinetworkPolicyTracker getMultinetworkPolicyTracker() {
-            return (WrappedMultinetworkPolicyTracker) mMultinetworkPolicyTracker;
-        }
-
-        @Override
-        protected NetworkStackClient getNetworkStack() {
-            return mNetworkStack;
-        }
-
-        @Override
-        public WakeupMessage makeWakeupMessage(
-                Context context, Handler handler, String cmdName, int cmd, Object obj) {
-            return new FakeWakeupMessage(context, handler, cmdName, cmd, 0, 0, obj);
-        }
-
-        @Override
-        public boolean hasService(String name) {
-            // Currenty, the only relevant service that ConnectivityService checks for is
-            // ETHERNET_SERVICE.
-            return Context.ETHERNET_SERVICE.equals(name);
-        }
-
-        @Override
-        protected IpConnectivityMetrics.Logger metricsLogger() {
-            return mMetricsService;
-        }
-
-        @Override
-        protected void registerNetdEventCallback() {
-        }
-
-        public void mockVpn(int uid) {
-            synchronized (mVpns) {
-                int userId = UserHandle.getUserId(uid);
-                mMockVpn = new MockVpn(userId);
-                // This has no effect unless the VPN is actually connected, because things like
-                // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN
-                // netId, and check if that network is actually connected.
-                mVpns.put(userId, mMockVpn);
-            }
-        }
-
-        public void waitForIdle(int timeoutMs) {
-            HandlerUtilsKt.waitForIdle(mHandlerThread, timeoutMs);
-        }
-
-        public void waitForIdle() {
-            waitForIdle(TIMEOUT_MS);
-        }
-
-        public void setUidRulesChanged(int uidRules) throws RemoteException {
-            mPolicyListener.onUidRulesChanged(Process.myUid(), uidRules);
-        }
-
-        public void setRestrictBackgroundChanged(boolean restrictBackground)
-                throws RemoteException {
-            mPolicyListener.onRestrictBackgroundChanged(restrictBackground);
+            return mConfigMeteredMultipathPreference;
         }
     }
 
@@ -1296,13 +1004,22 @@
         LocalServices.addService(
                 NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
 
-        mService = new WrappedConnectivityService(mServiceContext,
+        mAlarmManagerThread = new HandlerThread("TestAlarmManager");
+        mAlarmManagerThread.start();
+        initAlarmManager(mAlarmManager, mAlarmManagerThread.getThreadHandler());
+
+        mCsHandlerThread = new HandlerThread("TestConnectivityService");
+        final ConnectivityService.Dependencies deps = makeDependencies();
+        mService = new ConnectivityService(mServiceContext,
                 mNetworkManagementService,
                 mStatsService,
                 mNpm,
+                mMockDnsResolver,
                 mock(IpConnectivityLog.class),
                 mMockNetd,
-                mMockDnsResolver);
+                deps);
+        mService.mLingerDelayMs = TEST_LINGER_DELAY_MS;
+        verify(deps).makeMultinetworkPolicyTracker(any(), any(), any());
 
         final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
                 ArgumentCaptor.forClass(INetworkPolicyListener.class);
@@ -1313,7 +1030,7 @@
         // getSystemService() correctly.
         mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
         mService.systemReady();
-        mService.mockVpn(Process.myUid());
+        mockVpn(Process.myUid());
         mCm.bindProcessToNetwork(null);
 
         // Ensure that the default setting for Captive Portals is used for most tests
@@ -1322,6 +1039,57 @@
         setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
     }
 
+    private ConnectivityService.Dependencies makeDependencies() {
+        final MockableSystemProperties systemProperties = spy(new MockableSystemProperties());
+        when(systemProperties.getInt("net.tcp.default_init_rwnd", 0)).thenReturn(0);
+        when(systemProperties.getBoolean("ro.radio.noril", false)).thenReturn(false);
+
+        final ConnectivityService.Dependencies deps = mock(ConnectivityService.Dependencies.class);
+        doReturn(mCsHandlerThread).when(deps).makeHandlerThread();
+        doReturn(new TestNetIdManager()).when(deps).makeNetIdManager();
+        doReturn(mNetworkStack).when(deps).getNetworkStack();
+        doReturn(systemProperties).when(deps).getSystemProperties();
+        doReturn(mock(Tethering.class)).when(deps).makeTethering(any(), any(), any(), any(), any());
+        doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
+        doReturn(mMetricsService).when(deps).getMetricsLogger();
+        doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
+        doReturn(mIpConnectivityMetrics).when(deps).getIpConnectivityMetrics();
+        doReturn(true).when(deps).hasService(Context.ETHERNET_SERVICE);
+        doAnswer(inv -> {
+            mPolicyTracker = new WrappedMultinetworkPolicyTracker(
+                    inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
+            return mPolicyTracker;
+        }).when(deps).makeMultinetworkPolicyTracker(any(), any(), any());
+
+        return deps;
+    }
+
+    private static void initAlarmManager(final AlarmManager am, final Handler alarmHandler) {
+        doAnswer(inv -> {
+            final long when = inv.getArgument(1);
+            final WakeupMessage wakeupMsg = inv.getArgument(3);
+            final Handler handler = inv.getArgument(4);
+
+            long delayMs = when - SystemClock.elapsedRealtime();
+            if (delayMs < 0) delayMs = 0;
+            if (delayMs > UNREASONABLY_LONG_ALARM_WAIT_MS) {
+                fail("Attempting to send msg more than " + UNREASONABLY_LONG_ALARM_WAIT_MS
+                        + "ms into the future: " + delayMs);
+            }
+            alarmHandler.postDelayed(() -> handler.post(wakeupMsg::onAlarm), wakeupMsg /* token */,
+                    delayMs);
+
+            return null;
+        }).when(am).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), anyLong(), anyString(),
+                any(WakeupMessage.class), any());
+
+        doAnswer(inv -> {
+            final WakeupMessage wakeupMsg = inv.getArgument(0);
+            alarmHandler.removeCallbacksAndMessages(wakeupMsg /* token */);
+            return null;
+        }).when(am).cancel(any(WakeupMessage.class));
+    }
+
     @After
     public void tearDown() throws Exception {
         setAlwaysOnNetworks(false);
@@ -1338,6 +1106,9 @@
             mEthernetNetworkAgent = null;
         }
         FakeSettingsProvider.clearSettingsProvider();
+
+        mCsHandlerThread.quitSafely();
+        mAlarmManagerThread.quitSafely();
     }
 
     private void mockDefaultPackages() throws Exception {
@@ -1357,21 +1128,6 @@
                 }));
     }
 
-   private static int transportToLegacyType(int transport) {
-        switch (transport) {
-            case TRANSPORT_ETHERNET:
-                return TYPE_ETHERNET;
-            case TRANSPORT_WIFI:
-                return TYPE_WIFI;
-            case TRANSPORT_CELLULAR:
-                return TYPE_MOBILE;
-            case TRANSPORT_VPN:
-                return TYPE_VPN;
-            default:
-                return TYPE_NONE;
-        }
-    }
-
     private void verifyActiveNetwork(int transport) {
         // Test getActiveNetworkInfo()
         assertNotNull(mCm.getActiveNetworkInfo());
@@ -1449,8 +1205,8 @@
     @Test
     public void testLingering() throws Exception {
         verifyNoNetwork();
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         assertNull(mCm.getActiveNetworkInfo());
         assertNull(mCm.getActiveNetwork());
         // Test bringing up validated cellular.
@@ -1474,7 +1230,7 @@
         assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
                 mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
         // Test cellular linger timeout.
-        waitFor(mCellNetworkAgent.getDisconnectedCV());
+        mCellNetworkAgent.expectDisconnected();
         waitForIdle();
         assertLength(1, mCm.getAllNetworks());
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1490,13 +1246,13 @@
     @Test
     public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
         // Test bringing up unvalidated WiFi
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up unvalidated cellular
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);
         waitForIdle();
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1505,7 +1261,7 @@
         waitForIdle();
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up validated cellular
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         cv = waitForConnectivityBroadcasts(2);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
@@ -1525,13 +1281,13 @@
     @Test
     public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
         // Test bringing up unvalidated cellular.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mCellNetworkAgent.connect(false);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test bringing up unvalidated WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         cv = waitForConnectivityBroadcasts(2);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
@@ -1551,7 +1307,7 @@
     @Test
     public void testUnlingeringDoesNotValidate() throws Exception {
         // Test bringing up unvalidated WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
@@ -1559,7 +1315,7 @@
         assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         // Test bringing up validated cellular.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         cv = waitForConnectivityBroadcasts(2);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
@@ -1579,13 +1335,13 @@
     @Test
     public void testCellularOutscoresWeakWifi() throws Exception {
         // Test bringing up validated cellular.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test bringing up validated WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         cv = waitForConnectivityBroadcasts(2);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
@@ -1606,45 +1362,41 @@
     public void testReapingNetwork() throws Exception {
         // Test bringing up WiFi without NET_CAPABILITY_INTERNET.
         // Expect it to be torn down immediately because it satisfies no requests.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
-        ConditionVariable cv = mWiFiNetworkAgent.getDisconnectedCV();
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connectWithoutInternet();
-        waitFor(cv);
+        mWiFiNetworkAgent.expectDisconnected();
         // Test bringing up cellular without NET_CAPABILITY_INTERNET.
         // Expect it to be torn down immediately because it satisfies no requests.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
-        cv = mCellNetworkAgent.getDisconnectedCV();
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mCellNetworkAgent.connectWithoutInternet();
-        waitFor(cv);
+        mCellNetworkAgent.expectDisconnected();
         // Test bringing up validated WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
-        cv = waitForConnectivityBroadcasts(1);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        final ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up unvalidated cellular.
         // Expect it to be torn down because it could never be the highest scoring network
         // satisfying the default request even if it validated.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
-        cv = mCellNetworkAgent.getDisconnectedCV();
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);
-        waitFor(cv);
+        mCellNetworkAgent.expectDisconnected();
         verifyActiveNetwork(TRANSPORT_WIFI);
-        cv = mWiFiNetworkAgent.getDisconnectedCV();
         mWiFiNetworkAgent.disconnect();
-        waitFor(cv);
+        mWiFiNetworkAgent.expectDisconnected();
     }
 
     @Test
     public void testCellularFallback() throws Exception {
         // Test bringing up validated cellular.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test bringing up validated WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         cv = waitForConnectivityBroadcasts(2);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
@@ -1676,13 +1428,13 @@
     @Test
     public void testWiFiFallback() throws Exception {
         // Test bringing up unvalidated WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up validated cellular.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         cv = waitForConnectivityBroadcasts(2);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
@@ -1760,7 +1512,7 @@
 
         // Test unvalidated networks
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         cellNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
@@ -1775,7 +1527,7 @@
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         cv = waitForConnectivityBroadcasts(2);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -1799,7 +1551,7 @@
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
 
         // Test validated networks
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         genericNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
@@ -1812,7 +1564,7 @@
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         genericNetworkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
@@ -1850,9 +1602,9 @@
         TestNetworkCallback defaultCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultCallback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
-        mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
 
         mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
@@ -1891,7 +1643,7 @@
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         for (int i = 0; i < 4; i++) {
-            MockNetworkAgent oldNetwork, newNetwork;
+            TestNetworkAgentWrapper oldNetwork, newNetwork;
             if (i % 2 == 0) {
                 mWiFiNetworkAgent.adjustScore(-15);
                 oldNetwork = mWiFiNetworkAgent;
@@ -1943,7 +1695,7 @@
 
         mCm.registerNetworkCallback(request, callback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);   // Score: 10
         callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
@@ -1952,7 +1704,7 @@
 
         // Bring up wifi with a score of 20.
         // Cell stays up because it would satisfy the default request if it validated.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);   // Score: 20
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -1968,7 +1720,7 @@
 
         // Bring up wifi with a score of 70.
         // Cell is lingered because it would not satisfy any request, even if it validated.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.adjustScore(50);
         mWiFiNetworkAgent.connect(false);   // Score: 70
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -1987,7 +1739,7 @@
 
         // Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
         // it's arguably correct to linger it, since it was the default network before it validated.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         // TODO: Investigate sending validated before losing.
@@ -2008,12 +1760,12 @@
         assertEquals(null, mCm.getActiveNetwork());
 
         // If a network is lingering, and we add and remove a request from it, resume lingering.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2044,7 +1796,7 @@
         mCm.requestNetwork(cellRequest, noopCallback);
 
         // Now connect wifi, and expect it to become the default network.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -2065,7 +1817,7 @@
         TestNetworkCallback trackDefaultCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(trackDefaultCallback);
         trackDefaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
-        mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
+        mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
         mEthernetNetworkAgent.connect(true);
         callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
         callback.expectCallback(CallbackRecord.LOSING, mWiFiNetworkAgent);
@@ -2100,8 +1852,8 @@
         TestNetworkCallback defaultCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultCallback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
 
         mCellNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
@@ -2142,12 +1894,12 @@
         mCm.registerNetworkCallback(request, callback);
 
         // Bring up validated cell.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
 
         // Bring up unvalidated wifi with explicitlySelected=true.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(true, false);
         mWiFiNetworkAgent.connect(false);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2170,7 +1922,7 @@
         // Disconnect wifi, and then reconnect, again with explicitlySelected=true.
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(true, false);
         mWiFiNetworkAgent.connect(false);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2181,7 +1933,7 @@
         callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
 
         // Reconnect, again with explicitlySelected=true, but this time validate.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(true, false);
         mWiFiNetworkAgent.connect(true);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2191,7 +1943,7 @@
 
         // BUG: the network will no longer linger, even though it's validated and outscored.
         // TODO: fix this.
-        mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
+        mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
         mEthernetNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
         assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -2202,7 +1954,7 @@
         // wifi immediately.
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(true, true);
         mWiFiNetworkAgent.connect(false);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2215,7 +1967,7 @@
         // Check that the network is not scored specially and that the device prefers cell data.
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(false, true);
         mWiFiNetworkAgent.connect(false);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2277,7 +2029,7 @@
         assertTrue(testFactory.getMyStartRequested());
 
         // Now bring in a higher scored network.
-        MockNetworkAgent testAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        TestNetworkAgentWrapper testAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         // Rather than create a validated network which complicates things by registering it's
         // own NetworkRequest during startup, just bump up the score to cancel out the
         // unvalidated penalty.
@@ -2371,18 +2123,17 @@
     @Test
     public void testMMSonWiFi() throws Exception {
         // Test bringing up cellular without MMS NetworkRequest gets reaped
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
-        ConditionVariable cv = mCellNetworkAgent.getDisconnectedCV();
         mCellNetworkAgent.connectWithoutInternet();
-        waitFor(cv);
+        mCellNetworkAgent.expectDisconnected();
         waitForIdle();
         assertEmpty(mCm.getAllNetworks());
         verifyNoNetwork();
 
         // Test bringing up validated WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
-        cv = waitForConnectivityBroadcasts(1);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        final ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -2394,23 +2145,22 @@
         mCm.requestNetwork(builder.build(), networkCallback);
 
         // Test bringing up unvalidated cellular with MMS
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
         mCellNetworkAgent.connectWithoutInternet();
         networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         verifyActiveNetwork(TRANSPORT_WIFI);
 
         // Test releasing NetworkRequest disconnects cellular with MMS
-        cv = mCellNetworkAgent.getDisconnectedCV();
         mCm.unregisterNetworkCallback(networkCallback);
-        waitFor(cv);
+        mCellNetworkAgent.expectDisconnected();
         verifyActiveNetwork(TRANSPORT_WIFI);
     }
 
     @Test
     public void testMMSonCell() throws Exception {
         // Test bringing up cellular without MMS
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mCellNetworkAgent.connect(false);
         waitFor(cv);
@@ -2423,16 +2173,16 @@
         mCm.requestNetwork(builder.build(), networkCallback);
 
         // Test bringing up MMS cellular network
-        MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        TestNetworkAgentWrapper
+                mmsNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
         mmsNetworkAgent.connectWithoutInternet();
         networkCallback.expectAvailableCallbacksUnvalidated(mmsNetworkAgent);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
 
         // Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
-        cv = mmsNetworkAgent.getDisconnectedCV();
         mCm.unregisterNetworkCallback(networkCallback);
-        waitFor(cv);
+        mmsNetworkAgent.expectDisconnected();
         verifyActiveNetwork(TRANSPORT_CELLULAR);
     }
 
@@ -2446,12 +2196,12 @@
         mCm.registerNetworkCallback(request, callback);
 
         // Bring up validated mobile data.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
 
         // Bring up wifi with partial connectivity.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connectWithPartialConnectivity();
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
@@ -2484,7 +2234,7 @@
         // Disconnect and reconnect wifi with partial connectivity again.
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connectWithPartialConnectivity();
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
@@ -2500,7 +2250,7 @@
         // If user accepted partial connectivity before, and device reconnects to that network
         // again, but now the network has full connectivity. The network shouldn't contain
         // NET_CAPABILITY_PARTIAL_CONNECTIVITY.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         // acceptUnvalidated is also used as setting for accepting partial networks.
         mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */,
                 true /* acceptUnvalidated */);
@@ -2524,7 +2274,7 @@
         // The user accepted partial connectivity and selected "don't ask again". Now the user
         // reconnects to the partial connectivity network. Switch to wifi as soon as partial
         // connectivity is detected.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */,
                 true /* acceptUnvalidated */);
         mWiFiNetworkAgent.connectWithPartialConnectivity();
@@ -2548,7 +2298,7 @@
 
         // If the user accepted partial connectivity, and the device auto-reconnects to the partial
         // connectivity network, it should contain both PARTIAL_CONNECTIVITY and VALIDATED.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.explicitlySelected(false /* explicitlySelected */,
                 true /* acceptUnvalidated */);
 
@@ -2580,7 +2330,7 @@
 
         // Bring up a network with a captive portal.
         // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         String redirectUrl = "http://android.com/path";
         mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl);
         captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2629,7 +2379,7 @@
 
         // Bring up a network with a captive portal.
         // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         String firstRedirectUrl = "http://example.com/firstPath";
         mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
         captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2642,7 +2392,7 @@
 
         // Bring up a network with a captive portal.
         // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         String secondRedirectUrl = "http://example.com/secondPath";
         mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
         captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2680,7 +2430,7 @@
         mCm.registerNetworkCallback(validatedRequest, validatedCallback);
 
         // Bring up wifi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
@@ -2740,14 +2490,12 @@
         setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_AVOID);
         // Bring up a network with a captive portal.
         // Expect it to fail to connect and not result in any callbacks.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         String firstRedirectUrl = "http://example.com/firstPath";
 
-        ConditionVariable disconnectCv = mWiFiNetworkAgent.getDisconnectedCV();
-        ConditionVariable avoidCv = mWiFiNetworkAgent.getPreventReconnectReceived();
         mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
-        waitFor(disconnectCv);
-        waitFor(avoidCv);
+        mWiFiNetworkAgent.expectDisconnected();
+        mWiFiNetworkAgent.expectPreventReconnectReceived();
 
         assertNoCallbacks(captivePortalCallback, validatedCallback);
     }
@@ -2846,7 +2594,7 @@
         LocalStringNetworkSpecifier nsFoo = new LocalStringNetworkSpecifier("foo");
         LocalStringNetworkSpecifier nsBar = new LocalStringNetworkSpecifier("bar");
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         cEmpty1.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         cEmpty2.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2973,7 +2721,7 @@
             public void writeToParcel(Parcel dest, int flags) {}
         }
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
 
         UidAwareNetworkSpecifier networkSpecifier = new UidAwareNetworkSpecifier();
@@ -3026,14 +2774,14 @@
         cellNetworkCallback.assertNoCallback();
 
         // Bring up cell and expect CALLBACK_AVAILABLE.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring up wifi and expect CALLBACK_AVAILABLE.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         cellNetworkCallback.assertNoCallback();
         defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -3046,7 +2794,7 @@
         assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring up cell. Expect no default network callback, since it won't be the default.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultNetworkCallback.assertNoCallback();
@@ -3065,7 +2813,8 @@
         assertEquals(null, mCm.getActiveNetwork());
 
         final int uid = Process.myUid();
-        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -3090,7 +2839,7 @@
         mCm.requestNetwork(cellRequest, cellNetworkCallback);
 
         // Bring up the mobile network.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
 
         // We should get onAvailable(), onCapabilitiesChanged(), and
@@ -3160,7 +2909,7 @@
         waitForIdle();
     }
 
-    private boolean isForegroundNetwork(MockNetworkAgent network) {
+    private boolean isForegroundNetwork(TestNetworkAgentWrapper network) {
         NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
         assertNotNull(nc);
         return nc.hasCapability(NET_CAPABILITY_FOREGROUND);
@@ -3179,13 +2928,13 @@
         mCm.registerNetworkCallback(request, callback);
         mCm.registerNetworkCallback(fgRequest, fgCallback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         fgCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         assertTrue(isForegroundNetwork(mCellNetworkAgent));
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
 
         // When wifi connects, cell lingers.
@@ -3278,7 +3027,7 @@
             }
         });
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         // Don't request that the network validate, because otherwise connect() will block until
         // the network gets NET_CAPABILITY_VALIDATED, after all the callbacks below have fired,
         // and we won't actually measure anything.
@@ -3295,7 +3044,7 @@
                 onAvailableDispatchingDuration <= CONNECT_TIME_LIMIT_MS);
 
         // Give wifi a high enough score that we'll linger cell when wifi comes up.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.adjustScore(40);
         mWiFiNetworkAgent.connect(false);
 
@@ -3338,7 +3087,7 @@
         assertTrue(testFactory.getMyStartRequested());
 
         // Bring up wifi. The factory stops looking for a network.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         // Score 60 - 40 penalty for not validated yet, then 60 when it validates
         testFactory.expectAddRequestsWithScores(20, 60);
         mWiFiNetworkAgent.connect(true);
@@ -3355,7 +3104,7 @@
 
         // Bring up cell data and check that the factory stops looking.
         assertLength(1, mCm.getAllNetworks());
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         testFactory.expectAddRequestsWithScores(10, 50);  // Unvalidated, then validated
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
@@ -3384,48 +3133,46 @@
     @Test
     public void testAvoidBadWifiSetting() throws Exception {
         final ContentResolver cr = mServiceContext.getContentResolver();
-        final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
         final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
 
-        tracker.configRestrictsAvoidBadWifi = false;
+        mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
         String[] values = new String[] {null, "0", "1"};
         for (int i = 0; i < values.length; i++) {
             Settings.Global.putInt(cr, settingName, 1);
-            tracker.reevaluate();
+            mPolicyTracker.reevaluate();
             waitForIdle();
             String msg = String.format("config=false, setting=%s", values[i]);
             assertTrue(mService.avoidBadWifi());
-            assertFalse(msg, tracker.shouldNotifyWifiUnvalidated());
+            assertFalse(msg, mPolicyTracker.shouldNotifyWifiUnvalidated());
         }
 
-        tracker.configRestrictsAvoidBadWifi = true;
+        mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
 
         Settings.Global.putInt(cr, settingName, 0);
-        tracker.reevaluate();
+        mPolicyTracker.reevaluate();
         waitForIdle();
         assertFalse(mService.avoidBadWifi());
-        assertFalse(tracker.shouldNotifyWifiUnvalidated());
+        assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated());
 
         Settings.Global.putInt(cr, settingName, 1);
-        tracker.reevaluate();
+        mPolicyTracker.reevaluate();
         waitForIdle();
         assertTrue(mService.avoidBadWifi());
-        assertFalse(tracker.shouldNotifyWifiUnvalidated());
+        assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated());
 
         Settings.Global.putString(cr, settingName, null);
-        tracker.reevaluate();
+        mPolicyTracker.reevaluate();
         waitForIdle();
         assertFalse(mService.avoidBadWifi());
-        assertTrue(tracker.shouldNotifyWifiUnvalidated());
+        assertTrue(mPolicyTracker.shouldNotifyWifiUnvalidated());
     }
 
     @Test
     public void testAvoidBadWifi() throws Exception {
         final ContentResolver cr = mServiceContext.getContentResolver();
-        final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
 
         // Pretend we're on a carrier that restricts switching away from bad wifi.
-        tracker.configRestrictsAvoidBadWifi = true;
+        mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
 
         // File a request for cell to ensure it doesn't go down.
         final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
@@ -3444,17 +3191,17 @@
         mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
 
         Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);
-        tracker.reevaluate();
+        mPolicyTracker.reevaluate();
 
         // Bring up validated cell.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         Network cellNetwork = mCellNetworkAgent.getNetwork();
 
         // Bring up validated wifi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -3476,14 +3223,14 @@
 
         // Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect
         // that we switch back to cell.
-        tracker.configRestrictsAvoidBadWifi = false;
-        tracker.reevaluate();
+        mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
+        mPolicyTracker.reevaluate();
         defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), cellNetwork);
 
         // Switch back to a restrictive carrier.
-        tracker.configRestrictsAvoidBadWifi = true;
-        tracker.reevaluate();
+        mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
+        mPolicyTracker.reevaluate();
         defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), wifiNetwork);
 
@@ -3498,7 +3245,7 @@
 
         // Disconnect and reconnect wifi to clear the one-time switch above.
         mWiFiNetworkAgent.disconnect();
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -3512,7 +3259,7 @@
 
         // Simulate the user selecting "switch" and checking the don't ask again checkbox.
         Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
-        tracker.reevaluate();
+        mPolicyTracker.reevaluate();
 
         // We now switch to cell.
         defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
@@ -3525,11 +3272,11 @@
         // Simulate the user turning the cellular fallback setting off and then on.
         // We switch to wifi and then to cell.
         Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
-        tracker.reevaluate();
+        mPolicyTracker.reevaluate();
         defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), wifiNetwork);
         Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
-        tracker.reevaluate();
+        mPolicyTracker.reevaluate();
         defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), cellNetwork);
 
@@ -3547,14 +3294,13 @@
     @Test
     public void testMeteredMultipathPreferenceSetting() throws Exception {
         final ContentResolver cr = mServiceContext.getContentResolver();
-        final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
         final String settingName = Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
 
         for (int config : Arrays.asList(0, 3, 2)) {
             for (String setting: Arrays.asList(null, "0", "2", "1")) {
-                tracker.configMeteredMultipathPreference = config;
+                mPolicyTracker.mConfigMeteredMultipathPreference = config;
                 Settings.Global.putString(cr, settingName, setting);
-                tracker.reevaluate();
+                mPolicyTracker.reevaluate();
                 waitForIdle();
 
                 final int expected = (setting != null) ? Integer.parseInt(setting) : config;
@@ -3575,7 +3321,7 @@
         final TestNetworkCallback networkCallback = new TestNetworkCallback();
         mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS);
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
                 TEST_CALLBACK_TIMEOUT_MS);
@@ -3595,7 +3341,7 @@
         final TestNetworkCallback networkCallback = new TestNetworkCallback();
         mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS);
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
                 TEST_CALLBACK_TIMEOUT_MS);
@@ -3623,7 +3369,7 @@
         networkCallback.expectCallback(CallbackRecord.UNAVAILABLE, null);
 
         // create a network satisfying request - validate that request not triggered
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         networkCallback.assertNoCallback();
     }
@@ -3646,7 +3392,7 @@
         networkCallback.assertNoCallback();
 
         // create a network satisfying request - validate that request not triggered
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         networkCallback.assertNoCallback();
     }
@@ -3876,7 +3622,7 @@
             assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()));
         }
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
@@ -3940,10 +3686,10 @@
         callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
 
         // Check that a started keepalive can be stopped.
-        mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
+        mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS);
         ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
         callback.expectStarted();
-        mWiFiNetworkAgent.setStopKeepaliveError(PacketKeepalive.SUCCESS);
+        mWiFiNetworkAgent.setStopKeepaliveEvent(PacketKeepalive.SUCCESS);
         ka.stop();
         callback.expectStopped();
 
@@ -3961,7 +3707,7 @@
         ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
         callback.expectStarted();
         mWiFiNetworkAgent.disconnect();
-        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+        mWiFiNetworkAgent.expectDisconnected();
         callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
 
         // ... and that stopping it after that has no adverse effects.
@@ -3972,7 +3718,7 @@
 
         // Reconnect.
         myNet = connectKeepaliveNetwork(lp);
-        mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
+        mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS);
 
         // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
         mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
@@ -4092,12 +3838,12 @@
         }
 
         // Check that a started keepalive can be stopped.
-        mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS);
+        mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
         try (SocketKeepalive ka = mCm.createSocketKeepalive(
                 myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
             ka.start(validKaInterval);
             callback.expectStarted();
-            mWiFiNetworkAgent.setStopKeepaliveError(SocketKeepalive.SUCCESS);
+            mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS);
             ka.stop();
             callback.expectStopped();
 
@@ -4137,7 +3883,7 @@
             ka.start(validKaInterval);
             callback.expectStarted();
             mWiFiNetworkAgent.disconnect();
-            waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+            mWiFiNetworkAgent.expectDisconnected();
             callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
 
             // ... and that stopping it after that has no adverse effects.
@@ -4150,7 +3896,7 @@
 
         // Reconnect.
         myNet = connectKeepaliveNetwork(lp);
-        mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS);
+        mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
 
         // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
         mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
@@ -4187,7 +3933,7 @@
         // assertFalse(isUdpPortInUse(srcPort2));
 
         mWiFiNetworkAgent.disconnect();
-        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+        mWiFiNetworkAgent.expectDisconnected();
         mWiFiNetworkAgent = null;
     }
 
@@ -4263,7 +4009,7 @@
         testSocketV6.close();
 
         mWiFiNetworkAgent.disconnect();
-        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+        mWiFiNetworkAgent.expectDisconnected();
         mWiFiNetworkAgent = null;
     }
 
@@ -4279,8 +4025,8 @@
         lp.addLinkAddress(new LinkAddress(myIPv4, 25));
         lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
         Network myNet = connectKeepaliveNetwork(lp);
-        mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS);
-        mWiFiNetworkAgent.setStopKeepaliveError(SocketKeepalive.SUCCESS);
+        mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
+        mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS);
 
         TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
 
@@ -4316,7 +4062,7 @@
         // assertFalse(isUdpPortInUse(srcPort));
 
         mWiFiNetworkAgent.disconnect();
-        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+        mWiFiNetworkAgent.expectDisconnected();
         mWiFiNetworkAgent = null;
     }
 
@@ -4379,9 +4125,9 @@
         TestNetworkPinner.pin(mServiceContext, wifiRequest);
         assertNull(mCm.getBoundNetworkForProcess());
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
 
         // When wi-fi connects, expect to be pinned.
@@ -4394,7 +4140,7 @@
         assertNotPinnedToWifi();
 
         // Reconnecting does not cause the pin to come back.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         assertFalse(TestNetworkPinner.awaitPin(100));
         assertNotPinnedToWifi();
@@ -4416,14 +4162,14 @@
 
         // Pinning takes effect even if the pinned network is the default when the pin is set...
         TestNetworkPinner.pin(mServiceContext, wifiRequest);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         assertTrue(TestNetworkPinner.awaitPin(100));
         assertPinnedToWifiWithWifiDefault();
 
         // ... and is maintained even when that network is no longer the default.
         cv = waitForConnectivityBroadcasts(1);
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
         assertPinnedToWifiWithCellDefault();
@@ -4526,7 +4272,7 @@
         ConditionVariable broadcastCV = waitForConnectivityBroadcasts(1);
 
         verifyNoNetwork();
-        MockNetworkAgent wifiAware = new MockNetworkAgent(TRANSPORT_WIFI_AWARE);
+        TestNetworkAgentWrapper wifiAware = new TestNetworkAgentWrapper(TRANSPORT_WIFI_AWARE);
         assertNull(mCm.getActiveNetworkInfo());
 
         Network[] allNetworks = mCm.getAllNetworks();
@@ -4599,7 +4345,7 @@
 
         // Verify direct routes are added when network agent is first registered in
         // ConnectivityService.
-        MockNetworkAgent networkAgent = new MockNetworkAgent(TRANSPORT_WIFI, lp);
+        TestNetworkAgentWrapper networkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp);
         networkAgent.connect(true);
         networkCallback.expectCallback(CallbackRecord.AVAILABLE, networkAgent);
         networkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, networkAgent);
@@ -4631,8 +4377,8 @@
 
     @Test
     public void testStatsIfacesChanged() throws Exception {
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
 
         Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()};
         Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()};
@@ -4708,7 +4454,7 @@
         // Clear any interactions that occur as a result of CS starting up.
         reset(mMockDnsResolver);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         waitForIdle();
         verify(mMockDnsResolver, never()).setResolverConfiguration(any());
         verifyNoMoreInteractions(mMockDnsResolver);
@@ -4791,7 +4537,7 @@
                 .addTransportType(TRANSPORT_CELLULAR).build();
         mCm.requestNetwork(cellRequest, cellNetworkCallback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         waitForIdle();
         // CS tells netd about the empty DNS config for this network.
         verify(mMockDnsResolver, never()).setResolverConfiguration(any());
@@ -4880,7 +4626,7 @@
                 .addTransportType(TRANSPORT_CELLULAR).build();
         mCm.requestNetwork(cellRequest, cellNetworkCallback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         waitForIdle();
         LinkProperties lp = new LinkProperties();
         mCellNetworkAgent.sendLinkProperties(lp);
@@ -5015,7 +4761,7 @@
         mCm.registerDefaultNetworkCallback(defaultCallback);
         defaultCallback.assertNoCallback();
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
 
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -5025,14 +4771,16 @@
         vpnNetworkCallback.assertNoCallback();
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
-        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
         mMockVpn.setUids(ranges);
         // VPN networks do not satisfy the default request and are automatically validated
         // by NetworkMonitor
-        assertFalse(NetworkMonitorUtils.isValidationRequired(vpnNetworkAgent.mNetworkCapabilities));
+        assertFalse(NetworkMonitorUtils.isValidationRequired(
+                vpnNetworkAgent.getNetworkCapabilities()));
         vpnNetworkAgent.setNetworkValid();
 
         vpnNetworkAgent.connect(false);
@@ -5110,13 +4858,14 @@
         final TestNetworkCallback defaultCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultCallback);
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
 
         defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
-        MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -5140,13 +4889,14 @@
         final TestNetworkCallback defaultCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultCallback);
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
 
         defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
-        MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -5170,14 +4920,15 @@
         mCm.registerDefaultNetworkCallback(callback);
 
         // Bring up Ethernet.
-        mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
+        mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
         mEthernetNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
         callback.assertNoCallback();
 
         // Bring up a VPN that has the INTERNET capability, initially unvalidated.
         final int uid = Process.myUid();
-        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -5199,9 +4950,10 @@
         assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED));
         assertTrue(nc.hasCapability(NET_CAPABILITY_INTERNET));
 
-        assertFalse(NetworkMonitorUtils.isValidationRequired(vpnNetworkAgent.mNetworkCapabilities));
+        assertFalse(NetworkMonitorUtils.isValidationRequired(
+                vpnNetworkAgent.getNetworkCapabilities()));
         assertTrue(NetworkMonitorUtils.isPrivateDnsValidationRequired(
-                vpnNetworkAgent.mNetworkCapabilities));
+                vpnNetworkAgent.getNetworkCapabilities()));
 
         // Pretend that the VPN network validates.
         vpnNetworkAgent.setNetworkValid();
@@ -5229,7 +4981,8 @@
         mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
         vpnNetworkCallback.assertNoCallback();
 
-        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -5246,7 +4999,7 @@
         assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
 
         // Connect cell and use it as an underlying network.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
 
         mService.setUnderlyingNetworksForVpn(
@@ -5257,7 +5010,7 @@
                 && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
                 && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.connect(true);
 
@@ -5327,7 +5080,8 @@
         mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
         vpnNetworkCallback.assertNoCallback();
 
-        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -5345,7 +5099,7 @@
         assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
 
         // Connect to Cell; Cell is the default network.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
 
         vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
@@ -5354,7 +5108,7 @@
                 && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
 
         // Connect to WiFi; WiFi is the new default.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.connect(true);
 
@@ -5382,7 +5136,7 @@
     public void testIsActiveNetworkMeteredOverWifi() throws Exception {
         // Returns true by default when no network is available.
         assertTrue(mCm.isActiveNetworkMetered());
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
@@ -5394,7 +5148,7 @@
     public void testIsActiveNetworkMeteredOverCell() throws Exception {
         // Returns true by default when no network is available.
         assertTrue(mCm.isActiveNetworkMetered());
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
         mCellNetworkAgent.connect(true);
         waitForIdle();
@@ -5406,14 +5160,15 @@
     public void testIsActiveNetworkMeteredOverVpnTrackingPlatformDefault() throws Exception {
         // Returns true by default when no network is available.
         assertTrue(mCm.isActiveNetworkMetered());
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
         mCellNetworkAgent.connect(true);
         waitForIdle();
         assertTrue(mCm.isActiveNetworkMetered());
 
         // Connect VPN network. By default it is using current default network (Cell).
-        MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         final int uid = Process.myUid();
         ranges.add(new UidRange(uid, uid));
@@ -5429,7 +5184,7 @@
         assertTrue(mCm.isActiveNetworkMetered());
 
         // Connect WiFi.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
@@ -5460,20 +5215,21 @@
    public void testIsActiveNetworkMeteredOverVpnSpecifyingUnderlyingNetworks() throws Exception {
         // Returns true by default when no network is available.
         assertTrue(mCm.isActiveNetworkMetered());
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
         mCellNetworkAgent.connect(true);
         waitForIdle();
         assertTrue(mCm.isActiveNetworkMetered());
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
         assertFalse(mCm.isActiveNetworkMetered());
 
         // Connect VPN network.
-        MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         final int uid = Process.myUid();
         ranges.add(new UidRange(uid, uid));
@@ -5531,14 +5287,15 @@
     public void testIsActiveNetworkMeteredOverAlwaysMeteredVpn() throws Exception {
         // Returns true by default when no network is available.
         assertTrue(mCm.isActiveNetworkMetered());
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
         assertFalse(mCm.isActiveNetworkMetered());
 
         // Connect VPN network.
-        MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         final int uid = Process.myUid();
         ranges.add(new UidRange(uid, uid));
@@ -5582,21 +5339,21 @@
                 .build();
         mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
 
-        mService.setUidRulesChanged(RULE_REJECT_ALL);
+        setUidRulesChanged(RULE_REJECT_ALL);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
 
         // ConnectivityService should cache it not to invoke the callback again.
-        mService.setUidRulesChanged(RULE_REJECT_METERED);
+        setUidRulesChanged(RULE_REJECT_METERED);
         cellNetworkCallback.assertNoCallback();
 
-        mService.setUidRulesChanged(RULE_NONE);
+        setUidRulesChanged(RULE_NONE);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
 
-        mService.setUidRulesChanged(RULE_REJECT_METERED);
+        setUidRulesChanged(RULE_REJECT_METERED);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
 
         // Restrict the network based on UID rule and NOT_METERED capability change.
@@ -5607,18 +5364,18 @@
         cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
                 mCellNetworkAgent);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
-        mService.setUidRulesChanged(RULE_ALLOW_METERED);
+        setUidRulesChanged(RULE_ALLOW_METERED);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
 
-        mService.setUidRulesChanged(RULE_NONE);
+        setUidRulesChanged(RULE_NONE);
         cellNetworkCallback.assertNoCallback();
 
         // Restrict the network based on BackgroundRestricted.
-        mService.setRestrictBackgroundChanged(true);
+        setRestrictBackgroundChanged(true);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
-        mService.setRestrictBackgroundChanged(true);
+        setRestrictBackgroundChanged(true);
         cellNetworkCallback.assertNoCallback();
-        mService.setRestrictBackgroundChanged(false);
+        setRestrictBackgroundChanged(false);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
         cellNetworkCallback.assertNoCallback();
 
@@ -5631,18 +5388,18 @@
         mCm.registerDefaultNetworkCallback(defaultCallback);
 
         // No Networkcallbacks invoked before any network is active.
-        mService.setUidRulesChanged(RULE_REJECT_ALL);
-        mService.setUidRulesChanged(RULE_NONE);
-        mService.setUidRulesChanged(RULE_REJECT_METERED);
+        setUidRulesChanged(RULE_REJECT_ALL);
+        setUidRulesChanged(RULE_NONE);
+        setUidRulesChanged(RULE_REJECT_METERED);
         defaultCallback.assertNoCallback();
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
         defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellNetworkAgent);
 
         // Allow to use the network after switching to NOT_METERED network.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
         mWiFiNetworkAgent.connect(true);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -5658,8 +5415,8 @@
         defaultCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
 
         // Verify there's no Networkcallbacks invoked after data saver on/off.
-        mService.setRestrictBackgroundChanged(true);
-        mService.setRestrictBackgroundChanged(false);
+        setRestrictBackgroundChanged(true);
+        setRestrictBackgroundChanged(false);
         defaultCallback.assertNoCallback();
 
         mCellNetworkAgent.disconnect();
@@ -5709,7 +5466,7 @@
         mCm.registerNetworkCallback(networkRequest, networkCallback);
 
         // Prepare ipv6 only link properties.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         final int cellNetId = mCellNetworkAgent.getNetwork().netId;
         final LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
@@ -5756,7 +5513,7 @@
         verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
 
         // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
-        Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
+        Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent);
         assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix());
         mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
                 kNat64PrefixString, 96);
@@ -5863,7 +5620,7 @@
                 .build();
         mCm.registerNetworkCallback(networkRequest, networkCallback);
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         final LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
         mCellNetworkAgent.sendLinkProperties(cellLp);
@@ -5873,7 +5630,7 @@
         verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
                 eq(ConnectivityManager.TYPE_MOBILE));
 
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         final LinkProperties wifiLp = new LinkProperties();
         wifiLp.setInterfaceName(WIFI_IFNAME);
         mWiFiNetworkAgent.sendLinkProperties(wifiLp);
@@ -5898,7 +5655,7 @@
                 eq(ConnectivityManager.TYPE_MOBILE));
 
         // reconnect wifi
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         wifiLp.setInterfaceName(WIFI_IFNAME);
         mWiFiNetworkAgent.sendLinkProperties(wifiLp);
         mWiFiNetworkAgent.connect(true);
@@ -5944,7 +5701,7 @@
     public void testTcpBufferReset() throws Exception {
         final String testTcpBufferSizes = "1,2,3,4,5,6";
 
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         reset(mMockNetd);
         // Switching default network updates TCP buffer sizes.
         mCellNetworkAgent.connect(false);
@@ -5960,7 +5717,7 @@
     @Test
     public void testGetGlobalProxyForNetwork() throws Exception {
         final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         final Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
         when(mService.mProxyTracker.getGlobalProxy()).thenReturn(testProxyInfo);
         assertEquals(testProxyInfo, mService.getProxyForNetwork(wifiNetwork));
@@ -5969,7 +5726,7 @@
     @Test
     public void testGetProxyForActiveNetwork() throws Exception {
         final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
         assertNull(mService.getProxyForNetwork(null));
@@ -5988,14 +5745,15 @@
         final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
 
         // Set up a WiFi network with no proxy
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
         assertNull(mService.getProxyForNetwork(null));
 
         // Set up a VPN network with a proxy
         final int uid = Process.myUid();
-        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setUids(ranges);
@@ -6044,7 +5802,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
         final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
-        final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
+        final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
 
         // Connected VPN should have interface rules set up. There are two expected invocations,
         // one during VPN uid update, one during VPN LinkProperties update
@@ -6070,7 +5828,8 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
         final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
-        final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, Process.SYSTEM_UID, vpnRange);
+        final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(
+                lp, Process.SYSTEM_UID, vpnRange);
 
         // Legacy VPN should not have interface rules set up
         verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
@@ -6085,7 +5844,8 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
         // The uid range needs to cover the test app so the network is visible to it.
         final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
-        final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, Process.SYSTEM_UID, vpnRange);
+        final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(
+                lp, Process.SYSTEM_UID, vpnRange);
 
         // IPv6 unreachable route should not be misinterpreted as a default route
         verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
@@ -6098,7 +5858,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
         final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
-        final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
+        final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
 
         // Connected VPN should have interface rules set up. There are two expected invocations,
         // one during VPN uid update, one during VPN LinkProperties update
@@ -6147,7 +5907,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
         final UidRange vpnRange = UidRange.createForUser(VPN_USER);
-        final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID,
+        final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID,
                 Collections.singleton(vpnRange));
 
         reset(mMockNetd);
@@ -6169,9 +5929,10 @@
     }
 
 
-    private MockNetworkAgent establishVpn(LinkProperties lp, int establishingUid,
+    private TestNetworkAgentWrapper establishVpn(LinkProperties lp, int establishingUid,
             Set<UidRange> vpnRange) throws Exception {
-        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN, lp);
+        final TestNetworkAgentWrapper
+                vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp);
         vpnNetworkAgent.getNetworkCapabilities().setEstablishingVpnAppUid(establishingUid);
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
         mMockVpn.connect();
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 54f0816..31aa249 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -468,14 +468,12 @@
     }
     if (platformVersionName) {
       printer->Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data()));
-    }
-    if (platformVersionNameInt) {
+    } else if (platformVersionNameInt) {
       printer->Print(StringPrintf(" platformBuildVersionName='%d'", *platformVersionNameInt));
     }
     if (platformVersionCode) {
       printer->Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data()));
-    }
-    if (platformVersionCodeInt) {
+    } else if (platformVersionCodeInt) {
       printer->Print(StringPrintf(" platformBuildVersionCode='%d'", *platformVersionCodeInt));
     }
     if (compilesdkVersion) {
diff --git a/tools/aapt2/optimize/ResourcePathShortener.cpp b/tools/aapt2/optimize/ResourcePathShortener.cpp
index 7f5d104..7ff9bf5 100644
--- a/tools/aapt2/optimize/ResourcePathShortener.cpp
+++ b/tools/aapt2/optimize/ResourcePathShortener.cpp
@@ -16,6 +16,7 @@
 
 #include "optimize/ResourcePathShortener.h"
 
+#include <set>
 #include <unordered_set>
 
 #include "androidfw/StringPiece.h"
@@ -71,10 +72,19 @@
   return shortened_path;
 }
 
+// implement custom comparator of FileReference pointers so as to use the
+// underlying filepath as key rather than the integer address. This is to ensure
+// determinism of output for colliding files.
+struct PathComparator {
+    bool operator() (const FileReference* lhs, const FileReference* rhs) const {
+        return lhs->path->compare(*rhs->path);
+    }
+};
+
 bool ResourcePathShortener::Consume(IAaptContext* context, ResourceTable* table) {
   // used to detect collisions
   std::unordered_set<std::string> shortened_paths;
-  std::unordered_set<FileReference*> file_refs;
+  std::set<FileReference*, PathComparator> file_refs;
   for (auto& package : table->packages) {
     for (auto& type : package->types) {
       for (auto& entry : type->entries) {
diff --git a/tools/aapt2/optimize/ResourcePathShortener_test.cpp b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
index 1f45694..f5a02be 100644
--- a/tools/aapt2/optimize/ResourcePathShortener_test.cpp
+++ b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
@@ -29,6 +29,14 @@
   return android::StringPiece(iter, path.end() - iter);
 }
 
+void FillTable(aapt::test::ResourceTableBuilder& builder, int start, int end) {
+  for (int i=start; i<end; i++) {
+    builder.AddFileReference(
+        "android:drawable/xmlfile" + std::to_string(i),
+        "res/drawable/xmlfile" + std::to_string(i) + ".xml");
+  }
+}
+
 namespace aapt {
 
 TEST(ResourcePathShortenerTest, FileRefPathsChangedInResourceTable) {
@@ -114,4 +122,45 @@
   EXPECT_THAT(GetExtension(path_map[original_png_path]), Eq(android::StringPiece(".png")));
 }
 
+TEST(ResourcePathShortenerTest, DeterministicallyHandleCollisions) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+  // 4000 resources is the limit at which the hash space is expanded to 3
+  // letters to reduce collisions, we want as many collisions as possible thus
+  // N-1.
+  const auto kNumResources = 3999;
+  const auto kNumTries = 5;
+
+  test::ResourceTableBuilder builder1;
+  FillTable(builder1, 0, kNumResources);
+  std::unique_ptr<ResourceTable> table1 = builder1.Build();
+  std::map<std::string, std::string> expected_mapping;
+  ASSERT_TRUE(ResourcePathShortener(expected_mapping).Consume(context.get(), table1.get()));
+
+  // We are trying to ensure lack of non-determinism, it is not simple to prove
+  // a negative, thus we must try the test a few times so that the test itself
+  // is non-flaky. Basically create the pathmap 5 times from the same set of
+  // resources but a different order of addition and then ensure they are always
+  // mapped to the same short path.
+  for (int i=0; i<kNumTries; i++) {
+    test::ResourceTableBuilder builder2;
+    // This loop adds resources to the resource table in the range of
+    // [0:kNumResources).  Adding the file references in different order makes
+    // non-determinism more likely to surface. Thus we add resources
+    // [start_index:kNumResources) first then [0:start_index). We also use a
+    // different start_index each run.
+    int start_index = (kNumResources/kNumTries)*i;
+    FillTable(builder2, start_index, kNumResources);
+    FillTable(builder2, 0, start_index);
+    std::unique_ptr<ResourceTable> table2 = builder2.Build();
+
+    std::map<std::string, std::string> actual_mapping;
+    ASSERT_TRUE(ResourcePathShortener(actual_mapping).Consume(context.get(), table2.get()));
+
+    for (auto& item : actual_mapping) {
+      ASSERT_THAT(expected_mapping[item.first], Eq(item.second));
+    }
+  }
+}
+
 }   // namespace aapt
diff --git a/tools/codegen/src/com/android/codegen/ClassInfo.kt b/tools/codegen/src/com/android/codegen/ClassInfo.kt
index 7ee79f6..5061be2 100644
--- a/tools/codegen/src/com/android/codegen/ClassInfo.kt
+++ b/tools/codegen/src/com/android/codegen/ClassInfo.kt
@@ -1,30 +1,39 @@
 package com.android.codegen
 
-import com.github.javaparser.JavaParser
 import com.github.javaparser.ParseProblemException
+import com.github.javaparser.ParseResult
+import com.github.javaparser.ast.CompilationUnit
 import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
 
 open class ClassInfo(val sourceLines: List<String>) {
 
     private val userSourceCode = (sourceLines + "}").joinToString("\n")
-    val fileAst = try {
-        JavaParser.parse(userSourceCode)!!
+    val fileAst: CompilationUnit = try {
+        JAVA_PARSER.parse(userSourceCode).throwIfFailed()
     } catch (e: ParseProblemException) {
-        throw RuntimeException("Failed to parse code:\n" +
+        throw parseFailed(cause = e)
+    }
+
+    fun <T> ParseResult<T>.throwIfFailed(): T {
+        if (problems.isNotEmpty()) {
+            throw parseFailed(
+                    desc = this@throwIfFailed.problems.joinToString("\n"),
+                    cause = this@throwIfFailed.problems.mapNotNull { it.cause.orElse(null) }.firstOrNull())
+        }
+        return result.get()
+    }
+
+    private fun parseFailed(cause: Throwable? = null, desc: String = ""): RuntimeException {
+        return RuntimeException("Failed to parse code:\n" +
                 userSourceCode
                         .lines()
                         .mapIndexed { lnNum, ln -> "/*$lnNum*/$ln" }
-                        .joinToString("\n"),
-                e)
+                        .joinToString("\n") + "\n$desc",
+                cause)
     }
-    val classAst = fileAst.types[0] as ClassOrInterfaceDeclaration
 
-    fun hasMethod(name: String, vararg argTypes: String): Boolean {
-        return classAst.methods.any {
-            it.name.asString() == name &&
-                    it.parameters.map { it.type.asString() } == argTypes.toList()
-        }
-    }
+    val classAst = fileAst.types[0] as ClassOrInterfaceDeclaration
+    val nestedClasses = classAst.members.filterIsInstance<ClassOrInterfaceDeclaration>()
 
     val superInterfaces = (fileAst.types[0] as ClassOrInterfaceDeclaration)
             .implementedTypes.map { it.asString() }
@@ -42,8 +51,4 @@
             .filterNot { it.isTransient || it.isStatic }
             .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) }
             .apply { lastOrNull()?.isLast = true }
-    val lazyTransientFields = classAst.fields
-            .filter { it.isTransient && !it.isStatic }
-            .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) }
-            .filter { hasMethod("lazyInit${it.NameUpperCamel}") }
 }
\ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
index 33256b7..1f0d4b8 100644
--- a/tools/codegen/src/com/android/codegen/ClassPrinter.kt
+++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
@@ -1,9 +1,9 @@
 package com.android.codegen
 
+import com.github.javaparser.ast.Modifier
 import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
 import com.github.javaparser.ast.body.TypeDeclaration
-import com.github.javaparser.ast.expr.BooleanLiteralExpr
-import com.github.javaparser.ast.expr.NormalAnnotationExpr
+import com.github.javaparser.ast.expr.*
 import com.github.javaparser.ast.type.ClassOrInterfaceType
 
 /**
@@ -32,10 +32,31 @@
     val PluralOf by lazy { classRef("com.android.internal.util.DataClass.PluralOf") }
     val Each by lazy { classRef("com.android.internal.util.DataClass.Each") }
     val DataClassGenerated by lazy { classRef("com.android.internal.util.DataClass.Generated") }
+    val DataClassSuppressConstDefs by lazy { classRef("com.android.internal.util.DataClass.SuppressConstDefsGeneration") }
+    val DataClassSuppress by lazy { classRef("com.android.internal.util.DataClass.Suppress") }
     val GeneratedMember by lazy { classRef("com.android.internal.util.DataClass.Generated.Member") }
     val Parcelling by lazy { classRef("com.android.internal.util.Parcelling") }
+    val Parcelable by lazy { classRef("android.os.Parcelable") }
     val UnsupportedAppUsage by lazy { classRef("android.annotation.UnsupportedAppUsage") }
 
+    init {
+        val fieldsWithMissingNullablity = fields.filter { field ->
+            !field.isPrimitive
+                    && field.fieldAst.modifiers.none { it.keyword == Modifier.Keyword.TRANSIENT }
+                    && "@$Nullable" !in field.annotations
+                    && "@$NonNull" !in field.annotations
+        }
+        if (fieldsWithMissingNullablity.isNotEmpty()) {
+            abort("Non-primitive fields must have @$Nullable or @$NonNull annotation.\n" +
+                    "Missing nullability annotations on: "
+                    + fieldsWithMissingNullablity.joinToString(", ") { it.name })
+        }
+
+        if (!classAst.isFinal &&
+                classAst.extendedTypes.any { it.nameAsString == Parcelable }) {
+            abort("Parcelable classes must be final")
+        }
+    }
 
     /**
      * Optionally shortens a class reference if there's a corresponding import present
@@ -54,7 +75,7 @@
             return simpleName
         } else {
             val outerClass = pkg.substringAfterLast(".", "")
-            if (outerClass.firstOrNull()?.isUpperCase() ?: false) {
+            if (outerClass.firstOrNull()?.isUpperCase() == true) {
                 return classRef(pkg) + "." + simpleName
             }
         }
@@ -89,7 +110,9 @@
             ?.toMap()
             ?: emptyMap()
 
-    val internalAnnotations = setOf(ParcelWith, DataClassEnum, PluralOf, Each, UnsupportedAppUsage)
+    val internalAnnotations = setOf(ParcelWith, DataClassEnum, PluralOf, UnsupportedAppUsage,
+            DataClassSuppressConstDefs)
+    val knownNonValidationAnnotations = internalAnnotations + Each + Nullable
 
     /**
      * @return whether the given feature is enabled
@@ -99,9 +122,13 @@
         if (cliArgs.contains("--$kebabCase")) return true
 
         val annotationKey = "gen$upperCamelCase"
+        val annotationHiddenKey = "genHidden$upperCamelCase"
         if (dataClassAnnotationFeatures.containsKey(annotationKey)) {
             return dataClassAnnotationFeatures[annotationKey]!!
         }
+        if (dataClassAnnotationFeatures.containsKey(annotationHiddenKey)) {
+            return dataClassAnnotationFeatures[annotationHiddenKey]!!
+        }
 
         if (cliArgs.contains("--all")) return true
         if (hidden) return true
@@ -109,7 +136,9 @@
         return when (this) {
             FeatureFlag.SETTERS ->
                 !FeatureFlag.CONSTRUCTOR() && !FeatureFlag.BUILDER() && fields.any { !it.isFinal }
-            FeatureFlag.BUILDER -> cliArgs.contains(FLAG_BUILDER_PROTECTED_SETTERS) || onByDefault
+            FeatureFlag.BUILDER -> cliArgs.contains(FLAG_BUILDER_PROTECTED_SETTERS)
+                    || fields.any { it.hasDefault }
+                    || onByDefault
             FeatureFlag.CONSTRUCTOR -> !FeatureFlag.BUILDER()
             FeatureFlag.PARCELABLE -> "Parcelable" in superInterfaces
             FeatureFlag.AIDL -> FeatureFlag.PARCELABLE()
@@ -119,11 +148,17 @@
         }
     }
 
-    val FeatureFlag.hidden
-        get(): Boolean = when {
-            cliArgs.contains("--hidden-$kebabCase") -> true
-            this == FeatureFlag.BUILD_UPON -> FeatureFlag.BUILDER.hidden
-            else -> false
+    val FeatureFlag.hidden: Boolean
+        get(): Boolean {
+            val annotationHiddenKey = "genHidden$upperCamelCase"
+            if (dataClassAnnotationFeatures.containsKey(annotationHiddenKey)) {
+                return dataClassAnnotationFeatures[annotationHiddenKey]!!
+            }
+            return when {
+                cliArgs.contains("--hidden-$kebabCase") -> true
+                this == FeatureFlag.BUILD_UPON -> FeatureFlag.BUILDER.hidden
+                else -> false
+            }
         }
 
     var currentIndent = INDENT_SINGLE
@@ -287,6 +322,48 @@
 
     var BuilderClass = CANONICAL_BUILDER_CLASS
     var BuilderType = BuilderClass + genericArgs
+    val customBaseBuilderAst: ClassOrInterfaceDeclaration? by lazy {
+        nestedClasses.find { it.nameAsString == BASE_BUILDER_CLASS }
+    }
+
+    val suppressedMembers by lazy {
+        getSuppressedMembers(classAst)
+    }
+    val builderSuppressedMembers by lazy {
+        getSuppressedMembers(customBaseBuilderAst)
+    }
+
+    private fun getSuppressedMembers(clazz: ClassOrInterfaceDeclaration?): List<String> {
+        return clazz
+                ?.annotations
+                ?.find { it.nameAsString == DataClassSuppress }
+                ?.as_<SingleMemberAnnotationExpr>()
+                ?.memberValue
+                ?.run {
+                    when (this) {
+                        is ArrayInitializerExpr -> values.map { it.asLiteralStringValueExpr().value }
+                        is StringLiteralExpr -> listOf(value)
+                        else -> abort("Can't parse annotation arg: $this")
+                    }
+                }
+                ?: emptyList()
+    }
+
+    fun isMethodGenerationSuppressed(name: String, vararg argTypes: String): Boolean {
+        return name in suppressedMembers || hasMethod(name, *argTypes)
+    }
+
+    fun hasMethod(name: String, vararg argTypes: String): Boolean {
+        return classAst.methods.any {
+            it.name.asString() == name &&
+                    it.parameters.map { it.type.asString() } == argTypes.toList()
+        }
+    }
+
+    val lazyTransientFields = classAst.fields
+            .filter { it.isTransient && !it.isStatic }
+            .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) }
+            .filter { hasMethod("lazyInit${it.NameUpperCamel}") }
 
     init {
         val builderFactoryOverride = classAst.methods.find {
@@ -301,7 +378,7 @@
                 it.nameAsString == CANONICAL_BUILDER_CLASS
             }
             if (builderExtension != null) {
-                BuilderClass = GENERATED_BUILDER_CLASS
+                BuilderClass = BASE_BUILDER_CLASS
                 val tp = (builderExtension as ClassOrInterfaceDeclaration).typeParameters
                 BuilderType = if (tp.isEmpty()) BuilderClass
                 else "$BuilderClass<${tp.map { it.nameAsString }.joinToString(", ")}>"
diff --git a/tools/codegen/src/com/android/codegen/FieldInfo.kt b/tools/codegen/src/com/android/codegen/FieldInfo.kt
index f326fd5..ba00264 100644
--- a/tools/codegen/src/com/android/codegen/FieldInfo.kt
+++ b/tools/codegen/src/com/android/codegen/FieldInfo.kt
@@ -1,6 +1,5 @@
 package com.android.codegen
 
-import com.github.javaparser.JavaParser
 import com.github.javaparser.ast.body.FieldDeclaration
 import com.github.javaparser.ast.expr.ClassExpr
 import com.github.javaparser.ast.expr.Name
@@ -9,7 +8,6 @@
 import com.github.javaparser.ast.type.ArrayType
 import com.github.javaparser.ast.type.ClassOrInterfaceType
 import com.github.javaparser.javadoc.Javadoc
-import java.lang.Long
 
 data class FieldInfo(
     val index: Int,
@@ -85,8 +83,7 @@
             variableAst.initializer.orElse(null)?.let { return it }
             classInfo.classAst.methods.find {
                 it.nameAsString == "default$NameUpperCamel" && it.parameters.isEmpty()
-            }?.run { "$nameAsString()" }?.let { return it }
-            if (FieldClass == "List") return "${classPrinter.memberRef("java.util.Collections.emptyList")}()"
+            }?.run { return "$nameAsString()" }
             return null
         }
     val hasDefault get() = defaultExpr != null
@@ -95,7 +92,7 @@
     // Generic args
     val isArray = Type.endsWith("[]")
     val isList = FieldClass == "List" || FieldClass == "ArrayList"
-    val fieldBit = "0x${Long.toHexString(1L shl index)}"
+    val fieldBit = bitAtExpr(index)
     var isLast = false
     val isFinal = fieldAst.isFinal
     val fieldTypeGenegicArgs = when (typeAst) {
@@ -116,8 +113,9 @@
             classPrinter {
                 fieldAst.addAnnotation(SingleMemberAnnotationExpr(
                         Name(ParcelWith),
-                        ClassExpr(JavaParser.parseClassOrInterfaceType(
-                                "$Parcelling.BuiltIn.For$FieldClass"))))
+                        ClassExpr(JAVA_PARSER
+                                .parseClassOrInterfaceType("$Parcelling.BuiltIn.For$FieldClass")
+                                .throwIfFailed())))
             }
         }
         fieldAst.annotations.map { it.removeComment().toString() }
@@ -143,8 +141,10 @@
     }
     val annotationsAndType by lazy { (annotationsNoInternal + Type).joinToString(" ") }
     val sParcelling by lazy { customParcellingClass?.let { "sParcellingFor$NameUpperCamel" } }
+
+    val SetterParamType = if (isArray) "$FieldInnerType..." else Type
     val annotatedTypeForSetterParam by lazy {
-        (annotationsNoInternal + if (isArray) "$FieldInnerType..." else Type).joinToString(" ")
+        (annotationsNoInternal + SetterParamType).joinToString(" ")
     }
 
     // Utilities
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index ab64f4e..914e475 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -1,6 +1,7 @@
 package com.android.codegen
 
 import com.github.javaparser.ast.body.FieldDeclaration
+import com.github.javaparser.ast.body.MethodDeclaration
 import com.github.javaparser.ast.body.VariableDeclarator
 import com.github.javaparser.ast.expr.*
 import java.io.File
@@ -16,7 +17,7 @@
             val isLiteral = initializer is LiteralExpr
                     || (initializer is UnaryExpr && initializer.expression is LiteralExpr)
             isLiteral && variable.type.asString() in listOf("int", "String")
-        }
+        } && it.annotations.none { it.nameAsString == DataClassSuppressConstDefs }
     }.flatMap { field -> field.variables.map { it to field } }
     val intConsts = consts.filter { it.first.type.asString() == "int" }
     val strConsts = consts.filter { it.first.type.asString() == "String" }
@@ -67,12 +68,15 @@
         }
     }
 
-    val visibility = if (consts[0].second.isPublic) "public" else "/* package-*/"
+    val visibility = if (consts[0].second.isPublic) "public" else "/* package-private */"
 
     val Retention = classRef("java.lang.annotation.Retention")
     val RetentionPolicySource = memberRef("java.lang.annotation.RetentionPolicy.SOURCE")
     val ConstDef = classRef("android.annotation.${type.capitalize()}Def")
 
+    if (FeatureFlag.CONST_DEFS.hidden) {
+        +"/** @hide */"
+    }
     "@$ConstDef(${if_(flag, "flag = true, ")}prefix = \"${prefix}_\", value = {" {
         names.forEachLastAware { name, isLast ->
             +"$name${if_(!isLast, ",")}"
@@ -84,6 +88,9 @@
     +""
 
     if (type == "int") {
+        if (FeatureFlag.CONST_DEFS.hidden) {
+            +"/** @hide */"
+        }
         +GENERATED_MEMBER_HEADER
         val methodDefLine = "$visibility static String ${AnnotationName.decapitalize()}ToString(" +
                 "@$AnnotationName int value)"
@@ -131,7 +138,7 @@
 fun ClassPrinter.generateWithers() {
     fields.forEachApply {
         val metodName = "with$NameUpperCamel"
-        if (!hasMethod(metodName, Type)) {
+        if (!isMethodGenerationSuppressed(metodName, Type)) {
             generateFieldJavadoc(forceHide = FeatureFlag.WITHERS.hidden)
             """@$NonNull
                         $GENERATED_MEMBER_HEADER
@@ -171,7 +178,7 @@
  * ```
  */
 fun ClassPrinter.generateBuildUpon() {
-    if (hasMethod("buildUpon")) return
+    if (isMethodGenerationSuppressed("buildUpon")) return
 
     +"/**"
     +" * Provides an instance of {@link $BuilderClass} with state corresponding to this instance."
@@ -195,7 +202,15 @@
     val constructorVisibility = if (BuilderClass == CANONICAL_BUILDER_CLASS)
         "public" else "/* package-*/"
 
-    val OneTimeUseBuilder = classRef("android.provider.OneTimeUseBuilder")
+    val providedSubclassAst = nestedClasses.find {
+        it.extendedTypes.any { it.nameAsString == BASE_BUILDER_CLASS }
+    }
+
+    val BuilderSupertype = if (customBaseBuilderAst != null) {
+        customBaseBuilderAst!!.nameAsString
+    } else {
+        "Object"
+    }
 
     +"/**"
     +" * A builder for {@link $ClassName}"
@@ -203,104 +218,155 @@
     +" */"
     +"@SuppressWarnings(\"WeakerAccess\")"
     +GENERATED_MEMBER_HEADER
-    "public static class $BuilderClass$genericArgs" {
-        +"extends $OneTimeUseBuilder<$ClassType>"
+    !"public static class $BuilderClass$genericArgs"
+    if (BuilderSupertype != "Object") {
+        appendSameLine(" extends $BuilderSupertype")
     }
     " {" {
 
         +""
         fields.forEachApply {
-            +"protected $annotationsAndType $name;"
+            +"private $annotationsAndType $name;"
         }
         +""
-        +"protected long mBuilderFieldsSet = 0L;"
+        +"private long mBuilderFieldsSet = 0L;"
         +""
-        +"$constructorVisibility $BuilderClass() {};"
-        +""
+
+        val requiredFields = fields.filter { !it.hasDefault }
+
+        generateConstructorJavadoc(
+                fields = requiredFields,
+                ClassName = BuilderClass,
+                hidden = false)
+        "$constructorVisibility $BuilderClass(" {
+            requiredFields.forEachLastAware { field, isLast ->
+                +"${field.annotationsAndType} ${field._name}${if_(!isLast, ",")}"
+            }
+        }; " {" {
+            requiredFields.forEachApply {
+                generateSetFrom(_name)
+            }
+        }
 
         generateBuilderSetters(setterVisibility)
 
         generateBuilderBuild()
 
+        "private void checkNotUsed() {" {
+            "if ((mBuilderFieldsSet & ${bitAtExpr(fields.size)}) != 0)" {
+                "throw new IllegalStateException(" {
+                    +"\"This Builder should not be reused. Use a new Builder instance instead\""
+                }
+                +";"
+            }
+        }
+
         rmEmptyLine()
     }
 }
 
+private fun ClassPrinter.generateBuilderMethod(
+        defVisibility: String,
+        name: String,
+        ParamAnnotations: String? = null,
+        paramTypes: List<String>,
+        paramNames: List<String> = listOf("value"),
+        genJavadoc: ClassPrinter.() -> Unit,
+        genBody: ClassPrinter.() -> Unit) {
+
+    val providedMethod = customBaseBuilderAst?.members?.find {
+        it is MethodDeclaration
+                && it.nameAsString == name
+                && it.parameters.map { it.typeAsString } == paramTypes.toTypedArray().toList()
+    } as? MethodDeclaration
+
+    if ((providedMethod == null || providedMethod.isAbstract)
+            && name !in builderSuppressedMembers) {
+        val visibility = providedMethod?.visibility?.asString() ?: defVisibility
+        val ReturnType = providedMethod?.typeAsString ?: CANONICAL_BUILDER_CLASS
+        val Annotations = providedMethod?.annotations?.joinToString("\n")
+
+        genJavadoc()
+        +GENERATED_MEMBER_HEADER
+        if (providedMethod?.isAbstract == true) +"@Override"
+        if (!Annotations.isNullOrEmpty()) +Annotations
+        "$visibility @$NonNull $ReturnType $name(${if_(!ParamAnnotations.isNullOrEmpty(), "$ParamAnnotations ")}${
+                paramTypes.zip(paramNames).joinToString(", ") { (Type, paramName) -> "$Type $paramName" }
+        })" {
+            genBody()
+        }
+    }
+}
+
 private fun ClassPrinter.generateBuilderSetters(visibility: String) {
 
     fields.forEachApply {
         val maybeCast =
                 if_(BuilderClass != CANONICAL_BUILDER_CLASS, " ($CANONICAL_BUILDER_CLASS)")
 
-        generateFieldJavadoc()
-        +GENERATED_MEMBER_HEADER
-        "$visibility $CANONICAL_BUILDER_CLASS set$NameUpperCamel($annotatedTypeForSetterParam value)" {
+        val setterName = "set$NameUpperCamel"
+
+        generateBuilderMethod(
+                name = setterName,
+                defVisibility = visibility,
+                ParamAnnotations = annotationsNoInternal.joinToString(" "),
+                paramTypes = listOf(SetterParamType),
+                genJavadoc = { generateFieldJavadoc() }) {
             +"checkNotUsed();"
             +"mBuilderFieldsSet |= $fieldBit;"
             +"$name = value;"
             +"return$maybeCast this;"
         }
 
+        val javadocSeeSetter = "/** @see #$setterName */"
+        val adderName = "add$SingularName"
 
-        val javadocSeeSetter = "/** @see #set$NameUpperCamel */"
         val singularNameCustomizationHint = if (SingularNameOrNull == null) {
             "// You can refine this method's name by providing item's singular name, e.g.:\n" +
                     "// @DataClass.PluralOf(\"item\")) mItems = ...\n\n"
         } else ""
 
-        if (isList && FieldInnerType != null) {
 
-            +javadocSeeSetter
-            +GENERATED_MEMBER_HEADER
-            "$visibility $CANONICAL_BUILDER_CLASS add$SingularName(@$NonNull $FieldInnerType value)" {
+        if (isList && FieldInnerType != null) {
+            generateBuilderMethod(
+                    name = adderName,
+                    defVisibility = visibility,
+                    paramTypes = listOf(FieldInnerType),
+                    genJavadoc = { +javadocSeeSetter }) {
+
                 !singularNameCustomizationHint
-                +"if ($name == null) set$NameUpperCamel(new $ArrayList<>());"
+                +"if ($name == null) $setterName(new $ArrayList<>());"
                 +"$name.add(value);"
                 +"return$maybeCast this;"
             }
         }
 
         if (Type.contains("Map<")) {
-            val (Key, Value) = fieldTypeGenegicArgs
-
-            +javadocSeeSetter
-            +GENERATED_MEMBER_HEADER
-            "$visibility $CANONICAL_BUILDER_CLASS add$SingularName($Key key, $Value value)" {
+            generateBuilderMethod(
+                    name = adderName,
+                    defVisibility = visibility,
+                    paramTypes = fieldTypeGenegicArgs,
+                    paramNames = listOf("key", "value"),
+                    genJavadoc = { +javadocSeeSetter }) {
                 !singularNameCustomizationHint
-                +"if ($name == null) set$NameUpperCamel(new $LinkedHashMap());"
+                +"if ($name == null) $setterName(new $LinkedHashMap());"
                 +"$name.put(key, value);"
                 +"return$maybeCast this;"
             }
         }
-
-        if (Type == "boolean") {
-            +javadocSeeSetter
-            +GENERATED_MEMBER_HEADER
-            "$visibility $CANONICAL_BUILDER_CLASS mark$NameUpperCamel()" {
-                +"return set$NameUpperCamel(true);"
-            }
-
-            +javadocSeeSetter
-            +GENERATED_MEMBER_HEADER
-            "$visibility $CANONICAL_BUILDER_CLASS markNot$NameUpperCamel()" {
-                +"return set$NameUpperCamel(false);"
-            }
-        }
     }
 }
 
 private fun ClassPrinter.generateBuilderBuild() {
     +"/** Builds the instance. This builder should not be touched after calling this! */"
     "public $ClassType build()" {
-        +"markUsed();"
+        +"checkNotUsed();"
+        +"mBuilderFieldsSet |= ${bitAtExpr(fields.size)}; // Mark builder used"
+        +""
         fields.forEachApply {
-            if (!isNullable || hasDefault) {
+            if (hasDefault) {
                 "if ((mBuilderFieldsSet & $fieldBit) == 0)" {
-                    if (!isNullable && !hasDefault) {
-                        +"throw new IllegalStateException(\"Required field not set: $nameLowerCamel\");"
-                    } else {
-                        +"$name = $defaultExpr;"
-                    }
+                    +"$name = $defaultExpr;"
                 }
             }
         }
@@ -348,7 +414,7 @@
     }
 
     val Parcel = classRef("android.os.Parcel")
-    if (!hasMethod("writeToParcel", Parcel, "int")) {
+    if (!isMethodGenerationSuppressed("writeToParcel", Parcel, "int")) {
         +"@Override"
         +GENERATED_MEMBER_HEADER
         "public void writeToParcel($Parcel dest, int flags)" {
@@ -390,7 +456,7 @@
         }
     }
 
-    if (!hasMethod("describeContents")) {
+    if (!isMethodGenerationSuppressed("describeContents")) {
         +"@Override"
         +GENERATED_MEMBER_HEADER
         +"public int describeContents() { return 0; }"
@@ -442,8 +508,6 @@
                             FieldClass.endsWith("Map") -> "new $LinkedHashMap<>()"
                             FieldClass == "List" || FieldClass == "ArrayList" ->
                                 "new ${classRef("java.util.ArrayList")}<>()"
-//                            isArray && FieldInnerType in (PRIMITIVE_TYPES + "String") ->
-//                                "new $FieldInnerType[in.readInt()]"
                             else -> ""
                         }
                         val passContainer = containerInitExpr.isNotEmpty()
@@ -519,7 +583,7 @@
 }
 
 fun ClassPrinter.generateEqualsHashcode() {
-    if (!hasMethod("equals", "Object")) {
+    if (!isMethodGenerationSuppressed("equals", "Object")) {
         +"@Override"
         +GENERATED_MEMBER_HEADER
         "public boolean equals(Object o)" {
@@ -546,7 +610,7 @@
         }
     }
 
-    if (!hasMethod("hashCode")) {
+    if (!isMethodGenerationSuppressed("hashCode")) {
         +"@Override"
         +GENERATED_MEMBER_HEADER
         "public int hashCode()" {
@@ -572,7 +636,7 @@
 
 //TODO support IntDef flags?
 fun ClassPrinter.generateToString() {
-    if (!hasMethod("toString")) {
+    if (!isMethodGenerationSuppressed("toString")) {
         +"@Override"
         +GENERATED_MEMBER_HEADER
         "public String toString()" {
@@ -599,7 +663,7 @@
 
 fun ClassPrinter.generateSetters() {
     fields.forEachApply {
-        if (!hasMethod("set$NameUpperCamel", Type)
+        if (!isMethodGenerationSuppressed("set$NameUpperCamel", Type)
                 && !fieldAst.isPublic
                 && !isFinal) {
 
@@ -618,7 +682,7 @@
         val methodPrefix = if (Type == "boolean") "is" else "get"
         val methodName = methodPrefix + NameUpperCamel
 
-        if (!hasMethod(methodName) && !fieldAst.isPublic) {
+        if (!isMethodGenerationSuppressed(methodName) && !fieldAst.isPublic) {
 
             generateFieldJavadoc(forceHide = FeatureFlag.GETTERS.hidden)
             +GENERATED_MEMBER_HEADER
@@ -662,23 +726,8 @@
 }
 
 fun FieldInfo.generateSetFrom(source: String) = classPrinter {
-    !"$name = "
-    if (Type in PRIMITIVE_TYPES || mayBeNull) {
-        +"$source;"
-    } else if (defaultExpr != null) {
-        "$source != null" {
-            +"? $source"
-            +": $defaultExpr;"
-        }
-    } else {
-        val checkNotNull = memberRef("com.android.internal.util.Preconditions.checkNotNull")
-        +"$checkNotNull($source);"
-    }
-    if (isNonEmpty) {
-        "if ($isEmptyExpr)" {
-            +"throw new IllegalArgumentException(\"$nameLowerCamel cannot be empty\");"
-        }
-    }
+    +"$name = $source;"
+    generateFieldValidation(field = this@generateSetFrom)
 }
 
 fun ClassPrinter.generateConstructor(visibility: String = "public") {
@@ -697,15 +746,18 @@
             generateSetFrom(nameLowerCamel)
         }
 
-        generateStateValidation()
-
         generateOnConstructedCallback()
     }
 }
 
-private fun ClassPrinter.generateConstructorJavadoc() {
+private fun ClassPrinter.generateConstructorJavadoc(
+        fields: List<FieldInfo> = this.fields,
+        ClassName: String = this.ClassName,
+        hidden: Boolean = FeatureFlag.CONSTRUCTOR.hidden) {
     if (fields.all { it.javadoc == null } && !FeatureFlag.CONSTRUCTOR.hidden) return
     +"/**"
+    +" * Creates a new $ClassName."
+    +" *"
     fields.filter { it.javadoc != null }.forEachApply {
         javadocTextNoAnnotationLines?.apply {
             +" * @param $nameLowerCamel"
@@ -718,87 +770,97 @@
     +" */"
 }
 
-private fun ClassPrinter.generateStateValidation() {
-    val Size = classRef("android.annotation.Size")
-    val knownNonValidationAnnotations = internalAnnotations + Nullable
-
-    val validate = memberRef("com.android.internal.util.AnnotationValidations.validate")
-    fun appendValidateCall(annotation: AnnotationExpr, valueToValidate: String) {
-        "$validate(" {
-            !"${annotation.nameAsString}.class, null, $valueToValidate"
-            val params = when (annotation) {
-                is MarkerAnnotationExpr -> emptyMap()
-                is SingleMemberAnnotationExpr -> mapOf("value" to annotation.memberValue)
-                is NormalAnnotationExpr ->
-                    annotation.pairs.map { it.name.asString() to it.value }.toMap()
-                else -> throw IllegalStateException()
-            }
-            params.forEach { name, value ->
-                !",\n\"$name\", $value"
+private fun ClassPrinter.appendLinesWithContinuationIndent(text: String) {
+    val lines = text.lines()
+    if (lines.isNotEmpty()) {
+        !lines[0]
+    }
+    if (lines.size >= 2) {
+        "" {
+            lines.drop(1).forEach {
+                +it
             }
         }
-        +";"
     }
+}
 
-    fields.forEachApply {
-        if (intOrStringDef != null) {
-            if (intOrStringDef!!.type == ConstDef.Type.INT_FLAGS) {
-                +""
-                +"//noinspection PointlessBitwiseExpression"
-                "$Preconditions.checkFlagsArgument(" {
-                    "$name, 0" {
-                        intOrStringDef!!.CONST_NAMES.forEach {
-                            +"| $it"
+private fun ClassPrinter.generateFieldValidation(field: FieldInfo) = field.run {
+    if (isNonEmpty) {
+        "if ($isEmptyExpr)" {
+            +"throw new IllegalArgumentException(\"$nameLowerCamel cannot be empty\");"
+        }
+    }
+    if (intOrStringDef != null) {
+        if (intOrStringDef!!.type == ConstDef.Type.INT_FLAGS) {
+            +""
+            "$Preconditions.checkFlagsArgument(" {
+                +"$name, "
+                appendLinesWithContinuationIndent(intOrStringDef!!.CONST_NAMES.joinToString("\n| "))
+            }
+            +";"
+        } else {
+            +""
+            !"if ("
+            appendLinesWithContinuationIndent(intOrStringDef!!.CONST_NAMES.joinToString("\n&& ") {
+                "!(${isEqualToExpr(it)})"
+            })
+            rmEmptyLine(); ") {" {
+                "throw new ${classRef<IllegalArgumentException>()}(" {
+                    "\"$nameLowerCamel was \" + $internalGetter + \" but must be one of: \"" {
+
+                        intOrStringDef!!.CONST_NAMES.forEachLastAware { CONST_NAME, isLast ->
+                            +"""+ "$CONST_NAME(" + $CONST_NAME + ")${if_(!isLast, ", ")}""""
                         }
                     }
                 }
                 +";"
-            } else {
-                +""
-                +"//noinspection PointlessBooleanExpression"
-                "if (true" {
-                    intOrStringDef!!.CONST_NAMES.forEach { CONST_NAME ->
-                        +"&& !(${isEqualToExpr(CONST_NAME)})"
-                    }
-                }; rmEmptyLine(); ") {" {
-                    "throw new ${classRef<IllegalArgumentException>()}(" {
-                        "\"$nameLowerCamel was \" + $internalGetter + \" but must be one of: \"" {
-
-                            intOrStringDef!!.CONST_NAMES.forEachLastAware { CONST_NAME, isLast ->
-                                +"""+ "$CONST_NAME(" + $CONST_NAME + ")${if_(!isLast, ", ")}""""
-                            }
-                        }
-                    }
-                    +";"
-                }
-            }
-        }
-
-        val eachLine = fieldAst.annotations.find { it.nameAsString == Each }?.range?.orElse(null)?.end?.line
-        val perElementValidations = if (eachLine == null) emptyList() else fieldAst.annotations.filter {
-            it.nameAsString != Each &&
-                it.range.orElse(null)?.begin?.line?.let { it >= eachLine } ?: false
-        }
-
-        fieldAst.annotations.filterNot {
-            it.nameAsString == intOrStringDef?.AnnotationName
-                    || it.nameAsString in knownNonValidationAnnotations
-                    || it in perElementValidations
-        }.forEach { annotation ->
-            appendValidateCall(annotation,
-                    valueToValidate = if (annotation.nameAsString == Size) sizeExpr else name)
-        }
-
-        if (perElementValidations.isNotEmpty()) {
-            +"int ${nameLowerCamel}Size = $sizeExpr;"
-            "for (int i = 0; i < ${nameLowerCamel}Size; i++) {" {
-                perElementValidations.forEach { annotation ->
-                    appendValidateCall(annotation,
-                            valueToValidate = elemAtIndexExpr("i"))
-                }
             }
         }
     }
+
+    val eachLine = fieldAst.annotations.find { it.nameAsString == Each }?.range?.orElse(null)?.end?.line
+    val perElementValidations = if (eachLine == null) emptyList() else fieldAst.annotations.filter {
+        it.nameAsString != Each &&
+                it.range.orElse(null)?.begin?.line?.let { it >= eachLine } ?: false
+    }
+
+    val Size = classRef("android.annotation.Size")
+    fieldAst.annotations.filterNot {
+        it.nameAsString == intOrStringDef?.AnnotationName
+                || it.nameAsString in knownNonValidationAnnotations
+                || it in perElementValidations
+    }.forEach { annotation ->
+        appendValidateCall(annotation,
+                valueToValidate = if (annotation.nameAsString == Size) sizeExpr else name)
+    }
+
+    if (perElementValidations.isNotEmpty()) {
+        +"int ${nameLowerCamel}Size = $sizeExpr;"
+        "for (int i = 0; i < ${nameLowerCamel}Size; i++) {" {
+            perElementValidations.forEach { annotation ->
+                appendValidateCall(annotation,
+                        valueToValidate = elemAtIndexExpr("i"))
+            }
+        }
+    }
+}
+
+fun ClassPrinter.appendValidateCall(annotation: AnnotationExpr, valueToValidate: String) {
+    val validate = memberRef("com.android.internal.util.AnnotationValidations.validate")
+    "$validate(" {
+        !"${annotation.nameAsString}.class, null, $valueToValidate"
+        val params = when (annotation) {
+            is MarkerAnnotationExpr -> emptyMap()
+            is SingleMemberAnnotationExpr -> mapOf("value" to annotation.memberValue)
+            is NormalAnnotationExpr ->
+                annotation.pairs.map { it.name.asString() to it.value }.toMap()
+            else -> throw IllegalStateException()
+        }
+        params.forEach { name, value ->
+            !",\n\"$name\", $value"
+        }
+    }
+    +";"
 }
 
 private fun ClassPrinter.generateOnConstructedCallback(prefix: String = "") {
@@ -845,3 +907,15 @@
         }
     }
 }
+
+fun ClassPrinter.generateMetadata(file: File) {
+    "@$DataClassGenerated(" {
+        +"time = ${System.currentTimeMillis()}L,"
+        +"codegenVersion = \"$CODEGEN_VERSION\","
+        +"sourceFile = \"${file.relativeTo(File(System.getenv("ANDROID_BUILD_TOP")))}\","
+        +"inputSignatures = \"${getInputSignatures().joinToString("\\n")}\""
+    }
+    +""
+    +"@Deprecated"
+    +"private void __metadata() {}\n"
+}
\ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt b/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt
index d1dc88f..24cf469 100644
--- a/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt
+++ b/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt
@@ -1,6 +1,6 @@
 package com.android.codegen
 
-import com.github.javaparser.ast.body.TypeDeclaration
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
 import com.github.javaparser.ast.expr.*
 import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations
 import com.github.javaparser.ast.type.ClassOrInterfaceType
@@ -8,9 +8,17 @@
 
 
 fun ClassPrinter.getInputSignatures(): List<String> {
+    return generateInputSignaturesForClass(classAst) +
+            annotationToString(classAst.annotations.find { it.nameAsString == DataClass }) +
+            generateInputSignaturesForClass(customBaseBuilderAst)
+}
+
+private fun ClassPrinter.generateInputSignaturesForClass(classAst: ClassOrInterfaceDeclaration?): List<String> {
+    if (classAst == null) return emptyList()
+
     return classAst.fields.map { fieldAst ->
         buildString {
-            append(fieldAst.modifiers.joinToString(" ") {it.asString()})
+            append(fieldAst.modifiers.joinToString(" ") { it.keyword.asString() })
             append(" ")
             append(annotationsToString(fieldAst))
             append(" ")
@@ -20,7 +28,7 @@
         }
     } + classAst.methods.map { methodAst ->
         buildString {
-            append(methodAst.modifiers.joinToString(" ") {it.asString()})
+            append(methodAst.modifiers.joinToString(" ") { it.keyword.asString() })
             append(" ")
             append(annotationsToString(methodAst))
             append(" ")
@@ -28,19 +36,26 @@
             append(" ")
             append(methodAst.nameAsString)
             append("(")
-            append(methodAst.parameters.joinToString(",") {getFullClassName(it.type)})
+            append(methodAst.parameters.joinToString(",") { getFullClassName(it.type) })
             append(")")
         }
-    }
+    } + ("class ${classAst.nameAsString}" +
+            " extends ${classAst.extendedTypes.map { getFullClassName(it) }.ifEmpty { listOf("java.lang.Object") }.joinToString(", ")}" +
+            " implements [${classAst.implementedTypes.joinToString(", ") { getFullClassName(it) }}]")
 }
 
 private fun ClassPrinter.annotationsToString(annotatedAst: NodeWithAnnotations<*>): String {
-    return annotatedAst.annotations.joinToString(" ") {
-        annotationToString(it)
-    }
+    return annotatedAst
+            .annotations
+            .groupBy { it.nameAsString } // dedupe annotations by name (javaparser bug?)
+            .values
+            .joinToString(" ") {
+                annotationToString(it[0])
+            }
 }
 
-private fun ClassPrinter.annotationToString(ann: AnnotationExpr): String {
+private fun ClassPrinter.annotationToString(ann: AnnotationExpr?): String {
+    if (ann == null) return ""
     return buildString {
         append("@")
         append(getFullClassName(ann.nameAsString))
@@ -78,11 +93,11 @@
 
 private fun ClassPrinter.getFullClassName(type: Type): String {
     return if (type is ClassOrInterfaceType) {
+
         getFullClassName(buildString {
             type.scope.ifPresent { append(it).append(".") }
-            type.isArrayType
             append(type.nameAsString)
-        }) + (type.typeArguments.orElse(null)?.let { args -> args.joinToString(", ") {getFullClassName(it)}}?.let { "<$it>" } ?: "")
+        }) + (type.typeArguments.orElse(null)?.let { args -> args.joinToString(",") {getFullClassName(it)}}?.let { "<$it>" } ?: "")
     } else getFullClassName(type.asString())
 }
 
@@ -100,10 +115,16 @@
     val thisPackagePrefix = fileAst.packageDeclaration.map { it.nameAsString + "." }.orElse("")
     val thisClassPrefix = thisPackagePrefix + classAst.nameAsString + "."
 
-    classAst.childNodes.filterIsInstance<TypeDeclaration<*>>().find {
+    if (classAst.nameAsString == className) return thisPackagePrefix + classAst.nameAsString
+
+    nestedClasses.find {
         it.nameAsString == className
     }?.let { return thisClassPrefix + it.nameAsString }
 
+    if (className == CANONICAL_BUILDER_CLASS || className == BASE_BUILDER_CLASS) {
+        return thisClassPrefix + className
+    }
+
     constDefs.find { it.AnnotationName == className }?.let { return thisClassPrefix + className }
 
     if (tryOrNull { Class.forName("java.lang.$className") } != null) {
diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt
index 8fafa7c..0f932f3 100755
--- a/tools/codegen/src/com/android/codegen/Main.kt
+++ b/tools/codegen/src/com/android/codegen/Main.kt
@@ -1,5 +1,6 @@
 package com.android.codegen
 
+import com.github.javaparser.JavaParser
 import java.io.File
 
 
@@ -9,14 +10,12 @@
 
 val PRIMITIVE_TYPES = listOf("byte", "short", "int", "long", "char", "float", "double", "boolean")
 
-const val CANONICAL_BUILDER_CLASS = "Builder"
-const val GENERATED_BUILDER_CLASS = "GeneratedBuilder"
-
 val BUILTIN_SPECIAL_PARCELLINGS = listOf("Pattern")
 
 const val FLAG_BUILDER_PROTECTED_SETTERS = "--builder-protected-setters"
 const val FLAG_NO_FULL_QUALIFIERS = "--no-full-qualifiers"
 
+val JAVA_PARSER = JavaParser()
 
 /** @see [FeatureFlag] */
 val USAGE = """
@@ -66,10 +65,10 @@
       Will be called in constructor, after all the fields have been initialized.
       This is a good place to put any custom validation logic that you may have
 
-  static class $CANONICAL_BUILDER_CLASS extends $GENERATED_BUILDER_CLASS
-      If a class extending $GENERATED_BUILDER_CLASS is specified, generated builder's setters will
+  static class $CANONICAL_BUILDER_CLASS extends $BASE_BUILDER_CLASS
+      If a class extending $BASE_BUILDER_CLASS is specified, generated builder's setters will
       return the provided $CANONICAL_BUILDER_CLASS type.
-      $GENERATED_BUILDER_CLASS's constructor(s) will be package-private to encourage using $CANONICAL_BUILDER_CLASS instead
+      $BASE_BUILDER_CLASS's constructor(s) will be package-private to encourage using $CANONICAL_BUILDER_CLASS instead
       This allows you to extend the generated builder, adding or overriding any methods you may want
 
 
@@ -131,7 +130,6 @@
 
 
         // $GENERATED_WARNING_PREFIX v$CODEGEN_VERSION.
-        //   on ${currentTimestamp()}
         //
         // DO NOT MODIFY!
         //
@@ -143,14 +141,6 @@
 
         if (FeatureFlag.CONST_DEFS()) generateConstDefs()
 
-        "@$DataClassGenerated(" {
-            +"time = ${System.currentTimeMillis()}L,"
-            +"codegenVersion = \"$CODEGEN_VERSION\","
-            +"sourceFile = \"${file.relativeTo(File(System.getenv("ANDROID_BUILD_TOP")))}\","
-            +"inputSignatures = \"${getInputSignatures().joinToString("\\n")}\""
-        }
-        +"\n"
-
 
         if (FeatureFlag.CONSTRUCTOR()) {
             generateConstructor("public")
@@ -160,6 +150,7 @@
                 || FeatureFlag.PARCELABLE()) {
             generateConstructor("/* package-private */")
         }
+        if (FeatureFlag.COPY_CONSTRUCTOR()) generateCopyConstructor()
 
         if (FeatureFlag.GETTERS()) generateGetters()
         if (FeatureFlag.SETTERS()) generateSetters()
@@ -168,7 +159,6 @@
 
         if (FeatureFlag.FOR_EACH_FIELD()) generateForEachField()
 
-        if (FeatureFlag.COPY_CONSTRUCTOR()) generateCopyConstructor()
         if (FeatureFlag.WITHERS()) generateWithers()
 
         if (FeatureFlag.PARCELABLE()) generateParcelable()
@@ -178,6 +168,8 @@
 
         if (FeatureFlag.AIDL()) generateAidl(file)
 
+        generateMetadata(file)
+
         rmEmptyLine()
     }
     stringBuilder.append("\n}\n")
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index 175eea6..7d50ad1 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,4 +1,7 @@
 package com.android.codegen
 
 const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.0"
\ No newline at end of file
+const val CODEGEN_VERSION = "1.0.0"
+
+const val CANONICAL_BUILDER_CLASS = "Builder"
+const val BASE_BUILDER_CLASS = "BaseBuilder"
diff --git a/tools/codegen/src/com/android/codegen/Utils.kt b/tools/codegen/src/com/android/codegen/Utils.kt
index 95c9909..a1f068a 100644
--- a/tools/codegen/src/com/android/codegen/Utils.kt
+++ b/tools/codegen/src/com/android/codegen/Utils.kt
@@ -1,8 +1,10 @@
 package com.android.codegen
 
+import com.github.javaparser.ast.Modifier
 import com.github.javaparser.ast.expr.AnnotationExpr
 import com.github.javaparser.ast.expr.Expression
 import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr
+import com.github.javaparser.ast.nodeTypes.NodeWithModifiers
 import java.time.Instant
 import java.time.ZoneId
 import java.time.format.DateTimeFormatter
@@ -22,6 +24,8 @@
 
 fun if_(cond: Boolean, then: String) = if (cond) then else ""
 
+fun <T> Any?.as_(): T = this as T
+
 inline infix fun Int.times(action: () -> Unit) {
     for (i in 1..this) action()
 }
@@ -73,4 +77,14 @@
 fun currentTimestamp() = DateTimeFormatter
         .ofLocalizedDateTime(/* date */ FormatStyle.MEDIUM, /* time */ FormatStyle.LONG)
         .withZone(ZoneId.systemDefault())
-        .format(Instant.now())
\ No newline at end of file
+        .format(Instant.now())
+
+val NodeWithModifiers<*>.visibility get() = accessSpecifier
+
+fun abort(msg: String): Nothing {
+    System.err.println("ERROR: $msg")
+    System.exit(1)
+    throw InternalError() // can't get here
+}
+
+fun bitAtExpr(bitIndex: Int) = "0x${java.lang.Long.toHexString(1L shl bitIndex)}"
diff --git a/tools/preload-check/Android.bp b/tools/preload-check/Android.bp
index 2488341..87b31d2 100644
--- a/tools/preload-check/Android.bp
+++ b/tools/preload-check/Android.bp
@@ -19,4 +19,5 @@
     libs: ["tradefed"],
     test_suites: ["general-tests"],
     required: ["preload-check-device"],
+    data: [":preload-check-device"],
 }
diff --git a/tools/preload-check/device/Android.bp b/tools/preload-check/device/Android.bp
index 7782b0d..f40d8ba 100644
--- a/tools/preload-check/device/Android.bp
+++ b/tools/preload-check/device/Android.bp
@@ -20,7 +20,6 @@
 
     sdk_version: "current",
     srcs: ["src/**/*.java"],
-    test_suites: ["general-tests"],
     dex_preopt: {
         enabled: false,
     },
diff --git a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
index e5ec17a..d00def6 100644
--- a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
+++ b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
@@ -17,6 +17,8 @@
 
 package android.processor.staledataclass
 
+import com.android.codegen.BASE_BUILDER_CLASS
+import com.android.codegen.CANONICAL_BUILDER_CLASS
 import com.android.codegen.CODEGEN_NAME
 import com.android.codegen.CODEGEN_VERSION
 import com.sun.tools.javac.code.Symbol
@@ -29,6 +31,7 @@
 import javax.lang.model.SourceVersion
 import javax.lang.model.element.AnnotationMirror
 import javax.lang.model.element.Element
+import javax.lang.model.element.ElementKind
 import javax.lang.model.element.TypeElement
 import javax.tools.Diagnostic
 
@@ -63,10 +66,14 @@
         if (dataClassAnnotation == null) {
             dataClassAnnotation = annotations.find {
                 it.qualifiedName.toString() == DATACLASS_ANNOTATION_NAME
-            }
+            } ?: return true
         }
 
-        val generatedAnnotatedElements = roundEnv.getElementsAnnotatedWith(generatedAnnotation)
+        val generatedAnnotatedElements = if (generatedAnnotation != null) {
+            roundEnv.getElementsAnnotatedWith(generatedAnnotation)
+        } else {
+            emptySet()
+        }
         generatedAnnotatedElements.forEach {
             processSingleFile(it)
         }
@@ -107,20 +114,30 @@
 
     private fun processSingleFile(elementAnnotatedWithGenerated: Element) {
 
-        val inputSignatures = elementAnnotatedWithGenerated
-                .enclosingElement
-                .enclosedElements
-                .filterNot {
-                    it.annotationMirrors.any { "Generated" in it.annotationType.toString() }
-                }.map {
-                    elemToString(it)
-                }.toSet()
+        val classElement = elementAnnotatedWithGenerated.enclosingElement
+
+        val inputSignatures = computeSignaturesForClass(classElement)
+                .plus(computeSignaturesForClass(classElement.enclosedElements.find {
+                    it.kind == ElementKind.CLASS
+                            && !isGenerated(it)
+                            && it.simpleName.toString() == BASE_BUILDER_CLASS
+                }))
+                .plus(computeSignaturesForClass(classElement.enclosedElements.find {
+                    it.kind == ElementKind.CLASS
+                            && !isGenerated(it)
+                            && it.simpleName.toString() == CANONICAL_BUILDER_CLASS
+                }))
+                .plus(classElement
+                        .annotationMirrors
+                        .find { it.annotationType.toString() == DATACLASS_ANNOTATION_NAME }
+                        .toString())
+                .toSet()
 
         val annotationParams = elementAnnotatedWithGenerated
                 .annotationMirrors
                 .find { ann -> isGeneratedAnnotation(ann) }!!
                 .elementValues
-                .map { (k, v) -> k.getSimpleName().toString() to v.getValue() }
+                .map { (k, v) -> k.simpleName.toString() to v.value }
                 .toMap()
 
         val lastGenerated = annotationParams["time"] as Long
@@ -140,7 +157,7 @@
         }
 
         val source = repoRoot!!.resolve(sourceRelative)
-        val clazz = elementAnnotatedWithGenerated.enclosingElement.toString()
+        val clazz = classElement.toString()
 
         if (inputSignatures != lastGenInputSignatures) {
             error(buildString {
@@ -157,6 +174,23 @@
         }
     }
 
+    private fun computeSignaturesForClass(classElement: Element?): List<String> {
+        if (classElement == null) return emptyList()
+        val type = classElement as TypeElement
+        return classElement
+                .enclosedElements
+                .filterNot {
+                    it.kind == ElementKind.CLASS
+                            || it.kind == ElementKind.CONSTRUCTOR
+                            || isGenerated(it)
+                }.map {
+                    elemToString(it)
+                } + "class ${classElement.simpleName} extends ${type.superclass} implements [${type.interfaces.joinToString(", ")}]"
+    }
+
+    private fun isGenerated(it: Element) =
+            it.annotationMirrors.any { "Generated" in it.annotationType.toString() }
+
     private fun error(msg: String) {
         processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, msg)
     }
diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh
index 219a45e..7a0dfb0 100755
--- a/wifi/tests/runtests.sh
+++ b/wifi/tests/runtests.sh
@@ -12,7 +12,7 @@
 echo "+ mmma -j32 $ANDROID_BUILD_TOP/frameworks/base/wifi/tests"
 # NOTE Don't actually run the command above since this shell doesn't inherit functions from the
 #      caller.
-make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk MODULES-IN-frameworks-base-wifi-tests
+$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode MODULES-IN-frameworks-base-wifi-tests
 
 set -x # print commands