Merge "Close the GZIPOutputStream to release the deflater" into sc-dev
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java
index 999860f..e65abcf 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java
@@ -48,7 +48,8 @@
     @Override
     public boolean onStopJob(final JobParameters params) {
         Slog.d(TAG, "Idle maintenance job is stopped; id=" + params.getJobId()
-                + ", reason=" + JobParameters.getReasonCodeDescription(params.getStopReason()));
+                + ", reason="
+                + JobParameters.getLegacyReasonCodeDescription(params.getLegacyStopReason()));
         return false;
     }
 
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index 0d3e001..60f6475 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -16,10 +16,14 @@
 
 package android.app.job;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.usage.UsageStatsManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ClipData;
+import android.content.pm.PackageManager;
 import android.net.Network;
 import android.net.NetworkRequest;
 import android.net.Uri;
@@ -30,6 +34,9 @@
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Contains the parameters used to configure/identify your job. You do not create this object
  * yourself, instead it is handed in to your application by the System.
@@ -82,7 +89,7 @@
      */
     // TODO(142420609): make it @SystemApi for mainline
     @NonNull
-    public static String getReasonCodeDescription(int reasonCode) {
+    public static String getLegacyReasonCodeDescription(int reasonCode) {
         switch (reasonCode) {
             case REASON_CANCELED: return "canceled";
             case REASON_CONSTRAINTS_NOT_SATISFIED: return "constraints";
@@ -96,12 +103,119 @@
     }
 
     /** @hide */
-    // @SystemApi TODO make it a system api for mainline
+    // TODO: move current users of legacy reasons to new public reasons
     @NonNull
     public static int[] getJobStopReasonCodes() {
         return JOB_STOP_REASON_CODES;
     }
 
+    /**
+     * There is no reason the job is stopped. This is the value returned from the JobParameters
+     * object passed to {@link JobService#onStartJob(JobParameters)}.
+     */
+    public static final int STOP_REASON_UNDEFINED = 0;
+    /**
+     * The job was cancelled directly by the app, either by calling
+     * {@link JobScheduler#cancel(int)}, {@link JobScheduler#cancelAll()}, or by scheduling a
+     * new job with the same job ID.
+     */
+    public static final int STOP_REASON_CANCELLED_BY_APP = 1;
+    /** The job was stopped to run a higher priority job of the app. */
+    public static final int STOP_REASON_PREEMPT = 2;
+    /**
+     * The job used up its maximum execution time and timed out. Each individual job has a maximum
+     * execution time limit, regardless of how much total quota the app has. See the note on
+     * {@link JobScheduler} for the execution time limits.
+     */
+    public static final int STOP_REASON_TIMEOUT = 3;
+    /**
+     * The device state (eg. Doze, battery saver, memory usage, etc) requires JobScheduler stop this
+     * job.
+     */
+    public static final int STOP_REASON_DEVICE_STATE = 4;
+    /**
+     * The requested battery-not-low constraint is no longer satisfied.
+     *
+     * @see JobInfo.Builder#setRequiresBatteryNotLow(boolean)
+     */
+    public static final int STOP_REASON_CONSTRAINT_BATTERY_NOT_LOW = 5;
+    /**
+     * The requested charging constraint is no longer satisfied.
+     *
+     * @see JobInfo.Builder#setRequiresCharging(boolean)
+     */
+    public static final int STOP_REASON_CONSTRAINT_CHARGING = 6;
+    /**
+     * The requested connectivity constraint is no longer satisfied.
+     *
+     * @see JobInfo.Builder#setRequiredNetwork(NetworkRequest)
+     * @see JobInfo.Builder#setRequiredNetworkType(int)
+     */
+    public static final int STOP_REASON_CONSTRAINT_CONNECTIVITY = 7;
+    /**
+     * The requested idle constraint is no longer satisfied.
+     *
+     * @see JobInfo.Builder#setRequiresDeviceIdle(boolean)
+     */
+    public static final int STOP_REASON_CONSTRAINT_DEVICE_IDLE = 8;
+    /**
+     * The requested storage-not-low constraint is no longer satisfied.
+     *
+     * @see JobInfo.Builder#setRequiresStorageNotLow(boolean)
+     */
+    public static final int STOP_REASON_CONSTRAINT_STORAGE_NOT_LOW = 9;
+    /**
+     * The app has consumed all of its current quota. Each app is assigned a quota of how much
+     * it can run jobs within a certain time frame. The quota is informed, in part, by app standby
+     * buckets. Once an app has used up all of its quota, it won't be able to start jobs until
+     * quota is replenished, is changed, or is temporarily not applied.
+     *
+     * @see UsageStatsManager#getAppStandbyBucket()
+     */
+    public static final int STOP_REASON_QUOTA = 10;
+    /**
+     * The app is restricted from running in the background.
+     *
+     * @see ActivityManager#isBackgroundRestricted()
+     * @see PackageManager#isInstantApp()
+     */
+    public static final int STOP_REASON_BACKGROUND_RESTRICTION = 11;
+    /**
+     * The current standby bucket requires that the job stop now.
+     *
+     * @see UsageStatsManager#STANDBY_BUCKET_RESTRICTED
+     */
+    public static final int STOP_REASON_APP_STANDBY = 12;
+    /**
+     * The user stopped the job. This can happen either through force-stop, or via adb shell
+     * commands.
+     */
+    public static final int STOP_REASON_USER = 13;
+    /** The system is doing some processing that requires stopping this job. */
+    public static final int STOP_REASON_SYSTEM_PROCESSING = 14;
+
+    /** @hide */
+    @IntDef(prefix = {"STOP_REASON_"}, value = {
+            STOP_REASON_UNDEFINED,
+            STOP_REASON_CANCELLED_BY_APP,
+            STOP_REASON_PREEMPT,
+            STOP_REASON_TIMEOUT,
+            STOP_REASON_DEVICE_STATE,
+            STOP_REASON_CONSTRAINT_BATTERY_NOT_LOW,
+            STOP_REASON_CONSTRAINT_CHARGING,
+            STOP_REASON_CONSTRAINT_CONNECTIVITY,
+            STOP_REASON_CONSTRAINT_DEVICE_IDLE,
+            STOP_REASON_CONSTRAINT_STORAGE_NOT_LOW,
+            STOP_REASON_QUOTA,
+            STOP_REASON_BACKGROUND_RESTRICTION,
+            STOP_REASON_APP_STANDBY,
+            STOP_REASON_USER,
+            STOP_REASON_SYSTEM_PROCESSING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StopReason {
+    }
+
     @UnsupportedAppUsage
     private final int jobId;
     private final PersistableBundle extras;
@@ -116,7 +230,8 @@
     private final String[] mTriggeredContentAuthorities;
     private final Network network;
 
-    private int stopReason; // Default value of stopReason is REASON_CANCELED
+    private int mStopReason = STOP_REASON_UNDEFINED;
+    private int mLegacyStopReason; // Default value of stopReason is REASON_CANCELED
     private String debugStopReason; // Human readable stop reason for debugging.
 
     /** @hide */
@@ -145,15 +260,23 @@
     }
 
     /**
-     * Reason onStopJob() was called on this job.
-     * @hide
+     * @return The reason {@link JobService#onStopJob(JobParameters)} was called on this job. Will
+     * be {@link #STOP_REASON_UNDEFINED} if {@link JobService#onStopJob(JobParameters)} has not
+     * yet been called.
      */
+    @StopReason
     public int getStopReason() {
-        return stopReason;
+        return mStopReason;
+    }
+
+    /** @hide */
+    public int getLegacyStopReason() {
+        return mLegacyStopReason;
     }
 
     /**
      * Reason onStopJob() was called on this job.
+     *
      * @hide
      */
     public String getDebugStopReason() {
@@ -368,13 +491,16 @@
         } else {
             network = null;
         }
-        stopReason = in.readInt();
+        mStopReason = in.readInt();
+        mLegacyStopReason = in.readInt();
         debugStopReason = in.readString();
     }
 
     /** @hide */
-    public void setStopReason(int reason, String debugStopReason) {
-        stopReason = reason;
+    public void setStopReason(@StopReason int reason, int legacyStopReason,
+            String debugStopReason) {
+        mStopReason = reason;
+        mLegacyStopReason = legacyStopReason;
         this.debugStopReason = debugStopReason;
     }
 
@@ -406,7 +532,8 @@
         } else {
             dest.writeInt(0);
         }
-        dest.writeInt(stopReason);
+        dest.writeInt(mStopReason);
+        dest.writeInt(mLegacyStopReason);
         dest.writeString(debugStopReason);
     }
 
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobService.java b/apex/jobscheduler/framework/java/android/app/job/JobService.java
index 0f3d299..fa7a2d3 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobService.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobService.java
@@ -139,19 +139,23 @@
      * Once this method is called, you no longer need to call
      * {@link #jobFinished(JobParameters, boolean)}.
      *
-     * <p>This will happen if the requirements specified at schedule time are no longer met. For
+     * <p>This may happen if the requirements specified at schedule time are no longer met. For
      * example you may have requested WiFi with
      * {@link android.app.job.JobInfo.Builder#setRequiredNetworkType(int)}, yet while your
      * job was executing the user toggled WiFi. Another example is if you had specified
-     * {@link android.app.job.JobInfo.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
-     * idle maintenance window. You are solely responsible for the behavior of your application
-     * upon receipt of this message; your app will likely start to misbehave if you ignore it.
+     * {@link android.app.job.JobInfo.Builder#setRequiresDeviceIdle(boolean)}, and the phone left
+     * its idle maintenance window. There are many other reasons a job can be stopped early besides
+     * constraints no longer being satisfied. {@link JobParameters#getStopReason()} will return the
+     * reason this method was called. You are solely responsible for the behavior of your
+     * application upon receipt of this message; your app will likely start to misbehave if you
+     * ignore it.
      * <p>
      * Once this method returns (or times out), the system releases the wakelock that it is holding
      * on behalf of the job.</p>
      *
-     * @param params The parameters identifying this job, as supplied to
-     *               the job in the {@link #onStartJob(JobParameters)} callback.
+     * @param params The parameters identifying this job, similar to what was supplied to the job in
+     *               the {@link #onStartJob(JobParameters)} callback, but with the stop reason
+     *               included.
      * @return {@code true} to indicate to the JobManager whether you'd like to reschedule
      * this job based on the retry criteria provided at job creation-time; or {@code false}
      * to end the job entirely.  Regardless of the value returned, your job must stop executing.
diff --git a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
index 7833a03..6ae91a0 100644
--- a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.app.job.JobInfo;
+import android.app.job.JobParameters;
 import android.util.proto.ProtoOutputStream;
 
 import java.util.List;
@@ -36,7 +37,7 @@
     /**
      * Cancel the jobs for a given uid (e.g. when app data is cleared)
      */
-    void cancelJobsForUid(int uid, String reason);
+    void cancelJobsForUid(int uid, @JobParameters.StopReason int reason, String debugReason);
 
     /**
      * These are for activity manager to communicate to use what is currently performing backups.
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 b958c3f..325be1b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -266,6 +266,8 @@
 
     String[] mRecycledPreemptReasonForContext = new String[MAX_JOB_CONTEXTS_COUNT];
 
+    int[] mRecycledPreemptReasonCodeForContext = new int[MAX_JOB_CONTEXTS_COUNT];
+
     String[] mRecycledShouldStopJobReason = new String[MAX_JOB_CONTEXTS_COUNT];
 
     private final ArraySet<JobStatus> mRunningJobs = new ArraySet<>();
@@ -505,6 +507,7 @@
         int[] preferredUidForContext = mRecycledPreferredUidForContext;
         int[] workTypeForContext = mRecycledWorkTypeForContext;
         String[] preemptReasonForContext = mRecycledPreemptReasonForContext;
+        int[] preemptReasonCodeForContext = mRecycledPreemptReasonCodeForContext;
         String[] shouldStopJobReason = mRecycledShouldStopJobReason;
 
         updateCounterConfigLocked();
@@ -528,6 +531,7 @@
             slotChanged[i] = false;
             preferredUidForContext[i] = js.getPreferredUid();
             preemptReasonForContext[i] = null;
+            preemptReasonCodeForContext[i] = JobParameters.STOP_REASON_UNDEFINED;
             shouldStopJobReason[i] = shouldStopRunningJobLocked(js);
         }
         if (DEBUG) {
@@ -551,6 +555,7 @@
             int allWorkTypes = getJobWorkTypes(nextPending);
             int workType = mWorkCountTracker.canJobStart(allWorkTypes);
             boolean startingJob = false;
+            int preemptReasonCode = JobParameters.STOP_REASON_UNDEFINED;
             String preemptReason = null;
             // TODO(141645789): rewrite this to look at empty contexts first so we don't
             // unnecessarily preempt
@@ -582,6 +587,7 @@
                         // assign the new job to this context since we'll reassign when the
                         // preempted job finally stops.
                         preemptReason = reason;
+                        preemptReasonCode = JobParameters.STOP_REASON_DEVICE_STATE;
                     }
                     continue;
                 }
@@ -597,6 +603,7 @@
                     minPriorityForPreemption = jobPriority;
                     selectedContextId = j;
                     preemptReason = "higher priority job found";
+                    preemptReasonCode = JobParameters.STOP_REASON_PREEMPT;
                     // In this case, we're just going to preempt a low priority job, we're not
                     // actually starting a job, so don't set startingJob.
                 }
@@ -604,6 +611,7 @@
             if (selectedContextId != -1) {
                 contextIdToJobMap[selectedContextId] = nextPending;
                 slotChanged[selectedContextId] = true;
+                preemptReasonCodeForContext[selectedContextId] = preemptReasonCode;
                 preemptReasonForContext[selectedContextId] = preemptReason;
             }
             if (startingJob) {
@@ -631,8 +639,13 @@
                     }
                     // preferredUid will be set to uid of currently running job.
                     activeServices.get(i).cancelExecutingJobLocked(
+                            preemptReasonCodeForContext[i],
                             JobParameters.REASON_PREEMPT, preemptReasonForContext[i]);
-                    preservePreferredUid = true;
+                    // Only preserve the UID if we're preempting for the same UID. If we're stopping
+                    // the job because something is pending (eg. EJs), then we shouldn't preserve
+                    // the UID.
+                    preservePreferredUid =
+                            preemptReasonCodeForContext[i] == JobParameters.STOP_REASON_PREEMPT;
                 } else {
                     final JobStatus pendingJob = contextIdToJobMap[i];
                     if (DEBUG) {
@@ -657,7 +670,8 @@
             final JobStatus jobStatus = jsc.getRunningJobLocked();
 
             if (jobStatus != null && !jsc.isWithinExecutionGuaranteeTime()) {
-                jsc.cancelExecutingJobLocked(JobParameters.REASON_TIMEOUT, debugReason);
+                jsc.cancelExecutingJobLocked(JobParameters.STOP_REASON_DEVICE_STATE,
+                        JobParameters.REASON_TIMEOUT, debugReason);
             }
         }
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
index 6ffac91..02f9129 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
@@ -374,7 +374,7 @@
                             pw.print(pe.stopReasons.valueAt(k));
                             pw.print("x ");
                             pw.print(JobParameters
-                                    .getReasonCodeDescription(pe.stopReasons.keyAt(k)));
+                                    .getLegacyReasonCodeDescription(pe.stopReasons.keyAt(k)));
                         }
                         pw.println();
                     }
@@ -621,7 +621,7 @@
                 if (reason != null) {
                     pw.print(mEventReasons[index]);
                 } else {
-                    pw.print(JobParameters.getReasonCodeDescription(
+                    pw.print(JobParameters.getLegacyReasonCodeDescription(
                             (mEventCmds[index] & EVENT_STOP_REASON_MASK)
                                     >> EVENT_STOP_REASON_SHIFT));
                 }
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 2b08ba5..a041f8c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -746,8 +746,11 @@
                                             Slog.d(TAG, "Removing jobs for package " + pkgName
                                                     + " in user " + userId);
                                         }
+                                        // By the time we get here, the process should have already
+                                        // been stopped, so the app wouldn't get the stop reason,
+                                        // so just put USER instead of UNINSTALL or DISABLED.
                                         cancelJobsForPackageAndUid(pkgName, pkgUid,
-                                                "app disabled");
+                                                JobParameters.STOP_REASON_USER, "app disabled");
                                     }
                                 } catch (RemoteException|IllegalArgumentException e) {
                                     /*
@@ -785,7 +788,11 @@
                     if (DEBUG) {
                         Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
                     }
-                    cancelJobsForPackageAndUid(pkgName, uidRemoved, "app uninstalled");
+                    // By the time we get here, the process should have already
+                    // been stopped, so the app wouldn't get the stop reason,
+                    // so just put USER instead of UNINSTALL or DISABLED.
+                    cancelJobsForPackageAndUid(pkgName, uidRemoved,
+                            JobParameters.STOP_REASON_USER, "app uninstalled");
                     synchronized (mLock) {
                         for (int c = 0; c < mControllers.size(); ++c) {
                             mControllers.get(c).onAppRemovedLocked(pkgName, pkgUid);
@@ -837,7 +844,8 @@
                     if (DEBUG) {
                         Slog.d(TAG, "Removing jobs for pkg " + pkgName + " at uid " + pkgUid);
                     }
-                    cancelJobsForPackageAndUid(pkgName, pkgUid, "app force stopped");
+                    cancelJobsForPackageAndUid(pkgName, pkgUid,
+                            JobParameters.STOP_REASON_USER, "app force stopped");
                 }
             }
         }
@@ -924,8 +932,7 @@
         final String servicePkg = job.getService().getPackageName();
         if (job.isPersisted() && (packageName == null || packageName.equals(servicePkg))) {
             // Only limit schedule calls for persisted jobs scheduled by the app itself.
-            final String pkg =
-                    packageName == null ? job.getService().getPackageName() : packageName;
+            final String pkg = packageName == null ? servicePkg : packageName;
             if (!mQuotaTracker.isWithinQuota(userId, pkg, QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG)) {
                 if (mQuotaTracker.isWithinQuota(userId, pkg, QUOTA_TRACKER_SCHEDULE_LOGGED)) {
                     // Don't log too frequently
@@ -972,14 +979,10 @@
             mQuotaTracker.noteEvent(userId, pkg, QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG);
         }
 
-        try {
-            if (ActivityManager.getService().isAppStartModeDisabled(uId,
-                    job.getService().getPackageName())) {
-                Slog.w(TAG, "Not scheduling job " + uId + ":" + job.toString()
-                        + " -- package not allowed to start");
-                return JobScheduler.RESULT_FAILURE;
-            }
-        } catch (RemoteException e) {
+        if (mActivityManagerInternal.isAppStartModeDisabled(uId, servicePkg)) {
+            Slog.w(TAG, "Not scheduling job " + uId + ":" + job.toString()
+                    + " -- package not allowed to start");
+            return JobScheduler.RESULT_FAILURE;
         }
 
         synchronized (mLock) {
@@ -1029,7 +1032,8 @@
 
             if (toCancel != null) {
                 // Implicitly replaces the existing job record with the new instance
-                cancelJobImplLocked(toCancel, jobStatus, "job rescheduled by app");
+                cancelJobImplLocked(toCancel, jobStatus, JobParameters.STOP_REASON_CANCELLED_BY_APP,
+                        "job rescheduled by app");
             } else {
                 startTrackingJobLocked(jobStatus, null);
             }
@@ -1105,7 +1109,10 @@
             final List<JobStatus> jobsForUser = mJobs.getJobsByUser(userHandle);
             for (int i=0; i<jobsForUser.size(); i++) {
                 JobStatus toRemove = jobsForUser.get(i);
-                cancelJobImplLocked(toRemove, null, "user removed");
+                // By the time we get here, the process should have already been stopped, so the
+                // app wouldn't get the stop reason, so just put USER instead of UNINSTALL.
+                cancelJobImplLocked(toRemove, null, JobParameters.STOP_REASON_USER,
+                        "user removed");
             }
         }
     }
@@ -1117,7 +1124,8 @@
         }
     }
 
-    void cancelJobsForPackageAndUid(String pkgName, int uid, String reason) {
+    void cancelJobsForPackageAndUid(String pkgName, int uid, @JobParameters.StopReason int reason,
+            String debugReason) {
         if ("android".equals(pkgName)) {
             Slog.wtfStack(TAG, "Can't cancel all jobs for system package");
             return;
@@ -1127,7 +1135,7 @@
             for (int i = jobsForUid.size() - 1; i >= 0; i--) {
                 final JobStatus job = jobsForUid.get(i);
                 if (job.getSourcePackageName().equals(pkgName)) {
-                    cancelJobImplLocked(job, null, reason);
+                    cancelJobImplLocked(job, null, reason, debugReason);
                 }
             }
         }
@@ -1137,10 +1145,11 @@
      * Entry point from client to cancel all jobs originating from their uid.
      * This will remove the job from the master list, and cancel the job if it was staged for
      * execution or being executed.
-     * @param uid Uid to check against for removal of a job.
      *
+     * @param uid Uid to check against for removal of a job.
      */
-    public boolean cancelJobsForUid(int uid, String reason) {
+    public boolean cancelJobsForUid(int uid, @JobParameters.StopReason int reason,
+            String debugReason) {
         if (uid == Process.SYSTEM_UID) {
             Slog.wtfStack(TAG, "Can't cancel all jobs for system uid");
             return false;
@@ -1151,7 +1160,7 @@
             final List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
             for (int i=0; i<jobsForUid.size(); i++) {
                 JobStatus toRemove = jobsForUid.get(i);
-                cancelJobImplLocked(toRemove, null, reason);
+                cancelJobImplLocked(toRemove, null, reason, debugReason);
                 jobsCanceled = true;
             }
         }
@@ -1162,15 +1171,17 @@
      * Entry point from client to cancel the job corresponding to the jobId provided.
      * This will remove the job from the master list, and cancel the job if it was staged for
      * execution or being executed.
-     * @param uid Uid of the calling client.
+     *
+     * @param uid   Uid of the calling client.
      * @param jobId Id of the job, provided at schedule-time.
      */
-    public boolean cancelJob(int uid, int jobId, int callingUid) {
+    private boolean cancelJob(int uid, int jobId, int callingUid,
+            @JobParameters.StopReason int reason) {
         JobStatus toCancel;
         synchronized (mLock) {
             toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
             if (toCancel != null) {
-                cancelJobImplLocked(toCancel, null,
+                cancelJobImplLocked(toCancel, null, reason,
                         "cancel() called by app, callingUid=" + callingUid
                         + " uid=" + uid + " jobId=" + jobId);
             }
@@ -1184,7 +1195,8 @@
      * {@code incomingJob} is non-null, it replaces {@code cancelled} in the store of
      * currently scheduled jobs.
      */
-    private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob, String reason) {
+    private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob,
+            @JobParameters.StopReason int reason, String debugReason) {
         if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
         cancelled.unprepareLocked();
         stopTrackingJobLocked(cancelled, incomingJob, true /* writeBack */);
@@ -1193,7 +1205,8 @@
             mJobPackageTracker.noteNonpending(cancelled);
         }
         // Cancel if running.
-        stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED, reason);
+        stopJobOnServiceContextLocked(cancelled, reason, JobParameters.REASON_CANCELED,
+                debugReason);
         // If this is a replacement, bring in the new version of the job
         if (incomingJob != null) {
             if (DEBUG) Slog.i(TAG, "Tracking replacement job " + incomingJob.toShortString());
@@ -1232,7 +1245,8 @@
                     JobServiceContext jsc = mActiveServices.get(i);
                     final JobStatus executing = jsc.getRunningJobLocked();
                     if (executing != null && !executing.canRunInDoze()) {
-                        jsc.cancelExecutingJobLocked(JobParameters.REASON_DEVICE_IDLE,
+                        jsc.cancelExecutingJobLocked(JobParameters.STOP_REASON_DEVICE_STATE,
+                                JobParameters.REASON_DEVICE_IDLE,
                                 "cancelled due to doze");
                     }
                 }
@@ -1430,7 +1444,8 @@
                 if (DEBUG) {
                     Slog.v(TAG, "  replacing " + oldJob + " with " + newJob);
                 }
-                cancelJobImplLocked(oldJob, newJob, "deferred rtc calculation");
+                cancelJobImplLocked(oldJob, newJob, JobParameters.STOP_REASON_SYSTEM_PROCESSING,
+                        "deferred rtc calculation");
             }
         }
     };
@@ -1550,12 +1565,13 @@
         return removed;
     }
 
-    private boolean stopJobOnServiceContextLocked(JobStatus job, int reason, String debugReason) {
+    private boolean stopJobOnServiceContextLocked(JobStatus job,
+            @JobParameters.StopReason int reason, int legacyReason, String debugReason) {
         for (int i=0; i<mActiveServices.size(); i++) {
             JobServiceContext jsc = mActiveServices.get(i);
             final JobStatus executing = jsc.getRunningJobLocked();
             if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
-                jsc.cancelExecutingJobLocked(reason, debugReason);
+                jsc.cancelExecutingJobLocked(reason, legacyReason, debugReason);
                 return true;
             }
         }
@@ -1880,7 +1896,7 @@
                         queueReadyJobsForExecutionLocked();
                         break;
                     case MSG_STOP_JOB:
-                        cancelJobImplLocked((JobStatus) message.obj, null,
+                        cancelJobImplLocked((JobStatus) message.obj, null, message.arg1,
                                 "app no longer allowed to run");
                         break;
 
@@ -1895,7 +1911,9 @@
                         final boolean disabled = message.arg2 != 0;
                         updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
                         if (disabled) {
-                            cancelJobsForUid(uid, "uid gone");
+                            cancelJobsForUid(uid,
+                                    JobParameters.STOP_REASON_BACKGROUND_RESTRICTION,
+                                    "uid gone");
                         }
                         synchronized (mLock) {
                             mDeviceIdleJobsController.setUidActiveLocked(uid, false);
@@ -1913,7 +1931,9 @@
                         final int uid = message.arg1;
                         final boolean disabled = message.arg2 != 0;
                         if (disabled) {
-                            cancelJobsForUid(uid, "app uid idle");
+                            cancelJobsForUid(uid,
+                                    JobParameters.STOP_REASON_BACKGROUND_RESTRICTION,
+                                    "app uid idle");
                         }
                         synchronized (mLock) {
                             mDeviceIdleJobsController.setUidActiveLocked(uid, false);
@@ -1965,10 +1985,12 @@
                 if (running.getEffectiveStandbyBucket() == RESTRICTED_INDEX
                         && !running.areDynamicConstraintsSatisfied()) {
                     serviceContext.cancelExecutingJobLocked(
+                            running.getStopReason(),
                             JobParameters.REASON_RESTRICTED_BUCKET,
                             "cancelled due to restricted bucket");
                 } else {
                     serviceContext.cancelExecutingJobLocked(
+                            running.getStopReason(),
                             JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED,
                             "cancelled due to unsatisfied constraints");
                 }
@@ -1977,7 +1999,9 @@
                 if (restriction != null) {
                     final int reason = restriction.getReason();
                     serviceContext.cancelExecutingJobLocked(reason,
-                            "restricted due to " + JobParameters.getReasonCodeDescription(reason));
+                            restriction.getLegacyReason(),
+                            "restricted due to " + JobParameters.getLegacyReasonCodeDescription(
+                                    reason));
                 }
             }
         }
@@ -2058,15 +2082,14 @@
         @Override
         public void accept(JobStatus job) {
             if (isReadyToBeExecutedLocked(job)) {
-                try {
-                    if (ActivityManager.getService().isAppStartModeDisabled(job.getUid(),
-                            job.getJob().getService().getPackageName())) {
-                        Slog.w(TAG, "Aborting job " + job.getUid() + ":"
-                                + job.getJob().toString() + " -- package not allowed to start");
-                        mHandler.obtainMessage(MSG_STOP_JOB, job).sendToTarget();
-                        return;
-                    }
-                } catch (RemoteException e) {
+                if (mActivityManagerInternal.isAppStartModeDisabled(job.getUid(),
+                        job.getJob().getService().getPackageName())) {
+                    Slog.w(TAG, "Aborting job " + job.getUid() + ":"
+                            + job.getJob().toString() + " -- package not allowed to start");
+                    mHandler.obtainMessage(MSG_STOP_JOB,
+                            JobParameters.STOP_REASON_BACKGROUND_RESTRICTION, 0, job)
+                            .sendToTarget();
+                    return;
                 }
 
                 final boolean shouldForceBatchJob;
@@ -2276,7 +2299,7 @@
         if (restriction != null) {
             if (DEBUG) {
                 Slog.v(TAG, "areComponentsInPlaceLocked: " + job.toShortString()
-                        + " restricted due to " + restriction.getReason());
+                        + " restricted due to " + restriction.getLegacyReason());
             }
             return false;
         }
@@ -2367,8 +2390,9 @@
         }
 
         @Override
-        public void cancelJobsForUid(int uid, String reason) {
-            JobSchedulerService.this.cancelJobsForUid(uid, reason);
+        public void cancelJobsForUid(int uid, @JobParameters.StopReason int reason,
+                String debugReason) {
+            JobSchedulerService.this.cancelJobsForUid(uid, reason, debugReason);
         }
 
         @Override
@@ -2706,6 +2730,7 @@
             final long ident = Binder.clearCallingIdentity();
             try {
                 JobSchedulerService.this.cancelJobsForUid(uid,
+                        JobParameters.STOP_REASON_CANCELLED_BY_APP,
                         "cancelAll() called by app, callingUid=" + uid);
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -2718,7 +2743,8 @@
 
             final long ident = Binder.clearCallingIdentity();
             try {
-                JobSchedulerService.this.cancelJob(uid, jobId, uid);
+                JobSchedulerService.this.cancelJob(uid, jobId, uid,
+                        JobParameters.STOP_REASON_CANCELLED_BY_APP);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -2924,12 +2950,13 @@
 
         if (!hasJobId) {
             pw.println("Canceling all jobs for " + pkgName + " in user " + userId);
-            if (!cancelJobsForUid(pkgUid, "cancel shell command for package")) {
+            if (!cancelJobsForUid(pkgUid, JobParameters.STOP_REASON_USER,
+                    "cancel shell command for package")) {
                 pw.println("No matching jobs found.");
             }
         } else {
             pw.println("Canceling job " + pkgName + "/#" + jobId + " in user " + userId);
-            if (!cancelJob(pkgUid, jobId, Process.SHELL_UID)) {
+            if (!cancelJob(pkgUid, jobId, Process.SHELL_UID, JobParameters.STOP_REASON_USER)) {
                 pw.println("No matching job found.");
             }
         }
@@ -3164,8 +3191,9 @@
                         for (int i = mJobRestrictions.size() - 1; i >= 0; i--) {
                             final JobRestriction restriction = mJobRestrictions.get(i);
                             if (restriction.isJobRestricted(job)) {
-                                final int reason = restriction.getReason();
-                                pw.print(" " + JobParameters.getReasonCodeDescription(reason));
+                                final int reason = restriction.getLegacyReason();
+                                pw.print(" ");
+                                pw.print(JobParameters.getLegacyReasonCodeDescription(reason));
                             }
                         }
                     } else {
@@ -3430,7 +3458,7 @@
                         final long restrictionsToken = proto.start(
                                 JobSchedulerServiceDumpProto.RegisteredJob.RESTRICTIONS);
                         proto.write(JobSchedulerServiceDumpProto.JobRestriction.REASON,
-                                restriction.getReason());
+                                restriction.getLegacyReason());
                         proto.write(JobSchedulerServiceDumpProto.JobRestriction.IS_RESTRICTING,
                                 restriction.isJobRestricted(job));
                         proto.end(restrictionsToken);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 9ef46df..e8bcbfb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -354,8 +354,9 @@
 
     /** Called externally when a job that was scheduled for execution should be cancelled. */
     @GuardedBy("mLock")
-    void cancelExecutingJobLocked(int reason, @NonNull String debugReason) {
-        doCancelLocked(reason, debugReason);
+    void cancelExecutingJobLocked(@JobParameters.StopReason int reason,
+            int legacyStopReason, @NonNull String debugReason) {
+        doCancelLocked(reason, legacyStopReason, debugReason);
     }
 
     int getPreferredUid() {
@@ -387,7 +388,8 @@
                 && (pkgName == null || pkgName.equals(executing.getSourcePackageName()))
                 && (!matchJobId || jobId == executing.getJobId())) {
             if (mVerb == VERB_EXECUTING) {
-                mParams.setStopReason(JobParameters.REASON_TIMEOUT, reason);
+                mParams.setStopReason(JobParameters.STOP_REASON_TIMEOUT,
+                        JobParameters.REASON_TIMEOUT, reason);
                 sendStopMessageLocked("force timeout from shell");
                 return true;
             }
@@ -614,7 +616,8 @@
     }
 
     @GuardedBy("mLock")
-    private void doCancelLocked(int stopReasonCode, @Nullable String debugReason) {
+    private void doCancelLocked(@JobParameters.StopReason int stopReasonCode, int legacyStopReason,
+            @Nullable String debugReason) {
         if (mVerb == VERB_FINISHED) {
             if (DEBUG) {
                 Slog.d(TAG,
@@ -622,8 +625,8 @@
             }
             return;
         }
-        mParams.setStopReason(stopReasonCode, debugReason);
-        if (stopReasonCode == JobParameters.REASON_PREEMPT) {
+        mParams.setStopReason(stopReasonCode, legacyStopReason, debugReason);
+        if (legacyStopReason == JobParameters.REASON_PREEMPT) {
             mPreferredUid = mRunningJob != null ? mRunningJob.getUid() :
                     NO_PREFERRED_UID;
         }
@@ -781,7 +784,8 @@
                     // Not an error - client ran out of time.
                     Slog.i(TAG, "Client timed out while executing (no jobFinished received)."
                             + " Sending onStop: " + getRunningJobNameLocked());
-                    mParams.setStopReason(JobParameters.REASON_TIMEOUT, "client timed out");
+                    mParams.setStopReason(JobParameters.STOP_REASON_TIMEOUT,
+                            JobParameters.REASON_TIMEOUT, "client timed out");
                     sendStopMessageLocked("timeout while executing");
                 } else {
                     // We've given the app the minimum execution time. See if we should stop it or
@@ -790,7 +794,11 @@
                     if (reason != null) {
                         Slog.i(TAG, "Stopping client after min execution time: "
                                 + getRunningJobNameLocked() + " because " + reason);
-                        mParams.setStopReason(JobParameters.REASON_TIMEOUT, reason);
+                        // Tell the developer we're stopping the job due to device state instead
+                        // of timeout since all of the reasons could equate to "the system needs
+                        // the resources the app is currently using."
+                        mParams.setStopReason(JobParameters.STOP_REASON_DEVICE_STATE,
+                                JobParameters.REASON_TIMEOUT, reason);
                         sendStopMessageLocked(reason);
                     } else {
                         Slog.i(TAG, "Letting " + getRunningJobNameLocked()
@@ -844,12 +852,12 @@
         }
         applyStoppedReasonLocked(reason);
         completedJob = mRunningJob;
-        final int stopReason = mParams.getStopReason();
-        mJobPackageTracker.noteInactive(completedJob, stopReason, reason);
+        final int legacyStopReason = mParams.getLegacyStopReason();
+        mJobPackageTracker.noteInactive(completedJob, legacyStopReason, reason);
         FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
                 completedJob.getSourceUid(), null, completedJob.getBatteryName(),
                 FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__FINISHED,
-                stopReason, completedJob.getStandbyBucket(), completedJob.getJobId(),
+                legacyStopReason, completedJob.getStandbyBucket(), completedJob.getJobId(),
                 completedJob.hasChargingConstraint(),
                 completedJob.hasBatteryNotLowConstraint(),
                 completedJob.hasStorageNotLowConstraint(),
@@ -860,7 +868,7 @@
                 completedJob.hasContentTriggerConstraint());
         try {
             mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(), mRunningJob.getSourceUid(),
-                    stopReason);
+                    legacyStopReason);
         } catch (RemoteException e) {
             // Whatever.
         }
@@ -879,7 +887,7 @@
         service = null;
         mAvailable = true;
         removeOpTimeOutLocked();
-        mCompletedListener.onJobCompletedLocked(completedJob, stopReason, reschedule);
+        mCompletedListener.onJobCompletedLocked(completedJob, legacyStopReason, reschedule);
         mJobConcurrencyManager.onJobCompletedLocked(this, completedJob, workType);
     }
 
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 a230b23..548a1ac 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
@@ -210,7 +210,8 @@
             jobStatus.maybeLogBucketMismatch();
         }
         boolean didChange =
-                jobStatus.setBackgroundNotRestrictedConstraintSatisfied(nowElapsed, canRun);
+                jobStatus.setBackgroundNotRestrictedConstraintSatisfied(nowElapsed, canRun,
+                        !mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(uid, packageName));
         didChange |= jobStatus.setUidActive(isActive);
         return didChange;
     }
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 bad8dc1..659cfa7 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
@@ -24,6 +24,7 @@
 
 import android.app.AppGlobals;
 import android.app.job.JobInfo;
+import android.app.job.JobParameters;
 import android.app.job.JobWorkItem;
 import android.content.ClipData;
 import android.content.ComponentName;
@@ -353,6 +354,9 @@
      */
     private long mLastFailedRunTime;
 
+    /** Whether or not the app is background restricted by the user (FAS). */
+    private boolean mIsUserBgRestricted;
+
     /**
      * Transient: when a job is inflated from disk before we have a reliable RTC clock time,
      * we retain the canonical (delay, deadline) scheduling tuple read out of the persistent
@@ -409,6 +413,9 @@
     /** The job's dynamic requirements have been satisfied. */
     private boolean mReadyDynamicSatisfied;
 
+    /** The reason a job most recently went from ready to not ready. */
+    private int mReasonReadyToUnready = JobParameters.STOP_REASON_UNDEFINED;
+
     /** Provide a handle to the service that this job will be run on. */
     public int getServiceToken() {
         return callingUid;
@@ -1042,6 +1049,11 @@
         mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsed;
     }
 
+    @JobParameters.StopReason
+    public int getStopReason() {
+        return mReasonReadyToUnready;
+    }
+
     /**
      * Return the fractional position of "now" within the "run time" window of
      * this job.
@@ -1172,7 +1184,9 @@
     }
 
     /** @return true if the constraint was changed, false otherwise. */
-    boolean setBackgroundNotRestrictedConstraintSatisfied(final long nowElapsed, boolean state) {
+    boolean setBackgroundNotRestrictedConstraintSatisfied(final long nowElapsed, boolean state,
+            boolean isUserBgRestricted) {
+        mIsUserBgRestricted = isUserBgRestricted;
         if (setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, nowElapsed, state)) {
             // The constraint was changed. Update the ready flag.
             mReadyNotRestrictedInBg = state;
@@ -1226,6 +1240,7 @@
                     "Constraint " + constraint + " is " + (!state ? "NOT " : "") + "satisfied for "
                             + toShortString());
         }
+        final boolean wasReady = !state && isReady();
         satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
         mSatisfiedConstraintsOfInterest = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
         mReadyDynamicSatisfied = mDynamicConstraints != 0
@@ -1244,9 +1259,81 @@
         mConstraintChangeHistoryIndex =
                 (mConstraintChangeHistoryIndex + 1) % NUM_CONSTRAINT_CHANGE_HISTORY;
 
+        // Can't use isReady() directly since "cache booleans" haven't updated yet.
+        final boolean isReady = readinessStatusWithConstraint(constraint, state);
+        if (wasReady && !isReady) {
+            mReasonReadyToUnready = constraintToStopReason(constraint);
+        } else if (!wasReady && isReady) {
+            mReasonReadyToUnready = JobParameters.STOP_REASON_UNDEFINED;
+        }
+
         return true;
     }
 
+    @JobParameters.StopReason
+    private int constraintToStopReason(int constraint) {
+        switch (constraint) {
+            case CONSTRAINT_BATTERY_NOT_LOW:
+                if ((requiredConstraints & constraint) != 0) {
+                    // The developer requested this constraint, so it makes sense to return the
+                    // explicit constraint reason.
+                    return JobParameters.STOP_REASON_CONSTRAINT_BATTERY_NOT_LOW;
+                }
+                // Hard-coding right now since the current dynamic constraint sets don't overlap
+                // TODO: return based on active dynamic constraint sets when they start overlapping
+                return JobParameters.STOP_REASON_APP_STANDBY;
+            case CONSTRAINT_CHARGING:
+                if ((requiredConstraints & constraint) != 0) {
+                    // The developer requested this constraint, so it makes sense to return the
+                    // explicit constraint reason.
+                    return JobParameters.STOP_REASON_CONSTRAINT_CHARGING;
+                }
+                // Hard-coding right now since the current dynamic constraint sets don't overlap
+                // TODO: return based on active dynamic constraint sets when they start overlapping
+                return JobParameters.STOP_REASON_APP_STANDBY;
+            case CONSTRAINT_CONNECTIVITY:
+                return JobParameters.STOP_REASON_CONSTRAINT_CONNECTIVITY;
+            case CONSTRAINT_IDLE:
+                if ((requiredConstraints & constraint) != 0) {
+                    // The developer requested this constraint, so it makes sense to return the
+                    // explicit constraint reason.
+                    return JobParameters.STOP_REASON_CONSTRAINT_DEVICE_IDLE;
+                }
+                // Hard-coding right now since the current dynamic constraint sets don't overlap
+                // TODO: return based on active dynamic constraint sets when they start overlapping
+                return JobParameters.STOP_REASON_APP_STANDBY;
+            case CONSTRAINT_STORAGE_NOT_LOW:
+                return JobParameters.STOP_REASON_CONSTRAINT_STORAGE_NOT_LOW;
+
+            case CONSTRAINT_BACKGROUND_NOT_RESTRICTED:
+                // The BACKGROUND_NOT_RESTRICTED constraint could be dissatisfied either because
+                // the app is background restricted, or because we're restricting background work
+                // in battery saver. Assume that background restriction is the reason apps that
+                // are background restricted have their jobs stopped, and battery saver otherwise.
+                // This has the benefit of being consistent for background restricted apps
+                // (they'll always get BACKGROUND_RESTRICTION) as the reason, regardless of
+                // battery saver state.
+                if (mIsUserBgRestricted) {
+                    return JobParameters.STOP_REASON_BACKGROUND_RESTRICTION;
+                }
+                return JobParameters.STOP_REASON_DEVICE_STATE;
+            case CONSTRAINT_DEVICE_NOT_DOZING:
+                return JobParameters.STOP_REASON_DEVICE_STATE;
+
+            case CONSTRAINT_WITHIN_QUOTA:
+            case CONSTRAINT_WITHIN_EXPEDITED_QUOTA:
+                return JobParameters.STOP_REASON_QUOTA;
+
+            // These should never be stop reasons since they can never go from true to false.
+            case CONSTRAINT_CONTENT_TRIGGER:
+            case CONSTRAINT_DEADLINE:
+            case CONSTRAINT_TIMING_DELAY:
+            default:
+                Slog.wtf(TAG, "Unsupported constraint (" + constraint + ") --stop reason mapping");
+                return JobParameters.STOP_REASON_UNDEFINED;
+        }
+    }
+
     boolean isConstraintSatisfied(int constraint) {
         return (satisfiedConstraints&constraint) != 0;
     }
@@ -1330,33 +1417,42 @@
      * granted, based on its requirements.
      */
     boolean wouldBeReadyWithConstraint(int constraint) {
+        return readinessStatusWithConstraint(constraint, true);
+    }
+
+    private boolean readinessStatusWithConstraint(int constraint, boolean value) {
         boolean oldValue = false;
         int satisfied = mSatisfiedConstraintsOfInterest;
         switch (constraint) {
             case CONSTRAINT_BACKGROUND_NOT_RESTRICTED:
                 oldValue = mReadyNotRestrictedInBg;
-                mReadyNotRestrictedInBg = true;
+                mReadyNotRestrictedInBg = value;
                 break;
             case CONSTRAINT_DEADLINE:
                 oldValue = mReadyDeadlineSatisfied;
-                mReadyDeadlineSatisfied = true;
+                mReadyDeadlineSatisfied = value;
                 break;
             case CONSTRAINT_DEVICE_NOT_DOZING:
                 oldValue = mReadyNotDozing;
-                mReadyNotDozing = true;
+                mReadyNotDozing = value;
                 break;
             case CONSTRAINT_WITHIN_QUOTA:
                 oldValue = mReadyWithinQuota;
-                mReadyWithinQuota = true;
+                mReadyWithinQuota = value;
                 break;
             case CONSTRAINT_WITHIN_EXPEDITED_QUOTA:
                 oldValue = mReadyWithinExpeditedQuota;
-                mReadyWithinExpeditedQuota = true;
+                mReadyWithinExpeditedQuota = value;
                 break;
             default:
-                satisfied |= constraint;
+                if (value) {
+                    satisfied |= constraint;
+                } else {
+                    satisfied &= ~constraint;
+                }
                 mReadyDynamicSatisfied = mDynamicConstraints != 0
                         && mDynamicConstraints == (satisfied & mDynamicConstraints);
+
                 break;
         }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/restrictions/JobRestriction.java b/apex/jobscheduler/service/java/com/android/server/job/restrictions/JobRestriction.java
index ac59f95..2962b10 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/restrictions/JobRestriction.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/restrictions/JobRestriction.java
@@ -17,6 +17,7 @@
 package com.android.server.job.restrictions;
 
 import android.app.job.JobInfo;
+import android.app.job.JobParameters;
 import android.util.IndentingPrintWriter;
 import android.util.proto.ProtoOutputStream;
 
@@ -26,9 +27,8 @@
 /**
  * Used by {@link JobSchedulerService} to impose additional restrictions regarding whether jobs
  * should be scheduled or not based on the state of the system/device.
- * Every restriction is associated with exactly one reason (from {@link
- * android.app.job.JobParameters#JOB_STOP_REASON_CODES}), which could be retrieved using {@link
- * #getReason()}.
+ * Every restriction is associated with exactly one stop reason, which could be retrieved using
+ * {@link #getReason()} (and the legacy reason via {@link #getLegacyReason()}).
  * Note, that this is not taken into account for the jobs that have priority
  * {@link JobInfo#PRIORITY_FOREGROUND_APP} or higher.
  */
@@ -36,10 +36,13 @@
 
     final JobSchedulerService mService;
     private final int mReason;
+    private final int mLegacyReason;
 
-    JobRestriction(JobSchedulerService service, int reason) {
+    JobRestriction(JobSchedulerService service, @JobParameters.StopReason int reason,
+            int legacyReason) {
         mService = service;
         mReason = reason;
+        mLegacyReason = legacyReason;
     }
 
     /**
@@ -66,7 +69,12 @@
     public abstract void dumpConstants(ProtoOutputStream proto);
 
     /** @return reason code for the Restriction. */
+    @JobParameters.StopReason
     public final int getReason() {
         return mReason;
     }
+
+    public final int getLegacyReason() {
+        return mLegacyReason;
+    }
 }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java b/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java
index 954a5b8..8b699e9 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java
@@ -34,7 +34,7 @@
     private PowerManager mPowerManager;
 
     public ThermalStatusRestriction(JobSchedulerService service) {
-        super(service, JobParameters.REASON_DEVICE_THERMAL);
+        super(service, JobParameters.STOP_REASON_DEVICE_STATE, JobParameters.REASON_DEVICE_THERMAL);
     }
 
     @Override
diff --git a/core/api/current.txt b/core/api/current.txt
index dad2d7d..c18e122 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5830,8 +5830,8 @@
     method @NonNull public android.app.Notification.BigPictureStyle bigLargeIcon(@Nullable android.graphics.drawable.Icon);
     method @NonNull public android.app.Notification.BigPictureStyle bigPicture(@Nullable android.graphics.Bitmap);
     method @NonNull public android.app.Notification.BigPictureStyle bigPicture(@Nullable android.graphics.drawable.Icon);
-    method @NonNull public android.app.Notification.BigPictureStyle bigPictureContentDescription(@Nullable CharSequence);
     method @NonNull public android.app.Notification.BigPictureStyle setBigContentTitle(@Nullable CharSequence);
+    method @NonNull public android.app.Notification.BigPictureStyle setContentDescription(@Nullable CharSequence);
     method @NonNull public android.app.Notification.BigPictureStyle setSummaryText(@Nullable CharSequence);
     method @NonNull public android.app.Notification.BigPictureStyle showBigPictureWhenCollapsed(boolean);
   }
@@ -7970,6 +7970,7 @@
     method @NonNull public android.os.PersistableBundle getExtras();
     method public int getJobId();
     method @Nullable public android.net.Network getNetwork();
+    method public int getStopReason();
     method @NonNull public android.os.Bundle getTransientExtras();
     method @Nullable public String[] getTriggeredContentAuthorities();
     method @Nullable public android.net.Uri[] getTriggeredContentUris();
@@ -7978,6 +7979,21 @@
     method public boolean isOverrideDeadlineExpired();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.job.JobParameters> CREATOR;
+    field public static final int STOP_REASON_APP_STANDBY = 12; // 0xc
+    field public static final int STOP_REASON_BACKGROUND_RESTRICTION = 11; // 0xb
+    field public static final int STOP_REASON_CANCELLED_BY_APP = 1; // 0x1
+    field public static final int STOP_REASON_CONSTRAINT_BATTERY_NOT_LOW = 5; // 0x5
+    field public static final int STOP_REASON_CONSTRAINT_CHARGING = 6; // 0x6
+    field public static final int STOP_REASON_CONSTRAINT_CONNECTIVITY = 7; // 0x7
+    field public static final int STOP_REASON_CONSTRAINT_DEVICE_IDLE = 8; // 0x8
+    field public static final int STOP_REASON_CONSTRAINT_STORAGE_NOT_LOW = 9; // 0x9
+    field public static final int STOP_REASON_DEVICE_STATE = 4; // 0x4
+    field public static final int STOP_REASON_PREEMPT = 2; // 0x2
+    field public static final int STOP_REASON_QUOTA = 10; // 0xa
+    field public static final int STOP_REASON_SYSTEM_PROCESSING = 14; // 0xe
+    field public static final int STOP_REASON_TIMEOUT = 3; // 0x3
+    field public static final int STOP_REASON_UNDEFINED = 0; // 0x0
+    field public static final int STOP_REASON_USER = 13; // 0xd
   }
 
   public abstract class JobScheduler {
@@ -42128,7 +42144,7 @@
     method public static int getDefaultSmsSubscriptionId();
     method public static int getDefaultSubscriptionId();
     method public static int getDefaultVoiceSubscriptionId();
-    method public int getDeviceToDeviceStatusSharing(int);
+    method public int getDeviceToDeviceStatusSharingPreference(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions();
     method public static int getSlotIndex(int);
     method @Nullable public int[] getSubscriptionIds(int);
@@ -42141,7 +42157,7 @@
     method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
     method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void removeSubscriptionsFromGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDeviceToDeviceStatusSharing(int, int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDeviceToDeviceStatusSharingPreference(int, int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int);
     method public void setSubscriptionOverrideCongested(int, boolean, long);
     method public void setSubscriptionOverrideCongested(int, boolean, @NonNull int[], long);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 7bbabb6..1b3edcf 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1192,12 +1192,14 @@
 
   public class RestoreSet implements android.os.Parcelable {
     ctor public RestoreSet();
-    ctor public RestoreSet(String, String, long);
+    ctor public RestoreSet(@Nullable String, @Nullable String, long);
+    ctor public RestoreSet(@Nullable String, @Nullable String, long, int);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.backup.RestoreSet> CREATOR;
-    field public String device;
-    field public String name;
+    field public final int backupTransportFlags;
+    field @Nullable public String device;
+    field @Nullable public String name;
     field public long token;
   }
 
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 3bfddf7..e5a969a 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -244,6 +244,8 @@
     boolean requestAutofillData(in IAssistDataReceiver receiver, in Bundle receiverExtras,
             in IBinder activityToken, int flags);
     boolean isAssistDataAllowedOnCurrentActivity();
+    boolean requestAssistDataForTask(in IAssistDataReceiver receiver, int taskId,
+            in String callingPackageName);
 
     /**
      * Notify the system that the keyguard is going away.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 3a533c9..4eda6fe 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -20,8 +20,6 @@
 import static android.graphics.drawable.Icon.TYPE_URI;
 import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP;
 
-import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast;
-
 import static java.util.Objects.requireNonNull;
 
 import android.annotation.AttrRes;
@@ -1216,7 +1214,7 @@
     /**
      * {@link #extras} key: this is a content description of the big picture supplied from
      * {@link BigPictureStyle#bigPicture(Bitmap)}, supplied to
-     * {@link BigPictureStyle#bigPictureContentDescription(CharSequence)}.
+     * {@link BigPictureStyle#setContentDescription(CharSequence)}.
      */
     public static final String EXTRA_PICTURE_CONTENT_DESCRIPTION =
             "android.pictureContentDescription";
@@ -3701,8 +3699,6 @@
         private int mTextColorsAreForBackground = COLOR_INVALID;
         private int mPrimaryTextColor = COLOR_INVALID;
         private int mSecondaryTextColor = COLOR_INVALID;
-        private int mBackgroundColor = COLOR_INVALID;
-        private int mForegroundColor = COLOR_INVALID;
         private boolean mRebuildStyledRemoteViews;
 
         private boolean mTintActionButtons;
@@ -5041,7 +5037,8 @@
         private RemoteViews applyStandardTemplate(int resId, StandardTemplateParams p,
                 TemplateBindResult result) {
             p.headerless(resId == getBaseLayoutResource()
-                    || resId == getHeadsUpBaseLayoutResource());
+                    || resId == getHeadsUpBaseLayoutResource()
+                    || resId == R.layout.notification_template_material_media);
             RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId);
 
             resetStandardTemplate(contentView);
@@ -5092,7 +5089,7 @@
         }
 
         private CharSequence processTextSpans(CharSequence text) {
-            if (hasForegroundColor() || mInNightMode) {
+            if (mInNightMode) {
                 return ContrastColorUtil.clearColorSpans(text);
             }
             return text;
@@ -5103,10 +5100,6 @@
             contentView.setTextColor(id, getPrimaryTextColor(p));
         }
 
-        private boolean hasForegroundColor() {
-            return mForegroundColor != COLOR_INVALID;
-        }
-
         /**
          * @param p the template params to inflate this with
          * @return the primary text color
@@ -5140,75 +5133,15 @@
                     || mSecondaryTextColor == COLOR_INVALID
                     || mTextColorsAreForBackground != backgroundColor) {
                 mTextColorsAreForBackground = backgroundColor;
-                if (!hasForegroundColor() || !isColorized(p)) {
-                    mPrimaryTextColor = ContrastColorUtil.resolvePrimaryColor(mContext,
-                            backgroundColor, mInNightMode);
-                    mSecondaryTextColor = ContrastColorUtil.resolveSecondaryColor(mContext,
-                            backgroundColor, mInNightMode);
-                    if (backgroundColor != COLOR_DEFAULT && isColorized(p)) {
-                        mPrimaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
-                                mPrimaryTextColor, backgroundColor, 4.5);
-                        mSecondaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
-                                mSecondaryTextColor, backgroundColor, 4.5);
-                    }
-                } else {
-                    double backLum = ContrastColorUtil.calculateLuminance(backgroundColor);
-                    double textLum = ContrastColorUtil.calculateLuminance(mForegroundColor);
-                    double contrast = ContrastColorUtil.calculateContrast(mForegroundColor,
-                            backgroundColor);
-                    // We only respect the given colors if worst case Black or White still has
-                    // contrast
-                    boolean backgroundLight = backLum > textLum
-                                    && satisfiesTextContrast(backgroundColor, Color.BLACK)
-                            || backLum <= textLum
-                                    && !satisfiesTextContrast(backgroundColor, Color.WHITE);
-                    if (contrast < 4.5f) {
-                        if (backgroundLight) {
-                            mSecondaryTextColor = ContrastColorUtil.findContrastColor(
-                                    mForegroundColor,
-                                    backgroundColor,
-                                    true /* findFG */,
-                                    4.5f);
-                            mPrimaryTextColor = ContrastColorUtil.changeColorLightness(
-                                    mSecondaryTextColor, -LIGHTNESS_TEXT_DIFFERENCE_LIGHT);
-                        } else {
-                            mSecondaryTextColor =
-                                    ContrastColorUtil.findContrastColorAgainstDark(
-                                    mForegroundColor,
-                                    backgroundColor,
-                                    true /* findFG */,
-                                    4.5f);
-                            mPrimaryTextColor = ContrastColorUtil.changeColorLightness(
-                                    mSecondaryTextColor, -LIGHTNESS_TEXT_DIFFERENCE_DARK);
-                        }
-                    } else {
-                        mPrimaryTextColor = mForegroundColor;
-                        mSecondaryTextColor = ContrastColorUtil.changeColorLightness(
-                                mPrimaryTextColor, backgroundLight ? LIGHTNESS_TEXT_DIFFERENCE_LIGHT
-                                        : LIGHTNESS_TEXT_DIFFERENCE_DARK);
-                        if (ContrastColorUtil.calculateContrast(mSecondaryTextColor,
-                                backgroundColor) < 4.5f) {
-                            // oh well the secondary is not good enough
-                            if (backgroundLight) {
-                                mSecondaryTextColor = ContrastColorUtil.findContrastColor(
-                                        mSecondaryTextColor,
-                                        backgroundColor,
-                                        true /* findFG */,
-                                        4.5f);
-                            } else {
-                                mSecondaryTextColor
-                                        = ContrastColorUtil.findContrastColorAgainstDark(
-                                        mSecondaryTextColor,
-                                        backgroundColor,
-                                        true /* findFG */,
-                                        4.5f);
-                            }
-                            mPrimaryTextColor = ContrastColorUtil.changeColorLightness(
-                                    mSecondaryTextColor, backgroundLight
-                                            ? -LIGHTNESS_TEXT_DIFFERENCE_LIGHT
-                                            : -LIGHTNESS_TEXT_DIFFERENCE_DARK);
-                        }
-                    }
+                mPrimaryTextColor = ContrastColorUtil.resolvePrimaryColor(mContext,
+                        backgroundColor, mInNightMode);
+                mSecondaryTextColor = ContrastColorUtil.resolveSecondaryColor(mContext,
+                        backgroundColor, mInNightMode);
+                if (backgroundColor != COLOR_DEFAULT && isColorized(p)) {
+                    mPrimaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
+                            mPrimaryTextColor, backgroundColor, 4.5);
+                    mSecondaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
+                            mSecondaryTextColor, backgroundColor, 4.5);
                 }
             }
         }
@@ -5254,11 +5187,7 @@
                 result = new TemplateBindResult();
             }
             bindLargeIcon(contentView, p, result);
-            if (p.mHeaderless) {
-                // views in the headerless (collapsed) state
-                result.mHeadingExtraMarginSet.applyToView(contentView,
-                        R.id.notification_headerless_view_column);
-            } else {
+            if (!p.mHeaderless) {
                 // views in states with a header (big states)
                 result.mHeadingExtraMarginSet.applyToView(contentView, R.id.notification_header);
                 result.mTitleMarginSet.applyToView(contentView, R.id.title);
@@ -5278,6 +5207,8 @@
                 @NonNull TemplateBindResult result) {
             final Resources resources = mContext.getResources();
             final float density = resources.getDisplayMetrics().density;
+            final float iconMarginDp = resources.getDimension(
+                    R.dimen.notification_right_icon_content_margin) / density;
             final float contentMarginDp = resources.getDimension(
                     R.dimen.notification_content_margin_end) / density;
             final float expanderSizeDp = resources.getDimension(
@@ -5299,7 +5230,7 @@
                     }
                 }
             }
-            final float extraMarginEndDpIfVisible = viewWidthDp + contentMarginDp;
+            final float extraMarginEndDpIfVisible = viewWidthDp + iconMarginDp;
             result.setRightIconState(largeIconShown, viewWidthDp,
                     extraMarginEndDpIfVisible, expanderSizeDp);
         }
@@ -5363,7 +5294,7 @@
 
         private void bindHeaderChronometerAndTime(RemoteViews contentView,
                 StandardTemplateParams p, boolean hasTextToLeft) {
-            if (showsTimeOrChronometer()) {
+            if (!p.mHideTime && showsTimeOrChronometer()) {
                 if (hasTextToLeft) {
                     contentView.setViewVisibility(R.id.time_divider, View.VISIBLE);
                     setTextViewColorSecondary(contentView, R.id.time_divider, p);
@@ -5394,6 +5325,9 @@
          */
         private boolean bindHeaderText(RemoteViews contentView, StandardTemplateParams p,
                 boolean hasTextToLeft) {
+            if (p.mHideSubText) {
+                return false;
+            }
             CharSequence summaryText = p.summaryText;
             if (summaryText == null && mStyle != null && mStyle.mSummaryTextSet
                     && mStyle.hasSummaryInHeader()) {
@@ -5424,6 +5358,9 @@
          */
         private boolean bindHeaderTextSecondary(RemoteViews contentView, StandardTemplateParams p,
                 boolean hasTextToLeft) {
+            if (p.mHideSubText) {
+                return false;
+            }
             if (!TextUtils.isEmpty(p.headerTextSecondary)) {
                 contentView.setTextViewText(R.id.header_text_secondary, processTextSpans(
                         processLegacyText(p.headerTextSecondary)));
@@ -6654,7 +6591,7 @@
          */
         private @ColorInt int getUnresolvedBackgroundColor(StandardTemplateParams p) {
             if (isColorized(p)) {
-                return mBackgroundColor != COLOR_INVALID ? mBackgroundColor : getRawColor(p);
+                return getRawColor(p);
             } else {
                 return COLOR_DEFAULT;
             }
@@ -6682,21 +6619,6 @@
         }
 
         /**
-         * Set a color palette to be used as the background and textColors
-         *
-         * @param backgroundColor the color to be used as the background
-         * @param foregroundColor the color to be used as the foreground
-         *
-         * @hide
-         */
-        public void setColorPalette(@ColorInt int backgroundColor, @ColorInt int foregroundColor) {
-            mBackgroundColor = backgroundColor;
-            mForegroundColor = foregroundColor;
-            mTextColorsAreForBackground = COLOR_INVALID;
-            ensureColors(mParams.reset().fillTextsFrom(this));
-        }
-
-        /**
          * Forces all styled remoteViews to be built from scratch and not use any cached
          * RemoteViews.
          * This is needed for legacy apps that are baking in their remoteviews into the
@@ -6752,24 +6674,14 @@
         if (mLargeIcon != null || largeIcon != null) {
             Resources resources = context.getResources();
             Class<? extends Style> style = getNotificationStyle();
-            int maxWidth = resources.getDimensionPixelSize(isLowRam
+            int maxSize = resources.getDimensionPixelSize(isLowRam
                     ? R.dimen.notification_right_icon_size_low_ram
                     : R.dimen.notification_right_icon_size);
-            int maxHeight = maxWidth;
-            if (MediaStyle.class.equals(style)
-                    || DecoratedMediaCustomViewStyle.class.equals(style)) {
-                maxHeight = resources.getDimensionPixelSize(isLowRam
-                        ? R.dimen.notification_media_image_max_height_low_ram
-                        : R.dimen.notification_media_image_max_height);
-                maxWidth = resources.getDimensionPixelSize(isLowRam
-                        ? R.dimen.notification_media_image_max_width_low_ram
-                        : R.dimen.notification_media_image_max_width);
-            }
             if (mLargeIcon != null) {
-                mLargeIcon.scaleDownIfNecessary(maxWidth, maxHeight);
+                mLargeIcon.scaleDownIfNecessary(maxSize, maxSize);
             }
             if (largeIcon != null) {
-                largeIcon = Icon.scaleDownIfNecessary(largeIcon, maxWidth, maxHeight);
+                largeIcon = Icon.scaleDownIfNecessary(largeIcon, maxSize, maxSize);
             }
         }
         reduceImageSizesForRemoteView(contentView, context, isLowRam);
@@ -6856,9 +6768,6 @@
      * @hide
      */
     public boolean isColorized() {
-        if (isColorizedMedia()) {
-            return true;
-        }
         return extras.getBoolean(EXTRA_COLORIZED)
                 && (hasColorizedPermission() || isForegroundService());
     }
@@ -6872,27 +6781,6 @@
     }
 
     /**
-     * @return true if this notification is colorized and it is a media notification
-     *
-     * @hide
-     */
-    public boolean isColorizedMedia() {
-        Class<? extends Style> style = getNotificationStyle();
-        if (MediaStyle.class.equals(style)) {
-            Boolean colorized = (Boolean) extras.get(EXTRA_COLORIZED);
-            if ((colorized == null || colorized) && hasMediaSession()) {
-                return true;
-            }
-        } else if (DecoratedMediaCustomViewStyle.class.equals(style)) {
-            if (extras.getBoolean(EXTRA_COLORIZED) && hasMediaSession()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-
-    /**
      * @return true if this is a media notification
      *
      * @hide
@@ -7180,15 +7068,6 @@
 
         /**
          * @hide
-         * @return true if the style positions the progress bar on the second line; false if the
-         *         style hides the progress bar
-         */
-        protected boolean hasProgress() {
-            return true;
-        }
-
-        /**
-         * @hide
          * @return Whether we should put the summary be put into the notification header
          */
         public boolean hasSummaryInHeader() {
@@ -7292,7 +7171,7 @@
          * Set the content description of the big picture.
          */
         @NonNull
-        public BigPictureStyle bigPictureContentDescription(
+        public BigPictureStyle setContentDescription(
                 @Nullable CharSequence contentDescription) {
             mPictureContentDescription = contentDescription;
             return this;
@@ -9041,7 +8920,7 @@
          */
         @Override
         public RemoteViews makeContentView(boolean increasedHeight) {
-            return makeMediaContentView();
+            return makeMediaContentView(null /* customContent */);
         }
 
         /**
@@ -9049,7 +8928,7 @@
          */
         @Override
         public RemoteViews makeBigContentView() {
-            return makeMediaBigContentView();
+            return makeMediaBigContentView(null /* customContent */);
         }
 
         /**
@@ -9057,7 +8936,7 @@
          */
         @Override
         public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
-            return makeMediaContentView();
+            return makeMediaContentView(null /* customContent */);
         }
 
         /** @hide */
@@ -9127,88 +9006,72 @@
             container.setContentDescription(buttonId, action.title);
         }
 
-        private RemoteViews makeMediaContentView() {
-            StandardTemplateParams p = mBuilder.mParams.reset()
-                    .viewType(StandardTemplateParams.VIEW_TYPE_NORMAL)
-                    .hideProgress(true)
-                    .fillTextsFrom(mBuilder);
-            RemoteViews view = mBuilder.applyStandardTemplate(
-                    R.layout.notification_template_material_media, p,
-                    null /* result */);
-
+        /** @hide */
+        protected RemoteViews makeMediaContentView(@Nullable RemoteViews customContent) {
             final int numActions = mBuilder.mActions.size();
-            final int numActionsToShow = mActionsToShowInCompact == null
-                    ? 0
-                    : Math.min(mActionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT);
+            final int numActionsToShow = Math.min(mActionsToShowInCompact == null
+                    ? 0 : mActionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT);
             if (numActionsToShow > numActions) {
                 throw new IllegalArgumentException(String.format(
                         "setShowActionsInCompactView: action %d out of bounds (max %d)",
                         numActions, numActions - 1));
             }
+
+            StandardTemplateParams p = mBuilder.mParams.reset()
+                    .viewType(StandardTemplateParams.VIEW_TYPE_NORMAL)
+                    .hideTime(numActionsToShow > 1)    // hide if actions wider than a large icon
+                    .hideSubText(numActionsToShow > 1) // hide if actions wider than a large icon
+                    .hideLargeIcon(numActionsToShow > 0)  // large icon or actions; not both
+                    .hideProgress(true)
+                    .fillTextsFrom(mBuilder);
+            TemplateBindResult result = new TemplateBindResult();
+            RemoteViews template = mBuilder.applyStandardTemplate(
+                    R.layout.notification_template_material_media, p,
+                    null /* result */);
+
             for (int i = 0; i < MAX_MEDIA_BUTTONS_IN_COMPACT; i++) {
                 if (i < numActionsToShow) {
                     final Action action = mBuilder.mActions.get(mActionsToShowInCompact[i]);
-                    bindMediaActionButton(view, MEDIA_BUTTON_IDS[i], action, p);
+                    bindMediaActionButton(template, MEDIA_BUTTON_IDS[i], action, p);
                 } else {
-                    view.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE);
+                    template.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE);
                 }
             }
-            handleImage(view);
-            // handle the content margin
-            int endMargin = R.dimen.notification_content_margin_end;
-            if (mBuilder.mN.hasLargeIcon()) {
-                endMargin = R.dimen.notification_media_image_margin_end;
-            }
-            view.setViewLayoutMarginDimen(R.id.notification_main_column,
-                            RemoteViews.MARGIN_END, endMargin);
-            return view;
+            // Prevent a swooping expand animation when there are no actions
+            boolean hasActions = numActionsToShow != 0;
+            template.setViewVisibility(R.id.media_actions, hasActions ? View.VISIBLE : View.GONE);
+
+            // Add custom view if provided by subclass.
+            buildCustomContentIntoTemplate(mBuilder.mContext, template, customContent, p, result,
+                    DevFlags.DECORATION_PARTIAL);
+            return template;
         }
 
-        private RemoteViews makeMediaBigContentView() {
+        /** @hide */
+        protected RemoteViews makeMediaBigContentView(@Nullable RemoteViews customContent) {
             final int actionCount = Math.min(mBuilder.mActions.size(), MAX_MEDIA_BUTTONS);
-            // Dont add an expanded view if there is no more content to be revealed
-            int actionsInCompact = mActionsToShowInCompact == null
-                    ? 0
-                    : Math.min(mActionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT);
-            if (!mBuilder.mN.hasLargeIcon() && actionCount <= actionsInCompact) {
-                return null;
-            }
             StandardTemplateParams p = mBuilder.mParams.reset()
                     .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
                     .hideProgress(true)
                     .fillTextsFrom(mBuilder);
-            RemoteViews big = mBuilder.applyStandardTemplate(
-                    R.layout.notification_template_material_big_media, p , null /* result */);
+            TemplateBindResult result = new TemplateBindResult();
+            RemoteViews template = mBuilder.applyStandardTemplate(
+                    R.layout.notification_template_material_big_media, p , result);
 
             for (int i = 0; i < MAX_MEDIA_BUTTONS; i++) {
                 if (i < actionCount) {
-                    bindMediaActionButton(big, MEDIA_BUTTON_IDS[i], mBuilder.mActions.get(i), p);
+                    bindMediaActionButton(template,
+                            MEDIA_BUTTON_IDS[i], mBuilder.mActions.get(i), p);
                 } else {
-                    big.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE);
+                    template.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE);
                 }
             }
-            handleImage(big);
-            return big;
-        }
-
-        private void handleImage(RemoteViews contentView) {
-            if (mBuilder.mN.hasLargeIcon()) {
-                contentView.setViewLayoutMarginDimen(R.id.title, RemoteViews.MARGIN_END, 0);
-                contentView.setViewLayoutMarginDimen(R.id.text, RemoteViews.MARGIN_END, 0);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        @Override
-        protected boolean hasProgress() {
-            return false;
+            buildCustomContentIntoTemplate(mBuilder.mContext, template, customContent, p, result,
+                    DevFlags.DECORATION_PARTIAL);
+            return template;
         }
     }
 
-
-
     /**
      * Helper class for generating large-format notifications that include a large image attachment.
      *
@@ -9896,9 +9759,7 @@
          */
         @Override
         public RemoteViews makeContentView(boolean increasedHeight) {
-            RemoteViews remoteViews = super.makeContentView(false /* increasedHeight */);
-            return buildIntoRemoteView(remoteViews, R.id.notification_content_container,
-                    mBuilder.mN.contentView);
+            return makeMediaContentView(mBuilder.mN.contentView);
         }
 
         /**
@@ -9906,24 +9767,10 @@
          */
         @Override
         public RemoteViews makeBigContentView() {
-            RemoteViews customRemoteView = mBuilder.mN.bigContentView != null
+            RemoteViews customContent = mBuilder.mN.bigContentView != null
                     ? mBuilder.mN.bigContentView
                     : mBuilder.mN.contentView;
-            return makeBigContentViewWithCustomContent(customRemoteView);
-        }
-
-        private RemoteViews makeBigContentViewWithCustomContent(RemoteViews customRemoteView) {
-            RemoteViews remoteViews = super.makeBigContentView();
-            if (remoteViews != null) {
-                return buildIntoRemoteView(remoteViews, R.id.notification_main_column,
-                        customRemoteView);
-            } else if (customRemoteView != mBuilder.mN.contentView){
-                remoteViews = super.makeContentView(false /* increasedHeight */);
-                return buildIntoRemoteView(remoteViews, R.id.notification_content_container,
-                        customRemoteView);
-            } else {
-                return null;
-            }
+            return makeMediaBigContentView(customContent);
         }
 
         /**
@@ -9931,10 +9778,10 @@
          */
         @Override
         public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
-            RemoteViews customRemoteView = mBuilder.mN.headsUpContentView != null
+            RemoteViews customContent = mBuilder.mN.headsUpContentView != null
                     ? mBuilder.mN.headsUpContentView
                     : mBuilder.mN.contentView;
-            return makeBigContentViewWithCustomContent(customRemoteView);
+            return makeMediaBigContentView(customContent);
         }
 
         /**
@@ -9949,18 +9796,21 @@
             return false;
         }
 
-        private RemoteViews buildIntoRemoteView(RemoteViews remoteViews, int id,
-                RemoteViews customContent) {
+        private RemoteViews buildIntoRemoteView(RemoteViews template, RemoteViews customContent,
+                boolean headerless) {
             if (customContent != null) {
                 // Need to clone customContent before adding, because otherwise it can no longer be
                 // parceled independently of remoteViews.
                 customContent = customContent.clone();
                 customContent.overrideTextColors(mBuilder.getPrimaryTextColor(mBuilder.mParams));
-                remoteViews.removeAllViews(id);
-                remoteViews.addView(id, customContent);
-                remoteViews.addFlags(RemoteViews.FLAG_REAPPLY_DISALLOWED);
+                if (headerless) {
+                    template.removeFromParent(R.id.notification_top_line);
+                }
+                template.removeAllViews(R.id.notification_main_column);
+                template.addView(R.id.notification_main_column, customContent);
+                template.addFlags(RemoteViews.FLAG_REAPPLY_DISALLOWED);
             }
-            return remoteViews;
+            return template;
         }
     }
 
@@ -12253,6 +12103,8 @@
         boolean mHeaderless;
         boolean mHideAppName;
         boolean mHideTitle;
+        boolean mHideSubText;
+        boolean mHideTime;
         boolean mHideActions;
         boolean mHideProgress;
         boolean mHideSnoozeButton;
@@ -12275,6 +12127,8 @@
             mHeaderless = false;
             mHideAppName = false;
             mHideTitle = false;
+            mHideSubText = false;
+            mHideTime = false;
             mHideActions = false;
             mHideProgress = false;
             mHideSnoozeButton = false;
@@ -12288,6 +12142,7 @@
             summaryText = null;
             headerTextSecondary = null;
             maxRemoteInputHistory = Style.MAX_REMOTE_INPUT_HISTORY_LINES;
+            hideLargeIcon = false;
             allowColorization = true;
             mReduceHighlights = false;
             return this;
@@ -12312,6 +12167,16 @@
             return this;
         }
 
+        public StandardTemplateParams hideSubText(boolean hideSubText) {
+            mHideSubText = hideSubText;
+            return this;
+        }
+
+        public StandardTemplateParams hideTime(boolean hideTime) {
+            mHideTime = hideTime;
+            return this;
+        }
+
         final StandardTemplateParams hideActions(boolean hideActions) {
             this.mHideActions = hideActions;
             return this;
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index 6b2e649..d640a6f 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -189,7 +189,7 @@
         } else {
             palette = Palette
                     .from(bitmap, new CelebiQuantizer())
-                    .maximumColorCount(256)
+                    .maximumColorCount(5)
                     .resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA)
                     .generate();
         }
diff --git a/core/java/android/app/backup/RestoreSet.java b/core/java/android/app/backup/RestoreSet.java
index 6759346..51430c0 100644
--- a/core/java/android/app/backup/RestoreSet.java
+++ b/core/java/android/app/backup/RestoreSet.java
@@ -16,6 +16,7 @@
 
 package android.app.backup;
 
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -32,12 +33,14 @@
      * Name of this restore set.  May be user generated, may simply be the name
      * of the handset model, e.g. "T-Mobile G1".
      */
+    @Nullable
     public String name;
 
     /**
      * Identifier of the device whose data this is.  This will be as unique as
      * is practically possible; for example, it might be an IMEI.
      */
+    @Nullable
     public String device;
 
     /**
@@ -47,15 +50,48 @@
      */
     public long token;
 
+    /**
+     * Properties of the {@link BackupTransport} transport that was used to obtain the data in
+     * this restore set.
+     */
+    public final int backupTransportFlags;
 
+    /**
+     * Constructs a RestoreSet object that identifies a set of data that can be restored.
+     */
     public RestoreSet() {
         // Leave everything zero / null
+        backupTransportFlags = 0;
     }
 
-    public RestoreSet(String _name, String _dev, long _token) {
-        name = _name;
-        device = _dev;
-        token = _token;
+    /**
+     * Constructs a RestoreSet object that identifies a set of data that can be restored.
+     *
+     * @param name The name of the restore set.
+     * @param device The name of the device where the restore data is coming from.
+     * @param token The unique identifier for the current restore set.
+     */
+    public RestoreSet(@Nullable String name, @Nullable String device, long token) {
+        this(name, device, token, /* backupTransportFlags */ 0);
+    }
+
+    /**
+     * Constructs a RestoreSet object that identifies a set of data that can be restored.
+     *
+     * @param name The name of the restore set.
+     * @param device The name of the device where the restore data is coming from.
+     * @param token The unique identifier for the current restore set.
+     * @param backupTransportFlags Flags returned by {@link BackupTransport#getTransportFlags()}
+     *                             implementation of the backup transport used by the source device
+     *                             to create this restore set. See {@link BackupAgent} for possible
+     *                             flag values.
+     */
+    public RestoreSet(@Nullable String name, @Nullable String device, long token,
+            int backupTransportFlags) {
+        this.name = name;
+        this.device = device;
+        this.token = token;
+        this.backupTransportFlags = backupTransportFlags;
     }
 
     // Parcelable implementation
@@ -67,6 +103,7 @@
         out.writeString(name);
         out.writeString(device);
         out.writeLong(token);
+        out.writeInt(backupTransportFlags);
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<RestoreSet> CREATOR
@@ -84,5 +121,6 @@
         name = in.readString();
         device = in.readString();
         token = in.readLong();
+        backupTransportFlags = in.readInt();
     }
 }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index fa6472e..4674aa2 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -6030,7 +6030,7 @@
                     pw.print(":");
                     for (int it=0; it<types.size(); it++) {
                         pw.print(" ");
-                        pw.print(JobParameters.getReasonCodeDescription(types.keyAt(it)));
+                        pw.print(JobParameters.getLegacyReasonCodeDescription(types.keyAt(it)));
                         pw.print("(");
                         pw.print(types.valueAt(it));
                         pw.print("x)");
diff --git a/core/java/android/util/SparseDoubleArray.java b/core/java/android/util/SparseDoubleArray.java
new file mode 100644
index 0000000..dc93a47
--- /dev/null
+++ b/core/java/android/util/SparseDoubleArray.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.util;
+
+/**
+ * SparseDoubleArrays map integers to doubles.  Unlike a normal array of doubles,
+ * there can be gaps in the indices.  It is intended to be more memory efficient
+ * than using a HashMap to map Integers to Doubles, both because it avoids
+ * auto-boxing keys and values and its data structure doesn't rely on an extra entry object
+ * for each mapping.
+ *
+ * <p>Note that this container keeps its mappings in an array data structure,
+ * using a binary search to find keys.  The implementation is not intended to be appropriate for
+ * data structures
+ * that may contain large numbers of items.  It is generally slower than a traditional
+ * HashMap, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array.  For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)</code>.</p>
+ *
+ * @see SparseLongArray
+ *
+ * @hide
+ */
+public class SparseDoubleArray implements Cloneable {
+    /**
+     * The int->double map, but storing the doubles as longs using
+     * {@link Double#doubleToRawLongBits(double)}.
+     */
+    private SparseLongArray mValues;
+
+    /** Creates a new SparseDoubleArray containing no mappings. */
+    public SparseDoubleArray() {
+        this(10);
+    }
+
+    /**
+     * Creates a new SparseDoubleArray, containing no mappings, that will not
+     * require any additional memory allocation to store the specified
+     * number of mappings.  If you supply an initial capacity of 0, the
+     * sparse array will be initialized with a light-weight representation
+     * not requiring any additional array allocations.
+     */
+    public SparseDoubleArray(int initialCapacity) {
+        mValues = new SparseLongArray(initialCapacity);
+    }
+
+    @Override
+    public SparseDoubleArray clone() {
+        SparseDoubleArray clone = null;
+        try {
+            clone = (SparseDoubleArray) super.clone();
+            clone.mValues = mValues.clone();
+        } catch (CloneNotSupportedException cnse) {
+            /* ignore */
+        }
+        return clone;
+    }
+
+    /**
+     * Gets the double mapped from the specified key, or <code>0</code>
+     * if no such mapping has been made.
+     */
+    public double get(int key) {
+        final int index = mValues.indexOfKey(key);
+        if (index < 0) {
+            return 0.0d;
+        }
+        return valueAt(index);
+    }
+
+    /**
+     * Adds a mapping from the specified key to the specified value,
+     * replacing the previous mapping from the specified key if there
+     * was one.
+     */
+    public void put(int key, double value) {
+        mValues.put(key, Double.doubleToRawLongBits(value));
+    }
+
+    /**
+     * Adds a mapping from the specified key to the specified value,
+     * <b>adding</b> its value to the previous mapping from the specified key if there
+     * was one.
+     *
+     * <p>This differs from {@link #put} because instead of replacing any previous value, it adds
+     * (in the numerical sense) to it.
+     */
+    public void add(int key, double summand) {
+        final double oldValue = get(key);
+        put(key, oldValue + summand);
+    }
+
+    /** Returns the number of key-value mappings that this SparseDoubleArray currently stores. */
+    public int size() {
+        return mValues.size();
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, returns
+     * the key from the <code>index</code>th key-value mapping that this
+     * SparseDoubleArray stores.
+     *
+     * @see SparseLongArray#keyAt(int)
+     */
+    public int keyAt(int index) {
+        return mValues.keyAt(index);
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, returns
+     * the value from the <code>index</code>th key-value mapping that this
+     * SparseDoubleArray stores.
+     *
+     * @see SparseLongArray#valueAt(int)
+     */
+    public double valueAt(int index) {
+        return Double.longBitsToDouble(mValues.valueAt(index));
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation composes a string by iterating over its mappings.
+     */
+    @Override
+    public String toString() {
+        if (size() <= 0) {
+            return "{}";
+        }
+
+        StringBuilder buffer = new StringBuilder(size() * 34);
+        buffer.append('{');
+        for (int i = 0; i < size(); i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            int key = keyAt(i);
+            buffer.append(key);
+            buffer.append('=');
+            double value = valueAt(i);
+            buffer.append(value);
+        }
+        buffer.append('}');
+        return buffer.toString();
+    }
+}
diff --git a/core/java/android/view/NotificationTopLineView.java b/core/java/android/view/NotificationTopLineView.java
index 05636de..bd20f5b 100644
--- a/core/java/android/view/NotificationTopLineView.java
+++ b/core/java/android/view/NotificationTopLineView.java
@@ -26,6 +26,9 @@
 
 import com.android.internal.R;
 
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  * The top line of content in a notification view.
  * This includes the text views and badges but excludes the icon and the expander.
@@ -34,17 +37,23 @@
  */
 @RemoteViews.RemoteView
 public class NotificationTopLineView extends ViewGroup {
+    private final OverflowAdjuster mOverflowAdjuster = new OverflowAdjuster();
     private final int mGravityY;
     private final int mChildMinWidth;
+    private final int mChildHideWidth;
     @Nullable private View mAppName;
     @Nullable private View mTitle;
     private View mHeaderText;
+    private View mHeaderTextDivider;
     private View mSecondaryHeaderText;
+    private View mSecondaryHeaderTextDivider;
     private OnClickListener mFeedbackListener;
     private HeaderTouchListener mTouchListener = new HeaderTouchListener();
     private View mFeedbackIcon;
     private int mHeaderTextMarginEnd;
 
+    private Set<View> mViewsToDisappear = new HashSet<>();
+
     private int mMaxAscent;
     private int mMaxDescent;
 
@@ -66,6 +75,7 @@
         super(context, attrs, defStyleAttr, defStyleRes);
         Resources res = getResources();
         mChildMinWidth = res.getDimensionPixelSize(R.dimen.notification_header_shrink_min_width);
+        mChildHideWidth = res.getDimensionPixelSize(R.dimen.notification_header_shrink_hide_width);
 
         // NOTE: Implementation only supports TOP, BOTTOM, and CENTER_VERTICAL gravities,
         // with CENTER_VERTICAL being the default.
@@ -88,7 +98,9 @@
         mAppName = findViewById(R.id.app_name_text);
         mTitle = findViewById(R.id.title);
         mHeaderText = findViewById(R.id.header_text);
+        mHeaderTextDivider = findViewById(R.id.header_text_divider);
         mSecondaryHeaderText = findViewById(R.id.header_text_secondary);
+        mSecondaryHeaderTextDivider = findViewById(R.id.header_text_secondary_divider);
         mFeedbackIcon = findViewById(R.id.feedback);
     }
 
@@ -125,48 +137,37 @@
             maxChildHeight = Math.max(maxChildHeight, childHeight);
         }
 
+        mViewsToDisappear.clear();
         // Ensure that there is at least enough space for the icons
         int endMargin = Math.max(mHeaderTextMarginEnd, getPaddingEnd());
         if (totalWidth > givenWidth - endMargin) {
             int overFlow = totalWidth - givenWidth + endMargin;
 
-            // First shrink the app name, down to a minimum size
-            overFlow = shrinkViewForOverflow(heightSpec, overFlow, mAppName, mChildMinWidth);
-
-            // Next, shrink the header text (this usually has subText)
-            //   This shrinks the subtext first, but not all the way (yet!)
-            overFlow = shrinkViewForOverflow(heightSpec, overFlow, mHeaderText, mChildMinWidth);
-
-            // Next, shrink the secondary header text  (this rarely has conversationTitle)
-            overFlow = shrinkViewForOverflow(heightSpec, overFlow, mSecondaryHeaderText, 0);
-
-            // Next, shrink the title text (this has contentTitle; only in headerless views)
-            overFlow = shrinkViewForOverflow(heightSpec, overFlow, mTitle, mChildMinWidth);
-
-            // Finally, if there is still overflow, shrink the header down to 0 if still necessary.
-            shrinkViewForOverflow(heightSpec, overFlow, mHeaderText, 0);
+            mOverflowAdjuster.resetForOverflow(overFlow, heightSpec)
+                    // First shrink the app name, down to a minimum size
+                    .adjust(mAppName, null, mChildMinWidth)
+                    // Next, shrink the header text (this usually has subText)
+                    //   This shrinks the subtext first, but not all the way (yet!)
+                    .adjust(mHeaderText, mHeaderTextDivider, mChildMinWidth)
+                    // Next, shrink the secondary header text  (this rarely has conversationTitle)
+                    .adjust(mSecondaryHeaderText, mSecondaryHeaderTextDivider, 0)
+                    // Next, shrink the title text (this has contentTitle; only in headerless views)
+                    .adjust(mTitle, null, mChildMinWidth)
+                    // Next, shrink the header down to 0 if still necessary.
+                    .adjust(mHeaderText, mHeaderTextDivider, 0)
+                    // Finally, shrink the title to 0 if necessary (media is super cramped)
+                    .adjust(mTitle, null, 0)
+                    // Clean up
+                    .finish();
         }
         setMeasuredDimension(givenWidth, wrapHeight ? maxChildHeight : givenHeight);
     }
 
-    private int shrinkViewForOverflow(int heightSpec, int overFlow, View targetView,
-            int minimumWidth) {
-        if (targetView != null) {
-            final int oldWidth = targetView.getMeasuredWidth();
-            if (overFlow > 0 && targetView.getVisibility() != GONE && oldWidth > minimumWidth) {
-                // we're still too big
-                int newSize = Math.max(minimumWidth, oldWidth - overFlow);
-                int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST);
-                targetView.measure(childWidthSpec, heightSpec);
-                overFlow -= oldWidth - newSize;
-            }
-        }
-        return overFlow;
-    }
-
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        int left = getPaddingStart();
+        final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+        final int width = getWidth();
+        int start = getPaddingStart();
         int childCount = getChildCount();
         int ownHeight = b - t;
         int childSpace = ownHeight - mPaddingTop - mPaddingBottom;
@@ -182,8 +183,6 @@
             }
             int childHeight = child.getMeasuredHeight();
             MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
-            int layoutLeft;
-            int layoutRight;
 
             // Calculate vertical alignment of the views, accounting for the view baselines
             int childTop;
@@ -219,19 +218,16 @@
                 default:
                     childTop = mPaddingTop;
             }
-
-            left += params.getMarginStart();
-            int right = left + child.getMeasuredWidth();
-            layoutLeft = left;
-            layoutRight = right;
-            left = right + params.getMarginEnd();
-
-            if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
-                int ltrLeft = layoutLeft;
-                layoutLeft = getWidth() - layoutRight;
-                layoutRight = getWidth() - ltrLeft;
+            if (mViewsToDisappear.contains(child)) {
+                child.layout(start, childTop, start, childTop + childHeight);
+            } else {
+                start += params.getMarginStart();
+                int end = start + child.getMeasuredWidth();
+                int layoutLeft = isRtl ? width - end : start;
+                int layoutRight = isRtl ? width - start : end;
+                start = end + params.getMarginEnd();
+                child.layout(layoutLeft, childTop, layoutRight, childTop + childHeight);
             }
-            child.layout(layoutLeft, childTop, layoutRight, childTop + childHeight);
         }
         updateTouchListener();
     }
@@ -400,4 +396,83 @@
         }
         return mTouchListener.onTouchUp(upX, upY, downX, downY);
     }
+
+    private final class OverflowAdjuster {
+        private int mOverflow;
+        private int mHeightSpec;
+        private View mRegrowView;
+
+        OverflowAdjuster resetForOverflow(int overflow, int heightSpec) {
+            mOverflow = overflow;
+            mHeightSpec = heightSpec;
+            mRegrowView = null;
+            return this;
+        }
+
+        /**
+         * Shrink the targetView's width by up to overFlow, down to minimumWidth.
+         * @param targetView the view to shrink the width of
+         * @param targetDivider a divider view which should be set to 0 width if the targetView is
+         * @param minimumWidth the minimum width allowed for the targetView
+         * @return this object
+         */
+        OverflowAdjuster adjust(View targetView, View targetDivider, int minimumWidth) {
+            if (mOverflow <= 0 || targetView == null || targetView.getVisibility() == View.GONE) {
+                return this;
+            }
+            final int oldWidth = targetView.getMeasuredWidth();
+            if (oldWidth <= minimumWidth) {
+                return this;
+            }
+            // we're too big
+            int newSize = Math.max(minimumWidth, oldWidth - mOverflow);
+            if (minimumWidth == 0 && newSize < mChildHideWidth
+                    && mRegrowView != null && mRegrowView != targetView) {
+                // View is so small it's better to hide it entirely (and its divider and margins)
+                // so we can give that space back to another previously shrunken view.
+                newSize = 0;
+            }
+
+            int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST);
+            targetView.measure(childWidthSpec, mHeightSpec);
+            mOverflow -= oldWidth - newSize;
+
+            if (newSize == 0) {
+                mViewsToDisappear.add(targetView);
+                mOverflow -= getHorizontalMargins(targetView);
+                if (targetDivider != null && targetDivider.getVisibility() != GONE) {
+                    mViewsToDisappear.add(targetDivider);
+                    int oldDividerWidth = targetDivider.getMeasuredWidth();
+                    int dividerWidthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.AT_MOST);
+                    targetDivider.measure(dividerWidthSpec, mHeightSpec);
+                    mOverflow -= (oldDividerWidth + getHorizontalMargins(targetDivider));
+                }
+            }
+            if (mOverflow < 0 && mRegrowView != null) {
+                // We're now under-flowing, so regrow the last view.
+                final int regrowCurrentSize = mRegrowView.getMeasuredWidth();
+                final int maxSize = regrowCurrentSize - mOverflow;
+                int regrowWidthSpec = MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST);
+                mRegrowView.measure(regrowWidthSpec, mHeightSpec);
+                finish();
+                return this;
+            }
+
+            if (newSize != 0) {
+                // if we shrunk this view (but did not completely hide it) store it for potential
+                // re-growth if we proactively shorten a future view.
+                mRegrowView = targetView;
+            }
+            return this;
+        }
+
+        void finish() {
+            resetForOverflow(0, 0);
+        }
+
+        private int getHorizontalMargins(View view) {
+            MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
+            return params.getMarginStart() + params.getMarginEnd();
+        }
+    }
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 66ee23a1..dbccf10 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1370,17 +1370,10 @@
             // can be used by code on the system process to escape that and enable
             // HW accelerated drawing.  (This is basically for the lock screen.)
 
-            final boolean fakeHwAccelerated = (attrs.privateFlags &
-                    WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
             final boolean forceHwAccelerated = (attrs.privateFlags &
                     WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
 
-            if (fakeHwAccelerated) {
-                // This is exclusively for the preview windows the window manager
-                // shows for launching applications, so they will look more like
-                // the app being launched.
-                mAttachInfo.mHardwareAccelerationRequested = true;
-            } else if (ThreadedRenderer.sRendererEnabled || forceHwAccelerated) {
+            if (ThreadedRenderer.sRendererEnabled || forceHwAccelerated) {
                 if (mAttachInfo.mThreadedRenderer != null) {
                     mAttachInfo.mThreadedRenderer.destroy();
                 }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 04512c9..9df87dc 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -2218,26 +2218,6 @@
         public int flags;
 
         /**
-         * If the window has requested hardware acceleration, but this is not
-         * allowed in the process it is in, then still render it as if it is
-         * hardware accelerated.  This is used for the starting preview windows
-         * in the system process, which don't need to have the overhead of
-         * hardware acceleration (they are just a static rendering), but should
-         * be rendered as such to match the actual window of the app even if it
-         * is hardware accelerated.
-         * Even if the window isn't hardware accelerated, still do its rendering
-         * as if it was.
-         * Like {@link #FLAG_HARDWARE_ACCELERATED} except for trusted system windows
-         * that need hardware acceleration (e.g. LockScreen), where hardware acceleration
-         * is generally disabled. This flag must be specified in addition to
-         * {@link #FLAG_HARDWARE_ACCELERATED} to enable hardware acceleration for system
-         * windows.
-         *
-         * @hide
-         */
-        public static final int PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED = 0x00000001;
-
-        /**
          * In the system process, we globally do not use hardware acceleration
          * because there are many threads doing UI there and they conflict.
          * If certain parts of the UI that really do want to use hardware
@@ -2463,7 +2443,6 @@
          * @hide
          */
         @IntDef(flag = true, prefix="PRIVATE_FLAG_", value = {
-                PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED,
                 PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED,
                 PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS,
                 SYSTEM_FLAG_SHOW_FOR_ALL_USERS,
@@ -2499,10 +2478,6 @@
         @UnsupportedAppUsage
         @ViewDebug.ExportedProperty(flagMapping = {
                 @ViewDebug.FlagToString(
-                        mask = PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED,
-                        equals = PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED,
-                        name = "FAKE_HARDWARE_ACCELERATED"),
-                @ViewDebug.FlagToString(
                         mask = PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED,
                         equals = PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED,
                         name = "FORCE_HARDWARE_ACCELERATED"),
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 37220fe..c5bce28 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -608,7 +608,12 @@
         Preconditions.checkArgumentNonnegative(afterLength);
 
         final Editable content = getEditable();
-        if (content == null) return null;
+        // If {@link #getEditable()} is null or {@code mEditable} is equal to {@link #getEditable()}
+        // (a.k.a, a fake editable), it means we cannot get valid content from the editable, so
+        // fallback to retrieve surrounding text from other APIs.
+        if (content == null || mEditable == content) {
+            return InputConnection.super.getSurroundingText(beforeLength, afterLength, flags);
+        }
 
         int selStart = Selection.getSelectionStart(content);
         int selEnd = Selection.getSelectionEnd(content);
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 34a60bb..38019c9 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -325,16 +325,16 @@
 
         CharSequence textBeforeCursor = getTextBeforeCursor(beforeLength, flags);
         if (textBeforeCursor == null) {
-            textBeforeCursor = "";
+            return null;
+        }
+        CharSequence textAfterCursor = getTextAfterCursor(afterLength, flags);
+        if (textAfterCursor == null) {
+            return null;
         }
         CharSequence selectedText = getSelectedText(flags);
         if (selectedText == null) {
             selectedText = "";
         }
-        CharSequence textAfterCursor = getTextAfterCursor(afterLength, flags);
-        if (textAfterCursor == null) {
-            textAfterCursor = "";
-        }
         CharSequence surroundingText =
                 TextUtils.concat(textBeforeCursor, selectedText, textAfterCursor);
         return new SurroundingText(surroundingText, textBeforeCursor.length(),
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 3709aa1..616a0d0 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -15,6 +15,7 @@
  */
 package android.window;
 
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 
 import android.annotation.ColorInt;
@@ -32,6 +33,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -183,6 +185,7 @@
          * Create SplashScreenWindowView object from materials.
          */
         public SplashScreenView build() {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "SplashScreenView#build");
             final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
             final SplashScreenView view = (SplashScreenView)
                     layoutInflater.inflate(R.layout.splash_screen_view, null, false);
@@ -226,6 +229,7 @@
                         + view.mBrandingImageView + " drawable: " + mBrandingDrawable
                         + " size w: " + mBrandingImageWidth + " h: " + mBrandingImageHeight);
             }
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             return view;
         }
     }
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 02cbccc..a5b894d 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -130,12 +130,6 @@
     // Flags related to media notifications
 
     /**
-     * (boolean) If {@code true}, enables the seekbar in compact media notifications.
-     */
-    public static final String COMPACT_MEDIA_SEEKBAR_ENABLED =
-            "compact_media_notification_seekbar_enabled";
-
-    /**
      * (int) Maximum number of days to retain the salt for hashing direct share targets in logging
      */
     public static final String HASH_SALT_MAX_DAYS = "hash_salt_max_days";
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7f87885..a043756 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -89,6 +89,7 @@
 import android.util.Printer;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseDoubleArray;
 import android.util.SparseIntArray;
 import android.util.SparseLongArray;
 import android.util.TimeUtils;
@@ -12548,81 +12549,6 @@
     }
 
     /**
-     * SparseDoubleArray map integers to doubles.
-     * Its implementation is the same as that of {@link SparseLongArray}; see there for details.
-     *
-     * @see SparseLongArray
-     */
-    private static class SparseDoubleArray {
-        /**
-         * The int->double map, but storing the doubles as longs using
-         * {@link Double.doubleToRawLongBits(double)}.
-         */
-        private final SparseLongArray mValues = new SparseLongArray();
-
-        /**
-         * Gets the double mapped from the specified key, or <code>0</code>
-         * if no such mapping has been made.
-         */
-        public double get(int key) {
-            if (mValues.indexOfKey(key) >= 0) {
-                return Double.longBitsToDouble(mValues.get(key));
-            }
-            return 0;
-        }
-
-        /**
-         * Adds a mapping from the specified key to the specified value,
-         * replacing the previous mapping from the specified key if there
-         * was one.
-         */
-        public void put(int key, double value) {
-            mValues.put(key, Double.doubleToRawLongBits(value));
-        }
-
-        /**
-         * Adds a mapping from the specified key to the specified value,
-         * <b>adding</b> to the previous mapping from the specified key if there
-         * was one.
-         */
-        public void add(int key, double summand) {
-            final double oldValue = get(key);
-            put(key, oldValue + summand);
-        }
-
-        /**
-         * Returns the number of key-value mappings that this SparseDoubleArray
-         * currently stores.
-         */
-        public int size() {
-            return mValues.size();
-        }
-
-        /**
-         * Given an index in the range <code>0...size()-1</code>, returns
-         * the key from the <code>index</code>th key-value mapping that this
-         * SparseDoubleArray stores.
-         *
-         * @see SparseLongArray#keyAt(int)
-         */
-        public int keyAt(int index) {
-            return mValues.keyAt(index);
-        }
-
-        /**
-         * Given an index in the range <code>0...size()-1</code>, returns
-         * the value from the <code>index</code>th key-value mapping that this
-         * SparseDoubleArray stores.
-         *
-         * @see SparseLongArray#valueAt(int)
-         */
-        public double valueAt(int index) {
-            return Double.longBitsToDouble(mValues.valueAt(index));
-        }
-
-    }
-
-    /**
      * Read and record Rail Energy data.
      */
     public void updateRailStatsLocked() {
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index f42d5da..8ff3c10 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -19,31 +19,19 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.NotificationHeaderView;
-import android.view.View;
-import android.view.ViewGroup;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.RemoteViews;
 
 import java.util.ArrayList;
 
 /**
- * A TextView that can float around an image on the end.
+ * The Layout class which handles template details for the Notification.MediaStyle
  *
  * @hide
  */
 @RemoteViews.RemoteView
 public class MediaNotificationView extends FrameLayout {
 
-    private final int mNotificationContentMarginEnd;
-    private final int mNotificationContentImageMarginEnd;
-    private ImageView mRightIcon;
-    private View mActions;
-    private NotificationHeaderView mHeader;
-    private View mMainColumn;
-    private View mMediaContent;
-    private int mImagePushIn;
     private ArrayList<VisibilityChangeListener> mListeners;
 
     public MediaNotificationView(Context context) {
@@ -58,120 +46,14 @@
         this(context, attrs, defStyleAttr, 0);
     }
 
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        boolean hasIcon = mRightIcon.getVisibility() != GONE;
-        if (!hasIcon) {
-            resetHeaderIndention();
-        }
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        int mode = MeasureSpec.getMode(widthMeasureSpec);
-        boolean reMeasure = false;
-        mImagePushIn = 0;
-        if (hasIcon && mode != MeasureSpec.UNSPECIFIED) {
-            int size = MeasureSpec.getSize(widthMeasureSpec);
-            size = size - mActions.getMeasuredWidth();
-            ViewGroup.MarginLayoutParams layoutParams =
-                    (MarginLayoutParams) mRightIcon.getLayoutParams();
-            int imageEndMargin = layoutParams.getMarginEnd();
-            size -= imageEndMargin;
-            int fullHeight = mMediaContent.getMeasuredHeight();
-            if (size > fullHeight) {
-                size = fullHeight;
-            } else if (size < fullHeight) {
-                size = Math.max(0, size);
-                mImagePushIn = fullHeight - size;
-            }
-            if (layoutParams.width != fullHeight || layoutParams.height != fullHeight) {
-                layoutParams.width = fullHeight;
-                layoutParams.height = fullHeight;
-                mRightIcon.setLayoutParams(layoutParams);
-                reMeasure = true;
-            }
-
-            // lets ensure that the main column doesn't run into the image
-            ViewGroup.MarginLayoutParams params
-                    = (MarginLayoutParams) mMainColumn.getLayoutParams();
-            int marginEnd = size + imageEndMargin + mNotificationContentMarginEnd;
-            if (marginEnd != params.getMarginEnd()) {
-                params.setMarginEnd(marginEnd);
-                mMainColumn.setLayoutParams(params);
-                reMeasure = true;
-            }
-            // TODO(b/172652345): validate all this logic (especially positioning of expand button)
-            // margin for the entire header line
-            int headerMarginEnd = imageEndMargin;
-            // margin for the header text (not including the expand button and other icons)
-            int headerExtraMarginEnd = Math.max(0,
-                    size + imageEndMargin - mHeader.getTopLineBaseMarginEnd());
-            if (headerExtraMarginEnd != mHeader.getTopLineExtraMarginEnd()) {
-                mHeader.setTopLineExtraMarginEnd(headerExtraMarginEnd);
-                reMeasure = true;
-            }
-            params = (MarginLayoutParams) mHeader.getLayoutParams();
-            if (params.getMarginEnd() != headerMarginEnd) {
-                params.setMarginEnd(headerMarginEnd);
-                mHeader.setLayoutParams(params);
-                reMeasure = true;
-            }
-            if (mHeader.getPaddingEnd() != mNotificationContentImageMarginEnd) {
-                mHeader.setPaddingRelative(mHeader.getPaddingStart(),
-                        mHeader.getPaddingTop(),
-                        mNotificationContentImageMarginEnd,
-                        mHeader.getPaddingBottom());
-                reMeasure = true;
-            }
-        }
-        if (reMeasure) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        if (mImagePushIn > 0) {
-            if (this.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
-                mImagePushIn *= -1;
-            }
-            mRightIcon.layout(mRightIcon.getLeft() + mImagePushIn, mRightIcon.getTop(),
-                    mRightIcon.getRight()  + mImagePushIn, mRightIcon.getBottom());
-        }
-    }
-
-    private void resetHeaderIndention() {
-        if (mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
-            mHeader.setPaddingRelative(mHeader.getPaddingStart(),
-                    mHeader.getPaddingTop(),
-                    mNotificationContentMarginEnd,
-                    mHeader.getPaddingBottom());
-        }
-        ViewGroup.MarginLayoutParams headerParams =
-                (MarginLayoutParams) mHeader.getLayoutParams();
-        headerParams.setMarginEnd(0);
-        if (headerParams.getMarginEnd() != 0) {
-            headerParams.setMarginEnd(0);
-            mHeader.setLayoutParams(headerParams);
-        }
-    }
-
     public MediaNotificationView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mNotificationContentMarginEnd = context.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.notification_content_margin_end);
-        mNotificationContentImageMarginEnd = context.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.notification_content_image_margin_end);
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mRightIcon = findViewById(com.android.internal.R.id.right_icon);
-        mActions = findViewById(com.android.internal.R.id.media_actions);
-        mHeader = findViewById(com.android.internal.R.id.notification_header);
-        mMainColumn = findViewById(com.android.internal.R.id.notification_main_column);
-        mMediaContent = findViewById(com.android.internal.R.id.notification_media_content);
     }
 
     @Override
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 29fa70d..8d7f542 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3554,7 +3554,7 @@
          @hide
     -->
     <permission android:name="android.permission.GET_TOP_ACTIVITY_INFO"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signature|recents" />
 
     <!-- Allows an application to retrieve the current state of keys and
          switches.
diff --git a/core/res/res/layout/notification_material_media_action.xml b/core/res/res/layout/notification_material_media_action.xml
index dd79a0b..5f1b60e 100644
--- a/core/res/res/layout/notification_material_media_action.xml
+++ b/core/res/res/layout/notification_material_media_action.xml
@@ -24,7 +24,6 @@
     android:paddingTop="8dp"
     android:paddingStart="8dp"
     android:paddingEnd="8dp"
-    android:layout_marginEnd="2dp"
     android:gravity="center"
     android:background="@drawable/notification_material_media_action_background"
     android:visibility="gone"
diff --git a/core/res/res/layout/notification_material_media_seekbar.xml b/core/res/res/layout/notification_material_media_seekbar.xml
deleted file mode 100644
index 4aa8acc..0000000
--- a/core/res/res/layout/notification_material_media_seekbar.xml
+++ /dev/null
@@ -1,65 +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
-  -->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/notification_media_progress"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:layout_alignParentBottom="true"
-    >
-    <SeekBar android:id="@+id/notification_media_progress_bar"
-        style="@style/Widget.ProgressBar.Horizontal"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:maxHeight="3dp"
-        android:paddingTop="24dp"
-        android:paddingBottom="24dp"
-        android:clickable="true"
-        android:layout_marginBottom="-24dp"
-        android:layout_marginTop="-12dp"
-        android:splitTrack="false"
-    />
-    <FrameLayout
-        android:id="@+id/notification_media_progress_time"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:layout_marginBottom="11dp"
-        >
-
-        <!-- width is set to "match_parent" to avoid extra layout calls -->
-        <TextView android:id="@+id/notification_media_elapsed_time"
-            style="@style/Widget.DeviceDefault.Notification.Text"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentLeft="true"
-            android:layout_marginStart="@dimen/notification_content_margin_start"
-            android:gravity="start"
-        />
-
-        <TextView android:id="@+id/notification_media_total_time"
-            style="@style/Widget.DeviceDefault.Notification.Text"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentRight="true"
-            android:layout_marginEnd="@dimen/notification_content_margin_end"
-            android:gravity="end"
-        />
-    </FrameLayout>
-</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index bad9a6b..e644cd5 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -46,20 +46,6 @@
         android:padding="@dimen/notification_icon_circle_padding"
         />
 
-    <ImageView
-        android:id="@+id/right_icon"
-        android:layout_width="@dimen/notification_right_icon_size"
-        android:layout_height="@dimen/notification_right_icon_size"
-        android:layout_gravity="center_vertical|end"
-        android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
-        android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
-        android:layout_marginEnd="@dimen/notification_header_expand_icon_size"
-        android:background="@drawable/notification_large_icon_outline"
-        android:clipToOutline="true"
-        android:importantForAccessibility="no"
-        android:scaleType="centerCrop"
-        />
-
     <FrameLayout
         android:id="@+id/alternate_expand_target"
         android:layout_width="@dimen/notification_content_margin_start"
@@ -68,95 +54,116 @@
         android:importantForAccessibility="no"
         />
 
-    <FrameLayout
-        android:id="@+id/expand_button_touch_container"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:layout_gravity="end">
-
-        <include layout="@layout/notification_expand_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical|end"
-            />
-
-    </FrameLayout>
-
     <LinearLayout
-        android:id="@+id/notification_headerless_view_column"
+        android:id="@+id/notification_headerless_view_row"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:layout_marginBottom="@dimen/notification_headerless_margin_twoline"
-        android:layout_marginTop="@dimen/notification_headerless_margin_twoline"
-        android:orientation="vertical"
+        android:layout_height="match_parent"
+        android:layout_marginStart="@dimen/notification_content_margin_start"
+        android:orientation="horizontal"
         >
 
-        <!-- extends ViewGroup -->
-        <NotificationTopLineView
-            android:id="@+id/notification_top_line"
-            android:layout_width="wrap_content"
-            android:layout_height="@dimen/notification_headerless_line_height"
-            android:layout_marginEnd="@dimen/notification_heading_margin_end"
-            android:layout_marginStart="@dimen/notification_content_margin_start"
-            android:clipChildren="false"
-            android:theme="@style/Theme.DeviceDefault.Notification"
-            >
-
-            <!--
-            NOTE: The notification_top_line_views layout contains the app_name_text.
-            In order to include the title view at the beginning, the Notification.Builder
-            has logic to hide that view whenever this title view is to be visible.
-            -->
-
-            <TextView
-                android:id="@+id/title"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginEnd="@dimen/notification_header_separating_margin"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                android:singleLine="true"
-                android:textAlignment="viewStart"
-                android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
-                />
-
-            <include layout="@layout/notification_top_line_views" />
-
-        </NotificationTopLineView>
-
         <LinearLayout
-            android:id="@+id/notification_main_column"
-            android:layout_width="match_parent"
+            android:id="@+id/notification_headerless_view_column"
+            android:layout_width="0px"
             android:layout_height="wrap_content"
-            android:layout_marginEnd="@dimen/notification_heading_margin_end"
-            android:layout_marginStart="@dimen/notification_content_margin_start"
+            android:layout_gravity="center_vertical"
+            android:layout_weight="1"
+            android:layout_marginBottom="@dimen/notification_headerless_margin_twoline"
+            android:layout_marginTop="@dimen/notification_headerless_margin_twoline"
             android:orientation="vertical"
             >
 
-            <com.android.internal.widget.NotificationVanishingFrameLayout
-                android:layout_width="match_parent"
+            <NotificationTopLineView
+                android:id="@+id/notification_top_line"
+                android:layout_width="wrap_content"
                 android:layout_height="@dimen/notification_headerless_line_height"
+                android:clipChildren="false"
+                android:theme="@style/Theme.DeviceDefault.Notification"
                 >
-                <!-- This is the simplest way to keep this text vertically centered without using
-                 gravity="center_vertical" which causes jumpiness in expansion animations. -->
-                <include
-                    layout="@layout/notification_template_text"
-                    android:layout_width="match_parent"
-                    android:layout_height="@dimen/notification_text_height"
-                    android:layout_gravity="center_vertical"
-                    android:layout_marginTop="0dp"
-                    />
-            </com.android.internal.widget.NotificationVanishingFrameLayout>
 
-            <include
-                layout="@layout/notification_template_progress"
+                <!--
+                NOTE: The notification_top_line_views layout contains the app_name_text.
+                In order to include the title view at the beginning, the Notification.Builder
+                has logic to hide that view whenever this title view is to be visible.
+                -->
+
+                <TextView
+                    android:id="@+id/title"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginEnd="@dimen/notification_header_separating_margin"
+                    android:ellipsize="marquee"
+                    android:fadingEdge="horizontal"
+                    android:singleLine="true"
+                    android:textAlignment="viewStart"
+                    android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
+                    />
+
+                <include layout="@layout/notification_top_line_views" />
+
+            </NotificationTopLineView>
+
+            <LinearLayout
+                android:id="@+id/notification_main_column"
                 android:layout_width="match_parent"
-                android:layout_height="@dimen/notification_headerless_line_height"
-                />
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                >
+
+                <com.android.internal.widget.NotificationVanishingFrameLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/notification_headerless_line_height"
+                    >
+                    <!-- This is the simplest way to keep this text vertically centered without
+                     gravity="center_vertical" which causes jumpiness in expansion animations. -->
+                    <include
+                        layout="@layout/notification_template_text"
+                        android:layout_width="match_parent"
+                        android:layout_height="@dimen/notification_text_height"
+                        android:layout_gravity="center_vertical"
+                        android:layout_marginTop="0dp"
+                        />
+                </com.android.internal.widget.NotificationVanishingFrameLayout>
+
+                <include
+                    layout="@layout/notification_template_progress"
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/notification_headerless_line_height"
+                    />
+
+            </LinearLayout>
 
         </LinearLayout>
 
+        <ImageView
+            android:id="@+id/right_icon"
+            android:layout_width="@dimen/notification_right_icon_size"
+            android:layout_height="@dimen/notification_right_icon_size"
+            android:layout_gravity="center_vertical|end"
+            android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
+            android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
+            android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+            android:background="@drawable/notification_large_icon_outline"
+            android:clipToOutline="true"
+            android:importantForAccessibility="no"
+            android:scaleType="centerCrop"
+            />
+
+        <FrameLayout
+            android:id="@+id/expand_button_touch_container"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:minWidth="@dimen/notification_content_margin_end"
+            >
+
+            <include layout="@layout/notification_expand_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical|end"
+                />
+
+        </FrameLayout>
+
     </LinearLayout>
 
 </com.android.internal.widget.NotificationMaxHeightFrameLayout>
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index aa20ad3..ff64315 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -20,17 +20,8 @@
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:background="#00000000"
     android:tag="bigMediaNarrow"
     >
-    <!-- The size will actually be determined at runtime -->
-    <ImageView
-        android:id="@+id/right_icon"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_gravity="top|end"
-        android:scaleType="centerCrop"
-        />
 
     <include
         layout="@layout/notification_template_header"
@@ -49,46 +40,27 @@
             android:id="@+id/notification_main_column"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginTop="46dp"
+            android:layout_marginTop="@dimen/notification_content_margin_top"
             android:layout_marginStart="@dimen/notification_content_margin_start"
             android:layout_marginBottom="@dimen/notification_content_margin"
             android:layout_marginEnd="@dimen/notification_content_margin_end"
             android:orientation="vertical"
             >
-            <!-- TODO(b/172652345): fix the media style -->
-            <!--<include layout="@layout/notification_template_part_line1"/>-->
-            <!--<include layout="@layout/notification_template_text"/>-->
-
-            <TextView android:id="@+id/title"
-                android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:singleLine="true"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                android:textAlignment="viewStart"
-                />
-
-            <com.android.internal.widget.ImageFloatingTextView
-                style="@style/Widget.DeviceDefault.Notification.Text"
-                android:id="@+id/text"
-                android:layout_width="match_parent"
-                android:layout_height="@dimen/notification_text_height"
-                android:layout_gravity="top"
-                android:layout_marginTop="0.5dp"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                android:gravity="top"
-                android:singleLine="true"
-                android:textAlignment="viewStart"
-                />
+            <include layout="@layout/notification_template_part_line1"/>
+            <include layout="@layout/notification_template_text"/>
         </LinearLayout>
 
         <LinearLayout
             android:id="@+id/media_actions"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="-21dp"
+            android:paddingStart="44dp"
+            android:paddingEnd="44dp"
+            android:paddingBottom="@dimen/media_notification_actions_padding_bottom"
+            android:gravity="top"
             android:orientation="horizontal"
             android:layoutDirection="ltr"
-            style="@style/NotificationMediaActionContainer"
             >
 
             <include
@@ -117,10 +89,8 @@
                 />
         </LinearLayout>
 
-        <ViewStub
-            android:id="@+id/notification_media_seekbar_container"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            />
     </LinearLayout>
+
+    <include layout="@layout/notification_template_right_icon" />
+
 </com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 542e59d..2991b17 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -19,101 +19,173 @@
     android:id="@+id/status_bar_latest_event_content"
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:background="#00000000"
+    android:layout_height="@dimen/notification_min_height"
     android:tag="media"
     >
-    <ImageView android:id="@+id/right_icon"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:adjustViewBounds="true"
-        android:layout_gravity="top|end"
+
+
+    <ImageView
+        android:id="@+id/left_icon"
+        android:layout_width="@dimen/notification_left_icon_size"
+        android:layout_height="@dimen/notification_left_icon_size"
+        android:layout_gravity="center_vertical|start"
+        android:layout_marginStart="@dimen/notification_left_icon_start"
+        android:background="@drawable/notification_large_icon_outline"
+        android:clipToOutline="true"
+        android:importantForAccessibility="no"
         android:scaleType="centerCrop"
-    />
-    <include layout="@layout/notification_template_header"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/media_notification_header_height"
+        android:visibility="gone"
         />
+
+    <com.android.internal.widget.CachingIconView
+        android:id="@+id/icon"
+        android:layout_width="@dimen/notification_icon_circle_size"
+        android:layout_height="@dimen/notification_icon_circle_size"
+        android:layout_gravity="center_vertical|start"
+        android:layout_marginStart="@dimen/notification_icon_circle_start"
+        android:background="@drawable/notification_icon_circle"
+        android:padding="@dimen/notification_icon_circle_padding"
+        />
+
+    <FrameLayout
+        android:id="@+id/alternate_expand_target"
+        android:layout_width="@dimen/notification_content_margin_start"
+        android:layout_height="match_parent"
+        android:layout_gravity="start"
+        android:importantForAccessibility="no"
+        />
+
     <LinearLayout
+        android:id="@+id/notification_headerless_view_row"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:id="@+id/notification_media_content"
+        android:layout_height="match_parent"
+        android:layout_marginStart="@dimen/notification_content_margin_start"
+        android:orientation="horizontal"
         >
+
         <LinearLayout
-            android:id="@+id/notification_main_column"
-            android:layout_width="match_parent"
+            android:id="@+id/notification_headerless_view_column"
+            android:layout_width="0px"
             android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:layout_marginStart="@dimen/notification_content_margin_start"
-            android:layout_marginTop="46dp"
-            android:layout_alignParentTop="true"
-            android:tag="media"
+            android:layout_gravity="center_vertical"
+            android:layout_weight="1"
+            android:layout_marginBottom="@dimen/notification_headerless_margin_twoline"
+            android:layout_marginTop="@dimen/notification_headerless_margin_twoline"
+            android:orientation="vertical"
             >
+
+            <NotificationTopLineView
+                android:id="@+id/notification_top_line"
+                android:layout_width="wrap_content"
+                android:layout_height="@dimen/notification_headerless_line_height"
+                android:clipChildren="false"
+                android:theme="@style/Theme.DeviceDefault.Notification"
+                >
+
+                <!--
+                NOTE: The notification_top_line_views layout contains the app_name_text.
+                In order to include the title view at the beginning, the Notification.Builder
+                has logic to hide that view whenever this title view is to be visible.
+                -->
+
+                <TextView
+                    android:id="@+id/title"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginEnd="@dimen/notification_header_separating_margin"
+                    android:ellipsize="marquee"
+                    android:fadingEdge="horizontal"
+                    android:singleLine="true"
+                    android:textAlignment="viewStart"
+                    android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
+                    />
+
+                <include layout="@layout/notification_top_line_views" />
+
+            </NotificationTopLineView>
+
             <LinearLayout
-                android:id="@+id/notification_content_container"
+                android:id="@+id/notification_main_column"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_gravity="fill_vertical"
-                android:layout_weight="1"
-                android:paddingBottom="@dimen/notification_content_margin"
                 android:orientation="vertical"
                 >
-                <!-- TODO(b/172652345): fix the media style -->
-                <!--<include layout="@layout/notification_template_part_line1"/>-->
-                <!--<include layout="@layout/notification_template_text"/>-->
 
-                <TextView android:id="@+id/title"
-                    android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
+                <com.android.internal.widget.NotificationVanishingFrameLayout
                     android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:singleLine="true"
-                    android:ellipsize="marquee"
-                    android:fadingEdge="horizontal"
-                    android:textAlignment="viewStart"
+                    android:layout_height="@dimen/notification_headerless_line_height"
+                    >
+                    <!-- This is the simplest way to keep this text vertically centered without
+                     gravity="center_vertical" which causes jumpiness in expansion animations. -->
+                    <include
+                        layout="@layout/notification_template_text"
+                        android:layout_width="match_parent"
+                        android:layout_height="@dimen/notification_text_height"
+                        android:layout_gravity="center_vertical"
+                        android:layout_marginTop="0dp"
+                        />
+                </com.android.internal.widget.NotificationVanishingFrameLayout>
+
+                <include
+                    layout="@layout/notification_template_progress"
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/notification_headerless_line_height"
                     />
 
-                <com.android.internal.widget.ImageFloatingTextView
-                    style="@style/Widget.DeviceDefault.Notification.Text"
-                    android:id="@+id/text"
-                    android:layout_width="match_parent"
-                    android:layout_height="@dimen/notification_text_height"
-                    android:layout_gravity="top"
-                    android:layout_marginTop="0.5dp"
-                    android:ellipsize="marquee"
-                    android:fadingEdge="horizontal"
-                    android:gravity="top"
-                    android:singleLine="true"
-                    android:textAlignment="viewStart"
-                    />
             </LinearLayout>
-            <LinearLayout
-                android:id="@+id/media_actions"
+
+        </LinearLayout>
+
+        <ImageView
+            android:id="@+id/right_icon"
+            android:layout_width="@dimen/notification_right_icon_size"
+            android:layout_height="@dimen/notification_right_icon_size"
+            android:layout_gravity="center_vertical|end"
+            android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
+            android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
+            android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+            android:background="@drawable/notification_large_icon_outline"
+            android:clipToOutline="true"
+            android:importantForAccessibility="no"
+            android:scaleType="centerCrop"
+            />
+
+        <LinearLayout
+            android:id="@+id/media_actions"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layoutDirection="ltr"
+            android:orientation="horizontal"
+            >
+            <include
+                layout="@layout/notification_material_media_action"
+                android:id="@+id/action0"
+                />
+            <include
+                layout="@layout/notification_material_media_action"
+                android:id="@+id/action1"
+                />
+            <include
+                layout="@layout/notification_material_media_action"
+                android:id="@+id/action2"
+                />
+        </LinearLayout>
+
+        <FrameLayout
+            android:id="@+id/expand_button_touch_container"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:minWidth="@dimen/notification_content_margin_end"
+            >
+
+            <include layout="@layout/notification_expand_button"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_gravity="top|end"
-                android:layout_marginStart="10dp"
-                android:layoutDirection="ltr"
-                android:orientation="horizontal"
-                >
-                <include
-                    layout="@layout/notification_material_media_action"
-                    android:id="@+id/action0"
+                android:layout_gravity="center_vertical|end"
                 />
-                <include
-                    layout="@layout/notification_material_media_action"
-                    android:id="@+id/action1"
-                />
-                <include
-                    layout="@layout/notification_material_media_action"
-                    android:id="@+id/action2"
-                />
-            </LinearLayout>
-        </LinearLayout>
-        <ViewStub android:id="@+id/notification_media_seekbar_container"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentBottom="true"
-        />
+
+        </FrameLayout>
+
     </LinearLayout>
 </com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 43dbd38..afbbe46 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -226,9 +226,6 @@
     <!-- The margin on the end of the top-line content views (accommodates the expander) -->
     <dimen name="notification_heading_margin_end">56dp</dimen>
 
-    <!-- The margin for text at the end of the image view for media notifications -->
-    <dimen name="notification_media_image_margin_end">72dp</dimen>
-
     <!-- The height of the notification action list -->
     <dimen name="notification_action_list_height">60dp</dimen>
 
@@ -345,6 +342,9 @@
     <!-- The minimum width of the app name in the header if it shrinks -->
     <dimen name="notification_header_shrink_min_width">72dp</dimen>
 
+    <!-- The minimum width of optional header fields below which the view is simply hidden -->
+    <dimen name="notification_header_shrink_hide_width">24sp</dimen>
+
     <!-- The size of the media actions in the media notification. -->
     <dimen name="media_notification_action_button_size">48dp</dimen>
 
@@ -360,9 +360,6 @@
     <!-- The absolute height for the header in a media notification. -->
     <dimen name="media_notification_header_height">@dimen/notification_header_height</dimen>
 
-    <!-- The margin of the content to an image-->
-    <dimen name="notification_content_image_margin_end">8dp</dimen>
-
     <!-- The padding at the end of actions when the snooze and bubble buttons are gone-->
     <dimen name="snooze_and_bubble_gone_padding_end">12dp</dimen>
 
@@ -483,9 +480,6 @@
     <!-- Top padding for notification when text is large and narrow (i.e. it has 3 lines -->
     <dimen name="notification_top_pad_large_text_narrow">-4dp</dimen>
 
-    <!-- Padding for notification icon when drawn with circle around it -->
-    <dimen name="notification_large_icon_circle_padding">11dp</dimen>
-
     <!-- The margin on top of the text of the notification -->
     <dimen name="notification_text_margin_top">6dp</dimen>
 
@@ -736,12 +730,10 @@
     <dimen name="notification_big_picture_max_height">284dp</dimen>
     <!-- The maximum width of a big picture in a notification. The images will be reduced to that width in case they are bigger. This value is determined by the standard panel size -->
     <dimen name="notification_big_picture_max_width">416dp</dimen>
-    <!-- The maximum height of a image in a media notification. The images will be reduced to that height in case they are bigger. This value is determined by the expanded media template-->
-    <dimen name="notification_media_image_max_height">140dp</dimen>
-    <!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.-->
-    <dimen name="notification_media_image_max_width">280dp</dimen>
     <!-- The size of the right icon -->
     <dimen name="notification_right_icon_size">48dp</dimen>
+    <!-- The margin between the right icon and the content. -->
+    <dimen name="notification_right_icon_content_margin">12dp</dimen>
     <!-- The top and bottom margin of the right icon in the normal notification states -->
     <dimen name="notification_right_icon_headerless_margin">20dp</dimen>
     <!-- The top margin of the right icon in the "big" notification states -->
@@ -762,10 +754,6 @@
     <dimen name="notification_big_picture_max_height_low_ram">208dp</dimen>
     <!-- The maximum width of a big picture in a notification. The images will be reduced to that width in case they are bigger. -->
     <dimen name="notification_big_picture_max_width_low_ram">294dp</dimen>
-    <!-- The maximum height of a image in a media notification. The images will be reduced to that height in case they are bigger. -->
-    <dimen name="notification_media_image_max_height_low_ram">100dp</dimen>
-    <!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.-->
-    <dimen name="notification_media_image_max_width_low_ram">100dp</dimen>
     <!-- The size of the right icon image when on low ram -->
     <dimen name="notification_right_icon_size_low_ram">@dimen/notification_right_icon_size</dimen>
     <!-- The maximum size of the grayscale icon -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index c7ded0c..fbf67e0 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1481,17 +1481,6 @@
         <item name="android:windowExitAnimation">@anim/slide_out_down</item>
     </style>
 
-    <!-- The style for the container of media actions in a notification. -->
-    <!-- @hide -->
-    <style name="NotificationMediaActionContainer">
-        <item name="layout_width">wrap_content</item>
-        <item name="layout_height">wrap_content</item>
-        <item name="layout_marginTop">-21dp</item>
-        <item name="paddingStart">8dp</item>
-        <item name="paddingBottom">@dimen/media_notification_actions_padding_bottom</item>
-        <item name="gravity">top</item>
-    </style>
-
     <!-- The style for normal action button on notification -->
     <style name="NotificationAction" parent="Widget.Material.Light.Button.Borderless.Small">
       <item name="textColor">@color/notification_action_button_text_color</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1d74d85..d6a6f4d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -200,12 +200,7 @@
   <java-symbol type="id" name="action2" />
   <java-symbol type="id" name="action3" />
   <java-symbol type="id" name="action4" />
-  <java-symbol type="id" name="notification_media_seekbar_container" />
   <java-symbol type="id" name="notification_media_content" />
-  <java-symbol type="id" name="notification_media_progress" />
-  <java-symbol type="id" name="notification_media_progress_bar" />
-  <java-symbol type="id" name="notification_media_elapsed_time" />
-  <java-symbol type="id" name="notification_media_total_time" />
   <java-symbol type="id" name="big_picture" />
   <java-symbol type="id" name="big_text" />
   <java-symbol type="id" name="chronometer" />
@@ -525,7 +520,6 @@
   <java-symbol type="dimen" name="notification_top_pad_narrow" />
   <java-symbol type="dimen" name="notification_top_pad_large_text" />
   <java-symbol type="dimen" name="notification_top_pad_large_text_narrow" />
-  <java-symbol type="dimen" name="notification_large_icon_circle_padding" />
   <java-symbol type="dimen" name="notification_badge_size" />
   <java-symbol type="dimen" name="immersive_mode_cling_width" />
   <java-symbol type="dimen" name="accessibility_magnification_indicator_width" />
@@ -1564,7 +1558,6 @@
   <java-symbol type="layout" name="immersive_mode_cling" />
   <java-symbol type="layout" name="user_switching_dialog" />
   <java-symbol type="layout" name="common_tab_settings" />
-  <java-symbol type="layout" name="notification_material_media_seekbar" />
   <java-symbol type="layout" name="resolver_list_per_profile" />
   <java-symbol type="layout" name="chooser_list_per_profile" />
   <java-symbol type="layout" name="resolver_empty_states" />
@@ -2921,6 +2914,7 @@
   <java-symbol type="drawable" name="ic_expand_bundle" />
   <java-symbol type="drawable" name="ic_collapse_bundle" />
   <java-symbol type="dimen" name="notification_header_shrink_min_width" />
+  <java-symbol type="dimen" name="notification_header_shrink_hide_width" />
   <java-symbol type="dimen" name="notification_content_margin_start" />
   <java-symbol type="dimen" name="notification_content_margin_end" />
   <java-symbol type="dimen" name="notification_heading_margin_end" />
@@ -3010,7 +3004,6 @@
   <java-symbol type="string" name="new_sms_notification_content" />
 
   <java-symbol type="dimen" name="media_notification_expanded_image_margin_bottom" />
-  <java-symbol type="dimen" name="notification_content_image_margin_end" />
 
   <java-symbol type="bool" name="config_strongAuthRequiredOnBoot" />
 
@@ -3019,8 +3012,6 @@
 
   <java-symbol type="id" name="aerr_wait" />
 
-  <java-symbol type="id" name="notification_content_container" />
-
   <java-symbol type="plurals" name="duration_minutes_shortest" />
   <java-symbol type="plurals" name="duration_hours_shortest" />
   <java-symbol type="plurals" name="duration_days_shortest" />
@@ -3138,7 +3129,6 @@
 
   <java-symbol type="bool" name="config_supportPreRebootSecurityLogs" />
 
-  <java-symbol type="dimen" name="notification_media_image_margin_end" />
   <java-symbol type="id" name="notification_action_list_margin_target" />
   <java-symbol type="dimen" name="notification_action_disabled_alpha" />
   <java-symbol type="id" name="tag_margin_end_when_icon_visible" />
@@ -3461,17 +3451,14 @@
 
   <java-symbol type="dimen" name="notification_big_picture_max_height"/>
   <java-symbol type="dimen" name="notification_big_picture_max_width"/>
-  <java-symbol type="dimen" name="notification_media_image_max_width"/>
-  <java-symbol type="dimen" name="notification_media_image_max_height"/>
   <java-symbol type="dimen" name="notification_right_icon_size"/>
+  <java-symbol type="dimen" name="notification_right_icon_content_margin"/>
   <java-symbol type="dimen" name="notification_actions_icon_drawable_size"/>
   <java-symbol type="dimen" name="notification_custom_view_max_image_height"/>
   <java-symbol type="dimen" name="notification_custom_view_max_image_width"/>
 
   <java-symbol type="dimen" name="notification_big_picture_max_height_low_ram"/>
   <java-symbol type="dimen" name="notification_big_picture_max_width_low_ram"/>
-  <java-symbol type="dimen" name="notification_media_image_max_width_low_ram"/>
-  <java-symbol type="dimen" name="notification_media_image_max_height_low_ram"/>
   <java-symbol type="dimen" name="notification_right_icon_size_low_ram"/>
   <java-symbol type="dimen" name="notification_grayscale_icon_max_size"/>
   <java-symbol type="dimen" name="notification_custom_view_max_image_height_low_ram"/>
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 252938a..0ea6364 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -16,8 +16,6 @@
 
 package android.app;
 
-import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotSame;
@@ -99,23 +97,6 @@
     }
 
     @Test
-    public void testColorSatisfiedWhenBgDarkTextDarker() {
-        Notification.Builder builder = getMediaNotification();
-        Notification n = builder.build();
-
-        assertTrue(n.isColorized());
-
-        // An initial guess where the foreground color is actually darker than an already dark bg
-        int backgroundColor = 0xff585868;
-        int initialForegroundColor = 0xff505868;
-        builder.setColorPalette(backgroundColor, initialForegroundColor);
-        int primaryTextColor = builder.getPrimaryTextColor(builder.mParams);
-        assertTrue(satisfiesTextContrast(primaryTextColor, backgroundColor));
-        int secondaryTextColor = builder.getSecondaryTextColor(builder.mParams);
-        assertTrue(satisfiesTextContrast(secondaryTextColor, backgroundColor));
-    }
-
-    @Test
     public void testHasCompletedProgress_noProgress() {
         Notification n = new Notification.Builder(mContext).build();
 
diff --git a/core/tests/coretests/src/android/util/SparseDoubleArrayTest.java b/core/tests/coretests/src/android/util/SparseDoubleArrayTest.java
new file mode 100644
index 0000000..2dd3f69
--- /dev/null
+++ b/core/tests/coretests/src/android/util/SparseDoubleArrayTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.util;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+/**
+ * Internal tests for {@link SparseDoubleArray}.
+ *
+ * Run using:
+ *  atest FrameworksCoreTests:android.util.SparseDoubleArrayTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SparseDoubleArrayTest {
+    private static final double EXACT_PRECISION = 0;
+    private static final double PRECISION = 0.000000001;
+
+    @Test
+    public void testPutGet() {
+        final SparseDoubleArray sda = new SparseDoubleArray();
+        assertEquals("Array should be empty", 0, sda.size());
+
+        final int[] keys = {1, 6, -14, 53251, 5, -13412, 12, 0, 2};
+        final double[] values = {7, -12.4, 7, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
+                Double.NaN,
+                4311236312.0 / 3431470161413514334123.0,
+                431123636434132151313412.0 / 34323.0,
+                0};
+        for (int i = 0; i < keys.length; i++) {
+            sda.put(keys[i], values[i]);
+        }
+
+        assertEquals("Wrong size array", keys.length, sda.size());
+        // Due to the implementation, we actually expect EXACT double equality.
+        for (int i = 0; i < keys.length; i++) {
+            assertEquals("Wrong value at index " + i, values[i], sda.get(keys[i]), EXACT_PRECISION);
+        }
+
+        // Now check something that was never put in
+        assertEquals("Wrong value for absent index", 0, sda.get(100000), EXACT_PRECISION);
+    }
+
+    @Test
+    public void testAdd() {
+        final SparseDoubleArray sda = new SparseDoubleArray();
+
+        sda.put(4, 6.1);
+        sda.add(4, -1.2);
+        sda.add(2, -1.2);
+
+        assertEquals(6.1 - 1.2, sda.get(4), PRECISION);
+        assertEquals(-1.2, sda.get(2), PRECISION);
+    }
+
+    @Test
+    public void testKeyValueAt() {
+        final SparseDoubleArray sda = new SparseDoubleArray();
+
+        final int[] keys = {1, 6, -14, 53251, 5, -13412, 12, 0, 2};
+        final double[] values = {7, -12.4, 7, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
+                Double.NaN,
+                4311236312.0 / 3431470161413514334123.0,
+                431123636434132151313412.0 / 34323.0,
+                0};
+        for (int i = 0; i < keys.length; i++) {
+            sda.put(keys[i], values[i]);
+        }
+
+        // Sort the sample data.
+        final ArrayMap<Integer, Double> map = new ArrayMap<>(keys.length);
+        for (int i = 0; i < keys.length; i++) {
+            map.put(keys[i], values[i]);
+        }
+        final int[] sortedKeys = Arrays.copyOf(keys, keys.length);
+        Arrays.sort(sortedKeys);
+
+        for (int i = 0; i < sortedKeys.length; i++) {
+            final int expectedKey = sortedKeys[i];
+            final double expectedValue = map.get(expectedKey);
+
+            assertEquals("Wrong key at index " + i, expectedKey, sda.keyAt(i), PRECISION);
+            assertEquals("Wrong value at index " + i, expectedValue, sda.valueAt(i), PRECISION);
+        }
+    }
+}
diff --git a/data/etc/car/com.android.car.carlauncher.xml b/data/etc/car/com.android.car.carlauncher.xml
index ac16af3..abde232 100644
--- a/data/etc/car/com.android.car.carlauncher.xml
+++ b/data/etc/car/com.android.car.carlauncher.xml
@@ -18,6 +18,7 @@
     <privapp-permissions package="com.android.car.carlauncher">
         <permission name="android.permission.ACTIVITY_EMBEDDING"/>
         <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+        <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
         <permission name="android.permission.PACKAGE_USAGE_STATS"/>
diff --git a/libs/WindowManager/Shell/AndroidManifest.xml b/libs/WindowManager/Shell/AndroidManifest.xml
index d2b3cf6..6bd0e0a 100644
--- a/libs/WindowManager/Shell/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/AndroidManifest.xml
@@ -17,6 +17,8 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.wm.shell">
+    <!-- System permission required by WM Shell Task Organizer. -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.ROTATE_SURFACE_FLINGER" />
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
 </manifest>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
index 4768cf5..fa94ec5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
@@ -126,7 +126,7 @@
      */
     public boolean getSettingsSwipeToNotificationEnabled(ContentResolver resolver) {
         return Settings.Secure.getInt(resolver,
-                Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1) == 1;
+                Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 0 /* Default OFF */) == 1;
     }
 
     void dump(PrintWriter pw, String prefix, ContentResolver resolver) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 3f46fee..18c6b66 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -16,6 +16,8 @@
 
 package com.android.wm.shell.startingsurface;
 
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.app.ActivityThread;
@@ -31,6 +33,7 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.os.Build;
+import android.os.Trace;
 import android.util.Slog;
 import android.view.SurfaceControl;
 import android.window.SplashScreenView;
@@ -70,6 +73,7 @@
     private int mIconNormalExitDistance;
     private int mIconEarlyExitDistance;
     private final TransactionPool mTransactionPool;
+    private final SplashScreenWindowAttrs mTmpAttrs = new SplashScreenWindowAttrs();
 
     SplashscreenContentDrawer(Context context, int maxAnimatableIconDuration,
             int iconExitAnimDuration, int appRevealAnimDuration, TransactionPool pool) {
@@ -109,49 +113,82 @@
         return new ColorDrawable(getSystemBGColor());
     }
 
-    SplashScreenView makeSplashScreenContentView(Context context, int iconRes,
-            int splashscreenContentResId) {
-        updateDensity();
-        // splash screen content will be deprecated after S.
-        final SplashScreenView ssc =
-                makeSplashscreenContentDrawable(context, splashscreenContentResId);
-
-        if (ssc != null) {
-            return ssc;
-        }
-
-        final SplashScreenWindowAttrs attrs =
-                SplashScreenWindowAttrs.createWindowAttrs(context);
-        final StartingWindowViewBuilder builder = new StartingWindowViewBuilder();
+    private @ColorInt int peekWindowBGColor(Context context) {
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "peekWindowBGColor");
         final Drawable themeBGDrawable;
-
-        if (attrs.mWindowBgColor != 0) {
-            themeBGDrawable = new ColorDrawable(attrs.mWindowBgColor);
-        } else if (attrs.mWindowBgResId != 0) {
-            themeBGDrawable = context.getDrawable(attrs.mWindowBgResId);
+        if (mTmpAttrs.mWindowBgColor != 0) {
+            themeBGDrawable = new ColorDrawable(mTmpAttrs.mWindowBgColor);
+        } else if (mTmpAttrs.mWindowBgResId != 0) {
+            themeBGDrawable = context.getDrawable(mTmpAttrs.mWindowBgResId);
         } else {
             Slog.w(TAG, "Window background not exist!");
             themeBGDrawable = createDefaultBackgroundDrawable();
         }
+        final int estimatedWindowBGColor = estimateWindowBGColor(themeBGDrawable);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        return estimatedWindowBGColor;
+    }
+
+    private int estimateWindowBGColor(Drawable themeBGDrawable) {
+        final DrawableColorTester themeBGTester =
+                new DrawableColorTester(themeBGDrawable, true /* filterTransparent */);
+        if (themeBGTester.nonTransparentRatio() == 0) {
+            // the window background is transparent, unable to draw
+            Slog.w(TAG, "Window background is transparent, fill background with black color");
+            return getSystemBGColor();
+        } else {
+            return themeBGTester.getDominateColor();
+        }
+    }
+
+    SplashScreenView makeSplashScreenContentView(Context context, int iconRes) {
+        updateDensity();
+
+        getWindowAttrs(context, mTmpAttrs);
+        final StartingWindowViewBuilder builder = new StartingWindowViewBuilder();
         final int animationDuration;
         final Drawable iconDrawable;
-        if (attrs.mReplaceIcon != null) {
-            iconDrawable = attrs.mReplaceIcon;
+        if (mTmpAttrs.mReplaceIcon != null) {
+            iconDrawable = mTmpAttrs.mReplaceIcon;
             animationDuration = Math.max(0,
-                    Math.min(attrs.mAnimationDuration, mMaxAnimatableIconDuration));
+                    Math.min(mTmpAttrs.mAnimationDuration, mMaxAnimatableIconDuration));
         } else {
             iconDrawable = iconRes != 0 ? context.getDrawable(iconRes)
                     : context.getPackageManager().getDefaultActivityIcon();
             animationDuration = 0;
         }
+        final int themeBGColor = peekWindowBGColor(context);
         // TODO (b/173975965) Tracking the performance on improved splash screen.
         return builder
                 .setContext(context)
-                .setThemeDrawable(themeBGDrawable)
+                .setWindowBGColor(themeBGColor)
                 .setIconDrawable(iconDrawable)
                 .setIconAnimationDuration(animationDuration)
-                .setBrandingDrawable(attrs.mBrandingImage)
-                .setIconBackground(attrs.mIconBgColor).build();
+                .setBrandingDrawable(mTmpAttrs.mBrandingImage)
+                .setIconBackground(mTmpAttrs.mIconBgColor).build();
+    }
+
+    private static void getWindowAttrs(Context context, SplashScreenWindowAttrs attrs) {
+        final TypedArray typedArray = context.obtainStyledAttributes(
+                com.android.internal.R.styleable.Window);
+        attrs.mWindowBgResId = typedArray.getResourceId(R.styleable.Window_windowBackground, 0);
+        attrs.mWindowBgColor = typedArray.getColor(
+                R.styleable.Window_windowSplashScreenBackground, Color.TRANSPARENT);
+        attrs.mReplaceIcon = typedArray.getDrawable(
+                R.styleable.Window_windowSplashScreenAnimatedIcon);
+        attrs.mAnimationDuration = typedArray.getInt(
+                R.styleable.Window_windowSplashScreenAnimationDuration, 0);
+        attrs.mBrandingImage = typedArray.getDrawable(
+                R.styleable.Window_windowSplashScreenBrandingImage);
+        attrs.mIconBgColor = typedArray.getColor(
+                R.styleable.Window_windowSplashScreenIconBackgroundColor, Color.TRANSPARENT);
+        typedArray.recycle();
+        if (DEBUG) {
+            Slog.d(TAG, "window attributes color: "
+                    + Integer.toHexString(attrs.mWindowBgColor)
+                    + " icon " + attrs.mReplaceIcon + " duration " + attrs.mAnimationDuration
+                    + " brandImage " + attrs.mBrandingImage);
+        }
     }
 
     static class SplashScreenWindowAttrs {
@@ -161,35 +198,9 @@
         private Drawable mBrandingImage = null;
         private int mIconBgColor = Color.TRANSPARENT;
         private int mAnimationDuration = 0;
-
-        static SplashScreenWindowAttrs createWindowAttrs(Context context) {
-            final SplashScreenWindowAttrs attrs = new SplashScreenWindowAttrs();
-            final TypedArray typedArray = context.obtainStyledAttributes(
-                    com.android.internal.R.styleable.Window);
-            attrs.mWindowBgResId = typedArray.getResourceId(R.styleable.Window_windowBackground, 0);
-            attrs.mWindowBgColor = typedArray.getColor(
-                    R.styleable.Window_windowSplashScreenBackground, Color.TRANSPARENT);
-            attrs.mReplaceIcon = typedArray.getDrawable(
-                    R.styleable.Window_windowSplashScreenAnimatedIcon);
-            attrs.mAnimationDuration = typedArray.getInt(
-                    R.styleable.Window_windowSplashScreenAnimationDuration, 0);
-            attrs.mBrandingImage = typedArray.getDrawable(
-                    R.styleable.Window_windowSplashScreenBrandingImage);
-            attrs.mIconBgColor = typedArray.getColor(
-                    R.styleable.Window_windowSplashScreenIconBackgroundColor, Color.TRANSPARENT);
-            typedArray.recycle();
-            if (DEBUG) {
-                Slog.d(TAG, "window attributes color: "
-                        + Integer.toHexString(attrs.mWindowBgColor)
-                        + " icon " + attrs.mReplaceIcon + " duration " + attrs.mAnimationDuration
-                        + " brandImage " + attrs.mBrandingImage);
-            }
-            return attrs;
-        }
     }
 
     private class StartingWindowViewBuilder {
-        private Drawable mThemeBGDrawable;
         private Drawable mIconDrawable;
         private int mIconAnimationDuration;
         private Context mContext;
@@ -203,8 +214,8 @@
         private Drawable mFinalIconDrawable;
         private float mScale = 1f;
 
-        StartingWindowViewBuilder setThemeDrawable(Drawable background) {
-            mThemeBGDrawable = background;
+        StartingWindowViewBuilder setWindowBGColor(@ColorInt int background) {
+            mThemeColor = background;
             mBuildComplete = false;
             return this;
         }
@@ -247,18 +258,14 @@
                 Slog.e(TAG, "Unable to create StartingWindowView, lack of materials!");
                 return null;
             }
-            if (mThemeBGDrawable == null) {
-                Slog.w(TAG, "Theme Background Drawable is null, forget to set Theme Drawable?");
-                mThemeBGDrawable = createDefaultBackgroundDrawable();
-            }
-            processThemeColor();
+
             if (!processAdaptiveIcon() && mIconDrawable != null) {
                 if (DEBUG) {
                     Slog.d(TAG, "The icon is not an AdaptiveIconDrawable");
                 }
                 mFinalIconDrawable = SplashscreenIconDrawableFactory.makeIconDrawable(
                         mIconBackground != Color.TRANSPARENT
-                        ? mIconBackground : mThemeColor, mIconDrawable);
+                        ? mIconBackground : mThemeColor, mIconDrawable, mIconSize);
             }
             final int iconSize = mFinalIconDrawable != null ? (int) (mIconSize * mScale) : 0;
             mCachedResult = fillViewWithIcon(mContext, iconSize, mFinalIconDrawable);
@@ -266,22 +273,10 @@
             return mCachedResult;
         }
 
-        private void createIconDrawable(Drawable iconDrawable) {
+        private void createIconDrawable(Drawable iconDrawable, int iconSize) {
             mFinalIconDrawable = SplashscreenIconDrawableFactory.makeIconDrawable(
                     mIconBackground != Color.TRANSPARENT
-                    ? mIconBackground : mThemeColor, iconDrawable);
-        }
-
-        private void processThemeColor() {
-            final DrawableColorTester themeBGTester =
-                    new DrawableColorTester(mThemeBGDrawable, true /* filterTransparent */);
-            if (themeBGTester.nonTransparentRatio() == 0) {
-                // the window background is transparent, unable to draw
-                Slog.w(TAG, "Window background is transparent, fill background with black color");
-                mThemeColor = getSystemBGColor();
-            } else {
-                mThemeColor = themeBGTester.getDominateColor();
-            }
+                    ? mIconBackground : mThemeColor, iconDrawable, iconSize);
         }
 
         private boolean processAdaptiveIcon() {
@@ -289,6 +284,7 @@
                 return false;
             }
 
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "processAdaptiveIcon");
             final AdaptiveIconDrawable adaptiveIconDrawable = (AdaptiveIconDrawable) mIconDrawable;
             final DrawableColorTester backIconTester =
                     new DrawableColorTester(adaptiveIconDrawable.getBackground());
@@ -325,29 +321,28 @@
                 if (DEBUG) {
                     Slog.d(TAG, "makeSplashScreenContentView: choose fg icon");
                 }
-                // Using AdaptiveIconDrawable here can help keep the shape consistent with the
-                // current settings.
-                createIconDrawable(iconForeground);
                 // Reference AdaptiveIcon description, outer is 108 and inner is 72, so we
                 // should enlarge the size 108/72 if we only draw adaptiveIcon's foreground.
                 if (foreIconTester.nonTransparentRatio() < ENLARGE_FOREGROUND_ICON_THRESHOLD) {
                     mScale = 1.5f;
                 }
+                // Using AdaptiveIconDrawable here can help keep the shape consistent with the
+                // current settings.
+                final int iconSize = (int) (0.5f + mIconSize * mScale);
+                createIconDrawable(iconForeground, iconSize);
             } else {
                 if (DEBUG) {
                     Slog.d(TAG, "makeSplashScreenContentView: draw whole icon");
                 }
-                if (mIconBackground != Color.TRANSPARENT) {
-                    createIconDrawable(adaptiveIconDrawable);
-                } else {
-                    mFinalIconDrawable = adaptiveIconDrawable;
-                }
+                createIconDrawable(adaptiveIconDrawable, mIconSize);
             }
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             return true;
         }
 
         private SplashScreenView fillViewWithIcon(Context context,
                 int iconSize, Drawable iconDrawable) {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon");
             final SplashScreenView.Builder builder = new SplashScreenView.Builder(context);
             builder.setIconSize(iconSize).setBackgroundColor(mThemeColor)
                     .setIconBackground(mIconBackground);
@@ -364,6 +359,7 @@
                 Slog.d(TAG, "fillViewWithIcon surfaceWindowView " + splashScreenView);
             }
             splashScreenView.makeSystemUIColorsTransparent();
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             return splashScreenView;
         }
     }
@@ -395,7 +391,7 @@
         return root < 0.1;
     }
 
-    private static SplashScreenView makeSplashscreenContentDrawable(Context ctx,
+    static SplashScreenView makeSplashscreenContent(Context ctx,
             int splashscreenContentResId) {
         // doesn't support windowSplashscreenContent after S
         // TODO add an allowlist to skip some packages if needed
@@ -525,6 +521,7 @@
                     new TransparentFilterQuantizer();
 
             ComplexDrawableTester(Drawable drawable, boolean filterTransparent) {
+                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "ComplexDrawableTester");
                 final Rect initialBounds = drawable.copyBounds();
                 int width = drawable.getIntrinsicWidth();
                 int height = drawable.getIntrinsicHeight();
@@ -559,6 +556,7 @@
                 }
                 mPalette = builder.generate();
                 bitmap.recycle();
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             }
 
             @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index 8626dbc..a4a83eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -16,11 +16,15 @@
 
 package com.android.wm.shell.startingsurface;
 
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Matrix;
@@ -28,11 +32,13 @@
 import android.graphics.Path;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.Shader;
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.util.PathParser;
 import android.window.SplashScreenView;
 
@@ -47,12 +53,57 @@
 public class SplashscreenIconDrawableFactory {
 
     static Drawable makeIconDrawable(@ColorInt int backgroundColor,
-            @NonNull Drawable foregroundDrawable) {
+            @NonNull Drawable foregroundDrawable, int iconSize) {
         if (foregroundDrawable instanceof Animatable) {
             return new AnimatableIconDrawable(backgroundColor, foregroundDrawable);
+        } else if (foregroundDrawable instanceof AdaptiveIconDrawable) {
+            return new ImmobileIconDrawable((AdaptiveIconDrawable) foregroundDrawable, iconSize);
         } else {
-            // TODO make a light weight drawable instead of AdaptiveIconDrawable
-            return new AdaptiveIconDrawable(new ColorDrawable(backgroundColor), foregroundDrawable);
+            return new ImmobileIconDrawable(new AdaptiveIconDrawable(
+                    new ColorDrawable(backgroundColor), foregroundDrawable), iconSize);
+        }
+    }
+
+    private static class ImmobileIconDrawable extends Drawable {
+        private Shader mLayersShader;
+        private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG
+                | Paint.FILTER_BITMAP_FLAG);
+
+        ImmobileIconDrawable(AdaptiveIconDrawable drawable, int iconSize) {
+            cachePaint(drawable, iconSize, iconSize);
+        }
+
+        private void cachePaint(AdaptiveIconDrawable drawable, int width, int height) {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "cachePaint");
+            final Bitmap layersBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+            final Canvas canvas = new Canvas(layersBitmap);
+            drawable.setBounds(0, 0, width, height);
+            drawable.draw(canvas);
+            mLayersShader = new BitmapShader(layersBitmap, Shader.TileMode.CLAMP,
+                    Shader.TileMode.CLAMP);
+            mPaint.setShader(mLayersShader);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            final Rect bounds = getBounds();
+            canvas.drawRect(bounds, mPaint);
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+
+        }
+
+        @Override
+        public void setColorFilter(ColorFilter colorFilter) {
+
+        }
+
+        @Override
+        public int getOpacity() {
+            return 1;
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index b592121..b500813 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -181,11 +181,7 @@
         }
 
         int windowFlags = 0;
-        final boolean enableHardAccelerated =
-                (activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0;
-        if (enableHardAccelerated) {
-            windowFlags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-        }
+        windowFlags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
 
         final boolean[] showWallpaper = new boolean[1];
         final int[] splashscreenContentResId = new int[1];
@@ -246,8 +242,6 @@
         params.packageName = activityInfo.packageName;
         params.windowAnimations = win.getWindowStyle().getResourceId(
                 com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
-        params.privateFlags |=
-                WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
         params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
         // Setting as trusted overlay to let touches pass through. This is safe because this
         // window is controlled by the system.
@@ -267,21 +261,31 @@
         final int taskId = taskInfo.taskId;
         SplashScreenView sView = null;
         try {
-            sView = mSplashscreenContentDrawer.makeSplashScreenContentView(context, iconRes,
-                            splashscreenContentResId[0]);
             final View view = win.getDecorView();
             final WindowManager wm = mContext.getSystemService(WindowManager.class);
-            if (postAddWindow(taskId, appToken, view, wm, params)) {
+            // splash screen content will be deprecated after S.
+            sView = SplashscreenContentDrawer.makeSplashscreenContent(
+                    context, splashscreenContentResId[0]);
+            final boolean splashscreenContentCompatible = sView != null;
+            if (splashscreenContentCompatible) {
+                win.setContentView(sView);
+            } else {
+                sView = mSplashscreenContentDrawer.makeSplashScreenContentView(context, iconRes);
                 win.setContentView(sView);
                 sView.cacheRootWindow(win);
             }
+            postAddWindow(taskId, appToken, view, wm, params);
         } catch (RuntimeException e) {
             // don't crash if something else bad happens, for example a
             // failure loading resources because we are loading from an app
             // on external storage that has been unmounted.
-            Slog.w(TAG, " failed creating starting window", e);
+            Slog.w(TAG, " failed creating starting window at taskId: " + taskId, e);
+            sView = null;
         } finally {
-            setSplashScreenRecord(taskId, sView);
+            final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
+            if (record != null) {
+                record.setSplashScreenView(sView);
+            }
         }
     }
 
@@ -328,7 +332,7 @@
         ActivityTaskManager.getInstance().onSplashScreenViewCopyFinished(taskId, parcelable);
     }
 
-    protected boolean postAddWindow(int taskId, IBinder appToken, View view, WindowManager wm,
+    protected void postAddWindow(int taskId, IBinder appToken, View view, WindowManager wm,
             WindowManager.LayoutParams params) {
         boolean shouldSaveView = true;
         try {
@@ -349,7 +353,6 @@
             removeWindowNoAnimate(taskId);
             saveSplashScreenRecord(taskId, view);
         }
-        return shouldSaveView;
     }
 
     private void saveSplashScreenRecord(int taskId, View view) {
@@ -358,13 +361,6 @@
         mStartingWindowRecords.put(taskId, tView);
     }
 
-    private void setSplashScreenRecord(int taskId, SplashScreenView splashScreenView) {
-        final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
-        if (record != null) {
-            record.setSplashScreenView(splashScreenView);
-        }
-    }
-
     private void removeWindowNoAnimate(int taskId) {
         removeWindowSynced(taskId, null, null, false);
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index 207db9e..8ae0a73 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -83,12 +83,11 @@
         }
 
         @Override
-        protected boolean postAddWindow(int taskId, IBinder appToken,
+        protected void postAddWindow(int taskId, IBinder appToken,
                 View view, WindowManager wm, WindowManager.LayoutParams params) {
             // listen for addView
             mAddWindowForTask = taskId;
             mViewThemeResId = view.getContext().getThemeResId();
-            return true;
         }
 
         @Override
diff --git a/location/java/android/location/util/identity/CallerIdentity.java b/location/java/android/location/util/identity/CallerIdentity.java
index 85a083e..ade0ea4 100644
--- a/location/java/android/location/util/identity/CallerIdentity.java
+++ b/location/java/android/location/util/identity/CallerIdentity.java
@@ -55,6 +55,20 @@
     }
 
     /**
+     * Returns a CallerIdentity with PID and listener ID information stripped. This is mostly
+     * useful for aggregating information for debug purposes, and should not be used in any API with
+     * security requirements.
+     */
+    public static CallerIdentity forAggregation(CallerIdentity callerIdentity) {
+        if (callerIdentity.getPid() == 0 && callerIdentity.getListenerId() == null) {
+            return callerIdentity;
+        }
+
+        return new CallerIdentity(callerIdentity.getUid(), 0, callerIdentity.getPackageName(),
+                callerIdentity.getAttributionTag(), null);
+    }
+
+    /**
      * Creates a CallerIdentity for the current process and context.
      */
     public static CallerIdentity fromContext(Context context) {
@@ -180,17 +194,6 @@
         }
     }
 
-    /**
-     * Returns a CallerIdentity corrosponding to this CallerIdentity but with a null listener id.
-     */
-    public CallerIdentity stripListenerId() {
-        if (mListenerId == null) {
-            return this;
-        } else {
-            return new CallerIdentity(mUid, mPid, mPackageName, mAttributionTag, null);
-        }
-    }
-
     @Override
     public String toString() {
         int length = 10 + mPackageName.length();
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 3de78bb..644afb7 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -99,9 +99,7 @@
 
 
 /**
- * MediaPlayer class can be used to control playback
- * of audio/video files and streams. An example on how to use the methods in
- * this class can be found in {@link android.widget.VideoView}.
+ * MediaPlayer class can be used to control playback of audio/video files and streams.
  *
  * <p>MediaPlayer is not thread-safe. Creation of and all access to player instances
  * should be on the same thread. If registering <a href="#Callbacks">callbacks</a>,
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index 9ca6d8f..b179c6d 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -45,6 +45,7 @@
   public final class NetworkCapabilities implements android.os.Parcelable {
     ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, long);
     method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
+    method public boolean hasUnwantedCapability(int);
     field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL
     field public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1L; // 0x1L
     field public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 2L; // 0x2L
@@ -57,7 +58,13 @@
     method @NonNull public android.net.NetworkCapabilities.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
   }
 
+  public class NetworkRequest implements android.os.Parcelable {
+    method public boolean hasUnwantedCapability(int);
+  }
+
   public static class NetworkRequest.Builder {
+    method @NonNull public android.net.NetworkRequest.Builder addUnwantedCapability(int);
+    method @NonNull public android.net.NetworkRequest.Builder removeUnwantedCapability(int);
     method @NonNull public android.net.NetworkRequest.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
   }
 
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index 703fca4..c19fcdd 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -216,6 +216,7 @@
     method public void markConnected();
     method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
     method public void onAutomaticReconnectDisabled();
+    method public void onBandwidthUpdateRequested();
     method public void onNetworkUnwanted();
     method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
     method public void onQosCallbackUnregistered(int);
@@ -233,6 +234,7 @@
     method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
     method public final void sendQosSessionLost(int, int);
     method public final void sendSocketKeepaliveEvent(int, int);
+    method @Deprecated public void setLegacySubtype(int, @NonNull String);
     method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
     method public void unregister();
     field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
@@ -253,7 +255,12 @@
   public static final class NetworkAgentConfig.Builder {
     ctor public NetworkAgentConfig.Builder();
     method @NonNull public android.net.NetworkAgentConfig build();
+    method @NonNull public android.net.NetworkAgentConfig.Builder disableNat64Detection();
+    method @NonNull public android.net.NetworkAgentConfig.Builder disableProvisioningNotification();
     method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyExtraInfo(@NonNull String);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubType(int);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubTypeName(@NonNull String);
     method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int);
     method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String);
     method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean);
@@ -388,6 +395,7 @@
   }
 
   public abstract class SocketKeepalive implements java.lang.AutoCloseable {
+    field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf
     field public static final int SUCCESS = 0; // 0x0
   }
 
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
index 3863ed1..1ff0140 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgent.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
@@ -362,9 +362,8 @@
     public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21;
 
     private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
-        // The subtype can be changed with (TODO) setLegacySubtype, but it starts
-        // with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description.
-        final NetworkInfo ni = new NetworkInfo(config.legacyType, 0, config.legacyTypeName, "");
+        final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType,
+                config.legacyTypeName, config.legacySubTypeName);
         ni.setIsAvailable(true);
         ni.setDetailedState(NetworkInfo.DetailedState.CONNECTING, null /* reason */,
                 config.getLegacyExtraInfo());
@@ -829,6 +828,7 @@
      * @hide
      */
     @Deprecated
+    @SystemApi
     public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) {
         mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName);
         queueOrSendNetworkInfo(mNetworkInfo);
@@ -962,6 +962,7 @@
      * shall try to overwrite this method and produce a bandwidth update if capable.
      * @hide
      */
+    @SystemApi
     public void onBandwidthUpdateRequested() {
         pollLceData();
     }
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
index 5e50a64..fb6fcc1 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
@@ -165,6 +165,12 @@
     }
 
     /**
+     * The legacy Sub type of this network agent, or TYPE_NONE if unset.
+     * @hide
+     */
+    public int legacySubType = ConnectivityManager.TYPE_NONE;
+
+    /**
      * Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network.
      * Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode.
      *
@@ -190,6 +196,13 @@
     }
 
     /**
+     * The name of the legacy Sub network type. It's a free-form string.
+     * @hide
+     */
+    @NonNull
+    public String legacySubTypeName = "";
+
+    /**
      * The legacy extra info of the agent. The extra info should only be :
      * <ul>
      *   <li>For cellular agents, the APN name.</li>
@@ -225,6 +238,8 @@
             skip464xlat = nac.skip464xlat;
             legacyType = nac.legacyType;
             legacyTypeName = nac.legacyTypeName;
+            legacySubType = nac.legacySubType;
+            legacySubTypeName = nac.legacySubTypeName;
             mLegacyExtraInfo = nac.mLegacyExtraInfo;
         }
     }
@@ -290,7 +305,6 @@
          * and reduce idle traffic on networks that are known to be IPv6-only without a NAT64.
          *
          * @return this builder, to facilitate chaining.
-         * @hide
          */
         @NonNull
         public Builder disableNat64Detection() {
@@ -303,7 +317,6 @@
          * perform its own carrier-specific provisioning procedure.
          *
          * @return this builder, to facilitate chaining.
-         * @hide
          */
         @NonNull
         public Builder disableProvisioningNotification() {
@@ -324,6 +337,18 @@
         }
 
         /**
+         * Sets the legacy sub-type for this network.
+         *
+         * @param legacySubType the type
+         * @return this builder, to facilitate chaining.
+         */
+        @NonNull
+        public Builder setLegacySubType(final int legacySubType) {
+            mConfig.legacySubType = legacySubType;
+            return this;
+        }
+
+        /**
          * Sets the name of the legacy type of the agent. It's a free-form string used in logging.
          * @param legacyTypeName the name
          * @return this builder, to facilitate chaining.
@@ -335,10 +360,20 @@
         }
 
         /**
+         * Sets the name of the legacy Sub-type of the agent. It's a free-form string.
+         * @param legacySubTypeName the name
+         * @return this builder, to facilitate chaining.
+         */
+        @NonNull
+        public Builder setLegacySubTypeName(@NonNull String legacySubTypeName) {
+            mConfig.legacySubTypeName = legacySubTypeName;
+            return this;
+        }
+
+        /**
          * Sets the legacy extra info of the agent.
          * @param legacyExtraInfo the legacy extra info.
          * @return this builder, to facilitate chaining.
-         * @hide
          */
         @NonNull
         public Builder setLegacyExtraInfo(@NonNull String legacyExtraInfo) {
@@ -412,6 +447,8 @@
         out.writeInt(skip464xlat ? 1 : 0);
         out.writeInt(legacyType);
         out.writeString(legacyTypeName);
+        out.writeInt(legacySubType);
+        out.writeString(legacySubTypeName);
         out.writeString(mLegacyExtraInfo);
     }
 
@@ -429,6 +466,8 @@
             networkAgentConfig.skip464xlat = in.readInt() != 0;
             networkAgentConfig.legacyType = in.readInt();
             networkAgentConfig.legacyTypeName = in.readString();
+            networkAgentConfig.legacySubType = in.readInt();
+            networkAgentConfig.legacySubTypeName = in.readString();
             networkAgentConfig.mLegacyExtraInfo = in.readString();
             return networkAgentConfig;
         }
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index c9c0940..881fa8c 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -639,19 +639,31 @@
     }
 
     /**
-     * Removes (if found) the given capability from this {@code NetworkCapability} instance.
+     * Removes (if found) the given capability from this {@code NetworkCapability}
+     * instance that were added via addCapability(int) or setCapabilities(int[], int[]).
      *
      * @param capability the capability to be removed.
      * @return This NetworkCapabilities instance, to facilitate chaining.
      * @hide
      */
     public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) {
-        // Note that this method removes capabilities that were added via addCapability(int),
-        // addUnwantedCapability(int) or setCapabilities(int[], int[]).
         checkValidCapability(capability);
         final long mask = ~(1 << capability);
         mNetworkCapabilities &= mask;
-        mUnwantedNetworkCapabilities &= mask;
+        return this;
+    }
+
+    /**
+     * Removes (if found) the given unwanted capability from this {@code NetworkCapability}
+     * instance that were added via addUnwantedCapability(int) or setCapabilities(int[], int[]).
+     *
+     * @param capability the capability to be removed.
+     * @return This NetworkCapabilities instance, to facilitate chaining.
+     * @hide
+     */
+    public @NonNull NetworkCapabilities removeUnwantedCapability(@NetCapability int capability) {
+        checkValidCapability(capability);
+        mUnwantedNetworkCapabilities &= ~(1 << capability);
         return this;
     }
 
@@ -723,6 +735,7 @@
     }
 
     /** @hide */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public boolean hasUnwantedCapability(@NetCapability int capability) {
         return isValidCapability(capability)
                 && ((mUnwantedNetworkCapabilities & (1 << capability)) != 0);
@@ -736,10 +749,16 @@
         return ((mNetworkCapabilities & CONNECTIVITY_MANAGED_CAPABILITIES) != 0);
     }
 
-    /** Note this method may result in having the same capability in wanted and unwanted lists. */
     private void combineNetCapabilities(@NonNull NetworkCapabilities nc) {
-        this.mNetworkCapabilities |= nc.mNetworkCapabilities;
-        this.mUnwantedNetworkCapabilities |= nc.mUnwantedNetworkCapabilities;
+        final long wantedCaps = this.mNetworkCapabilities | nc.mNetworkCapabilities;
+        final long unwantedCaps =
+                this.mUnwantedNetworkCapabilities | nc.mUnwantedNetworkCapabilities;
+        if ((wantedCaps & unwantedCaps) != 0) {
+            throw new IllegalArgumentException(
+                    "Cannot have the same capability in wanted and unwanted lists.");
+        }
+        this.mNetworkCapabilities = wantedCaps;
+        this.mUnwantedNetworkCapabilities = unwantedCaps;
     }
 
     /**
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index f9b3db1..bcbc04f7 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -313,12 +313,31 @@
          *
          * @hide
          */
+        @NonNull
+        @SuppressLint("MissingGetterMatchingBuilder")
+        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
         public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
             mNetworkCapabilities.addUnwantedCapability(capability);
             return this;
         }
 
         /**
+         * Removes (if found) the given unwanted capability from this builder instance.
+         *
+         * @param capability The unwanted capability to remove.
+         * @return The builder to facilitate chaining.
+         *
+         * @hide
+         */
+        @NonNull
+        @SuppressLint("BuilderSetStyle")
+        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+        public Builder removeUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
+            mNetworkCapabilities.removeUnwantedCapability(capability);
+            return this;
+        }
+
+        /**
          * Completely clears all the {@code NetworkCapabilities} from this builder instance,
          * removing even the capabilities that are set by default when the object is constructed.
          *
@@ -575,6 +594,7 @@
      *
      * @hide
      */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public boolean hasUnwantedCapability(@NetCapability int capability) {
         return networkCapabilities.hasUnwantedCapability(capability);
     }
diff --git a/packages/Connectivity/framework/src/android/net/SocketKeepalive.java b/packages/Connectivity/framework/src/android/net/SocketKeepalive.java
index d007a95..f6cae72 100644
--- a/packages/Connectivity/framework/src/android/net/SocketKeepalive.java
+++ b/packages/Connectivity/framework/src/android/net/SocketKeepalive.java
@@ -55,36 +55,68 @@
     static final String TAG = "SocketKeepalive";
 
     /**
-     * No errors.
+     * Success. It indicates there is no error.
      * @hide
      */
     @SystemApi
     public static final int SUCCESS = 0;
 
-    /** @hide */
+    /**
+     * No keepalive. This should only be internally as it indicates There is no keepalive.
+     * It should not propagate to applications.
+     * @hide
+     */
     public static final int NO_KEEPALIVE = -1;
 
-    /** @hide */
+    /**
+     * Data received.
+     * @hide
+     */
     public static final int DATA_RECEIVED = -2;
 
-    /** @hide */
+    /**
+     * The binder died.
+     * @hide
+     */
     public static final int BINDER_DIED = -10;
 
-    /** The specified {@code Network} is not connected. */
+    /**
+     * The invalid network. It indicates the specified {@code Network} is not connected.
+     */
     public static final int ERROR_INVALID_NETWORK = -20;
-    /** The specified IP addresses are invalid. For example, the specified source IP address is
-     * not configured on the specified {@code Network}. */
+
+    /**
+     * The invalid IP addresses. Indicates the specified IP addresses are invalid.
+     * For example, the specified source IP address is not configured on the
+     * specified {@code Network}.
+     */
     public static final int ERROR_INVALID_IP_ADDRESS = -21;
-    /** The requested port is invalid. */
+
+    /**
+     * The port is invalid.
+     */
     public static final int ERROR_INVALID_PORT = -22;
-    /** The packet length is invalid (e.g., too long). */
+
+    /**
+     * The length is invalid (e.g. too long).
+     */
     public static final int ERROR_INVALID_LENGTH = -23;
-    /** The packet transmission interval is invalid (e.g., too short). */
+
+    /**
+     * The interval is invalid (e.g. too short).
+     */
     public static final int ERROR_INVALID_INTERVAL = -24;
-    /** The target socket is invalid. */
+
+    /**
+     * The socket is invalid.
+     */
     public static final int ERROR_INVALID_SOCKET = -25;
-    /** The target socket is not idle. */
+
+    /**
+     * The socket is not idle.
+     */
     public static final int ERROR_SOCKET_NOT_IDLE = -26;
+
     /**
      * The stop reason is uninitialized. This should only be internally used as initial state
      * of stop reason, instead of propagating to application.
@@ -92,15 +124,29 @@
      */
     public static final int ERROR_STOP_REASON_UNINITIALIZED = -27;
 
-    /** The device does not support this request. */
+    /**
+     * The request is unsupported.
+     */
     public static final int ERROR_UNSUPPORTED = -30;
-    /** @hide TODO: delete when telephony code has been updated. */
-    public static final int ERROR_HARDWARE_UNSUPPORTED = ERROR_UNSUPPORTED;
-    /** The hardware returned an error. */
+
+    /**
+     * There was a hardware error.
+     */
     public static final int ERROR_HARDWARE_ERROR = -31;
-    /** The limitation of resource is reached. */
+
+    /**
+     * Resources are insufficient (e.g. all hardware slots are in use).
+     */
     public static final int ERROR_INSUFFICIENT_RESOURCES = -32;
 
+    /**
+     * There was no such slot. This should only be internally as it indicates
+     * a programming error in the system server. It should not propagate to
+     * applications.
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_NO_SUCH_SLOT = -33;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -111,7 +157,8 @@
             ERROR_INVALID_LENGTH,
             ERROR_INVALID_INTERVAL,
             ERROR_INVALID_SOCKET,
-            ERROR_SOCKET_NOT_IDLE
+            ERROR_SOCKET_NOT_IDLE,
+            ERROR_NO_SUCH_SLOT
     })
     public @interface ErrorCode {}
 
@@ -122,7 +169,6 @@
             ERROR_INVALID_LENGTH,
             ERROR_UNSUPPORTED,
             ERROR_INSUFFICIENT_RESOURCES,
-            ERROR_HARDWARE_UNSUPPORTED
     })
     public @interface KeepaliveEvent {}
 
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 5d4078d..fbb84fd 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -242,7 +242,7 @@
     <bool name="def_hdmiControlAutoDeviceOff">true</bool>
 
     <!-- Default for Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED -->
-    <bool name="def_swipe_bottom_to_notification_enabled">true</bool>
+    <bool name="def_swipe_bottom_to_notification_enabled">false</bool>
 
     <!-- Default for Settings.Secure.ONE_HANDED_MODE_ENABLED -->
     <bool name="def_one_handed_mode_enabled">false</bool>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index eedcdab..b1689f6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -48,7 +48,6 @@
 import com.android.systemui.qs.carrier.QSCarrierGroupController;
 import com.android.systemui.qs.dagger.QSScope;
 import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusIconContainer;
 import com.android.systemui.statusbar.policy.Clock;
@@ -86,7 +85,6 @@
     private final View mRingerContainer;
     private final QSTileHost mQSTileHost;
     private final StatusBarIconController mStatusBarIconController;
-    private final CommandQueue mCommandQueue;
     private final DemoModeController mDemoModeController;
     private final UserTracker mUserTracker;
     private final StatusIconContainer mIconContainer;
@@ -204,7 +202,7 @@
             PrivacyItemController privacyItemController, RingerModeTracker ringerModeTracker,
             ActivityStarter activityStarter, UiEventLogger uiEventLogger,
             QSTileHost qsTileHost, StatusBarIconController statusBarIconController,
-            CommandQueue commandQueue, DemoModeController demoModeController,
+            DemoModeController demoModeController,
             UserTracker userTracker, QuickQSPanelController quickQSPanelController,
             QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder,
             PrivacyLogger privacyLogger,
@@ -219,7 +217,6 @@
         mUiEventLogger = uiEventLogger;
         mQSTileHost = qsTileHost;
         mStatusBarIconController = statusBarIconController;
-        mCommandQueue = commandQueue;
         mDemoModeController = demoModeController;
         mUserTracker = userTracker;
         mLifecycle = new LifecycleRegistry(mLifecycleOwner);
@@ -238,7 +235,7 @@
         mRingerContainer = mView.findViewById(R.id.ringer_container);
         mIconContainer = mView.findViewById(R.id.statusIcons);
 
-        mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer, mCommandQueue);
+        mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer);
         mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
         mColorExtractor = colorExtractor;
         mOnColorsChangedListener = (extractor, which) -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index ca3923f..c565a271 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -38,8 +38,6 @@
 import android.os.AsyncTask;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.provider.DeviceConfig;
-import android.provider.DeviceConfig.Properties;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationStats;
 import android.service.notification.StatusBarNotification;
@@ -48,7 +46,6 @@
 import android.view.View;
 import android.widget.ImageView;
 
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
@@ -147,23 +144,6 @@
     private ImageView mBackdropFront;
     private ImageView mBackdropBack;
 
-    private boolean mShowCompactMediaSeekbar;
-    private final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener =
-            new DeviceConfig.OnPropertiesChangedListener() {
-        @Override
-        public void onPropertiesChanged(Properties properties) {
-            for (String name : properties.getKeyset()) {
-                if (SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED.equals(name)) {
-                    String value = properties.getString(name, null);
-                    if (DEBUG_MEDIA) {
-                        Log.v(TAG, "DEBUG_MEDIA: compact media seekbar flag updated: " + value);
-                    }
-                    mShowCompactMediaSeekbar = "true".equals(value);
-                }
-            }
-        }
-    };
-
     private final MediaController.Callback mMediaListener = new MediaController.Callback() {
         @Override
         public void onPlaybackStateChanged(PlaybackState state) {
@@ -231,14 +211,6 @@
             setupNotifPipeline();
             mUsingNotifPipeline = true;
         }
-
-        mShowCompactMediaSeekbar = "true".equals(
-                DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
-                    SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED));
-
-        deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
-                mContext.getMainExecutor(),
-                mPropertiesChangedListener);
     }
 
     private void setupNotifPipeline() {
@@ -405,10 +377,6 @@
         return mMediaMetadata;
     }
 
-    public boolean getShowCompactMediaSeekbar() {
-        return mShowCompactMediaSeekbar;
-    }
-
     public Icon getMediaIcon() {
         if (mMediaNotificationKey == null) {
             return null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageGradientColorizer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageGradientColorizer.java
deleted file mode 100644
index f5a76f0..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageGradientColorizer.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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
- */
-
-package com.android.systemui.statusbar.notification;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Shader;
-import android.graphics.drawable.Drawable;
-
-/**
- * A utility class to colorize bitmaps with a color gradient and a special blending mode
- */
-public class ImageGradientColorizer {
-    public Bitmap colorize(Drawable drawable, int backgroundColor, boolean isRtl) {
-        int width = drawable.getIntrinsicWidth();
-        int height = drawable.getIntrinsicHeight();
-        int size = Math.min(width, height);
-        int widthInset = (width - size) / 2;
-        int heightInset = (height - size) / 2;
-        drawable = drawable.mutate();
-        drawable.setBounds(- widthInset, - heightInset, width - widthInset, height - heightInset);
-        Bitmap newBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
-        Canvas canvas = new Canvas(newBitmap);
-
-        // Values to calculate the luminance of a color
-        float lr = 0.2126f;
-        float lg = 0.7152f;
-        float lb = 0.0722f;
-
-        // Extract the red, green, blue components of the color extraction color in
-        // float and int form
-        int tri = Color.red(backgroundColor);
-        int tgi = Color.green(backgroundColor);
-        int tbi = Color.blue(backgroundColor);
-
-        float tr = tri / 255f;
-        float tg = tgi / 255f;
-        float tb = tbi / 255f;
-
-        // Calculate the luminance of the color extraction color
-        float cLum = (tr * lr + tg * lg + tb * lb) * 255;
-
-        ColorMatrix m = new ColorMatrix(new float[] {
-                lr, lg, lb, 0, tri - cLum,
-                lr, lg, lb, 0, tgi - cLum,
-                lr, lg, lb, 0, tbi - cLum,
-                0, 0, 0, 1, 0,
-        });
-
-        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        LinearGradient linearGradient =  new LinearGradient(0, 0, size, 0,
-                new int[] {0, Color.argb(0.5f, 1, 1, 1), Color.BLACK},
-                new float[] {0.0f, 0.4f, 1.0f}, Shader.TileMode.CLAMP);
-        paint.setShader(linearGradient);
-        Bitmap fadeIn = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
-        Canvas fadeInCanvas = new Canvas(fadeIn);
-        drawable.clearColorFilter();
-        drawable.draw(fadeInCanvas);
-
-        if (isRtl) {
-            // Let's flip the gradient
-            fadeInCanvas.translate(size, 0);
-            fadeInCanvas.scale(-1, 1);
-        }
-        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
-        fadeInCanvas.drawPaint(paint);
-
-        Paint coloredPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        coloredPaint.setColorFilter(new ColorMatrixColorFilter(m));
-        coloredPaint.setAlpha((int) (0.5f * 255));
-        canvas.drawBitmap(fadeIn, 0, 0, coloredPaint);
-
-        linearGradient =  new LinearGradient(0, 0, size, 0,
-                new int[] {0, Color.argb(0.5f, 1, 1, 1), Color.BLACK},
-                new float[] {0.0f, 0.6f, 1.0f}, Shader.TileMode.CLAMP);
-        paint.setShader(linearGradient);
-        fadeInCanvas.drawPaint(paint);
-        canvas.drawBitmap(fadeIn, 0, 0, null);
-
-        return newBitmap;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
index 2586e94..732c115 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
@@ -16,237 +16,30 @@
 
 package com.android.systemui.statusbar.notification;
 
-import android.app.Notification;
-import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.util.LayoutDirection;
 
-import androidx.annotation.VisibleForTesting;
 import androidx.palette.graphics.Palette;
 
-import com.android.internal.util.ContrastColorUtil;
-import com.android.settingslib.Utils;
-
 import java.util.List;
 
 /**
- * A class the processes media notifications and extracts the right text and background colors.
+ * A gutted class that now contains only a color extraction utility used by the
+ * MediaArtworkProcessor, which has otherwise supplanted this.
+ *
+ * TODO(b/182926117): move this into MediaArtworkProcessor.kt
  */
 public class MediaNotificationProcessor {
 
     /**
-     * The fraction below which we select the vibrant instead of the light/dark vibrant color
-     */
-    private static final float POPULATION_FRACTION_FOR_MORE_VIBRANT = 1.0f;
-
-    /**
-     * Minimum saturation that a muted color must have if there exists if deciding between two
-     * colors
-     */
-    private static final float MIN_SATURATION_WHEN_DECIDING = 0.19f;
-
-    /**
-     * Minimum fraction that any color must have to be picked up as a text color
-     */
-    private static final double MINIMUM_IMAGE_FRACTION = 0.002;
-
-    /**
-     * The population fraction to select the dominant color as the text color over a the colored
-     * ones.
-     */
-    private static final float POPULATION_FRACTION_FOR_DOMINANT = 0.01f;
-
-    /**
      * The population fraction to select a white or black color as the background over a color.
      */
     private static final float POPULATION_FRACTION_FOR_WHITE_OR_BLACK = 2.5f;
     private static final float BLACK_MAX_LIGHTNESS = 0.08f;
     private static final float WHITE_MIN_LIGHTNESS = 0.90f;
     private static final int RESIZE_BITMAP_AREA = 150 * 150;
-    private final ImageGradientColorizer mColorizer;
-    private final Context mContext;
-    private final Palette.Filter mBlackWhiteFilter = (rgb, hsl) -> !isWhiteOrBlack(hsl);
 
-    /**
-     * The context of the notification. This is the app context of the package posting the
-     * notification.
-     */
-    private final Context mPackageContext;
-
-    public MediaNotificationProcessor(Context context, Context packageContext) {
-        this(context, packageContext, new ImageGradientColorizer());
-    }
-
-    @VisibleForTesting
-    MediaNotificationProcessor(Context context, Context packageContext,
-            ImageGradientColorizer colorizer) {
-        mContext = context;
-        mPackageContext = packageContext;
-        mColorizer = colorizer;
-    }
-
-    /**
-     * Processes a builder of a media notification and calculates the appropriate colors that should
-     * be used.
-     *
-     * @param notification the notification that is being processed
-     * @param builder the recovered builder for the notification. this will be modified
-     */
-    public void processNotification(Notification notification, Notification.Builder builder) {
-        Icon largeIcon = notification.getLargeIcon();
-        Bitmap bitmap = null;
-        Drawable drawable = null;
-        if (largeIcon != null) {
-            // We're transforming the builder, let's make sure all baked in RemoteViews are
-            // rebuilt!
-            builder.setRebuildStyledRemoteViews(true);
-            drawable = largeIcon.loadDrawable(mPackageContext);
-            int backgroundColor = 0;
-            if (notification.isColorizedMedia()) {
-                int width = drawable.getIntrinsicWidth();
-                int height = drawable.getIntrinsicHeight();
-                int area = width * height;
-                if (area > RESIZE_BITMAP_AREA) {
-                    double factor = Math.sqrt((float) RESIZE_BITMAP_AREA / area);
-                    width = (int) (factor * width);
-                    height = (int) (factor * height);
-                }
-                bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-                Canvas canvas = new Canvas(bitmap);
-                drawable.setBounds(0, 0, width, height);
-                drawable.draw(canvas);
-
-                Palette.Builder paletteBuilder = generateArtworkPaletteBuilder(bitmap);
-                Palette palette = paletteBuilder.generate();
-                Palette.Swatch backgroundSwatch = findBackgroundSwatch(palette);
-                backgroundColor = backgroundSwatch.getRgb();
-                // we want most of the full region again, slightly shifted to the right
-                float textColorStartWidthFraction = 0.4f;
-                paletteBuilder.setRegion((int) (bitmap.getWidth() * textColorStartWidthFraction), 0,
-                        bitmap.getWidth(),
-                        bitmap.getHeight());
-                // We're not filtering on white or black
-                if (!isWhiteOrBlack(backgroundSwatch.getHsl())) {
-                    final float backgroundHue = backgroundSwatch.getHsl()[0];
-                    paletteBuilder.addFilter((rgb, hsl) -> {
-                        // at least 10 degrees hue difference
-                        float diff = Math.abs(hsl[0] - backgroundHue);
-                        return diff > 10 && diff < 350;
-                    });
-                }
-                paletteBuilder.addFilter(mBlackWhiteFilter);
-                palette = paletteBuilder.generate();
-                int foregroundColor = selectForegroundColor(backgroundColor, palette);
-                builder.setColorPalette(backgroundColor, foregroundColor);
-            } else {
-                backgroundColor = Utils.getColorAttr(mContext, android.R.attr.colorBackground)
-                        .getDefaultColor();
-            }
-            Bitmap colorized = mColorizer.colorize(drawable, backgroundColor,
-                    mContext.getResources().getConfiguration().getLayoutDirection() ==
-                            LayoutDirection.RTL);
-            builder.setLargeIcon(Icon.createWithBitmap(colorized));
-        }
-    }
-
-    /**
-     * Select a foreground color depending on whether the background color is dark or light
-     * @param backgroundColor Background color to coordinate with
-     * @param palette Artwork palette, should be obtained from {@link generateArtworkPaletteBuilder}
-     * @return foreground color
-     */
-    public static int selectForegroundColor(int backgroundColor, Palette palette) {
-        if (ContrastColorUtil.isColorLight(backgroundColor)) {
-            return selectForegroundColorForSwatches(palette.getDarkVibrantSwatch(),
-                    palette.getVibrantSwatch(),
-                    palette.getDarkMutedSwatch(),
-                    palette.getMutedSwatch(),
-                    palette.getDominantSwatch(),
-                    Color.BLACK);
-        } else {
-            return selectForegroundColorForSwatches(palette.getLightVibrantSwatch(),
-                    palette.getVibrantSwatch(),
-                    palette.getLightMutedSwatch(),
-                    palette.getMutedSwatch(),
-                    palette.getDominantSwatch(),
-                    Color.WHITE);
-        }
-    }
-
-    private static int selectForegroundColorForSwatches(Palette.Swatch moreVibrant,
-            Palette.Swatch vibrant, Palette.Swatch moreMutedSwatch, Palette.Swatch mutedSwatch,
-            Palette.Swatch dominantSwatch, int fallbackColor) {
-        Palette.Swatch coloredCandidate = selectVibrantCandidate(moreVibrant, vibrant);
-        if (coloredCandidate == null) {
-            coloredCandidate = selectMutedCandidate(mutedSwatch, moreMutedSwatch);
-        }
-        if (coloredCandidate != null) {
-            if (dominantSwatch == coloredCandidate) {
-                return coloredCandidate.getRgb();
-            } else if ((float) coloredCandidate.getPopulation() / dominantSwatch.getPopulation()
-                    < POPULATION_FRACTION_FOR_DOMINANT
-                    && dominantSwatch.getHsl()[1] > MIN_SATURATION_WHEN_DECIDING) {
-                return dominantSwatch.getRgb();
-            } else {
-                return coloredCandidate.getRgb();
-            }
-        } else if (hasEnoughPopulation(dominantSwatch)) {
-            return dominantSwatch.getRgb();
-        } else {
-            return fallbackColor;
-        }
-    }
-
-    private static Palette.Swatch selectMutedCandidate(Palette.Swatch first,
-            Palette.Swatch second) {
-        boolean firstValid = hasEnoughPopulation(first);
-        boolean secondValid = hasEnoughPopulation(second);
-        if (firstValid && secondValid) {
-            float firstSaturation = first.getHsl()[1];
-            float secondSaturation = second.getHsl()[1];
-            float populationFraction = first.getPopulation() / (float) second.getPopulation();
-            if (firstSaturation * populationFraction > secondSaturation) {
-                return first;
-            } else {
-                return second;
-            }
-        } else if (firstValid) {
-            return first;
-        } else if (secondValid) {
-            return second;
-        }
-        return null;
-    }
-
-    private static Palette.Swatch selectVibrantCandidate(Palette.Swatch first,
-            Palette.Swatch second) {
-        boolean firstValid = hasEnoughPopulation(first);
-        boolean secondValid = hasEnoughPopulation(second);
-        if (firstValid && secondValid) {
-            int firstPopulation = first.getPopulation();
-            int secondPopulation = second.getPopulation();
-            if (firstPopulation / (float) secondPopulation
-                    < POPULATION_FRACTION_FOR_MORE_VIBRANT) {
-                return second;
-            } else {
-                return first;
-            }
-        } else if (firstValid) {
-            return first;
-        } else if (secondValid) {
-            return second;
-        }
-        return null;
-    }
-
-    private static boolean hasEnoughPopulation(Palette.Swatch swatch) {
-        // We want a fraction that is at least 1% of the image
-        return swatch != null
-                && (swatch.getPopulation() / (float) RESIZE_BITMAP_AREA > MINIMUM_IMAGE_FRACTION);
+    private MediaNotificationProcessor() {
     }
 
     /**
@@ -279,7 +72,7 @@
         List<Palette.Swatch> swatches = palette.getSwatches();
         float highestNonWhitePopulation = -1;
         Palette.Swatch second = null;
-        for (Palette.Swatch swatch: swatches) {
+        for (Palette.Swatch swatch : swatches) {
             if (swatch != dominantSwatch
                     && swatch.getPopulation() > highestNonWhitePopulation
                     && !isWhiteOrBlack(swatch.getHsl())) {
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 6cf5c30..815cfb3 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
@@ -668,7 +668,6 @@
                 && expandedView.findViewById(com.android.internal.R.id.media_actions) != null;
         boolean isMessagingLayout = contractedView instanceof MessagingLayout;
         boolean isCallLayout = contractedView instanceof CallLayout;
-        boolean showCompactMediaSeekbar = mMediaManager.getShowCompactMediaSeekbar();
 
         if (customView && beforeS && !mIsSummaryWithChildren) {
             if (beforeN) {
@@ -678,12 +677,6 @@
             } else {
                 smallHeight = mMaxSmallHeightBeforeS;
             }
-        } else if (isMediaLayout) {
-            // TODO(b/172652345): MediaStyle notifications currently look broken when we enforce
-            //  the standard notification height, so we have to afford them more vertical space to
-            //  make sure we don't crop them terribly.  We actually need to revisit this and give
-            //  them a headerless design, then remove this hack.
-            smallHeight = showCompactMediaSeekbar ? mMaxSmallHeightMedia : mMaxSmallHeightBeforeS;
         } else if (isMessagingLayout) {
             // TODO(b/173204301): MessagingStyle notifications currently look broken when we enforce
             //  the standard notification height, so we have to afford them more vertical space to
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 58b87cd..73c4b05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -40,13 +40,11 @@
 import com.android.internal.widget.ImageMessageConsumer;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.media.MediaDataManagerKt;
 import com.android.systemui.media.MediaFeatureFlag;
 import com.android.systemui.statusbar.InflationTask;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
 import com.android.systemui.statusbar.notification.InflationException;
-import com.android.systemui.statusbar.notification.MediaNotificationProcessor;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -799,13 +797,6 @@
                     // For all of our templates, we want it to be RTL
                     packageContext = new RtlEnabledContext(packageContext);
                 }
-                Notification notification = sbn.getNotification();
-                if (notification.isMediaNotification() && !(mIsMediaInQS
-                        && MediaDataManagerKt.isMediaNotification(sbn))) {
-                    MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext,
-                            packageContext);
-                    processor.processNotification(notification, recoveredBuilder);
-                }
                 if (mEntry.getRanking().isConversation()) {
                     mConversationProcessor.processNotification(mEntry, recoveredBuilder);
                 }
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 2535e5d..c75cd78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -16,341 +16,26 @@
 
 package com.android.systemui.statusbar.notification.row.wrapper;
 
-import static com.android.systemui.Dependency.MAIN_HANDLER;
-
-import android.annotation.Nullable;
-import android.app.Notification;
 import android.content.Context;
-import android.content.res.ColorStateList;
-import android.media.MediaMetadata;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
-import android.metrics.LogMaker;
-import android.os.Handler;
-import android.text.format.DateUtils;
-import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewStub;
-import android.widget.SeekBar;
-import android.widget.TextView;
 
-import com.android.internal.R;
-import com.android.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;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
-import java.util.Timer;
-import java.util.TimerTask;
-
 /**
  * Wraps a notification containing a media template
  */
 public class NotificationMediaTemplateViewWrapper extends NotificationTemplateViewWrapper {
 
-    private static final long PROGRESS_UPDATE_INTERVAL = 1000; // 1s
-    private static final String COMPACT_MEDIA_TAG = "media";
-    private final Handler mHandler = Dependency.get(MAIN_HANDLER);
-    private Timer mSeekBarTimer;
     private View mActions;
-    private SeekBar mSeekBar;
-    private TextView mSeekBarElapsedTime;
-    private TextView mSeekBarTotalTime;
-    private long mDuration = 0;
-    private MediaController mMediaController;
-    private MediaMetadata mMediaMetadata;
-    private NotificationMediaManager mMediaManager;
-    private View mSeekBarView;
-    private Context mContext;
-    private MetricsLogger mMetricsLogger;
-    private boolean mIsViewVisible;
-
-    @VisibleForTesting
-    protected SeekBar.OnSeekBarChangeListener mSeekListener =
-            new SeekBar.OnSeekBarChangeListener() {
-        @Override
-        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-        }
-
-        @Override
-        public void onStartTrackingTouch(SeekBar seekBar) {
-        }
-
-        @Override
-        public void onStopTrackingTouch(SeekBar seekBar) {
-            if (mMediaController != null) {
-                mMediaController.getTransportControls().seekTo(mSeekBar.getProgress());
-                mMetricsLogger.write(newLog(MetricsEvent.TYPE_UPDATE));
-            }
-        }
-    };
-
-    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
-        public void onPlaybackStateChanged(@Nullable PlaybackState state) {
-            if (state == null) {
-                return;
-            }
-
-            if (state.getState() != PlaybackState.STATE_PLAYING) {
-                // Update the UI once, in case playback info changed while we were paused
-                updatePlaybackUi(state);
-                clearTimer();
-            } else if (mSeekBarTimer == null && mSeekBarView != null
-                    && mSeekBarView.getVisibility() != View.GONE) {
-                startTimer();
-            }
-        }
-
-        @Override
-        public void onMetadataChanged(@Nullable MediaMetadata metadata) {
-            if (mMediaMetadata == null || !mMediaMetadata.equals(metadata)) {
-                mMediaMetadata = metadata;
-                updateDuration();
-            }
-        }
-    };
 
     protected NotificationMediaTemplateViewWrapper(Context ctx, View view,
             ExpandableNotificationRow row) {
         super(ctx, view, row);
-        mContext = ctx;
-        mMediaManager = Dependency.get(NotificationMediaManager.class);
-        mMetricsLogger = Dependency.get(MetricsLogger.class);
     }
 
     private void resolveViews() {
         mActions = mView.findViewById(com.android.internal.R.id.media_actions);
-        mIsViewVisible = mView.isShown();
-
-        final MediaSession.Token token = mRow.getEntry().getSbn().getNotification().extras
-                .getParcelable(Notification.EXTRA_MEDIA_SESSION);
-
-        boolean showCompactSeekbar = mMediaManager.getShowCompactMediaSeekbar();
-        if (token == null || (COMPACT_MEDIA_TAG.equals(mView.getTag()) && !showCompactSeekbar)) {
-            if (mSeekBarView != null) {
-                mSeekBarView.setVisibility(View.GONE);
-            }
-            return;
-        }
-
-        // Check for existing media controller and clean up / create as necessary
-        boolean shouldUpdateListeners = false;
-        if (mMediaController == null || !mMediaController.getSessionToken().equals(token)) {
-            if (mMediaController != null) {
-                mMediaController.unregisterCallback(mMediaCallback);
-            }
-            mMediaController = new MediaController(mContext, token);
-            shouldUpdateListeners = true;
-        }
-
-        mMediaMetadata = mMediaController.getMetadata();
-        if (mMediaMetadata != null) {
-            long duration = mMediaMetadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
-            if (duration <= 0) {
-                // Don't include the seekbar if this is a livestream
-                if (mSeekBarView != null && mSeekBarView.getVisibility() != View.GONE) {
-                    mSeekBarView.setVisibility(View.GONE);
-                    mMetricsLogger.write(newLog(MetricsEvent.TYPE_CLOSE));
-                    clearTimer();
-                } else if (mSeekBarView == null && shouldUpdateListeners) {
-                    // Only log if the controller changed, otherwise we would log multiple times for
-                    // the same notification when user pauses/resumes
-                    mMetricsLogger.write(newLog(MetricsEvent.TYPE_CLOSE));
-                }
-                return;
-            } else if (mSeekBarView != null && mSeekBarView.getVisibility() == View.GONE) {
-                // Otherwise, make sure the seekbar is visible
-                mSeekBarView.setVisibility(View.VISIBLE);
-                mMetricsLogger.write(newLog(MetricsEvent.TYPE_OPEN));
-                updateDuration();
-                startTimer();
-            }
-        }
-
-        // Inflate the seekbar template
-        ViewStub stub = mView.findViewById(R.id.notification_media_seekbar_container);
-        if (stub instanceof ViewStub) {
-            LayoutInflater layoutInflater = LayoutInflater.from(stub.getContext());
-            stub.setLayoutInflater(layoutInflater);
-            stub.setLayoutResource(R.layout.notification_material_media_seekbar);
-            mSeekBarView = stub.inflate();
-            mMetricsLogger.write(newLog(MetricsEvent.TYPE_OPEN));
-
-            mSeekBar = mSeekBarView.findViewById(R.id.notification_media_progress_bar);
-            mSeekBar.setOnSeekBarChangeListener(mSeekListener);
-
-            mSeekBarElapsedTime = mSeekBarView.findViewById(R.id.notification_media_elapsed_time);
-            mSeekBarTotalTime = mSeekBarView.findViewById(R.id.notification_media_total_time);
-
-            shouldUpdateListeners = true;
-        }
-
-        if (shouldUpdateListeners) {
-            if (mView instanceof MediaNotificationView) {
-                MediaNotificationView mediaView = (MediaNotificationView) mView;
-                mediaView.addVisibilityListener(mVisibilityListener);
-                mView.addOnAttachStateChangeListener(mAttachStateListener);
-            }
-
-            if (mSeekBarTimer == null) {
-                if (mMediaController != null && canSeekMedia(mMediaController.getPlaybackState())) {
-                    // Log initial state, since it will not be updated
-                    mMetricsLogger.write(newLog(MetricsEvent.TYPE_DETAIL, 1));
-                } else {
-                    setScrubberVisible(false);
-                }
-                updateDuration();
-                startTimer();
-                mMediaController.registerCallback(mMediaCallback);
-            }
-        }
-        updateSeekBarTint(mSeekBarView);
-    }
-
-    private void startTimer() {
-        clearTimer();
-        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) {
-            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;
-        }
-
-        long actions = state.getActions();
-        return ((actions & PlaybackState.ACTION_SEEK_TO) != 0);
-    }
-
-    private void setScrubberVisible(boolean isVisible) {
-        if (mSeekBar == null || mSeekBar.isEnabled() == isVisible) {
-            return;
-        }
-
-        mSeekBar.getThumb().setAlpha(isVisible ? 255 : 0);
-        mSeekBar.setEnabled(isVisible);
-        mMetricsLogger.write(newLog(MetricsEvent.TYPE_DETAIL, isVisible ? 1 : 0));
-    }
-
-    private void updateDuration() {
-        if (mMediaMetadata != null && mSeekBar != null) {
-            long duration = mMediaMetadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
-            if (mDuration != duration) {
-                mDuration = duration;
-                mSeekBar.setMax((int) mDuration);
-                mSeekBarTotalTime.setText(millisecondsToTimeString(duration));
-            }
-        }
-    }
-
-    protected final Runnable mOnUpdateTimerTick = new Runnable() {
-        @Override
-        public void run() {
-            if (mMediaController != null && mSeekBar != null) {
-                PlaybackState playbackState = mMediaController.getPlaybackState();
-                if (playbackState != null) {
-                    updatePlaybackUi(playbackState);
-                } else {
-                    clearTimer();
-                }
-            } else {
-                clearTimer();
-            }
-        }
-    };
-
-    private void updatePlaybackUi(PlaybackState state) {
-        if (mSeekBar == null || mSeekBarElapsedTime == null) {
-            return;
-        }
-
-        long position = state.getPosition();
-        mSeekBar.setProgress((int) position);
-
-        mSeekBarElapsedTime.setText(millisecondsToTimeString(position));
-
-        // Update scrubber in case available actions have changed
-        setScrubberVisible(canSeekMedia(state));
-    }
-
-    private String millisecondsToTimeString(long milliseconds) {
-        long seconds = milliseconds / 1000;
-        String text = DateUtils.formatElapsedTime(seconds);
-        return text;
     }
 
     @Override
@@ -361,28 +46,6 @@
         super.onContentUpdated(row);
     }
 
-    private void updateSeekBarTint(View seekBarContainer) {
-        if (seekBarContainer == null) {
-            return;
-        }
-
-        if (this.getNotificationHeader() == null) {
-            return;
-        }
-
-        int tintColor = getOriginalIconColor();
-        mSeekBarElapsedTime.setTextColor(tintColor);
-        mSeekBarTotalTime.setTextColor(tintColor);
-        mSeekBarTotalTime.setShadowLayer(1.5f, 1.5f, 1.5f, mBackgroundColor);
-
-        ColorStateList tintList = ColorStateList.valueOf(tintColor);
-        mSeekBar.setThumbTintList(tintList);
-        tintList = tintList.withAlpha(192); // 75%
-        mSeekBar.setProgressTintList(tintList);
-        tintList = tintList.withAlpha(128); // 50%
-        mSeekBar.setProgressBackgroundTintList(tintList);
-    }
-
     @Override
     protected void updateTransformedTypes() {
         // This also clears the existing types
@@ -394,36 +57,7 @@
     }
 
     @Override
-    public boolean isDimmable() {
-        return getCustomBackgroundColor() == 0;
-    }
-
-    @Override
     public boolean shouldClipToRounding(boolean topRounded, boolean bottomRounded) {
         return true;
     }
-
-    /**
-     * Returns an initialized LogMaker for logging changes to the seekbar
-     * @return new LogMaker
-     */
-    private LogMaker newLog(int event) {
-        String packageName = mRow.getEntry().getSbn().getPackageName();
-
-        return new LogMaker(MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR)
-                .setType(event)
-                .setPackageName(packageName);
-    }
-
-    /**
-     * Returns an initialized LogMaker for logging changes with subtypes
-     * @return new LogMaker
-     */
-    private LogMaker newLog(int event, int subtype) {
-        String packageName = mRow.getEntry().getSbn().getPackageName();
-        return new LogMaker(MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR)
-                .setType(event)
-                .setSubtype(subtype)
-                .setPackageName(packageName);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 39f5847c..562d0ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -42,6 +42,9 @@
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Contains the collapsed status bar and handles hiding/showing based on disable flags
  * and keyguard state. Also manages lifecycle to make sure the views it contains are being
@@ -70,6 +73,8 @@
     private View mOperatorNameFrame;
     private CommandQueue mCommandQueue;
 
+    private List<String> mBlockedIcons = new ArrayList<>();
+
     private SignalCallback mSignalCallback = new SignalCallback() {
         @Override
         public void setIsAirplaneMode(NetworkController.IconState icon) {
@@ -101,9 +106,12 @@
             mStatusBar.restoreHierarchyState(
                     savedInstanceState.getSparseParcelableArray(EXTRA_PANEL_STATE));
         }
-        mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons),
-                Dependency.get(CommandQueue.class));
+        mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));
         mDarkIconManager.setShouldLog(true);
+        mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_volume));
+        mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_alarm_clock));
+        mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_call_strength));
+        mDarkIconManager.setBlockList(mBlockedIcons);
         Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
         mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
         mClockView = mStatusBar.findViewById(R.id.clock);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 33798d6..2d760e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -47,7 +47,6 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
@@ -59,6 +58,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * The header group on Keyguard.
@@ -89,6 +90,7 @@
     private int mSystemIconsBaseMargin;
     private View mSystemIconsContainer;
     private TintedIconManager mIconManager;
+    private List<String> mBlockedIcons = new ArrayList<>();
 
     private View mCutoutSpace;
     private ViewGroup mStatusIconArea;
@@ -121,6 +123,7 @@
         mStatusIconContainer = findViewById(R.id.statusIcons);
 
         loadDimens();
+        loadBlockList();
         mBatteryController = Dependency.get(BatteryController.class);
     }
 
@@ -181,6 +184,14 @@
                 R.dimen.rounded_corner_content_padding);
     }
 
+    // Set hidden status bar items
+    private void loadBlockList() {
+        Resources r = getResources();
+        mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_volume));
+        mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_alarm_clock));
+        mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_call_strength));
+    }
+
     private void updateVisibilities() {
         if (mMultiUserAvatar.getParent() != mStatusIconArea
                 && !mKeyguardUserSwitcherEnabled) {
@@ -336,8 +347,8 @@
         userInfoController.addCallback(this);
         userInfoController.reloadUserInfo();
         Dependency.get(ConfigurationController.class).addCallback(this);
-        mIconManager = new TintedIconManager(findViewById(R.id.statusIcons),
-                Dependency.get(CommandQueue.class));
+        mIconManager = new TintedIconManager(findViewById(R.id.statusIcons));
+        mIconManager.setBlockList(mBlockedIcons);
         Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager);
         onThemeChanged();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 8fe9a48..93b83d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -18,6 +18,7 @@
 import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE;
 import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Bundle;
 import android.text.TextUtils;
@@ -37,7 +38,6 @@
 import com.android.systemui.demomode.DemoModeCommandReceiver;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarMobileView;
 import com.android.systemui.statusbar.StatusBarWifiView;
@@ -46,6 +46,7 @@
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public interface StatusBarIconController {
@@ -54,15 +55,22 @@
      * When an icon is added with TAG_PRIMARY, it will be treated as the primary icon
      * in that slot and not added as a sub slot.
      */
-    public static final int TAG_PRIMARY = 0;
+    int TAG_PRIMARY = 0;
 
-    public void addIconGroup(IconManager iconManager);
-    public void removeIconGroup(IconManager iconManager);
-    public void setExternalIcon(String slot);
-    public void setIcon(String slot, int resourceId, CharSequence contentDescription);
-    public void setIcon(String slot, StatusBarIcon icon);
-    public void setSignalIcon(String slot, WifiIconState state);
-    public void setMobileIcons(String slot, List<MobileIconState> states);
+    /** */
+    void addIconGroup(IconManager iconManager);
+    /** */
+    void removeIconGroup(IconManager iconManager);
+    /** */
+    void setExternalIcon(String slot);
+    /** */
+    void setIcon(String slot, int resourceId, CharSequence contentDescription);
+    /** */
+    void setIcon(String slot, StatusBarIcon icon);
+    /** */
+    void setSignalIcon(String slot, WifiIconState state);
+    /** */
+    void setMobileIcons(String slot, List<MobileIconState> states);
     /**
      * Display the no calling & SMS icons.
      */
@@ -85,8 +93,9 @@
      * If you don't know what to pass for `tag`, either remove all icons for slot, or use
      * TAG_PRIMARY to refer to the first icon at a given slot.
      */
-    public void removeIcon(String slot, int tag);
-    public void removeAllIconsForSlot(String slot);
+    void removeIcon(String slot, int tag);
+    /** */
+    void removeAllIconsForSlot(String slot);
 
     // TODO: See if we can rename this tunable name.
     String ICON_HIDE_LIST = "icon_blacklist";
@@ -108,12 +117,12 @@
     /**
      * Version of ViewGroup that observes state from the DarkIconDispatcher.
      */
-    public static class DarkIconManager extends IconManager {
+    class DarkIconManager extends IconManager {
         private final DarkIconDispatcher mDarkIconDispatcher;
         private int mIconHPadding;
 
-        public DarkIconManager(LinearLayout linearLayout, CommandQueue commandQueue) {
-            super(linearLayout, commandQueue);
+        public DarkIconManager(LinearLayout linearLayout) {
+            super(linearLayout);
             mIconHPadding = mContext.getResources().getDimensionPixelSize(
                     R.dimen.status_bar_icon_padding);
             mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
@@ -169,11 +178,12 @@
         }
     }
 
-    public static class TintedIconManager extends IconManager {
+    /** */
+    class TintedIconManager extends IconManager {
         private int mColor;
 
-        public TintedIconManager(ViewGroup group, CommandQueue commandQueue) {
-            super(group, commandQueue);
+        public TintedIconManager(ViewGroup group) {
+            super(group);
         }
 
         @Override
@@ -219,7 +229,9 @@
         private boolean mIsInDemoMode;
         protected DemoStatusIcons mDemoStatusIcons;
 
-        public IconManager(ViewGroup group, CommandQueue commandQueue) {
+        protected ArrayList<String> mBlockList = new ArrayList<>();
+
+        public IconManager(ViewGroup group) {
             mGroup = group;
             mContext = group.getContext();
             mIconSize = mContext.getResources().getDimensionPixelSize(
@@ -234,6 +246,15 @@
             mDemoable = demoable;
         }
 
+        public void setBlockList(@Nullable List<String> blockList) {
+            mBlockList.clear();
+            if (blockList == null || blockList.isEmpty()) {
+                return;
+            }
+
+            mBlockList.addAll(blockList);
+        }
+
         public void setShouldLog(boolean should) {
             mShouldLog = should;
         }
@@ -249,6 +270,11 @@
 
         protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
                 StatusBarIconHolder holder) {
+            // This is a little hacky, and probably regrettable, but just set `blocked` on any icon
+            // that is in our blocked list, then we'll never see it
+            if (mBlockList.contains(slot)) {
+                blocked = true;
+            }
             switch (holder.getType()) {
                 case TYPE_ICON:
                     return addIcon(index, slot, blocked, holder.getIcon());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 6404aea..75900a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -66,6 +66,7 @@
 
     private Context mContext;
 
+    /** */
     @Inject
     public StatusBarIconControllerImpl(
             Context context,
@@ -84,6 +85,7 @@
         demoModeController.addCallback(this);
     }
 
+    /** */
     @Override
     public void addIconGroup(IconManager group) {
         mIconGroups.add(group);
@@ -101,12 +103,14 @@
         }
     }
 
+    /** */
     @Override
     public void removeIconGroup(IconManager group) {
         group.destroy();
         mIconGroups.remove(group);
     }
 
+    /** */
     @Override
     public void onTuningChanged(String key, String newValue) {
         if (!ICON_HIDE_LIST.equals(key)) {
@@ -149,6 +153,7 @@
         mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, hidden, holder));
     }
 
+    /** */
     @Override
     public void setIcon(String slot, int resourceId, CharSequence contentDescription) {
         int index = getSlotIndex(slot);
@@ -290,8 +295,9 @@
      * For backwards compatibility, in the event that someone gives us a slot and a status bar icon
      */
     private void setIcon(int index, StatusBarIcon icon) {
+        String slot = getSlotName(index);
         if (icon == null) {
-            removeAllIconsForSlot(getSlotName(index));
+            removeAllIconsForSlot(slot);
             return;
         }
 
@@ -299,6 +305,7 @@
         setIcon(index, holder);
     }
 
+    /** */
     @Override
     public void setIcon(int index, @NonNull StatusBarIconHolder holder) {
         boolean isNew = getIcon(index, holder.getTag()) == null;
@@ -328,6 +335,7 @@
         handleSet(index, holder);
     }
 
+    /** */
     @Override
     public void setIconAccessibilityLiveRegion(String slotName, int accessibilityLiveRegion) {
         Slot slot = getSlot(slotName);
@@ -344,15 +352,18 @@
         }
     }
 
+    /** */
     public void removeIcon(String slot) {
         removeAllIconsForSlot(slot);
     }
 
+    /** */
     @Override
     public void removeIcon(String slot, int tag) {
         removeIcon(getSlotIndex(slot), tag);
     }
 
+    /** */
     @Override
     public void removeAllIconsForSlot(String slotName) {
         Slot slot = getSlot(slotName);
@@ -369,6 +380,7 @@
         }
     }
 
+    /** */
     @Override
     public void removeIcon(int index, int tag) {
         if (getIcon(index, tag) == null) {
@@ -384,6 +396,7 @@
         mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
     }
 
+    /** */
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println(TAG + " state:");
@@ -402,6 +415,7 @@
         super.dump(pw);
     }
 
+    /** */
     @Override
     public void onDemoModeStarted() {
         for (IconManager manager : mIconGroups) {
@@ -411,6 +425,7 @@
         }
     }
 
+    /** */
     @Override
     public void onDemoModeFinished() {
         for (IconManager manager : mIconGroups) {
@@ -420,6 +435,7 @@
         }
     }
 
+    /** */
     @Override
     public void dispatchDemoCommand(String command, Bundle args) {
         for (IconManager manager : mIconGroups) {
@@ -429,6 +445,7 @@
         }
     }
 
+    /** */
     @Override
     public List<String> demoCommands() {
         List<String> s = new ArrayList<>();
@@ -436,6 +453,7 @@
         return s;
     }
 
+    /** */
     @Override
     public void onDensityOrFontScaleChanged() {
         loadDimens();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
index 19db02a..af342dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
@@ -39,7 +39,10 @@
     private MobileIconState mMobileState;
     private int mType = TYPE_ICON;
     private int mTag = 0;
-    private boolean mVisible = true;
+
+    private StatusBarIconHolder() {
+
+    }
 
     public static StatusBarIconHolder fromIcon(StatusBarIcon icon) {
         StatusBarIconHolder wrapper = new StatusBarIconHolder();
@@ -48,7 +51,10 @@
         return wrapper;
     }
 
-    public static StatusBarIconHolder fromResId(Context context, int resId,
+    /** */
+    public static StatusBarIconHolder fromResId(
+            Context context,
+            int resId,
             CharSequence contentDescription) {
         StatusBarIconHolder holder = new StatusBarIconHolder();
         holder.mIcon = new StatusBarIcon(UserHandle.SYSTEM, context.getPackageName(),
@@ -56,6 +62,7 @@
         return holder;
     }
 
+    /** */
     public static StatusBarIconHolder fromWifiIconState(WifiIconState state) {
         StatusBarIconHolder holder = new StatusBarIconHolder();
         holder.mWifiState = state;
@@ -63,6 +70,7 @@
         return holder;
     }
 
+    /** */
     public static StatusBarIconHolder fromMobileIconState(MobileIconState state) {
         StatusBarIconHolder holder = new StatusBarIconHolder();
         holder.mMobileState = state;
@@ -75,7 +83,8 @@
      * Creates a new StatusBarIconHolder from a CallIndicatorIconState.
      */
     public static StatusBarIconHolder fromCallIndicatorState(
-            Context context, CallIndicatorIconState state) {
+            Context context,
+            CallIndicatorIconState state) {
         StatusBarIconHolder holder = new StatusBarIconHolder();
         int resId = state.isNoCalling ? state.noCallingResId : state.callStrengthResId;
         String contentDescription = state.isNoCalling
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
index 4948c2b..3595095 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -33,7 +33,6 @@
 import com.android.systemui.qs.carrier.QSCarrierGroup
 import com.android.systemui.qs.carrier.QSCarrierGroupController
 import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.phone.StatusBarIconController
 import com.android.systemui.statusbar.phone.StatusIconContainer
 import com.android.systemui.statusbar.policy.Clock
@@ -78,8 +77,6 @@
     @Mock
     private lateinit var statusBarIconController: StatusBarIconController
     @Mock
-    private lateinit var commandQueue: CommandQueue
-    @Mock
     private lateinit var demoModeController: DemoModeController
     @Mock
     private lateinit var userTracker: UserTracker
@@ -130,7 +127,6 @@
                 uiEventLogger,
                 qsTileHost,
                 statusBarIconController,
-                commandQueue,
                 demoModeController,
                 userTracker,
                 quickQSPanelController,
@@ -233,4 +229,4 @@
         `when`(privacyItemController.micCameraAvailable).thenReturn(micCamera)
         `when`(privacyItemController.locationAvailable).thenReturn(location)
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java
index e6287e7..aeb5b03 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java
@@ -18,31 +18,18 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.junit.Assert.assertNotSame;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-
 import android.annotation.Nullable;
-import android.app.Notification;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.drawable.Drawable;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.widget.RemoteViews;
 
 import androidx.palette.graphics.Palette;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.tests.R;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -58,17 +45,8 @@
      */
     private static final int COLOR_TOLERANCE = 8;
 
-    private MediaNotificationProcessor mProcessor;
-    private Bitmap mBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
-    private ImageGradientColorizer mColorizer;
     @Nullable private Bitmap mArtwork;
 
-    @Before
-    public void setUp() {
-        mColorizer = spy(new TestableColorizer(mBitmap));
-        mProcessor = new MediaNotificationProcessor(getContext(), getContext(), mColorizer);
-    }
-
     @After
     public void tearDown() {
         if (mArtwork != null) {
@@ -78,53 +56,6 @@
     }
 
     @Test
-    public void testColorizedWithLargeIcon() {
-        Notification.Builder builder = new Notification.Builder(getContext()).setSmallIcon(
-                R.drawable.ic_person)
-                .setContentTitle("Title")
-                .setLargeIcon(mBitmap)
-                .setContentText("Text");
-        Notification notification = builder.build();
-        mProcessor.processNotification(notification, builder);
-        verify(mColorizer).colorize(any(), anyInt(), anyBoolean());
-    }
-
-    @Test
-    public void testNotColorizedWithoutLargeIcon() {
-        Notification.Builder builder = new Notification.Builder(getContext()).setSmallIcon(
-                R.drawable.ic_person)
-                .setContentTitle("Title")
-                .setContentText("Text");
-        Notification notification = builder.build();
-        mProcessor.processNotification(notification, builder);
-        verifyZeroInteractions(mColorizer);
-    }
-
-    @Test
-    public void testRemoteViewsReset() {
-        Notification.Builder builder = new Notification.Builder(getContext()).setSmallIcon(
-                R.drawable.ic_person)
-                .setContentTitle("Title")
-                .setStyle(new Notification.MediaStyle())
-                .setLargeIcon(mBitmap)
-                .setContentText("Text");
-        Notification notification = builder.build();
-        RemoteViews remoteViews = new RemoteViews(getContext().getPackageName(),
-                R.layout.custom_view_dark);
-        notification.contentView = remoteViews;
-        notification.bigContentView = remoteViews;
-        notification.headsUpContentView = remoteViews;
-        mProcessor.processNotification(notification, builder);
-        verify(mColorizer).colorize(any(), anyInt(), anyBoolean());
-        RemoteViews contentView = builder.createContentView();
-        assertNotSame(contentView, remoteViews);
-        contentView = builder.createBigContentView();
-        assertNotSame(contentView, remoteViews);
-        contentView = builder.createHeadsUpContentView();
-        assertNotSame(contentView, remoteViews);
-    }
-
-    @Test
     public void findBackgroundSwatch_white() {
         // Given artwork that is completely white.
         mArtwork = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Bitmap.Config.ARGB_8888);
@@ -153,17 +84,4 @@
         assertThat((float) Color.green(expected)).isWithin(COLOR_TOLERANCE).of(Color.green(actual));
         assertThat((float) Color.blue(expected)).isWithin(COLOR_TOLERANCE).of(Color.blue(actual));
     }
-
-    public static class TestableColorizer extends ImageGradientColorizer {
-        private final Bitmap mBitmap;
-
-        private TestableColorizer(Bitmap bitmap) {
-            mBitmap = bitmap;
-        }
-
-        @Override
-        public Bitmap colorize(Drawable drawable, int backgroundColor, boolean isRtl) {
-            return mBitmap;
-        }
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java
deleted file mode 100644
index fbe4d73..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.row.wrapper;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.app.Notification;
-import android.media.MediaMetadata;
-import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
-import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-import android.view.View;
-import android.widget.RemoteViews;
-import android.widget.SeekBar;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public class NotificationMediaTemplateViewWrapperTest extends SysuiTestCase {
-
-    private ExpandableNotificationRow mRow;
-    private Notification mNotif;
-    private View mView;
-    private NotificationMediaTemplateViewWrapper mWrapper;
-
-    @Mock
-    private MetricsLogger mMetricsLogger;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        allowTestableLooperAsMainThread();
-
-        mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
-
-        // These tests are for regular media style notifications, not controls in quick settings
-        Settings.System.putInt(mContext.getContentResolver(), "qs_media_player", 0);
-    }
-
-    private void makeTestNotification(long duration, boolean allowSeeking) throws Exception {
-        Notification.Builder builder = new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.ic_person)
-                .setContentTitle("Title")
-                .setContentText("Text");
-
-        MediaMetadata metadata = new MediaMetadata.Builder()
-                .putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
-                .build();
-        MediaSession session = new MediaSession(mContext, "TEST_CHANNEL");
-        session.setMetadata(metadata);
-
-        PlaybackState playbackState = new PlaybackState.Builder()
-                .setActions(allowSeeking ? PlaybackState.ACTION_SEEK_TO : 0)
-                .build();
-
-        session.setPlaybackState(playbackState);
-
-        builder.setStyle(new Notification.MediaStyle()
-                .setMediaSession(session.getSessionToken())
-        );
-
-        mNotif = builder.build();
-        assertTrue(mNotif.hasMediaSession());
-
-        NotificationTestHelper helper = new NotificationTestHelper(
-                mContext,
-                mDependency,
-                TestableLooper.get(this));
-        mRow = helper.createRow(mNotif);
-
-        RemoteViews views = new RemoteViews(mContext.getPackageName(),
-                com.android.internal.R.layout.notification_template_material_big_media);
-        mView = views.apply(mContext, null);
-        mWrapper = new NotificationMediaTemplateViewWrapper(mContext,
-                mView, mRow);
-        mWrapper.onContentUpdated(mRow);
-    }
-
-    @Test
-    public void testLogging_NoSeekbar() throws Exception {
-        // Media sessions with duration <= 0 should not include a seekbar
-        makeTestNotification(0, false);
-
-        verify(mMetricsLogger).write(argThat(logMaker ->
-                logMaker.getCategory() == MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR
-                        && logMaker.getType() == MetricsEvent.TYPE_CLOSE
-        ));
-
-        verify(mMetricsLogger, times(0)).write(argThat(logMaker ->
-                logMaker.getCategory() == MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR
-                        && logMaker.getType() == MetricsEvent.TYPE_OPEN
-        ));
-    }
-
-    @Test
-    public void testLogging_HasSeekbarNoScrubber() throws Exception {
-        // Media sessions that do not support seeking should have a seekbar, but no scrubber
-        makeTestNotification(1000, false);
-
-        verify(mMetricsLogger).write(argThat(logMaker ->
-                logMaker.getCategory() == MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR
-                        && logMaker.getType() == MetricsEvent.TYPE_OPEN
-        ));
-
-        // Ensure the callback runs at least once
-        mWrapper.mOnUpdateTimerTick.run();
-
-        verify(mMetricsLogger).write(argThat(logMaker ->
-                logMaker.getCategory() == MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR
-                && logMaker.getType() == MetricsEvent.TYPE_DETAIL
-                && logMaker.getSubtype() == 0
-        ));
-    }
-
-    @Test
-    public void testLogging_HasSeekbarAndScrubber() throws Exception {
-        makeTestNotification(1000, true);
-
-        verify(mMetricsLogger).write(argThat(logMaker ->
-                logMaker.getCategory() == MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR
-                        && logMaker.getType() == MetricsEvent.TYPE_OPEN
-        ));
-
-        verify(mMetricsLogger).write(argThat(logMaker ->
-                logMaker.getCategory() == MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR
-                        && logMaker.getType() == MetricsEvent.TYPE_DETAIL
-                        && logMaker.getSubtype() == 1
-        ));
-    }
-
-    @Test
-    public void testLogging_UpdateSeekbar() throws Exception {
-        makeTestNotification(1000, true);
-
-        SeekBar seekbar = mView.findViewById(
-                com.android.internal.R.id.notification_media_progress_bar);
-        assertTrue(seekbar != null);
-
-        mWrapper.mSeekListener.onStopTrackingTouch(seekbar);
-
-        verify(mMetricsLogger).write(argThat(logMaker ->
-                logMaker.getCategory() == MetricsEvent.MEDIA_NOTIFICATION_SEEKBAR
-                        && logMaker.getType() == MetricsEvent.TYPE_UPDATE));
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
index 7b7e2d3..f147f1ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
@@ -31,7 +31,6 @@
 
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarMobileView;
 import com.android.systemui.statusbar.StatusBarWifiView;
@@ -60,14 +59,14 @@
     @Test
     public void testSetCalledOnAdd_IconManager() {
         LinearLayout layout = new LinearLayout(mContext);
-        TestIconManager manager = new TestIconManager(layout, new CommandQueue(mContext));
+        TestIconManager manager = new TestIconManager(layout);
         testCallOnAdd_forManager(manager);
     }
 
     @Test
     public void testSetCalledOnAdd_DarkIconManager() {
         LinearLayout layout = new LinearLayout(mContext);
-        TestDarkIconManager manager = new TestDarkIconManager(layout, new CommandQueue(mContext));
+        TestDarkIconManager manager = new TestDarkIconManager(layout);
         testCallOnAdd_forManager(manager);
     }
 
@@ -104,8 +103,8 @@
     private static class TestDarkIconManager extends DarkIconManager
             implements TestableIconManager {
 
-        TestDarkIconManager(LinearLayout group, CommandQueue commandQueue) {
-            super(group, commandQueue);
+        TestDarkIconManager(LinearLayout group) {
+            super(group);
         }
 
         @Override
@@ -139,8 +138,8 @@
     }
 
     private static class TestIconManager extends IconManager implements TestableIconManager {
-        TestIconManager(ViewGroup group, CommandQueue commandQueue) {
-            super(group, commandQueue);
+        TestIconManager(ViewGroup group) {
+            super(group);
         }
 
         @Override
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 9ac93d9..b160d78 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -1205,8 +1205,6 @@
         }
 
         public void schedule() {
-            Slog.d(LOG_TAG,
-                    "TriggerDeviceDisappearedRunnable.schedule(address = " + mAddress + ")");
             mMainHandler.removeCallbacks(this);
             mMainHandler.postDelayed(this, this, DEVICE_DISAPPEARED_TIMEOUT_MS);
         }
@@ -1244,8 +1242,6 @@
     }
 
     private void onDeviceNearby(String address) {
-        Slog.i(LOG_TAG, "onDeviceNearby(address = " + address + ")");
-
         Date timestamp = new Date();
         Date oldTimestamp = mDevicesLastNearby.put(address, timestamp);
 
@@ -1259,13 +1255,11 @@
         boolean justAppeared = oldTimestamp == null
                 || timestamp.getTime() - oldTimestamp.getTime() >= DEVICE_DISAPPEARED_TIMEOUT_MS;
         if (justAppeared) {
+            Slog.i(LOG_TAG, "onDeviceNearby(justAppeared, address = " + address + ")");
             for (Association association : getAllAssociations(address)) {
                 if (association.isNotifyOnDeviceNearby()) {
-                    if (DEBUG) {
-                        Slog.i(LOG_TAG, "Device " + address
-                                + " managed by " + association.getPackageName()
-                                + " is nearby on " + timestamp);
-                    }
+                    Slog.i(LOG_TAG,
+                            "Sending onDeviceAppeared to " + association.getPackageName() + ")");
                     getDeviceListenerServiceConnector(association).run(
                             service -> service.onDeviceAppeared(association.getDeviceMacAddress()));
                 }
@@ -1279,12 +1273,8 @@
         boolean hasDeviceListeners = false;
         for (Association association : getAllAssociations(address)) {
             if (association.isNotifyOnDeviceNearby()) {
-                if (DEBUG) {
-                    Slog.i(LOG_TAG, "Device " + address
-                            + " managed by " + association.getPackageName()
-                            + " disappeared; last seen on " + mDevicesLastNearby.get(address));
-                }
-
+                Slog.i(LOG_TAG,
+                        "Sending onDeviceDisappeared to " + association.getPackageName() + ")");
                 getDeviceListenerServiceConnector(association).run(
                         service -> service.onDeviceDisappeared(address));
                 hasDeviceListeners = true;
diff --git a/services/core/Android.bp b/services/core/Android.bp
index ed2e625..bed76f3 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -226,6 +226,7 @@
         "java/com/android/server/connectivity/AutodestructReference.java",
         "java/com/android/server/connectivity/ConnectivityConstants.java",
         "java/com/android/server/connectivity/DnsManager.java",
+        "java/com/android/server/connectivity/FullScore.java",
         "java/com/android/server/connectivity/KeepaliveTracker.java",
         "java/com/android/server/connectivity/LingerMonitor.java",
         "java/com/android/server/connectivity/MockableSystemProperties.java",
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c4548a3..492759f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -182,6 +182,7 @@
 import android.app.WaitResult;
 import android.app.backup.BackupManager.OperationType;
 import android.app.backup.IBackupManager;
+import android.app.job.JobParameters;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageEvents.Event;
 import android.app.usage.UsageStatsManager;
@@ -3490,7 +3491,9 @@
 
                     // Clear its scheduled jobs
                     JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
-                    js.cancelJobsForUid(appInfo.uid, "clear data");
+                    // Clearing data is akin to uninstalling. The app is force stopped before we
+                    // get to this point, so the reason won't be checked by the app.
+                    js.cancelJobsForUid(appInfo.uid, JobParameters.STOP_REASON_USER, "clear data");
 
                     // Clear its pending alarms
                     AlarmManagerInternal ami = LocalServices.getService(AlarmManagerInternal.class);
diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java
index d8d6528..70a54cf 100644
--- a/services/core/java/com/android/server/am/AssistDataRequester.java
+++ b/services/core/java/com/android/server/am/AssistDataRequester.java
@@ -143,27 +143,45 @@
      * Request that autofill data be loaded asynchronously. The resulting data will be provided
      * through the {@link AssistDataRequesterCallbacks}.
      *
-     * See {@link #requestData(List, boolean, boolean, boolean, boolean, boolean, int, String)}.
+     * See {@link #requestData(List, boolean, boolean, boolean, boolean, boolean, int, String,
+     * boolean)}.
      */
     public void requestAutofillData(List<IBinder> activityTokens, int callingUid,
             String callingPackage) {
         requestData(activityTokens, true /* requestAutofillData */,
                 true /* fetchData */, false /* fetchScreenshot */,
                 true /* allowFetchData */, false /* allowFetchScreenshot */,
-                callingUid, callingPackage);
+                false /* ignoreTopActivityCheck */, callingUid, callingPackage);
     }
 
     /**
      * Request that assist data be loaded asynchronously. The resulting data will be provided
      * through the {@link AssistDataRequesterCallbacks}.
      *
-     * See {@link #requestData(List, boolean, boolean, boolean, boolean, boolean, int, String)}.
+     * See {@link #requestData(List, boolean, boolean, boolean, boolean, boolean, int, String,
+     * boolean)}.
      */
     public void requestAssistData(List<IBinder> activityTokens, final boolean fetchData,
             final boolean fetchScreenshot, boolean allowFetchData, boolean allowFetchScreenshot,
             int callingUid, String callingPackage) {
+        requestAssistData(activityTokens, fetchData, fetchScreenshot, allowFetchData,
+                allowFetchScreenshot, false /* ignoreTopActivityCheck */, callingUid,
+                callingPackage);
+    }
+
+    /**
+     * Request that assist data be loaded asynchronously. The resulting data will be provided
+     * through the {@link AssistDataRequesterCallbacks}.
+     *
+     * See {@link #requestData(List, boolean, boolean, boolean, boolean, boolean, int, String,
+     * boolean)}.
+     */
+    public void requestAssistData(List<IBinder> activityTokens, final boolean fetchData,
+            final boolean fetchScreenshot, boolean allowFetchData, boolean allowFetchScreenshot,
+            boolean ignoreTopActivityCheck, int callingUid, String callingPackage) {
         requestData(activityTokens, false /* requestAutofillData */, fetchData, fetchScreenshot,
-                allowFetchData, allowFetchScreenshot, callingUid, callingPackage);
+                allowFetchData, allowFetchScreenshot, ignoreTopActivityCheck, callingUid,
+                callingPackage);
     }
 
     /**
@@ -183,10 +201,13 @@
      *     is allowed to fetch the assist data
      * @param allowFetchScreenshot to be joined with other checks, determines whether or not the
      *     requester is allowed to fetch the assist screenshot
+     * @param ignoreTopActivityCheck overrides the check for whether the activity is in focus when
+     *     making the request. Used when passing an activity from Recents.
      */
     private void requestData(List<IBinder> activityTokens, final boolean requestAutofillData,
             final boolean fetchData, final boolean fetchScreenshot, boolean allowFetchData,
-            boolean allowFetchScreenshot, int callingUid, String callingPackage) {
+            boolean allowFetchScreenshot, boolean ignoreTopActivityCheck, int callingUid,
+            String callingPackage) {
         // TODO(b/34090158): Known issue, if the assist data is not allowed on the current activity,
         //                   then no assist data is requested for any of the other activities
 
@@ -230,7 +251,8 @@
                                         receiverExtras, topActivity, 0 /* flags */)
                                 : mActivityTaskManager.requestAssistContextExtras(
                                         ASSIST_CONTEXT_FULL, this, receiverExtras, topActivity,
-                                        /* focused= */ i == 0, /* newSessionId= */ i == 0);
+                                        /* checkActivityIsTop= */ (i == 0)
+                                        && !ignoreTopActivityCheck, /* newSessionId= */ i == 0);
                         if (result) {
                             mPendingDataCount++;
                         } else if (i == 0) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index c6f39aa..3eb4759 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -424,6 +424,12 @@
             });
         }
 
+        @Override
+        public void onSessionClosed() {
+            mHandler.post(() -> {
+              // TODO: implement this.
+            });
+        }
     }
 
     Sensor(@NonNull String tag, @NonNull FaceProvider provider, @NonNull Context context,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index 5631647..d843bc9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -403,6 +403,13 @@
                 invalidationClient.onAuthenticatorIdInvalidated(newAuthenticatorId);
             });
         }
+
+        @Override
+        public void onSessionClosed() {
+            mHandler.post(() -> {
+              // TODO: implement this.
+            });
+        }
     }
 
     Sensor(@NonNull String tag, @NonNull FingerprintProvider provider, @NonNull Context context,
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 74e4ae7..acf39f0 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -26,6 +26,7 @@
 import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
 import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
 import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
+import static android.net.SocketKeepalive.ERROR_NO_SUCH_SLOT;
 import static android.net.SocketKeepalive.ERROR_STOP_REASON_UNINITIALIZED;
 import static android.net.SocketKeepalive.ERROR_UNSUPPORTED;
 import static android.net.SocketKeepalive.MAX_INTERVAL_SEC;
@@ -528,6 +529,8 @@
             }
         } else if (reason == ERROR_STOP_REASON_UNINITIALIZED) {
             throw new IllegalStateException("Unexpected stop reason: " + reason);
+        } else if (reason == ERROR_NO_SUCH_SLOT) {
+            throw new IllegalStateException("No such slot: " + reason);
         } else {
             notifyErrorCallback(ki.mCallback, reason);
         }
diff --git a/services/core/java/com/android/server/content/SyncJobService.java b/services/core/java/com/android/server/content/SyncJobService.java
index aaf9cbc..1f46061 100644
--- a/services/core/java/com/android/server/content/SyncJobService.java
+++ b/services/core/java/com/android/server/content/SyncJobService.java
@@ -119,7 +119,7 @@
     public boolean onStopJob(JobParameters params) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Slog.v(TAG, "onStopJob called " + params.getJobId() + ", reason: "
-                    + params.getStopReason());
+                    + params.getLegacyStopReason());
         }
         final SyncOperation op = SyncOperation.maybeCreateFromJobExtras(params.getExtras());
         if (op == null) {
@@ -161,9 +161,9 @@
         m.obj = op;
 
         // Reschedule if this job was NOT explicitly canceled.
-        m.arg1 = params.getStopReason() != JobParameters.REASON_CANCELED ? 1 : 0;
+        m.arg1 = params.getLegacyStopReason() != JobParameters.REASON_CANCELED ? 1 : 0;
         // Apply backoff only if stop is called due to timeout.
-        m.arg2 = params.getStopReason() == JobParameters.REASON_TIMEOUT ? 1 : 0;
+        m.arg2 = params.getLegacyStopReason() == JobParameters.REASON_TIMEOUT ? 1 : 0;
 
         SyncManager.sendMessage(m);
         return false;
@@ -204,7 +204,8 @@
             return "job:null";
         } else {
             return "job:#" + params.getJobId() + ":"
-                    + "sr=[" + params.getStopReason() + "/" + params.getDebugStopReason() + "]:"
+                    + "sr=[" + params.getLegacyStopReason()
+                    + "/" + params.getDebugStopReason() + "]:"
                     + SyncOperation.maybeCreateFromJobExtras(params.getExtras());
         }
     }
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 2920ddb..6d1606d 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -31,6 +31,7 @@
 
 import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
 import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
+import static com.android.server.location.eventlog.LocationEventLog.EVENT_LOG;
 
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 
@@ -158,10 +159,9 @@
 
         public Lifecycle(Context context) {
             super(context);
-            LocationEventLog eventLog = new LocationEventLog();
             mUserInfoHelper = new LifecycleUserInfoHelper(context);
-            mSystemInjector = new SystemInjector(context, mUserInfoHelper, eventLog);
-            mService = new LocationManagerService(context, mSystemInjector, eventLog);
+            mSystemInjector = new SystemInjector(context, mUserInfoHelper);
+            mService = new LocationManagerService(context, mSystemInjector);
         }
 
         @Override
@@ -233,7 +233,6 @@
 
     private final Context mContext;
     private final Injector mInjector;
-    private final LocationEventLog mEventLog;
     private final LocalService mLocalService;
 
     private final GeofenceManager mGeofenceManager;
@@ -261,18 +260,20 @@
     @GuardedBy("mLock")
     private @Nullable OnProviderLocationTagsChangeListener mOnProviderLocationTagsChangeListener;
 
-    LocationManagerService(Context context, Injector injector, LocationEventLog eventLog) {
+    LocationManagerService(Context context, Injector injector) {
         mContext = context.createAttributionContext(ATTRIBUTION_TAG);
         mInjector = injector;
-        mEventLog = eventLog;
         mLocalService = new LocalService();
         LocalServices.addService(LocationManagerInternal.class, mLocalService);
 
         mGeofenceManager = new GeofenceManager(mContext, injector);
 
+        mInjector.getSettingsHelper().addOnLocationEnabledChangedListener(
+                this::onLocationModeChanged);
+
         // set up passive provider first since it will be required for all other location providers,
         // which are loaded later once the system is ready.
-        mPassiveManager = new PassiveLocationProviderManager(mContext, injector, mEventLog);
+        mPassiveManager = new PassiveLocationProviderManager(mContext, injector);
         addLocationProviderManager(mPassiveManager, new PassiveLocationProvider(mContext));
 
         // TODO: load the gps provider here as well, which will require refactoring
@@ -313,7 +314,7 @@
             }
 
             LocationProviderManager manager = new LocationProviderManager(mContext, mInjector,
-                    mEventLog, providerName, mPassiveManager);
+                    providerName, mPassiveManager);
             addLocationProviderManager(manager, null);
             return manager;
         }
@@ -335,7 +336,7 @@
                             Settings.Global.LOCATION_ENABLE_STATIONARY_THROTTLE, 1) != 0;
                     if (enableStationaryThrottling) {
                         realProvider = new StationaryThrottlingLocationProvider(manager.getName(),
-                                mInjector, realProvider, mEventLog);
+                                mInjector, realProvider);
                     }
                 }
                 manager.setRealProvider(realProvider);
@@ -355,9 +356,6 @@
     }
 
     void onSystemReady() {
-        mInjector.getSettingsHelper().addOnLocationEnabledChangedListener(
-                this::onLocationModeChanged);
-
         if (Build.IS_DEBUGGABLE) {
             // on debug builds, watch for location noteOps while location is off. there are some
             // scenarios (emergency location) where this is expected, but generally this should
@@ -385,7 +383,7 @@
                 com.android.internal.R.string.config_networkLocationProviderPackageName);
         if (networkProvider != null) {
             LocationProviderManager networkManager = new LocationProviderManager(mContext,
-                    mInjector, mEventLog, NETWORK_PROVIDER, mPassiveManager);
+                    mInjector, NETWORK_PROVIDER, mPassiveManager);
             addLocationProviderManager(networkManager, networkProvider);
         } else {
             Log.w(TAG, "no network location provider found");
@@ -404,7 +402,7 @@
                 com.android.internal.R.string.config_fusedLocationProviderPackageName);
         if (fusedProvider != null) {
             LocationProviderManager fusedManager = new LocationProviderManager(mContext, mInjector,
-                    mEventLog, FUSED_PROVIDER, mPassiveManager);
+                    FUSED_PROVIDER, mPassiveManager);
             addLocationProviderManager(fusedManager, fusedProvider);
         } else {
             Log.wtf(TAG, "no fused location provider found");
@@ -419,7 +417,7 @@
             mGnssManagerService.onSystemReady();
 
             LocationProviderManager gnssManager = new LocationProviderManager(mContext, mInjector,
-                    mEventLog, GPS_PROVIDER, mPassiveManager);
+                    GPS_PROVIDER, mPassiveManager);
             addLocationProviderManager(gnssManager, mGnssManagerService.getGnssLocationProvider());
         }
 
@@ -476,7 +474,7 @@
             Log.d(TAG, "[u" + userId + "] location enabled = " + enabled);
         }
 
-        mEventLog.logLocationEnabled(userId, enabled);
+        EVENT_LOG.logLocationEnabled(userId, enabled);
 
         Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION)
                 .putExtra(LocationManager.EXTRA_LOCATION_ENABLED, enabled)
@@ -1268,7 +1266,7 @@
 
                 ipw.println("Event Log:");
                 ipw.increaseIndent();
-                mEventLog.iterate(manager.getName(), ipw::println);
+                EVENT_LOG.iterate(manager.getName(), ipw::println);
                 ipw.decreaseIndent();
                 return;
             }
@@ -1313,7 +1311,7 @@
         ipw.println("Historical Aggregate Location Provider Data:");
         ipw.increaseIndent();
         ArrayMap<String, ArrayMap<CallerIdentity, LocationEventLog.AggregateStats>> aggregateStats =
-                mEventLog.copyAggregateStats();
+                EVENT_LOG.copyAggregateStats();
         for (int i = 0; i < aggregateStats.size(); i++) {
             ipw.print(aggregateStats.keyAt(i));
             ipw.println(":");
@@ -1344,7 +1342,7 @@
 
         ipw.println("Event Log:");
         ipw.increaseIndent();
-        mEventLog.iterate(ipw::println);
+        EVENT_LOG.iterate(ipw::println);
         ipw.decreaseIndent();
     }
 
@@ -1456,7 +1454,7 @@
         @GuardedBy("this")
         private boolean mSystemReady;
 
-        SystemInjector(Context context, UserInfoHelper userInfoHelper, LocationEventLog eventLog) {
+        SystemInjector(Context context, UserInfoHelper userInfoHelper) {
             mContext = context;
 
             mUserInfoHelper = userInfoHelper;
@@ -1466,7 +1464,7 @@
                     mAppOpsHelper);
             mSettingsHelper = new SystemSettingsHelper(context);
             mAppForegroundHelper = new SystemAppForegroundHelper(context);
-            mLocationPowerSaveModeHelper = new SystemLocationPowerSaveModeHelper(context, eventLog);
+            mLocationPowerSaveModeHelper = new SystemLocationPowerSaveModeHelper(context);
             mScreenInteractiveHelper = new SystemScreenInteractiveHelper(context);
             mDeviceStationaryHelper = new SystemDeviceStationaryHelper();
             mDeviceIdleHelper = new SystemDeviceIdleHelper(context);
diff --git a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
index 29ce378..045e06d0 100644
--- a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
@@ -44,6 +44,8 @@
 /** In memory event log for location events. */
 public class LocationEventLog extends LocalEventLog {
 
+    public static final LocationEventLog EVENT_LOG = new LocationEventLog();
+
     private static int getLogSize() {
         if (Build.IS_DEBUGGABLE || D) {
             return 500;
@@ -52,16 +54,17 @@
         }
     }
 
-    private static final int EVENT_LOCATION_ENABLED = 1;
-    private static final int EVENT_PROVIDER_ENABLED = 2;
-    private static final int EVENT_PROVIDER_MOCKED = 3;
-    private static final int EVENT_PROVIDER_REGISTER_CLIENT = 4;
-    private static final int EVENT_PROVIDER_UNREGISTER_CLIENT = 5;
-    private static final int EVENT_PROVIDER_UPDATE_REQUEST = 6;
-    private static final int EVENT_PROVIDER_RECEIVE_LOCATION = 7;
-    private static final int EVENT_PROVIDER_DELIVER_LOCATION = 8;
-    private static final int EVENT_PROVIDER_STATIONARY_THROTTLED = 9;
-    private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 10;
+    private static final int EVENT_USER_SWITCHED = 1;
+    private static final int EVENT_LOCATION_ENABLED = 2;
+    private static final int EVENT_PROVIDER_ENABLED = 3;
+    private static final int EVENT_PROVIDER_MOCKED = 4;
+    private static final int EVENT_PROVIDER_REGISTER_CLIENT = 5;
+    private static final int EVENT_PROVIDER_UNREGISTER_CLIENT = 6;
+    private static final int EVENT_PROVIDER_UPDATE_REQUEST = 7;
+    private static final int EVENT_PROVIDER_RECEIVE_LOCATION = 8;
+    private static final int EVENT_PROVIDER_DELIVER_LOCATION = 9;
+    private static final int EVENT_PROVIDER_STATIONARY_THROTTLED = 10;
+    private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 11;
 
     @GuardedBy("mAggregateStats")
     private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats;
@@ -90,19 +93,24 @@
                 packageMap = new ArrayMap<>(2);
                 mAggregateStats.put(provider, packageMap);
             }
-            CallerIdentity stripped = identity.stripListenerId();
-            AggregateStats stats = packageMap.get(stripped);
+            CallerIdentity aggregate = CallerIdentity.forAggregation(identity);
+            AggregateStats stats = packageMap.get(aggregate);
             if (stats == null) {
                 stats = new AggregateStats();
-                packageMap.put(stripped, stats);
+                packageMap.put(aggregate, stats);
             }
             return stats;
         }
     }
 
+    /** Logs a user switched event. */
+    public void logUserSwitched(int userIdFrom, int userIdTo) {
+        addLogEvent(EVENT_USER_SWITCHED, userIdFrom, userIdTo);
+    }
+
     /** Logs a location enabled/disabled event. */
     public void logLocationEnabled(int userId, boolean enabled) {
-        addLogEvent(EVENT_LOCATION_POWER_SAVE_MODE_CHANGE, userId, enabled);
+        addLogEvent(EVENT_LOCATION_ENABLED, userId, enabled);
     }
 
     /** Logs a location provider enabled/disabled event. */
@@ -183,8 +191,10 @@
     @Override
     protected LogEvent createLogEvent(long timeDelta, int event, Object... args) {
         switch (event) {
+            case EVENT_USER_SWITCHED:
+                return new UserSwitchedEvent(timeDelta, (Integer) args[0], (Integer) args[1]);
             case EVENT_LOCATION_ENABLED:
-                return new LocationEnabledEvent(timeDelta, (Integer) args[1], (Boolean) args[2]);
+                return new LocationEnabledEvent(timeDelta, (Integer) args[0], (Boolean) args[1]);
             case EVENT_PROVIDER_ENABLED:
                 return new ProviderEnabledEvent(timeDelta, (String) args[0], (Integer) args[1],
                         (Boolean) args[2]);
@@ -397,6 +407,23 @@
         }
     }
 
+    private static final class UserSwitchedEvent extends LogEvent {
+
+        private final int mUserIdFrom;
+        private final int mUserIdTo;
+
+        UserSwitchedEvent(long timeDelta, int userIdFrom, int userIdTo) {
+            super(timeDelta);
+            mUserIdFrom = userIdFrom;
+            mUserIdTo = userIdTo;
+        }
+
+        @Override
+        public String getLogString() {
+            return "current user switched from u" + mUserIdFrom + " to u" + mUserIdTo;
+        }
+    }
+
     private static final class LocationEnabledEvent extends LogEvent {
 
         private final int mUserId;
@@ -410,7 +437,7 @@
 
         @Override
         public String getLogString() {
-            return "[u" + mUserId + "] location setting " + (mEnabled ? "enabled" : "disabled");
+            return "location [u" + mUserId + "] " + (mEnabled ? "enabled" : "disabled");
         }
     }
 
diff --git a/services/core/java/com/android/server/location/injector/LocationPowerSaveModeHelper.java b/services/core/java/com/android/server/location/injector/LocationPowerSaveModeHelper.java
index cc00d56..53407d9 100644
--- a/services/core/java/com/android/server/location/injector/LocationPowerSaveModeHelper.java
+++ b/services/core/java/com/android/server/location/injector/LocationPowerSaveModeHelper.java
@@ -20,12 +20,11 @@
 
 import static com.android.server.location.LocationManagerService.D;
 import static com.android.server.location.LocationManagerService.TAG;
+import static com.android.server.location.eventlog.LocationEventLog.EVENT_LOG;
 
 import android.os.PowerManager.LocationPowerSaveMode;
 import android.util.Log;
 
-import com.android.server.location.eventlog.LocationEventLog;
-
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
@@ -43,11 +42,9 @@
         void onLocationPowerSaveModeChanged(@LocationPowerSaveMode int locationPowerSaveMode);
     }
 
-    private final LocationEventLog mLocationEventLog;
     private final CopyOnWriteArrayList<LocationPowerSaveModeChangedListener> mListeners;
 
-    public LocationPowerSaveModeHelper(LocationEventLog locationEventLog) {
-        mLocationEventLog = locationEventLog;
+    public LocationPowerSaveModeHelper() {
         mListeners = new CopyOnWriteArrayList<>();
     }
 
@@ -72,7 +69,7 @@
             Log.d(TAG, "location power save mode is now " + locationPowerSaveModeToString(
                     locationPowerSaveMode));
         }
-        mLocationEventLog.logLocationPowerSaveMode(locationPowerSaveMode);
+        EVENT_LOG.logLocationPowerSaveMode(locationPowerSaveMode);
 
         for (LocationPowerSaveModeChangedListener listener : mListeners) {
             listener.onLocationPowerSaveModeChanged(locationPowerSaveMode);
diff --git a/services/core/java/com/android/server/location/injector/SystemLocationPowerSaveModeHelper.java b/services/core/java/com/android/server/location/injector/SystemLocationPowerSaveModeHelper.java
index c47a64d..a675f54 100644
--- a/services/core/java/com/android/server/location/injector/SystemLocationPowerSaveModeHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemLocationPowerSaveModeHelper.java
@@ -25,7 +25,6 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
-import com.android.server.location.eventlog.LocationEventLog;
 
 import java.util.Objects;
 import java.util.function.Consumer;
@@ -42,8 +41,7 @@
     @LocationPowerSaveMode
     private volatile int mLocationPowerSaveMode;
 
-    public SystemLocationPowerSaveModeHelper(Context context, LocationEventLog locationEventLog) {
-        super(locationEventLog);
+    public SystemLocationPowerSaveModeHelper(Context context) {
         mContext = context;
     }
 
diff --git a/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java b/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
index 3f7345e..632ed6e 100644
--- a/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
@@ -35,6 +35,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Handler;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -348,31 +349,73 @@
      */
     @Override
     public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
-        int userId = ActivityManager.getCurrentUser();
+        int[] userIds;
+        try {
+            userIds = ActivityManager.getService().getRunningUserIds();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
 
-        ipw.print("Location Enabled: ");
-        ipw.println(isLocationEnabled(userId));
-
-        List<String> locationPackageBlacklist = mLocationPackageBlacklist.getValueForUser(userId);
-        if (!locationPackageBlacklist.isEmpty()) {
-            ipw.println("Location Deny Packages:");
-            ipw.increaseIndent();
-            for (String packageName : locationPackageBlacklist) {
-                ipw.println(packageName);
+        ipw.print("Location Setting: ");
+        ipw.increaseIndent();
+        if (userIds.length > 1) {
+            ipw.println();
+            for (int userId : userIds) {
+                ipw.print("[u");
+                ipw.print(userId);
+                ipw.print("] ");
+                ipw.println(isLocationEnabled(userId));
             }
-            ipw.decreaseIndent();
+        } else {
+            ipw.println(isLocationEnabled(userIds[0]));
+        }
+        ipw.decreaseIndent();
 
-            List<String> locationPackageWhitelist = mLocationPackageWhitelist.getValueForUser(
-                    userId);
-            if (!locationPackageWhitelist.isEmpty()) {
-                ipw.println("Location Allow Packages:");
+        ipw.println("Location Allow/Deny Packages:");
+        ipw.increaseIndent();
+        if (userIds.length > 1) {
+            for (int userId : userIds) {
+                List<String> locationPackageBlacklist = mLocationPackageBlacklist.getValueForUser(
+                        userId);
+                if (locationPackageBlacklist.isEmpty()) {
+                    continue;
+                }
+
+                ipw.print("user ");
+                ipw.print(userId);
+                ipw.println(":");
                 ipw.increaseIndent();
-                for (String packageName : locationPackageWhitelist) {
+
+                for (String packageName : locationPackageBlacklist) {
+                    ipw.print("[deny] ");
                     ipw.println(packageName);
                 }
+
+                List<String> locationPackageWhitelist = mLocationPackageWhitelist.getValueForUser(
+                        userId);
+                for (String packageName : locationPackageWhitelist) {
+                    ipw.print("[allow] ");
+                    ipw.println(packageName);
+                }
+
                 ipw.decreaseIndent();
             }
+        } else {
+            List<String> locationPackageBlacklist = mLocationPackageBlacklist.getValueForUser(
+                    userIds[0]);
+            for (String packageName : locationPackageBlacklist) {
+                ipw.print("[deny] ");
+                ipw.println(packageName);
+            }
+
+            List<String> locationPackageWhitelist = mLocationPackageWhitelist.getValueForUser(
+                    userIds[0]);
+            for (String packageName : locationPackageWhitelist) {
+                ipw.print("[allow] ");
+                ipw.println(packageName);
+            }
         }
+        ipw.decreaseIndent();
 
         Set<String> backgroundThrottlePackageWhitelist =
                 mBackgroundThrottlePackageWhitelist.getValue();
diff --git a/services/core/java/com/android/server/location/injector/SystemUserInfoHelper.java b/services/core/java/com/android/server/location/injector/SystemUserInfoHelper.java
index d4a8fbd..ed1e654 100644
--- a/services/core/java/com/android/server/location/injector/SystemUserInfoHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemUserInfoHelper.java
@@ -155,6 +155,11 @@
      */
     @Override
     public void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
+        int[] runningUserIds = getRunningUserIds();
+        if (runningUserIds.length > 1) {
+            pw.println("running users: u" + Arrays.toString(runningUserIds));
+        }
+
         ActivityManagerInternal activityManagerInternal = getActivityManagerInternal();
         if (activityManagerInternal == null) {
             return;
diff --git a/services/core/java/com/android/server/location/injector/UserInfoHelper.java b/services/core/java/com/android/server/location/injector/UserInfoHelper.java
index 0fcc1ec..c835370 100644
--- a/services/core/java/com/android/server/location/injector/UserInfoHelper.java
+++ b/services/core/java/com/android/server/location/injector/UserInfoHelper.java
@@ -18,6 +18,7 @@
 
 import static com.android.server.location.LocationManagerService.D;
 import static com.android.server.location.LocationManagerService.TAG;
+import static com.android.server.location.eventlog.LocationEventLog.EVENT_LOG;
 import static com.android.server.location.injector.UserInfoHelper.UserListener.CURRENT_USER_CHANGED;
 import static com.android.server.location.injector.UserInfoHelper.UserListener.USER_STARTED;
 import static com.android.server.location.injector.UserInfoHelper.UserListener.USER_STOPPED;
@@ -105,6 +106,7 @@
             Log.d(TAG, "current user changed from u" + Arrays.toString(fromUserIds) + " to u"
                     + Arrays.toString(toUserIds));
         }
+        EVENT_LOG.logUserSwitched(fromUserId, toUserId);
 
         for (UserListener listener : mListeners) {
             for (int userId : fromUserIds) {
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index dc8b1d0..102263b 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -37,6 +37,7 @@
 import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
 import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
 import static com.android.server.location.LocationPermissions.PERMISSION_NONE;
+import static com.android.server.location.eventlog.LocationEventLog.EVENT_LOG;
 
 import static java.lang.Math.max;
 import static java.lang.Math.min;
@@ -94,7 +95,6 @@
 import com.android.server.LocalServices;
 import com.android.server.location.LocationPermissions;
 import com.android.server.location.LocationPermissions.PermissionLevel;
-import com.android.server.location.eventlog.LocationEventLog;
 import com.android.server.location.fudger.LocationFudger;
 import com.android.server.location.injector.AlarmHelper;
 import com.android.server.location.injector.AppForegroundHelper;
@@ -333,7 +333,7 @@
                         + getRequest());
             }
 
-            mEventLog.logProviderClientRegistered(mName, getIdentity(), super.getRequest());
+            EVENT_LOG.logProviderClientRegistered(mName, getIdentity(), super.getRequest());
 
             // initialization order is important as there are ordering dependencies
             mPermitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel,
@@ -345,7 +345,7 @@
             onProviderListenerRegister();
 
             if (mForeground) {
-                mEventLog.logProviderClientForeground(mName, getIdentity());
+                EVENT_LOG.logProviderClientForeground(mName, getIdentity());
             }
         }
 
@@ -358,7 +358,7 @@
 
             onProviderListenerUnregister();
 
-            mEventLog.logProviderClientUnregistered(mName, getIdentity());
+            EVENT_LOG.logProviderClientUnregistered(mName, getIdentity());
 
             if (D) {
                 Log.d(TAG, mName + " provider removed registration from " + getIdentity());
@@ -383,7 +383,7 @@
                 Preconditions.checkState(Thread.holdsLock(mLock));
             }
 
-            mEventLog.logProviderClientActive(mName, getIdentity());
+            EVENT_LOG.logProviderClientActive(mName, getIdentity());
 
             if (!getRequest().isHiddenFromAppOps()) {
                 mLocationAttributionHelper.reportLocationStart(getIdentity(), getName(), getKey());
@@ -406,7 +406,7 @@
 
             onProviderListenerInactive();
 
-            mEventLog.logProviderClientInactive(mName, getIdentity());
+            EVENT_LOG.logProviderClientInactive(mName, getIdentity());
         }
 
         /**
@@ -543,9 +543,9 @@
                 mForeground = foreground;
 
                 if (mForeground) {
-                    mEventLog.logProviderClientForeground(mName, getIdentity());
+                    EVENT_LOG.logProviderClientForeground(mName, getIdentity());
                 } else {
-                    mEventLog.logProviderClientBackground(mName, getIdentity());
+                    EVENT_LOG.logProviderClientBackground(mName, getIdentity());
                 }
 
                 // note that onProviderLocationRequestChanged() is always called
@@ -654,7 +654,7 @@
     protected abstract class LocationRegistration extends Registration implements
             OnAlarmListener, ProviderEnabledListener {
 
-        private final PowerManager.WakeLock mWakeLock;
+        final PowerManager.WakeLock mWakeLock;
 
         private volatile ProviderTransport mProviderTransport;
         private int mNumLocationsDelivered = 0;
@@ -879,7 +879,7 @@
 
                     listener.deliverOnLocationChanged(deliverLocationResult,
                             mUseWakeLock ? mWakeLock::release : null);
-                    mEventLog.logProviderDeliveredLocations(mName, locationResult.size(),
+                    EVENT_LOG.logProviderDeliveredLocations(mName, locationResult.size(),
                             getIdentity());
                 }
 
@@ -1178,7 +1178,7 @@
 
                     // we currently don't hold a wakelock for getCurrentLocation deliveries
                     listener.deliverOnLocationChanged(deliverLocationResult, null);
-                    mEventLog.logProviderDeliveredLocations(mName,
+                    EVENT_LOG.logProviderDeliveredLocations(mName,
                             locationResult != null ? locationResult.size() : 0, getIdentity());
                 }
 
@@ -1247,7 +1247,6 @@
 
     private final CopyOnWriteArrayList<IProviderRequestListener> mProviderRequestListeners;
 
-    protected final LocationEventLog mEventLog;
     protected final LocationManagerInternal mLocationManagerInternal;
     protected final SettingsHelper mSettingsHelper;
     protected final UserInfoHelper mUserHelper;
@@ -1300,7 +1299,7 @@
     @GuardedBy("mLock")
     private @Nullable OnProviderLocationTagsChangeListener mOnLocationTagsChangeListener;
 
-    public LocationProviderManager(Context context, Injector injector, LocationEventLog eventLog,
+    public LocationProviderManager(Context context, Injector injector,
             String name, @Nullable PassiveLocationProviderManager passiveManager) {
         mContext = context;
         mName = Objects.requireNonNull(name);
@@ -1312,7 +1311,6 @@
         mEnabledListeners = new ArrayList<>();
         mProviderRequestListeners = new CopyOnWriteArrayList<>();
 
-        mEventLog = eventLog;
         mLocationManagerInternal = Objects.requireNonNull(
                 LocalServices.getService(LocationManagerInternal.class));
         mSettingsHelper = injector.getSettingsHelper();
@@ -1477,7 +1475,7 @@
         synchronized (mLock) {
             Preconditions.checkState(mState != STATE_STOPPED);
 
-            mEventLog.logProviderMocked(mName, provider != null);
+            EVENT_LOG.logProviderMocked(mName, provider != null);
 
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -1966,8 +1964,8 @@
     }
 
     @GuardedBy("mLock")
-    private void setProviderRequest(ProviderRequest request) {
-        mEventLog.logProviderUpdateRequest(mName, request);
+    void setProviderRequest(ProviderRequest request) {
+        EVENT_LOG.logProviderUpdateRequest(mName, request);
         mProvider.getController().setRequest(request);
 
         FgThread.getHandler().post(() -> {
@@ -2324,7 +2322,7 @@
             }
 
             // don't log location received for passive provider because it's spammy
-            mEventLog.logProviderReceivedLocations(mName, filtered.size());
+            EVENT_LOG.logProviderReceivedLocations(mName, filtered.size());
         } else {
             // passive provider should get already filtered results as input
             filtered = locationResult;
@@ -2424,7 +2422,7 @@
             if (D) {
                 Log.d(TAG, "[u" + userId + "] " + mName + " provider enabled = " + enabled);
             }
-            mEventLog.logProviderEnabled(mName, userId, enabled);
+            EVENT_LOG.logProviderEnabled(mName, userId, enabled);
         }
 
         // clear last locations if we become disabled
@@ -2464,7 +2462,7 @@
         updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
     }
 
-    private @Nullable Location getPermittedLocation(@Nullable Location fineLocation,
+    @Nullable Location getPermittedLocation(@Nullable Location fineLocation,
             @PermissionLevel int permissionLevel) {
         switch (permissionLevel) {
             case PERMISSION_FINE:
@@ -2477,7 +2475,7 @@
         }
     }
 
-    private @Nullable LocationResult getPermittedLocationResult(
+    @Nullable LocationResult getPermittedLocationResult(
             @Nullable LocationResult fineLocationResult, @PermissionLevel int permissionLevel) {
         switch (permissionLevel) {
             case PERMISSION_FINE:
@@ -2538,6 +2536,8 @@
         private @Nullable Location mFineBypassLocation;
         private @Nullable Location mCoarseBypassLocation;
 
+        LastLocation() {}
+
         public void clearMock() {
             if (mFineLocation != null && mFineLocation.isFromMockProvider()) {
                 mFineLocation = null;
diff --git a/services/core/java/com/android/server/location/provider/PassiveLocationProviderManager.java b/services/core/java/com/android/server/location/provider/PassiveLocationProviderManager.java
index 027f4e9..b35af4f 100644
--- a/services/core/java/com/android/server/location/provider/PassiveLocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/PassiveLocationProviderManager.java
@@ -24,7 +24,6 @@
 import android.os.Binder;
 
 import com.android.internal.util.Preconditions;
-import com.android.server.location.eventlog.LocationEventLog;
 import com.android.server.location.injector.Injector;
 
 import java.util.Collection;
@@ -34,9 +33,8 @@
  */
 public class PassiveLocationProviderManager extends LocationProviderManager {
 
-    public PassiveLocationProviderManager(Context context, Injector injector,
-            LocationEventLog eventLog) {
-        super(context, injector, eventLog, LocationManager.PASSIVE_PROVIDER, null);
+    public PassiveLocationProviderManager(Context context, Injector injector) {
+        super(context, injector, LocationManager.PASSIVE_PROVIDER, null);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
index 6f4aa64..ab7e526 100644
--- a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
@@ -21,6 +21,7 @@
 import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
 import static com.android.server.location.LocationManagerService.D;
 import static com.android.server.location.LocationManagerService.TAG;
+import static com.android.server.location.eventlog.LocationEventLog.EVENT_LOG;
 
 import android.annotation.Nullable;
 import android.location.Location;
@@ -33,7 +34,6 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.DeviceIdleInternal;
 import com.android.server.FgThread;
-import com.android.server.location.eventlog.LocationEventLog;
 import com.android.server.location.injector.DeviceIdleHelper;
 import com.android.server.location.injector.DeviceStationaryHelper;
 import com.android.server.location.injector.Injector;
@@ -54,12 +54,11 @@
 
     private static final long MAX_STATIONARY_LOCATION_AGE_MS = 30000;
 
-    private final Object mLock = new Object();
+    final Object mLock = new Object();
 
     private final String mName;
     private final DeviceIdleHelper mDeviceIdleHelper;
     private final DeviceStationaryHelper mDeviceStationaryHelper;
-    private final LocationEventLog mEventLog;
 
     @GuardedBy("mLock")
     private boolean mDeviceIdle = false;
@@ -72,21 +71,19 @@
     @GuardedBy("mLock")
     private ProviderRequest mOutgoingRequest = ProviderRequest.EMPTY_REQUEST;
     @GuardedBy("mLock")
-    private long mThrottlingIntervalMs = INTERVAL_DISABLED;
+    long mThrottlingIntervalMs = INTERVAL_DISABLED;
     @GuardedBy("mLock")
-    private @Nullable DeliverLastLocationRunnable mDeliverLastLocationCallback = null;
-
+    @Nullable DeliverLastLocationRunnable mDeliverLastLocationCallback = null;
     @GuardedBy("mLock")
-    private @Nullable Location mLastLocation;
+    @Nullable Location mLastLocation;
 
     public StationaryThrottlingLocationProvider(String name, Injector injector,
-            AbstractLocationProvider delegate, LocationEventLog eventLog) {
+            AbstractLocationProvider delegate) {
         super(DIRECT_EXECUTOR, delegate);
 
         mName = name;
         mDeviceIdleHelper = injector.getDeviceIdleHelper();
         mDeviceStationaryHelper = injector.getDeviceStationaryHelper();
-        mEventLog = eventLog;
 
         // must be last statement in the constructor because reference is escaping
         initializeDelegate();
@@ -209,7 +206,7 @@
                 if (D) {
                     Log.d(TAG, mName + " provider stationary throttled");
                 }
-                mEventLog.logProviderStationaryThrottled(mName, true);
+                EVENT_LOG.logProviderStationaryThrottled(mName, true);
             }
 
             if (mDeliverLastLocationCallback != null) {
@@ -227,7 +224,7 @@
             }
         } else {
             if (oldThrottlingIntervalMs != INTERVAL_DISABLED) {
-                mEventLog.logProviderStationaryThrottled(mName, false);
+                EVENT_LOG.logProviderStationaryThrottled(mName, false);
                 if (D) {
                     Log.d(TAG, mName + " provider stationary unthrottled");
                 }
@@ -257,6 +254,9 @@
     }
 
     private class DeliverLastLocationRunnable implements Runnable {
+
+        DeliverLastLocationRunnable() {}
+
         @Override
         public void run() {
             Location location;
diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
index c86e49b..317e61b 100644
--- a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
@@ -36,6 +36,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
+import com.android.server.FgThread;
 import com.android.server.location.provider.AbstractLocationProvider;
 import com.android.server.servicewatcher.ServiceWatcher;
 import com.android.server.servicewatcher.ServiceWatcher.BoundService;
@@ -55,6 +56,8 @@
     private static final String KEY_EXTRA_ATTRIBUTION_TAGS = "android:location_allow_listed_tags";
     private static final String EXTRA_ATTRIBUTION_TAGS_SEPARATOR = ";";
 
+    private static final long RESET_DELAY_MS = 1000;
+
     /**
      * Creates and registers this proxy. If no suitable service is available for the proxy, returns
      * null.
@@ -80,6 +83,9 @@
     final ArrayList<Runnable> mFlushListeners = new ArrayList<>(0);
 
     @GuardedBy("mLock")
+    @Nullable Runnable mResetter;
+
+    @GuardedBy("mLock")
     Proxy mProxy;
     @GuardedBy("mLock")
     @Nullable ComponentName mService;
@@ -111,6 +117,11 @@
             mProxy = new Proxy();
             mService = boundService.component;
 
+            if (mResetter != null) {
+                FgThread.getHandler().removeCallbacks(mResetter);
+                mResetter = null;
+            }
+
             // update extra attribution tag info from manifest
             if (boundService.metadata != null) {
                 String tagsList = boundService.metadata.getString(KEY_EXTRA_ATTRIBUTION_TAGS);
@@ -134,7 +145,22 @@
         synchronized (mLock) {
             mProxy = null;
             mService = null;
-            setState(prevState -> State.EMPTY_STATE);
+
+            // we need to clear the state - but most disconnections are very temporary. we give a
+            // grace period where we don't clear the state immediately so that transient
+            // interruptions are not visible to clients
+            mResetter = new Runnable() {
+                @Override
+                public void run() {
+                    synchronized (mLock) {
+                        if (mResetter == this) {
+                            setState(prevState -> State.EMPTY_STATE);
+                        }
+                    }
+                }
+            };
+            FgThread.getHandler().postDelayed(mResetter, RESET_DELAY_MS);
+
             flushListeners = mFlushListeners.toArray(new Runnable[0]);
             mFlushListeners.clear();
         }
@@ -245,7 +271,8 @@
                     identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
                 }
 
-                setState(prevState -> prevState
+                setState(prevState -> State.EMPTY_STATE
+                        .withExtraAttributionTags(prevState.extraAttributionTags)
                         .withAllowed(allowed)
                         .withProperties(properties)
                         .withIdentity(identity));
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index cc3a002..df1eb6d 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -22,7 +22,6 @@
 import android.net.IpConfiguration.ProxySettings;
 import android.net.LinkAddress;
 import android.net.ProxyInfo;
-import android.net.RouteInfo;
 import android.net.StaticIpConfiguration;
 import android.net.Uri;
 import android.util.ArrayMap;
@@ -42,6 +41,8 @@
 import java.io.InputStream;
 import java.net.Inet4Address;
 import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
 
 public class IpConfigStore {
     private static final String TAG = "IpConfigStore";
@@ -83,25 +84,25 @@
         boolean written = false;
 
         try {
-            switch (config.ipAssignment) {
+            switch (config.getIpAssignment()) {
                 case STATIC:
                     out.writeUTF(IP_ASSIGNMENT_KEY);
-                    out.writeUTF(config.ipAssignment.toString());
-                    StaticIpConfiguration staticIpConfiguration = config.staticIpConfiguration;
+                    out.writeUTF(config.getIpAssignment().toString());
+                    StaticIpConfiguration staticIpConfiguration = config.getStaticIpConfiguration();
                     if (staticIpConfiguration != null) {
-                        if (staticIpConfiguration.ipAddress != null) {
-                            LinkAddress ipAddress = staticIpConfiguration.ipAddress;
+                        if (staticIpConfiguration.getIpAddress() != null) {
+                            LinkAddress ipAddress = staticIpConfiguration.getIpAddress();
                             out.writeUTF(LINK_ADDRESS_KEY);
                             out.writeUTF(ipAddress.getAddress().getHostAddress());
                             out.writeInt(ipAddress.getPrefixLength());
                         }
-                        if (staticIpConfiguration.gateway != null) {
+                        if (staticIpConfiguration.getGateway() != null) {
                             out.writeUTF(GATEWAY_KEY);
                             out.writeInt(0);  // Default route.
                             out.writeInt(1);  // Have a gateway.
-                            out.writeUTF(staticIpConfiguration.gateway.getHostAddress());
+                            out.writeUTF(staticIpConfiguration.getGateway().getHostAddress());
                         }
-                        for (InetAddress inetAddr : staticIpConfiguration.dnsServers) {
+                        for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) {
                             out.writeUTF(DNS_KEY);
                             out.writeUTF(inetAddr.getHostAddress());
                         }
@@ -110,7 +111,7 @@
                     break;
                 case DHCP:
                     out.writeUTF(IP_ASSIGNMENT_KEY);
-                    out.writeUTF(config.ipAssignment.toString());
+                    out.writeUTF(config.getIpAssignment().toString());
                     written = true;
                     break;
                 case UNASSIGNED:
@@ -121,13 +122,13 @@
                     break;
             }
 
-            switch (config.proxySettings) {
+            switch (config.getProxySettings()) {
                 case STATIC:
-                    ProxyInfo proxyProperties = config.httpProxy;
+                    ProxyInfo proxyProperties = config.getHttpProxy();
                     String exclusionList = ProxyUtils.exclusionListAsString(
                             proxyProperties.getExclusionList());
                     out.writeUTF(PROXY_SETTINGS_KEY);
-                    out.writeUTF(config.proxySettings.toString());
+                    out.writeUTF(config.getProxySettings().toString());
                     out.writeUTF(PROXY_HOST_KEY);
                     out.writeUTF(proxyProperties.getHost());
                     out.writeUTF(PROXY_PORT_KEY);
@@ -139,16 +140,16 @@
                     written = true;
                     break;
                 case PAC:
-                    ProxyInfo proxyPacProperties = config.httpProxy;
+                    ProxyInfo proxyPacProperties = config.getHttpProxy();
                     out.writeUTF(PROXY_SETTINGS_KEY);
-                    out.writeUTF(config.proxySettings.toString());
+                    out.writeUTF(config.getProxySettings().toString());
                     out.writeUTF(PROXY_PAC_FILE);
                     out.writeUTF(proxyPacProperties.getPacFileUrl().toString());
                     written = true;
                     break;
                 case NONE:
                     out.writeUTF(PROXY_SETTINGS_KEY);
-                    out.writeUTF(config.proxySettings.toString());
+                    out.writeUTF(config.getProxySettings().toString());
                     written = true;
                     break;
                 case UNASSIGNED:
@@ -267,11 +268,14 @@
                 IpAssignment ipAssignment = IpAssignment.DHCP;
                 ProxySettings proxySettings = ProxySettings.NONE;
                 StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
+                LinkAddress linkAddress = null;
+                InetAddress gatewayAddress = null;
                 String proxyHost = null;
                 String pacFileUrl = null;
                 int proxyPort = -1;
                 String exclusionList = null;
                 String key;
+                final List<InetAddress> dnsServers = new ArrayList<>();
 
                 do {
                     key = in.readUTF();
@@ -286,15 +290,15 @@
                         } else if (key.equals(IP_ASSIGNMENT_KEY)) {
                             ipAssignment = IpAssignment.valueOf(in.readUTF());
                         } else if (key.equals(LINK_ADDRESS_KEY)) {
-                            LinkAddress linkAddr =
+                            LinkAddress parsedLinkAddress =
                                     new LinkAddress(
                                             InetAddresses.parseNumericAddress(in.readUTF()),
                                             in.readInt());
-                            if (linkAddr.getAddress() instanceof Inet4Address &&
-                                    staticIpConfiguration.ipAddress == null) {
-                                staticIpConfiguration.ipAddress = linkAddr;
+                            if (parsedLinkAddress.getAddress() instanceof Inet4Address
+                                    && linkAddress == null) {
+                                linkAddress = parsedLinkAddress;
                             } else {
-                                loge("Non-IPv4 or duplicate address: " + linkAddr);
+                                loge("Non-IPv4 or duplicate address: " + parsedLinkAddress);
                             }
                         } else if (key.equals(GATEWAY_KEY)) {
                             LinkAddress dest = null;
@@ -302,8 +306,8 @@
                             if (version == 1) {
                                 // only supported default gateways - leave the dest/prefix empty
                                 gateway = InetAddresses.parseNumericAddress(in.readUTF());
-                                if (staticIpConfiguration.gateway == null) {
-                                    staticIpConfiguration.gateway = gateway;
+                                if (gatewayAddress == null) {
+                                    gatewayAddress = gateway;
                                 } else {
                                     loge("Duplicate gateway: " + gateway.getHostAddress());
                                 }
@@ -317,17 +321,18 @@
                                 if (in.readInt() == 1) {
                                     gateway = InetAddresses.parseNumericAddress(in.readUTF());
                                 }
-                                RouteInfo route = new RouteInfo(dest, gateway);
-                                if (route.isIPv4Default() &&
-                                        staticIpConfiguration.gateway == null) {
-                                    staticIpConfiguration.gateway = gateway;
+                                // If the destination is a default IPv4 route, use the gateway
+                                // address unless already set.
+                                if (dest.getAddress() instanceof Inet4Address
+                                        && dest.getPrefixLength() == 0 && gatewayAddress == null) {
+                                    gatewayAddress = gateway;
                                 } else {
-                                    loge("Non-IPv4 default or duplicate route: " + route);
+                                    loge("Non-IPv4 default or duplicate route: "
+                                            + dest.getAddress());
                                 }
                             }
                         } else if (key.equals(DNS_KEY)) {
-                            staticIpConfiguration.dnsServers.add(
-                                    InetAddresses.parseNumericAddress(in.readUTF()));
+                            dnsServers.add(InetAddresses.parseNumericAddress(in.readUTF()));
                         } else if (key.equals(PROXY_SETTINGS_KEY)) {
                             proxySettings = ProxySettings.valueOf(in.readUTF());
                         } else if (key.equals(PROXY_HOST_KEY)) {
@@ -348,25 +353,31 @@
                     }
                 } while (true);
 
+                staticIpConfiguration = new StaticIpConfiguration.Builder()
+                    .setIpAddress(linkAddress)
+                    .setGateway(gatewayAddress)
+                    .setDnsServers(dnsServers)
+                    .build();
+
                 if (uniqueToken != null) {
                     IpConfiguration config = new IpConfiguration();
                     networks.put(uniqueToken, config);
 
                     switch (ipAssignment) {
                         case STATIC:
-                            config.staticIpConfiguration = staticIpConfiguration;
-                            config.ipAssignment = ipAssignment;
+                            config.setStaticIpConfiguration(staticIpConfiguration);
+                            config.setIpAssignment(ipAssignment);
                             break;
                         case DHCP:
-                            config.ipAssignment = ipAssignment;
+                            config.setIpAssignment(ipAssignment);
                             break;
                         case UNASSIGNED:
                             loge("BUG: Found UNASSIGNED IP on file, use DHCP");
-                            config.ipAssignment = IpAssignment.DHCP;
+                            config.setIpAssignment(IpAssignment.DHCP);
                             break;
                         default:
                             loge("Ignore invalid ip assignment while reading.");
-                            config.ipAssignment = IpAssignment.UNASSIGNED;
+                            config.setIpAssignment(IpAssignment.UNASSIGNED);
                             break;
                     }
 
@@ -374,25 +385,25 @@
                         case STATIC:
                             ProxyInfo proxyInfo = ProxyInfo.buildDirectProxy(proxyHost, proxyPort,
                                     ProxyUtils.exclusionStringAsList(exclusionList));
-                            config.proxySettings = proxySettings;
-                            config.httpProxy = proxyInfo;
+                            config.setProxySettings(proxySettings);
+                            config.setHttpProxy(proxyInfo);
                             break;
                         case PAC:
                             ProxyInfo proxyPacProperties =
                                     ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
-                            config.proxySettings = proxySettings;
-                            config.httpProxy = proxyPacProperties;
+                            config.setProxySettings(proxySettings);
+                            config.setHttpProxy(proxyPacProperties);
                             break;
                         case NONE:
-                            config.proxySettings = proxySettings;
+                            config.setProxySettings(proxySettings);
                             break;
                         case UNASSIGNED:
                             loge("BUG: Found UNASSIGNED proxy on file, use NONE");
-                            config.proxySettings = ProxySettings.NONE;
+                            config.setProxySettings(ProxySettings.NONE);
                             break;
                         default:
                             loge("Ignore invalid proxy settings while reading");
-                            config.proxySettings = ProxySettings.UNASSIGNED;
+                            config.setProxySettings(ProxySettings.UNASSIGNED);
                             break;
                     }
                 } else {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index d0aa28b..1b5bb95 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2341,8 +2341,6 @@
             params.packageName = packageName;
             params.windowAnimations = win.getWindowStyle().getResourceId(
                     com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
-            params.privateFlags |=
-                    WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
             params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
             // Setting as trusted overlay to let touches pass through. This is safe because this
             // window is controlled by the system.
diff --git a/services/core/java/com/android/server/timezone/TimeZoneUpdateIdler.java b/services/core/java/com/android/server/timezone/TimeZoneUpdateIdler.java
index a7767a4..23e3eba 100644
--- a/services/core/java/com/android/server/timezone/TimeZoneUpdateIdler.java
+++ b/services/core/java/com/android/server/timezone/TimeZoneUpdateIdler.java
@@ -16,8 +16,6 @@
 
 package com.android.server.timezone;
 
-import com.android.server.LocalServices;
-
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
 import android.app.job.JobScheduler;
@@ -26,6 +24,8 @@
 import android.content.Context;
 import android.util.Slog;
 
+import com.android.server.LocalServices;
+
 /**
  * A JobService used to trigger time zone rules update work when a device falls idle.
  */
@@ -55,7 +55,7 @@
     @Override
     public boolean onStopJob(JobParameters params) {
         // Reschedule if stopped unless it was cancelled due to unschedule().
-        boolean reschedule = params.getStopReason() != JobParameters.REASON_CANCELED;
+        boolean reschedule = params.getStopReason() != JobParameters.STOP_REASON_CANCELLED_BY_APP;
         Slog.d(TAG, "onStopJob() called: Reschedule=" + reschedule);
         return reschedule;
     }
diff --git a/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java
index 4fa920e..f054c57 100644
--- a/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java
@@ -47,7 +47,7 @@
             @NonNull String providerName,
             @NonNull LocationTimeZoneProviderProxy proxy) {
         super(providerMetricsLogger, threadingDomain, providerName,
-                new ZoneInfoDbTimeZoneIdValidator());
+                new ZoneInfoDbTimeZoneProviderEventPreProcessor());
         mProxy = Objects.requireNonNull(proxy);
     }
 
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
index cc815dc6..e116a87 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
@@ -20,7 +20,6 @@
 import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESULT_SUCCESS_KEY;
 
 import static com.android.server.timezonedetector.location.LocationTimeZoneManagerService.debugLog;
-import static com.android.server.timezonedetector.location.LocationTimeZoneManagerService.infoLog;
 import static com.android.server.timezonedetector.location.LocationTimeZoneManagerService.warnLog;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
@@ -86,18 +85,6 @@
     }
 
     /**
-     * Used by {@link LocationTimeZoneProvider} to check if time zone IDs are understood
-     * by the platform.
-     */
-    interface TimeZoneIdValidator {
-
-        /**
-         * Returns whether {@code timeZoneId} is supported by the platform or not.
-         */
-        boolean isValid(@NonNull String timeZoneId);
-    }
-
-    /**
      * Listener interface used to log provider events for metrics.
      */
     interface ProviderMetricsLogger {
@@ -386,19 +373,20 @@
     // Non-null and effectively final after initialize() is called.
     ProviderListener mProviderListener;
 
-    @NonNull private TimeZoneIdValidator mTimeZoneIdValidator;
+    @NonNull private final TimeZoneProviderEventPreProcessor mTimeZoneProviderEventPreProcessor;
 
     /** Creates the instance. */
     LocationTimeZoneProvider(@NonNull ProviderMetricsLogger providerMetricsLogger,
             @NonNull ThreadingDomain threadingDomain,
             @NonNull String providerName,
-            @NonNull TimeZoneIdValidator timeZoneIdValidator) {
+            @NonNull TimeZoneProviderEventPreProcessor timeZoneProviderEventPreProcessor) {
         mThreadingDomain = Objects.requireNonNull(threadingDomain);
         mProviderMetricsLogger = Objects.requireNonNull(providerMetricsLogger);
         mInitializationTimeoutQueue = threadingDomain.createSingleRunnableQueue();
         mSharedLock = threadingDomain.getLockObject();
         mProviderName = Objects.requireNonNull(providerName);
-        mTimeZoneIdValidator = Objects.requireNonNull(timeZoneIdValidator);
+        mTimeZoneProviderEventPreProcessor =
+                Objects.requireNonNull(timeZoneProviderEventPreProcessor);
     }
 
     /**
@@ -639,24 +627,8 @@
         mThreadingDomain.assertCurrentThread();
         Objects.requireNonNull(timeZoneProviderEvent);
 
-        // If the provider has made a suggestion with unknown time zone IDs it cannot be used to set
-        // the device's time zone. This logic prevents bad time zone IDs entering the time zone
-        // detection logic from third party code.
-        //
-        // An event containing an unknown time zone ID could occur if the provider is using a
-        // different TZDB version than the device. Provider developers are expected to take steps to
-        // avoid version skew problem, e.g. by ensuring atomic updates with the platform time zone
-        // rules, or providing IDs based on the device's TZDB version, so this is not considered a
-        // common case.
-        //
-        // Treating a suggestion containing unknown time zone IDs as "uncertain" in the primary
-        // enables immediate failover to a secondary provider, one that might provide valid IDs for
-        // the same location, which should provide better behavior than just ignoring the event.
-        if (hasInvalidTimeZones(timeZoneProviderEvent)) {
-            infoLog("event=" + timeZoneProviderEvent + " has unsupported time zones. "
-                    + "Replacing it with uncertain event.");
-            timeZoneProviderEvent = TimeZoneProviderEvent.createUncertainEvent();
-        }
+        timeZoneProviderEvent =
+                mTimeZoneProviderEventPreProcessor.preProcess(timeZoneProviderEvent);
 
         synchronized (mSharedLock) {
             debugLog("handleTimeZoneProviderEvent: mProviderName=" + mProviderName
@@ -755,20 +727,6 @@
         }
     }
 
-    private boolean hasInvalidTimeZones(@NonNull TimeZoneProviderEvent event) {
-        if (event.getSuggestion() == null) {
-            return false;
-        }
-
-        for (String timeZone : event.getSuggestion().getTimeZoneIds()) {
-            if (!mTimeZoneIdValidator.isValid(timeZone)) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
     @GuardedBy("mSharedLock")
     private void assertIsStarted() {
         ProviderState currentState = mCurrentState.get();
diff --git a/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidator.java b/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderEventPreProcessor.java
similarity index 64%
rename from services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidator.java
rename to services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderEventPreProcessor.java
index cab5ad2..951e9d0 100644
--- a/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidator.java
+++ b/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderEventPreProcessor.java
@@ -18,13 +18,16 @@
 
 import android.annotation.NonNull;
 
-import com.android.i18n.timezone.ZoneInfoDb;
+/**
+ * Used by {@link LocationTimeZoneProvider} to ensure that all time zone IDs are understood by the
+ * platform.
+ */
+public interface TimeZoneProviderEventPreProcessor {
 
-class ZoneInfoDbTimeZoneIdValidator implements
-        LocationTimeZoneProvider.TimeZoneIdValidator {
+    /**
+     * May return uncertain event if {@code timeZoneProviderEvent} is ill-formed or drop/rewrite
+     * time zone IDs.
+     */
+    TimeZoneProviderEvent preProcess(@NonNull TimeZoneProviderEvent timeZoneProviderEvent);
 
-    @Override
-    public boolean isValid(@NonNull String timeZoneId) {
-        return ZoneInfoDb.getInstance().hasTimeZone(timeZoneId);
-    }
 }
diff --git a/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessor.java b/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessor.java
new file mode 100644
index 0000000..0f4367d
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessor.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector.location;
+
+import static com.android.server.timezonedetector.location.LocationTimeZoneManagerService.infoLog;
+
+import android.annotation.NonNull;
+
+import com.android.i18n.timezone.ZoneInfoDb;
+
+/**
+ * {@link TimeZoneProviderEventPreProcessor} implementation which makes validations against
+ * {@link ZoneInfoDb}.
+ */
+public class ZoneInfoDbTimeZoneProviderEventPreProcessor
+        implements TimeZoneProviderEventPreProcessor {
+
+    /**
+     * Returns uncertain event if {@code event} has at least one unsupported time zone ID.
+     */
+    @Override
+    public TimeZoneProviderEvent preProcess(@NonNull TimeZoneProviderEvent event) {
+        if (event.getSuggestion() == null || event.getSuggestion().getTimeZoneIds().isEmpty()) {
+            return event;
+        }
+
+        // If the provider has made a suggestion with unknown time zone IDs it cannot be used to set
+        // the device's time zone. This logic prevents bad time zone IDs entering the time zone
+        // detection logic from third party code.
+        //
+        // An event containing an unknown time zone ID could occur if the provider is using a
+        // different TZDB version than the device. Provider developers are expected to take steps to
+        // avoid version skew problem, e.g. by ensuring atomic updates with the platform time zone
+        // rules, or providing IDs based on the device's TZDB version, so this is not considered a
+        // common case.
+        //
+        // Treating a suggestion containing unknown time zone IDs as "uncertain" in the primary
+        // enables immediate failover to a secondary provider, one that might provide valid IDs for
+        // the same location, which should provide better behavior than just ignoring the event.
+        if (hasInvalidZones(event)) {
+            return TimeZoneProviderEvent.createUncertainEvent();
+        }
+
+        return event;
+    }
+
+    private static boolean hasInvalidZones(TimeZoneProviderEvent event) {
+        for (String timeZone : event.getSuggestion().getTimeZoneIds()) {
+            if (!ZoneInfoDb.getInstance().hasTimeZone(timeZone)) {
+                infoLog("event=" + event + " has unsupported zone(" + timeZone + ")");
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 46913eb..29c5cec 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -251,6 +251,7 @@
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.ActivityManagerServiceDumpProcessesProto;
 import com.android.server.am.AppTimeTracker;
+import com.android.server.am.AssistDataRequester;
 import com.android.server.am.BaseErrorDialog;
 import com.android.server.am.PendingIntentController;
 import com.android.server.am.PendingIntentRecord;
@@ -2828,10 +2829,45 @@
 
     @Override
     public boolean requestAssistContextExtras(int requestType, IAssistDataReceiver receiver,
-            Bundle receiverExtras, IBinder activityToken, boolean focused, boolean newSessionId) {
+            Bundle receiverExtras, IBinder activityToken, boolean checkActivityIsTop,
+            boolean newSessionId) {
         return enqueueAssistContext(requestType, null, null, receiver, receiverExtras,
-                activityToken, focused, newSessionId, UserHandle.getCallingUserId(), null,
-                PENDING_ASSIST_EXTRAS_LONG_TIMEOUT, 0) != null;
+                activityToken, checkActivityIsTop, newSessionId, UserHandle.getCallingUserId(),
+                null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT, 0) != null;
+    }
+
+    @Override
+    public boolean requestAssistDataForTask(IAssistDataReceiver receiver, int taskId,
+            String callingPackageName) {
+        mAmInternal.enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
+                "requestAssistDataForTask()");
+        final long callingId = Binder.clearCallingIdentity();
+        LocalService.ActivityTokens tokens = null;
+        try {
+            tokens = mInternal.getTopActivityForTask(taskId);
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+        if (tokens == null) {
+            Log.e(TAG, "Could not find activity for task " + taskId);
+            return false;
+        }
+
+        final AssistDataReceiverProxy proxy =
+                new AssistDataReceiverProxy(receiver, callingPackageName);
+        Object lock = new Object();
+        AssistDataRequester requester = new AssistDataRequester(mContext, mWindowManager,
+                getAppOpsManager(), proxy, lock, AppOpsManager.OP_ASSIST_STRUCTURE,
+                AppOpsManager.OP_NONE);
+
+        List<IBinder> topActivityToken = new ArrayList<>();
+        topActivityToken.add(tokens.getActivityToken());
+        requester.requestAssistData(topActivityToken, true /* fetchData */,
+                false /* fetchScreenshot */, true /* allowFetchData */,
+                false /* allowFetchScreenshot*/, true /* ignoreFocusCheck */,
+                Binder.getCallingUid(), callingPackageName);
+
+        return true;
     }
 
     @Override
@@ -2845,7 +2881,7 @@
     @Override
     public Bundle getAssistContextExtras(int requestType) {
         PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
-                null, null, true /* focused */, true /* newSessionId */,
+                null, null, true /* checkActivityIsTop */, true /* newSessionId */,
                 UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT, 0);
         if (pae == null) {
             return null;
@@ -3048,8 +3084,8 @@
 
     private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
             IAssistDataReceiver receiver, Bundle receiverExtras, IBinder activityToken,
-            boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout,
-            int flags) {
+            boolean checkActivityIsTop, boolean newSessionId, int userHandle, Bundle args,
+            long timeout, int flags) {
         mAmInternal.enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
                 "enqueueAssistContext()");
 
@@ -3065,7 +3101,7 @@
                 Slog.w(TAG, "getAssistContextExtras failed: no process for " + activity);
                 return null;
             }
-            if (focused) {
+            if (checkActivityIsTop) {
                 if (activityToken != null) {
                     ActivityRecord caller = ActivityRecord.forTokenLocked(activityToken);
                     if (activity != caller) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 7925b69..0fcda81 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -660,15 +660,19 @@
                 new JobInfo.Builder(101, new ComponentName("foo", "bar")).build());
 
         markImplicitConstraintsSatisfied(job, false);
-        job.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+        job.setBackgroundNotRestrictedConstraintSatisfied(
+                sElapsedRealtimeClock.millis(), false, false);
         assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
-        job.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+        job.setBackgroundNotRestrictedConstraintSatisfied(
+                sElapsedRealtimeClock.millis(), true, false);
         assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
 
         markImplicitConstraintsSatisfied(job, true);
-        job.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
+        job.setBackgroundNotRestrictedConstraintSatisfied(
+                sElapsedRealtimeClock.millis(), false, false);
         assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
-        job.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+        job.setBackgroundNotRestrictedConstraintSatisfied(
+                sElapsedRealtimeClock.millis(), true, false);
         assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
     }
 
@@ -677,7 +681,7 @@
         job.setDeviceNotDozingConstraintSatisfied(
                 sElapsedRealtimeClock.millis(), isSatisfied, false);
         job.setBackgroundNotRestrictedConstraintSatisfied(
-                sElapsedRealtimeClock.millis(), isSatisfied);
+                sElapsedRealtimeClock.millis(), isSatisfied, false);
     }
 
     private static JobStatus createJobStatus(long earliestRunTimeElapsedMillis,
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index f73af53..ee1a4f4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -384,7 +384,8 @@
         // Make sure Doze and background-not-restricted don't affect tests.
         js.setDeviceNotDozingConstraintSatisfied(/* nowElapsed */ sElapsedRealtimeClock.millis(),
                 /* state */ true, /* allowlisted */false);
-        js.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
+        js.setBackgroundNotRestrictedConstraintSatisfied(
+                sElapsedRealtimeClock.millis(), true, false);
         return js;
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeLocationPowerSaveModeHelper.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeLocationPowerSaveModeHelper.java
index 0597443..ef48646 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeLocationPowerSaveModeHelper.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeLocationPowerSaveModeHelper.java
@@ -19,8 +19,6 @@
 import android.os.IPowerManager;
 import android.os.PowerManager.LocationPowerSaveMode;
 
-import com.android.server.location.eventlog.LocationEventLog;
-
 /**
  * Version of LocationPowerSaveModeHelper for testing. Power save mode is initialized as "no
  * change".
@@ -30,8 +28,7 @@
     @LocationPowerSaveMode
     private int mLocationPowerSaveMode;
 
-    public FakeLocationPowerSaveModeHelper(LocationEventLog locationEventLog) {
-        super(locationEventLog);
+    public FakeLocationPowerSaveModeHelper() {
         mLocationPowerSaveMode = IPowerManager.LOCATION_MODE_NO_CHANGE;
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/SystemLocationPowerSaveModeHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/SystemLocationPowerSaveModeHelperTest.java
index 6156ba9..28da027 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/SystemLocationPowerSaveModeHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/SystemLocationPowerSaveModeHelperTest.java
@@ -43,7 +43,6 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.LocalServices;
-import com.android.server.location.eventlog.LocationEventLog;
 import com.android.server.location.injector.LocationPowerSaveModeHelper.LocationPowerSaveModeChangedListener;
 
 import org.junit.After;
@@ -85,7 +84,7 @@
         Context context = mock(Context.class);
         doReturn(powerManager).when(context).getSystemService(PowerManager.class);
 
-        mHelper = new SystemLocationPowerSaveModeHelper(context, new LocationEventLog());
+        mHelper = new SystemLocationPowerSaveModeHelper(context);
         mHelper.onSystemReady();
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
index 1f102ac..ae70dad 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
@@ -16,8 +16,6 @@
 
 package com.android.server.location.injector;
 
-import com.android.server.location.eventlog.LocationEventLog;
-
 public class TestInjector implements Injector {
 
     private final FakeUserInfoHelper mUserInfoHelper;
@@ -35,17 +33,13 @@
     private final LocationUsageLogger mLocationUsageLogger;
 
     public TestInjector() {
-        this(new LocationEventLog());
-    }
-
-    public TestInjector(LocationEventLog eventLog) {
         mUserInfoHelper = new FakeUserInfoHelper();
         mAlarmHelper = new FakeAlarmHelper();
         mAppOpsHelper = new FakeAppOpsHelper();
         mLocationPermissionsHelper = new FakeLocationPermissionsHelper(mAppOpsHelper);
         mSettingsHelper = new FakeSettingsHelper();
         mAppForegroundHelper = new FakeAppForegroundHelper();
-        mLocationPowerSaveModeHelper = new FakeLocationPowerSaveModeHelper(eventLog);
+        mLocationPowerSaveModeHelper = new FakeLocationPowerSaveModeHelper();
         mScreenInteractiveHelper = new FakeScreenInteractiveHelper();
         mDeviceStationaryHelper = new FakeDeviceStationaryHelper();
         mDeviceIdleHelper = new FakeDeviceIdleHelper();
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 1b58e92..24b85f0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -83,7 +83,6 @@
 
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
-import com.android.server.location.eventlog.LocationEventLog;
 import com.android.server.location.injector.FakeUserInfoHelper;
 import com.android.server.location.injector.TestInjector;
 
@@ -161,19 +160,17 @@
         doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
         doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
 
-        LocationEventLog eventLog = new LocationEventLog();
-
-        mInjector = new TestInjector(eventLog);
+        mInjector = new TestInjector();
         mInjector.getUserInfoHelper().startUser(OTHER_USER);
 
-        mPassive = new PassiveLocationProviderManager(mContext, mInjector, eventLog);
+        mPassive = new PassiveLocationProviderManager(mContext, mInjector);
         mPassive.startManager();
         mPassive.setRealProvider(new PassiveLocationProvider(mContext));
 
         mProvider = new TestProvider(PROPERTIES, PROVIDER_IDENTITY);
         mProvider.setProviderAllowed(true);
 
-        mManager = new LocationProviderManager(mContext, mInjector, eventLog, NAME, mPassive);
+        mManager = new LocationProviderManager(mContext, mInjector, NAME, mPassive);
         mManager.startManager();
         mManager.setRealProvider(mProvider);
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
index c3cca64..04e0151 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
@@ -36,7 +36,6 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.server.location.eventlog.LocationEventLog;
 import com.android.server.location.injector.TestInjector;
 import com.android.server.location.test.FakeProvider;
 
@@ -77,7 +76,7 @@
         mDelegateProvider = new FakeProvider(mDelegate);
 
         mProvider = new StationaryThrottlingLocationProvider("test_provider", mInjector,
-                mDelegateProvider, new LocationEventLog());
+                mDelegateProvider);
         mProvider.getController().setListener(mListener);
         mProvider.getController().start();
     }
diff --git a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
index a7b32ac..68a6e60 100644
--- a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
@@ -96,7 +96,7 @@
                     case ACTION_JOB_STOPPED:
                         mTestJobStatus.running = false;
                         mTestJobStatus.jobId = params.getJobId();
-                        mTestJobStatus.stopReason = params.getStopReason();
+                        mTestJobStatus.stopReason = params.getLegacyStopReason();
                         break;
                 }
             }
diff --git a/services/tests/servicestests/src/com/android/server/job/MockPriorityJobService.java b/services/tests/servicestests/src/com/android/server/job/MockPriorityJobService.java
index 3ea86f2..87881bf 100644
--- a/services/tests/servicestests/src/com/android/server/job/MockPriorityJobService.java
+++ b/services/tests/servicestests/src/com/android/server/job/MockPriorityJobService.java
@@ -47,7 +47,7 @@
         int reason = params.getStopReason();
         int event = TestEnvironment.EVENT_STOP_JOB;
         Log.d(TAG, "stop reason: " + String.valueOf(reason));
-        if (reason == JobParameters.REASON_PREEMPT) {
+        if (reason == JobParameters.STOP_REASON_PREEMPT) {
             event = TestEnvironment.EVENT_PREEMPT_JOB;
             Log.d(TAG, "preempted " + String.valueOf(params.getJobId()));
         }
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
index 5a100a2..a0e9d97 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
@@ -72,7 +72,6 @@
     private TestCallback mTestCallback;
     private TestLocationTimeZoneProvider mTestPrimaryLocationTimeZoneProvider;
     private TestLocationTimeZoneProvider mTestSecondaryLocationTimeZoneProvider;
-    private FakeTimeZoneIdValidator mTimeZoneAvailabilityChecker;
 
     @Before
     public void setUp() {
@@ -84,13 +83,10 @@
         };
         mTestThreadingDomain = new TestThreadingDomain();
         mTestCallback = new TestCallback(mTestThreadingDomain);
-        mTimeZoneAvailabilityChecker = new FakeTimeZoneIdValidator();
         mTestPrimaryLocationTimeZoneProvider = new TestLocationTimeZoneProvider(
-                stubbedProviderMetricsLogger, mTestThreadingDomain, "primary",
-                mTimeZoneAvailabilityChecker);
+                stubbedProviderMetricsLogger, mTestThreadingDomain, "primary");
         mTestSecondaryLocationTimeZoneProvider = new TestLocationTimeZoneProvider(
-                stubbedProviderMetricsLogger, mTestThreadingDomain, "secondary",
-                mTimeZoneAvailabilityChecker);
+                stubbedProviderMetricsLogger, mTestThreadingDomain, "secondary");
     }
 
     @Test
@@ -1185,10 +1181,9 @@
          * Creates the instance.
          */
         TestLocationTimeZoneProvider(ProviderMetricsLogger providerMetricsLogger,
-                ThreadingDomain threadingDomain, String providerName,
-                TimeZoneIdValidator timeZoneIdValidator) {
+                ThreadingDomain threadingDomain, String providerName) {
             super(providerMetricsLogger, threadingDomain, providerName,
-                    timeZoneIdValidator);
+                    new FakeTimeZoneProviderEventPreProcessor());
         }
 
         public void setFailDuringInitialization(boolean failInitialization) {
@@ -1321,14 +1316,4 @@
             mTestProviderState.commitLatest();
         }
     }
-
-    private static final class FakeTimeZoneIdValidator
-            implements LocationTimeZoneProvider.TimeZoneIdValidator {
-
-        @Override
-        public boolean isValid(@NonNull String timeZoneId) {
-            return true;
-        }
-
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/FakeTimeZoneProviderEventPreProcessor.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/FakeTimeZoneProviderEventPreProcessor.java
new file mode 100644
index 0000000..e75d05c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/FakeTimeZoneProviderEventPreProcessor.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector.location;
+
+/**
+ * Fake implementation of {@link TimeZoneProviderEventPreProcessor} which assumes that all events
+ * are valid or always uncertain if {@link #enterUncertainMode()} was called.
+ */
+public final class FakeTimeZoneProviderEventPreProcessor
+        implements TimeZoneProviderEventPreProcessor {
+
+    private boolean mIsUncertain = false;
+
+    @Override
+    public TimeZoneProviderEvent preProcess(TimeZoneProviderEvent timeZoneProviderEvent) {
+        if (mIsUncertain) {
+            return TimeZoneProviderEvent.createUncertainEvent();
+        }
+        return timeZoneProviderEvent;
+    }
+
+    public void enterUncertainMode() {
+        mIsUncertain = true;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
index d13a04e..0edb559 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
@@ -52,10 +52,8 @@
 
 import java.time.Duration;
 import java.util.Arrays;
-import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -68,13 +66,13 @@
 
     private TestThreadingDomain mTestThreadingDomain;
     private TestProviderListener mProviderListener;
-    private FakeTimeZoneIdValidator mTimeZoneAvailabilityChecker;
+    private FakeTimeZoneProviderEventPreProcessor mTimeZoneProviderEventPreProcessor;
 
     @Before
     public void setUp() {
         mTestThreadingDomain = new TestThreadingDomain();
         mProviderListener = new TestProviderListener();
-        mTimeZoneAvailabilityChecker = new FakeTimeZoneIdValidator();
+        mTimeZoneProviderEventPreProcessor = new FakeTimeZoneProviderEventPreProcessor();
     }
 
     @Test
@@ -82,9 +80,10 @@
         String providerName = "arbitrary";
         RecordingProviderMetricsLogger providerMetricsLogger = new RecordingProviderMetricsLogger();
         TestLocationTimeZoneProvider provider = new TestLocationTimeZoneProvider(
-                providerMetricsLogger, mTestThreadingDomain, providerName,
-                mTimeZoneAvailabilityChecker);
-        mTimeZoneAvailabilityChecker.validIds("Europe/London");
+                providerMetricsLogger,
+                mTestThreadingDomain,
+                providerName,
+                mTimeZoneProviderEventPreProcessor);
 
         // initialize()
         provider.initialize(mProviderListener);
@@ -174,8 +173,10 @@
         String providerName = "primary";
         StubbedProviderMetricsLogger providerMetricsLogger = new StubbedProviderMetricsLogger();
         TestLocationTimeZoneProvider provider = new TestLocationTimeZoneProvider(
-                providerMetricsLogger, mTestThreadingDomain, providerName,
-                mTimeZoneAvailabilityChecker);
+                providerMetricsLogger,
+                mTestThreadingDomain,
+                providerName,
+                mTimeZoneProviderEventPreProcessor);
 
         TestCommand testCommand = TestCommand.createForTests("test", new Bundle());
         AtomicReference<Bundle> resultReference = new AtomicReference<>();
@@ -193,10 +194,11 @@
         String providerName = "primary";
         StubbedProviderMetricsLogger providerMetricsLogger = new StubbedProviderMetricsLogger();
         TestLocationTimeZoneProvider provider = new TestLocationTimeZoneProvider(
-                providerMetricsLogger, mTestThreadingDomain, providerName,
-                mTimeZoneAvailabilityChecker);
+                providerMetricsLogger,
+                mTestThreadingDomain,
+                providerName,
+                mTimeZoneProviderEventPreProcessor);
         provider.setStateChangeRecordingEnabled(true);
-        mTimeZoneAvailabilityChecker.validIds("Europe/London");
 
         // initialize()
         provider.initialize(mProviderListener);
@@ -234,14 +236,17 @@
     }
 
     @Test
-    public void considerSuggestionWithInvalidTimeZoneIdsAsUncertain() {
+    public void entersUncertainState_whenEventHasUnsupportedZones() {
         String providerName = "primary";
         StubbedProviderMetricsLogger providerMetricsLogger = new StubbedProviderMetricsLogger();
         TestLocationTimeZoneProvider provider = new TestLocationTimeZoneProvider(
-                providerMetricsLogger, mTestThreadingDomain, providerName,
-                mTimeZoneAvailabilityChecker);
+                providerMetricsLogger,
+                mTestThreadingDomain,
+                providerName,
+                mTimeZoneProviderEventPreProcessor);
         provider.setStateChangeRecordingEnabled(true);
         provider.initialize(mProviderListener);
+        mTimeZoneProviderEventPreProcessor.enterUncertainMode();
 
         ConfigurationInternal config = USER1_CONFIG_GEO_DETECTION_ENABLED;
         Duration arbitraryInitializationTimeout = Duration.ofMinutes(5);
@@ -309,8 +314,9 @@
         TestLocationTimeZoneProvider(@NonNull ProviderMetricsLogger providerMetricsLogger,
                 @NonNull ThreadingDomain threadingDomain,
                 @NonNull String providerName,
-                @NonNull TimeZoneIdValidator timeZoneIdValidator) {
-            super(providerMetricsLogger, threadingDomain, providerName, timeZoneIdValidator);
+                @NonNull TimeZoneProviderEventPreProcessor timeZoneProviderEventPreProcessor) {
+            super(providerMetricsLogger,
+                    threadingDomain, providerName, timeZoneProviderEventPreProcessor);
         }
 
         @Override
@@ -367,20 +373,6 @@
         }
     }
 
-    private static final class FakeTimeZoneIdValidator
-            implements LocationTimeZoneProvider.TimeZoneIdValidator {
-        private final Set<String> mValidTimeZoneIds = new HashSet<>();
-
-        @Override
-        public boolean isValid(@NonNull String timeZoneId) {
-            return mValidTimeZoneIds.contains(timeZoneId);
-        }
-
-        public void validIds(String... timeZoneIdss) {
-            mValidTimeZoneIds.addAll(asList(timeZoneIdss));
-        }
-    }
-
     private static class StubbedProviderMetricsLogger implements
             LocationTimeZoneProvider.ProviderMetricsLogger {
 
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidatorTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidatorTest.java
deleted file mode 100644
index 5561b2c..0000000
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidatorTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezonedetector.location;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.TimeZone;
-
-@Presubmit
-public class ZoneInfoDbTimeZoneIdValidatorTest {
-    private final LocationTimeZoneProvider.TimeZoneIdValidator mTzChecker =
-            new ZoneInfoDbTimeZoneIdValidator();
-
-    @Test
-    public void timeZoneIdsFromZoneInfoDbAreValid() {
-        for (String timeZone : TimeZone.getAvailableIDs()) {
-            assertWithMessage("Time zone %s should be supported", timeZone)
-                    .that(mTzChecker.isValid(timeZone)).isTrue();
-        }
-    }
-
-    @Test
-    public void nonExistingZones_areNotSupported() {
-        List<String> nonExistingTimeZones = Arrays.asList(
-                "SystemV/HST10", "Atlantic/Atlantis", "EUROPE/LONDON", "Etc/GMT-5:30"
-        );
-
-        for (String timeZone : nonExistingTimeZones) {
-            assertWithMessage(timeZone + " is not a valid time zone")
-                    .that(mTzChecker.isValid(timeZone))
-                    .isFalse();
-        }
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java
new file mode 100644
index 0000000..173705be
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector.location;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.platform.test.annotations.Presubmit;
+import android.service.timezone.TimeZoneProviderSuggestion;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.TimeZone;
+
+/** Tests for {@link ZoneInfoDbTimeZoneProviderEventPreProcessor}. */
+@Presubmit
+public class ZoneInfoDbTimeZoneProviderEventPreProcessorTest {
+
+    private static final long ARBITRARY_TIME_MILLIS = 11223344;
+
+    private final ZoneInfoDbTimeZoneProviderEventPreProcessor mPreProcessor =
+            new ZoneInfoDbTimeZoneProviderEventPreProcessor();
+
+    @Test
+    public void timeZoneIdsFromZoneInfoDbAreValid() {
+        for (String timeZone : TimeZone.getAvailableIDs()) {
+            TimeZoneProviderEvent event = timeZoneProviderEvent(timeZone);
+            assertWithMessage("Time zone %s should be supported", timeZone)
+                    .that(mPreProcessor.preProcess(event)).isEqualTo(event);
+        }
+    }
+
+    @Test
+    public void eventWithNonExistingZones_areMappedToUncertainEvent() {
+        List<String> nonExistingTimeZones = Arrays.asList(
+                "SystemV/HST10", "Atlantic/Atlantis", "EUROPE/LONDON", "Etc/GMT-5:30");
+
+        for (String timeZone : nonExistingTimeZones) {
+            TimeZoneProviderEvent event = timeZoneProviderEvent(timeZone);
+
+            assertWithMessage(timeZone + " is not a valid time zone")
+                    .that(mPreProcessor.preProcess(event))
+                    .isEqualTo(TimeZoneProviderEvent.createUncertainEvent());
+        }
+    }
+
+    private static TimeZoneProviderEvent timeZoneProviderEvent(String... timeZoneIds) {
+        return TimeZoneProviderEvent.createSuggestionEvent(
+                new TimeZoneProviderSuggestion.Builder()
+                        .setTimeZoneIds(Arrays.asList(timeZoneIds))
+                        .setElapsedRealtimeMillis(ARBITRARY_TIME_MILLIS)
+                .build());
+    }
+
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
index b9ffd65..a37d5c8 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
@@ -31,9 +31,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.media.session.MediaSession;
 import android.os.Build;
-import android.os.Process;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
@@ -73,7 +71,6 @@
     private NotificationRecord mRecordMinCallNonInterruptive;
     private NotificationRecord mRecordMinCall;
     private NotificationRecord mRecordHighCall;
-    private NotificationRecord mRecordDefaultMedia;
     private NotificationRecord mRecordEmail;
     private NotificationRecord mRecordInlineReply;
     private NotificationRecord mRecordSms;
@@ -139,15 +136,6 @@
                 new UserHandle(userId), "", 1999), getDefaultChannel());
         mRecordHighCall.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
 
-        Notification n3 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
-                .setStyle(new Notification.MediaStyle()
-                        .setMediaSession(new MediaSession.Token(Process.myUid(), null)))
-                .build();
-        mRecordDefaultMedia = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
-                pkg2, 1, "media", uid2, uid2, n3, new UserHandle(userId),
-                "", 1499), getDefaultChannel());
-        mRecordDefaultMedia.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
-
         Notification n4 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
                 .setStyle(new Notification.MessagingStyle("sender!")).build();
         mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
@@ -218,7 +206,7 @@
                 .setStyle(new Notification.MediaStyle())
                 .build();
         mNoMediaSessionMedia = new NotificationRecord(mContext, new StatusBarNotification(
-                pkg2, pkg2, 1, "cheater", uid2, uid2, n12, new UserHandle(userId),
+                pkg2, pkg2, 1, "media", uid2, uid2, n12, new UserHandle(userId),
                 "", 9258), getDefaultChannel());
         mNoMediaSessionMedia.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
 
@@ -247,7 +235,6 @@
         final List<NotificationRecord> expected = new ArrayList<>();
         expected.add(mRecordColorizedCall);
         expected.add(mRecordColorized);
-        expected.add(mRecordDefaultMedia);
         expected.add(mRecordHighCall);
         expected.add(mRecordInlineReply);
         if (mRecordSms != null) {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index f7580d7..a46621a 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -630,7 +630,7 @@
                     D2D_SHARING_STARRED_CONTACTS,
                     D2D_SHARING_ALL
             })
-    public @interface DeviceToDeviceStatusSharing {}
+    public @interface DeviceToDeviceStatusSharingPreference {}
 
     /**
      * TelephonyProvider column name for device to device sharing status.
@@ -3415,29 +3415,31 @@
      * app uses this method to indicate with whom they wish to share device to device status
      * information.
      * @param sharing the status sharing preference
-     * @param subId the unique Subscription ID in database
+     * @param subscriptionId the unique Subscription ID in database
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
-    public void setDeviceToDeviceStatusSharing(@DeviceToDeviceStatusSharing int sharing,
-            int subId) {
+    public void setDeviceToDeviceStatusSharingPreference(
+            @DeviceToDeviceStatusSharingPreference int sharing, int subscriptionId) {
         if (VDBG) {
-            logd("[setDeviceToDeviceStatusSharing] + sharing: " + sharing + " subId: " + subId);
+            logd("[setDeviceToDeviceStatusSharing] + sharing: " + sharing + " subId: "
+                    + subscriptionId);
         }
-        setSubscriptionPropertyHelper(subId, "setDeviceToDeviceSharingStatus",
-                (iSub)->iSub.setDeviceToDeviceStatusSharing(sharing, subId));
+        setSubscriptionPropertyHelper(subscriptionId, "setDeviceToDeviceSharingStatus",
+                (iSub)->iSub.setDeviceToDeviceStatusSharing(sharing, subscriptionId));
     }
 
     /**
      * Returns the user-chosen device to device status sharing preference
-     * @param subId Subscription id of subscription
+     * @param subscriptionId Subscription id of subscription
      * @return The device to device status sharing preference
      */
-    public @DeviceToDeviceStatusSharing int getDeviceToDeviceStatusSharing(int subId) {
+    public @DeviceToDeviceStatusSharingPreference int getDeviceToDeviceStatusSharingPreference(
+            int subscriptionId) {
         if (VDBG) {
-            logd("[getDeviceToDeviceStatusSharing] + subId: " + subId);
+            logd("[getDeviceToDeviceStatusSharing] + subId: " + subscriptionId);
         }
-        return getIntegerSubscriptionProperty(subId, D2D_STATUS_SHARING, D2D_SHARING_DISABLED,
-                mContext);
+        return getIntegerSubscriptionProperty(subscriptionId, D2D_STATUS_SHARING,
+                D2D_SHARING_DISABLED, mContext);
     }
 
     /**
diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
index a4d8353..fd126ad 100644
--- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
+++ b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
@@ -44,7 +44,7 @@
             setPartialConnectivityAcceptable(false)
             setUnvalidatedConnectivityAcceptable(true)
         }.build()
-        assertParcelSane(config, 10)
+        assertParcelSane(config, 12)
     }
 
     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index d40b88c..f161e52 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -531,11 +531,22 @@
         assertFalse(nc1.equalsNetCapabilities(nc2));
         nc2.addUnwantedCapability(NET_CAPABILITY_INTERNET);
         assertTrue(nc1.equalsNetCapabilities(nc2));
+        if (isAtLeastS()) {
+            // Remove a required capability doesn't affect unwanted capabilities.
+            // This is a behaviour change from S.
+            nc1.removeCapability(NET_CAPABILITY_INTERNET);
+            assertTrue(nc1.equalsNetCapabilities(nc2));
 
-        nc1.removeCapability(NET_CAPABILITY_INTERNET);
-        assertFalse(nc1.equalsNetCapabilities(nc2));
-        nc2.removeCapability(NET_CAPABILITY_INTERNET);
-        assertTrue(nc1.equalsNetCapabilities(nc2));
+            nc1.removeUnwantedCapability(NET_CAPABILITY_INTERNET);
+            assertFalse(nc1.equalsNetCapabilities(nc2));
+            nc2.removeUnwantedCapability(NET_CAPABILITY_INTERNET);
+            assertTrue(nc1.equalsNetCapabilities(nc2));
+        } else {
+            nc1.removeCapability(NET_CAPABILITY_INTERNET);
+            assertFalse(nc1.equalsNetCapabilities(nc2));
+            nc2.removeCapability(NET_CAPABILITY_INTERNET);
+            assertTrue(nc1.equalsNetCapabilities(nc2));
+        }
     }
 
     @Test
@@ -596,11 +607,20 @@
         // This will effectively move NOT_ROAMING capability from required to unwanted for nc1.
         nc1.addUnwantedCapability(NET_CAPABILITY_NOT_ROAMING);
 
-        nc2.combineCapabilities(nc1);
-        // We will get this capability in both requested and unwanted lists thus this request
-        // will never be satisfied.
-        assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
-        assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
+        if (isAtLeastS()) {
+            // From S, it is not allowed to have the same capability in both wanted and
+            // unwanted list.
+            assertThrows(IllegalArgumentException.class, () -> nc2.combineCapabilities(nc1));
+        } else {
+            nc2.combineCapabilities(nc1);
+            // We will get this capability in both requested and unwanted lists thus this request
+            // will never be satisfied.
+            assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+            assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
+        }
+
+        // Remove unwanted capability to continue other tests.
+        nc1.removeUnwantedCapability(NET_CAPABILITY_NOT_ROAMING);
 
         nc1.setSSID(TEST_SSID);
         nc2.combineCapabilities(nc1);