Merge "SpatializerHelper: Deliver metrics to MediaMetrics" into tm-dev
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 4710322..f49cdbf 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -1777,10 +1777,7 @@
          * {@link Build.VERSION_CODES#S}, but starting from Android version
          * {@link Build.VERSION_CODES#TIRAMISU}, expedited jobs for the foreground app are
          * guaranteed to be started before {@link JobScheduler#schedule(JobInfo)} returns (assuming
-         * all requested constraints are satisfied), similar to foreground services. However, this
-         * start guarantee means there is a higher chance of overlapping executions, as noted in
-         * {@link JobService}, so be sure to handle that properly if you intend to reschedule the
-         * job while it's actively running.
+         * all requested constraints are satisfied), similar to foreground services.
          *
          * @see JobInfo#isExpedited()
          */
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
index 388bbf1..632ecb2c 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
@@ -107,9 +107,7 @@
     /**
      * Schedule a job to be executed.  Will replace any currently scheduled job with the same
      * ID with the new information in the {@link JobInfo}.  If a job with the given ID is currently
-     * running, it will be stopped. Note that in some cases, the newly scheduled job may be started
-     * before the previously running job has been fully stopped. See {@link JobService} for
-     * additional details.
+     * running, it will be stopped.
      *
      * <p class="caution"><strong>Note:</strong> Scheduling a job can have a high cost, even if it's
      * rescheduling the same job and the job didn't execute, especially on platform versions before
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobService.java b/apex/jobscheduler/framework/java/android/app/job/JobService.java
index 7ed4b62..d184d44 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobService.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobService.java
@@ -32,16 +32,11 @@
  * {@link #onStopJob(android.app.job.JobParameters)}, which is meant to inform you that the
  * scheduling requirements are no longer being met.</p>
  *
- * As a subclass of {@link Service}, there will only be one active instance of any JobService
+ * <p>As a subclass of {@link Service}, there will only be one active instance of any JobService
  * subclasses, regardless of job ID. This means that if you schedule multiple jobs with different
  * job IDs but using the same JobService class, that JobService may receive multiple calls to
  * {@link #onStartJob(JobParameters)} and {@link #onStopJob(JobParameters)}, with each call being
- * for the separate jobs.
- *
- * <p class="note">Note that if you cancel and reschedule an already executing job,
- * there may be a small period of time where {@link #onStartJob(JobParameters)} has been called for
- * the newly scheduled job instance before {@link #onStopJob(JobParameters)} has been called or
- * fully processed for the old job.</p>
+ * for the separate jobs.</p>
  */
 public abstract class JobService extends Service {
     private static final String TAG = "JobService";
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index e9ce87f..2eb86c1 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -693,6 +693,7 @@
         synchronized (DeviceIdleController.this) {
             if (mStationaryListeners.size() > 0) {
                 startMonitoringMotionLocked();
+                scheduleMotionTimeoutAlarmLocked();
             }
         }
     };
@@ -3859,7 +3860,7 @@
     void handleMotionDetectedLocked(long timeout, String type) {
         if (mStationaryListeners.size() > 0) {
             postStationaryStatusUpdated();
-            scheduleMotionTimeoutAlarmLocked();
+            cancelMotionTimeoutAlarmLocked();
             // We need to re-register the motion listener, but we don't want the sensors to be
             // constantly active or to churn the CPU by registering too early, register after some
             // delay.
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 d5a7f28..28116a8 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -717,17 +717,9 @@
 
             final boolean isTopEj = nextPending.shouldTreatAsExpeditedJob()
                     && nextPending.lastEvaluatedBias == JobInfo.BIAS_TOP_APP;
-            // Avoid overlapping job execution as much as possible.
-            if (!isTopEj && isSimilarJobRunningLocked(nextPending)) {
-                if (DEBUG) {
-                    Slog.w(TAG, "Delaying execution of job because of similarly running one: "
-                            + nextPending);
-                }
-                // It would be nice to let the JobService running the other similar job know about
-                // this new job so that it doesn't unbind from the JobService and we can call
-                // onStartJob as soon as the older job finishes.
-                // TODO: optimize the job reschedule flow to reduce service binding churn
-                continue;
+            if (DEBUG && isSimilarJobRunningLocked(nextPending)) {
+                Slog.w(TAG, "Already running similar " + (isTopEj ? "TOP-EJ" : "job")
+                        + " to: " + nextPending);
             }
 
             // Find an available slot for nextPending. The context should be one of the following:
@@ -1206,13 +1198,8 @@
                     continue;
                 }
 
-                // Avoid overlapping job execution as much as possible.
-                if (isSimilarJobRunningLocked(nextPending)) {
-                    if (DEBUG) {
-                        Slog.w(TAG, "Avoiding execution of job because of similarly running one: "
-                                + nextPending);
-                    }
-                    continue;
+                if (DEBUG && isSimilarJobRunningLocked(nextPending)) {
+                    Slog.w(TAG, "Already running similar job to: " + nextPending);
                 }
 
                 if (worker.getPreferredUid() != nextPending.getUid()) {
@@ -1298,13 +1285,8 @@
                     continue;
                 }
 
-                // Avoid overlapping job execution as much as possible.
-                if (isSimilarJobRunningLocked(nextPending)) {
-                    if (DEBUG) {
-                        Slog.w(TAG, "Avoiding execution of job because of similarly running one: "
-                                + nextPending);
-                    }
-                    continue;
+                if (DEBUG && isSimilarJobRunningLocked(nextPending)) {
+                    Slog.w(TAG, "Already running similar job to: " + nextPending);
                 }
 
                 if (isPkgConcurrencyLimitedLocked(nextPending)) {
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 cd70e88..60afdc7 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1208,22 +1208,12 @@
             // This may throw a SecurityException.
             jobStatus.prepareLocked();
 
-            final boolean canExecuteImmediately;
             if (toCancel != null) {
                 // Implicitly replaces the existing job record with the new instance
-                final boolean wasJobExecuting = cancelJobImplLocked(toCancel, jobStatus,
-                        JobParameters.STOP_REASON_CANCELLED_BY_APP,
-                        JobParameters.INTERNAL_STOP_REASON_CANCELED,
-                        "job rescheduled by app");
-                // Avoid overlapping job executions. Don't push for immediate execution if an old
-                // job with the same ID was running, but let TOP EJs start immediately.
-                canExecuteImmediately = !wasJobExecuting
-                        || (jobStatus.isRequestedExpeditedJob()
-                        && mUidBiasOverride.get(jobStatus.getSourceUid(), JobInfo.BIAS_DEFAULT)
-                        == JobInfo.BIAS_TOP_APP);
+                cancelJobImplLocked(toCancel, jobStatus, JobParameters.STOP_REASON_CANCELLED_BY_APP,
+                        JobParameters.INTERNAL_STOP_REASON_CANCELED, "job rescheduled by app");
             } else {
                 startTrackingJobLocked(jobStatus, null);
-                canExecuteImmediately = true;
             }
 
             if (work != null) {
@@ -1266,12 +1256,7 @@
                 // list and try to run it.
                 mJobPackageTracker.notePending(jobStatus);
                 mPendingJobQueue.add(jobStatus);
-                if (canExecuteImmediately) {
-                    // Don't ask the JobConcurrencyManager to try to run the job immediately. The
-                    // JobServiceContext will ask the JobConcurrencyManager for another job once
-                    // it finishes cleaning up the old job.
-                    maybeRunPendingJobsLocked();
-                }
+                maybeRunPendingJobsLocked();
             } else {
                 evaluateControllerStatesLocked(jobStatus);
             }
@@ -1392,10 +1377,8 @@
      * is null, the cancelled job is removed outright from the system.  If
      * {@code incomingJob} is non-null, it replaces {@code cancelled} in the store of
      * currently scheduled jobs.
-     *
-     * @return true if the cancelled job was running
      */
-    private boolean cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob,
+    private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob,
             @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
         if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
         cancelled.unprepareLocked();
@@ -1406,7 +1389,7 @@
         }
         mChangedJobList.remove(cancelled);
         // Cancel if running.
-        boolean wasRunning = mConcurrencyManager.stopJobOnServiceContextLocked(
+        mConcurrencyManager.stopJobOnServiceContextLocked(
                 cancelled, reason, internalReasonCode, debugReason);
         // If this is a replacement, bring in the new version of the job
         if (incomingJob != null) {
@@ -1414,7 +1397,6 @@
             startTrackingJobLocked(incomingJob, cancelled);
         }
         reportActiveLocked();
-        return wasRunning;
     }
 
     void updateUidState(int uid, int procState) {
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index 9c7d702..2da00c7 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -382,7 +382,7 @@
             if (increased) {
                 mAgent.distributeBasicIncomeLocked(newBatteryLevel);
             } else if (newBatteryLevel == mCurrentBatteryLevel) {
-                Slog.wtf(TAG, "Battery level stayed the same");
+                // The broadcast is also sent when the plug type changes...
                 return;
             }
             mCurrentBatteryLevel = newBatteryLevel;
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
index c90291e..fb342b9 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
@@ -328,11 +328,13 @@
             appUsageHistory.lastUsedScreenTime = getScreenOnTime(nowElapsedRealtimeMs);
         }
 
-        if (appUsageHistory.currentBucket > newBucket) {
-            appUsageHistory.currentBucket = newBucket;
-            logAppStandbyBucketChanged(packageName, userId, newBucket, bucketingReason);
+        if (appUsageHistory.currentBucket >= newBucket) {
+            if (appUsageHistory.currentBucket > newBucket) {
+                appUsageHistory.currentBucket = newBucket;
+                logAppStandbyBucketChanged(packageName, userId, newBucket, bucketingReason);
+            }
+            appUsageHistory.bucketingReason = bucketingReason;
         }
-        appUsageHistory.bucketingReason = bucketingReason;
 
         return appUsageHistory;
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 1c4ec85..c9afdad 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -225,6 +225,11 @@
                     | PackageManager.MATCH_DISABLED_COMPONENTS
                     | PackageManager.MATCH_SYSTEM_ONLY;
 
+    private static final int NOTIFICATION_SEEN_PROMOTED_BUCKET_FOR_PRE_T_APPS =
+            STANDBY_BUCKET_WORKING_SET;
+    private static final long NOTIFICATION_SEEN_HOLD_DURATION_FOR_PRE_T_APPS =
+            COMPRESS_TIME ? 12 * ONE_MINUTE : 12 * ONE_HOUR;
+
     // To name the lock for stack traces
     static class Lock {}
 
@@ -320,11 +325,17 @@
     int mNotificationSeenPromotedBucket =
             ConstantsObserver.DEFAULT_NOTIFICATION_SEEN_PROMOTED_BUCKET;
     /**
-     * If true, tell each {@link AppIdleStateChangeListener} to give quota bump for each
+     * If {@code true}, tell each {@link AppIdleStateChangeListener} to give quota bump for each
      * notification seen event.
      */
     private boolean mTriggerQuotaBumpOnNotificationSeen =
             ConstantsObserver.DEFAULT_TRIGGER_QUOTA_BUMP_ON_NOTIFICATION_SEEN;
+    /**
+     * If {@code true}, we will retain the pre-T impact of notification signal on apps targeting
+     * pre-T sdk levels regardless of other flag changes.
+     */
+    boolean mRetainNotificationSeenImpactForPreTApps =
+            ConstantsObserver.DEFAULT_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS;
     /** Minimum time a system update event should keep the buckets elevated. */
     long mSystemUpdateUsageTimeoutMillis = ConstantsObserver.DEFAULT_SYSTEM_UPDATE_TIMEOUT;
     /** Maximum time to wait for a prediction before using simple timeouts to downgrade buckets. */
@@ -1098,17 +1109,29 @@
         final int subReason = usageEventToSubReason(eventType);
         final int reason = REASON_MAIN_USAGE | subReason;
         if (eventType == UsageEvents.Event.NOTIFICATION_SEEN) {
-            if (mTriggerQuotaBumpOnNotificationSeen) {
-                mHandler.obtainMessage(MSG_TRIGGER_LISTENER_QUOTA_BUMP, userId, -1, pkg)
-                        .sendToTarget();
+            final int notificationSeenPromotedBucket;
+            final long notificationSeenTimeoutMillis;
+            if (mRetainNotificationSeenImpactForPreTApps
+                    && getTargetSdkVersion(pkg) < Build.VERSION_CODES.TIRAMISU) {
+                notificationSeenPromotedBucket =
+                        NOTIFICATION_SEEN_PROMOTED_BUCKET_FOR_PRE_T_APPS;
+                notificationSeenTimeoutMillis =
+                        NOTIFICATION_SEEN_HOLD_DURATION_FOR_PRE_T_APPS;
+            } else {
+                if (mTriggerQuotaBumpOnNotificationSeen) {
+                    mHandler.obtainMessage(MSG_TRIGGER_LISTENER_QUOTA_BUMP, userId, -1, pkg)
+                            .sendToTarget();
+                }
+                notificationSeenPromotedBucket = mNotificationSeenPromotedBucket;
+                notificationSeenTimeoutMillis = mNotificationSeenTimeoutMillis;
             }
             // Notification-seen elevates to a higher bucket (depending on
             // {@link ConstantsObserver#KEY_NOTIFICATION_SEEN_PROMOTED_BUCKET}) but doesn't
             // change usage time.
             mAppIdleHistory.reportUsage(appHistory, pkg, userId,
-                    mNotificationSeenPromotedBucket, subReason,
-                    0, elapsedRealtime + mNotificationSeenTimeoutMillis);
-            nextCheckDelay = mNotificationSeenTimeoutMillis;
+                    notificationSeenPromotedBucket, subReason,
+                    0, elapsedRealtime + notificationSeenTimeoutMillis);
+            nextCheckDelay = notificationSeenTimeoutMillis;
         } else if (eventType == UsageEvents.Event.SLICE_PINNED) {
             // Mild usage elevates to WORKING_SET but doesn't change usage time.
             mAppIdleHistory.reportUsage(appHistory, pkg, userId,
@@ -1149,6 +1172,10 @@
         }
     }
 
+    private int getTargetSdkVersion(String packageName) {
+        return mInjector.getPackageManagerInternal().getPackageTargetSdkVersion(packageName);
+    }
+
     /**
      * Returns the lowest standby bucket that is better than {@code targetBucket} and has an
      * valid expiry time (i.e. the expiry time is not yet elapsed).
@@ -2226,6 +2253,9 @@
         pw.print("  mTriggerQuotaBumpOnNotificationSeen=");
         pw.print(mTriggerQuotaBumpOnNotificationSeen);
         pw.println();
+        pw.print("  mRetainNotificationSeenImpactForPreTApps=");
+        pw.print(mRetainNotificationSeenImpactForPreTApps);
+        pw.println();
         pw.print("  mSlicePinnedTimeoutMillis=");
         TimeUtils.formatDuration(mSlicePinnedTimeoutMillis, pw);
         pw.println();
@@ -2712,6 +2742,8 @@
                 "notification_seen_duration";
         private static final String KEY_NOTIFICATION_SEEN_PROMOTED_BUCKET =
                 "notification_seen_promoted_bucket";
+        private static final String KEY_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS =
+                "retain_notification_seen_impact_for_pre_t_apps";
         private static final String KEY_TRIGGER_QUOTA_BUMP_ON_NOTIFICATION_SEEN =
                 "trigger_quota_bump_on_notification_seen";
         private static final String KEY_SLICE_PINNED_HOLD_DURATION =
@@ -2773,6 +2805,7 @@
                 COMPRESS_TIME ? 12 * ONE_MINUTE : 12 * ONE_HOUR;
         public static final int DEFAULT_NOTIFICATION_SEEN_PROMOTED_BUCKET =
                 STANDBY_BUCKET_WORKING_SET;
+        public static final boolean DEFAULT_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS = false;
         public static final boolean DEFAULT_TRIGGER_QUOTA_BUMP_ON_NOTIFICATION_SEEN = false;
         public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT =
                 COMPRESS_TIME ? 2 * ONE_MINUTE : 2 * ONE_HOUR;
@@ -2874,6 +2907,11 @@
                                     KEY_NOTIFICATION_SEEN_PROMOTED_BUCKET,
                                     DEFAULT_NOTIFICATION_SEEN_PROMOTED_BUCKET);
                             break;
+                        case KEY_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS:
+                            mRetainNotificationSeenImpactForPreTApps = properties.getBoolean(
+                                    KEY_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS,
+                                    DEFAULT_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS);
+                            break;
                         case KEY_TRIGGER_QUOTA_BUMP_ON_NOTIFICATION_SEEN:
                             mTriggerQuotaBumpOnNotificationSeen = properties.getBoolean(
                                     KEY_TRIGGER_QUOTA_BUMP_ON_NOTIFICATION_SEEN,
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
index e407e31..a6a3aaf 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
@@ -19,6 +19,18 @@
       ]
     }
   ],
+  "presubmit-large": [
+    {
+      "name": "CtsUsageStatsTestCases",
+      "options": [
+        {"include-filter": "android.app.usage.cts.BroadcastResponseStatsTest"},
+        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
+        {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+        {"exclude-annotation": "androidx.test.filters.MediumTest"},
+        {"exclude-annotation": "androidx.test.filters.LargeTest"}
+      ]
+    }
+  ],
   "postsubmit": [
     {
       "name": "CtsUsageStatsTestCases"
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index fe99c71..48277fb 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2923,7 +2923,7 @@
     method public static int getHoverTooltipHideTimeout();
     method public static int getHoverTooltipShowTimeout();
     method public static int getLongPressTooltipHideTimeout();
-    method public int getPreferKeepClearForFocusDelay();
+    method public boolean isPreferKeepClearForFocusEnabled();
   }
 
   public class ViewDebug {
diff --git a/core/java/android/app/LocaleConfig.java b/core/java/android/app/LocaleConfig.java
index 7c83d58..bbe3ce3 100644
--- a/core/java/android/app/LocaleConfig.java
+++ b/core/java/android/app/LocaleConfig.java
@@ -99,7 +99,7 @@
             XmlResourceParser parser = res.getXml(resId);
             parseLocaleConfig(parser, res);
         } catch (Resources.NotFoundException e) {
-            Slog.w(TAG, "The resource file pointed to by the given resource ID isn't found.", e);
+            Slog.w(TAG, "The resource file pointed to by the given resource ID isn't found.");
             mStatus = STATUS_NOT_SPECIFIED;
         } catch (XmlPullParserException | IOException e) {
             Slog.w(TAG, "Failed to parse XML configuration from "
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 5ef3fc0..e96a986 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -345,6 +345,14 @@
         mAlwaysOnTop = alwaysOnTop ? ALWAYS_ON_TOP_ON : ALWAYS_ON_TOP_OFF;
     }
 
+    /**
+     * Unsets always-on-top to undefined.
+     * @hide
+     */
+    public void unsetAlwaysOnTop() {
+        mAlwaysOnTop = ALWAYS_ON_TOP_UNDEFINED;
+    }
+
     private void setAlwaysOnTop(@AlwaysOnTop int alwaysOnTop) {
         mAlwaysOnTop = alwaysOnTop;
     }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 93f91e5..b7f1136 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2515,7 +2515,8 @@
      * If another app already had delegated network logging access,
      * it will lose the delegation when a new app is delegated.
      *
-     * <p> Can only be granted by Device Owner or Profile Owner of a managed profile.
+     * <p> Device Owner can grant this access since Android 10. Profile Owner of a managed profile
+     * can grant this access since Android 12.
      */
     public static final String DELEGATION_NETWORK_LOGGING = "delegation-network-logging";
 
@@ -13255,9 +13256,11 @@
      * Called by a device owner, profile owner of a managed profile or delegated app with
      * {@link #DELEGATION_NETWORK_LOGGING} to control the network logging feature.
      *
-     * <p> Supported for a device owner from Android 8. Supported for a profile owner of a managed
-     * profile from Android 12. When network logging is enabled by a profile owner, the network logs
-     * will only include work profile network activity, not activity on the personal profile.
+     * <p> Supported for a device owner from Android 8 and a delegated app granted by a device
+     * owner from Android 10. Supported for a profile owner of a managed profile and a delegated
+     * app granted by a profile owner from Android 12. When network logging is enabled by a
+     * profile owner, the network logs will only include work profile network activity, not
+     * activity on the personal profile.
      *
      * <p> Network logs contain DNS lookup and connect() library call events. The following library
      *     functions are recorded while network logging is active:
diff --git a/core/java/android/app/admin/ProvisioningIntentHelper.java b/core/java/android/app/admin/ProvisioningIntentHelper.java
index 1c38559..894f706 100644
--- a/core/java/android/app/admin/ProvisioningIntentHelper.java
+++ b/core/java/android/app/admin/ProvisioningIntentHelper.java
@@ -18,10 +18,26 @@
 
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ALLOW_OFFLINE;
 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE;
 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_KEEP_SCREEN_ON;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCAL_TIME;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE;
 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SUPPORTED_MODES;
 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_USE_MOBILE_DATA;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_HIDDEN;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_PORT;
 import static android.app.admin.DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC;
 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_NFC;
 import static android.nfc.NfcAdapter.EXTRA_NDEF_MESSAGES;
@@ -44,6 +60,8 @@
 import java.io.IOException;
 import java.io.StringReader;
 import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
@@ -52,6 +70,8 @@
  */
 final class ProvisioningIntentHelper {
 
+    private static final Map<String, Class> EXTRAS_TO_CLASS_MAP = createExtrasToClassMap();
+
     private static final String TAG = "ProvisioningIntentHelper";
 
     /**
@@ -124,12 +144,11 @@
 
     private static void addPropertyToBundle(
             String propertyName, Properties properties, Bundle bundle) {
-        if(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME.equals(propertyName)) {
+        if (EXTRAS_TO_CLASS_MAP.get(propertyName) == ComponentName.class) {
             ComponentName componentName = ComponentName.unflattenFromString(
                     properties.getProperty(propertyName));
             bundle.putParcelable(propertyName, componentName);
-        } else if (EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE.equals(propertyName)
-                || EXTRA_PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE.equals(propertyName)) {
+        } else if (EXTRAS_TO_CLASS_MAP.get(propertyName) == PersistableBundle.class) {
             try {
                 bundle.putParcelable(propertyName,
                         deserializeExtrasBundle(properties, propertyName));
@@ -137,6 +156,13 @@
                 Log.e(TAG,
                         "Failed to parse " + propertyName + ".", e);
             }
+        } else if (EXTRAS_TO_CLASS_MAP.get(propertyName) == Boolean.class) {
+            bundle.putBoolean(propertyName,
+                    Boolean.parseBoolean(properties.getProperty(propertyName)));
+        } else if (EXTRAS_TO_CLASS_MAP.get(propertyName) == Long.class) {
+            bundle.putLong(propertyName, Long.parseLong(properties.getProperty(propertyName)));
+        } else if (EXTRAS_TO_CLASS_MAP.get(propertyName) == Integer.class) {
+            bundle.putInt(propertyName, Integer.parseInt(properties.getProperty(propertyName)));
         }
         else {
             bundle.putString(propertyName, properties.getProperty(propertyName));
@@ -213,4 +239,61 @@
         Log.i(TAG, "No compatible records found on nfcIntent");
         return null;
     }
+
+    private static Map<String, Class> createExtrasToClassMap() {
+        Map<String, Class> map = new HashMap<>();
+        for (String extra : getBooleanExtras()) {
+            map.put(extra, Boolean.class);
+        }
+        for (String extra : getLongExtras()) {
+            map.put(extra, Long.class);
+        }
+        for (String extra : getIntExtras()) {
+            map.put(extra, Integer.class);
+        }
+        for (String extra : getComponentNameExtras()) {
+            map.put(extra, ComponentName.class);
+        }
+        for (String extra : getPersistableBundleExtras()) {
+            map.put(extra, PersistableBundle.class);
+        }
+        return map;
+    }
+
+    private static Set<String> getPersistableBundleExtras() {
+        return Set.of(
+                EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE,
+                EXTRA_PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE);
+    }
+
+    private static Set<String> getComponentNameExtras() {
+        return Set.of(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME);
+    }
+
+    private static Set<String> getIntExtras() {
+        return Set.of(
+                EXTRA_PROVISIONING_WIFI_PROXY_PORT,
+                EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE,
+                EXTRA_PROVISIONING_SUPPORTED_MODES);
+    }
+
+    private static Set<String> getLongExtras() {
+        return Set.of(EXTRA_PROVISIONING_LOCAL_TIME);
+    }
+
+    private static Set<String> getBooleanExtras() {
+        return Set.of(
+                EXTRA_PROVISIONING_ALLOW_OFFLINE,
+                EXTRA_PROVISIONING_SHOULD_LAUNCH_RESULT_INTENT,
+                EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION,
+                EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED,
+                EXTRA_PROVISIONING_WIFI_HIDDEN,
+                EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT,
+                EXTRA_PROVISIONING_SKIP_ENCRYPTION,
+                EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS,
+                EXTRA_PROVISIONING_USE_MOBILE_DATA,
+                EXTRA_PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER,
+                EXTRA_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE,
+                EXTRA_PROVISIONING_KEEP_SCREEN_ON);
+    }
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index a50ff3841..7a88a057 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3259,7 +3259,7 @@
 
 
     /**
-     * Broadcast Action: Sent when the current battery level changes.
+     * Broadcast Action: Sent when the current battery level or plug type changes.
      *
      * It has {@link android.os.BatteryManager#EXTRA_EVENTS} that carries a list of {@link Bundle}
      * instances representing individual battery level changes with associated
diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java
index cf4e6a6..bf64d06 100644
--- a/core/java/android/service/dreams/DreamActivity.java
+++ b/core/java/android/service/dreams/DreamActivity.java
@@ -58,8 +58,9 @@
             setTitle(title);
         }
 
-        DreamService.DreamServiceWrapper callback =
-                (DreamService.DreamServiceWrapper) getIntent().getIBinderExtra(EXTRA_CALLBACK);
+        final Bundle extras = getIntent().getExtras();
+        final DreamService.DreamActivityCallback callback =
+                (DreamService.DreamActivityCallback) extras.getBinder(EXTRA_CALLBACK);
 
         if (callback != null) {
             callback.onActivityCreated(this);
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 47fc120..5217b28 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -36,6 +36,7 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
@@ -1272,7 +1273,7 @@
             Intent i = new Intent(this, DreamActivity.class);
             i.setPackage(getApplicationContext().getPackageName());
             i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            i.putExtra(DreamActivity.EXTRA_CALLBACK, mDreamServiceWrapper);
+            i.putExtra(DreamActivity.EXTRA_CALLBACK, new DreamActivityCallback(mDreamToken));
             final ServiceInfo serviceInfo = fetchServiceInfo(this,
                     new ComponentName(this, getClass()));
             i.putExtra(DreamActivity.EXTRA_DREAM_TITLE, fetchDreamLabel(this, serviceInfo));
@@ -1452,11 +1453,36 @@
         public void wakeUp() {
             mHandler.post(() -> DreamService.this.wakeUp(true /*fromSystem*/));
         }
+    }
 
-        /** @hide */
-        void onActivityCreated(DreamActivity a) {
-            mActivity = a;
-            onWindowCreated(a.getWindow());
+    /** @hide */
+    final class DreamActivityCallback extends Binder {
+        private final IBinder mActivityDreamToken;
+
+        DreamActivityCallback(IBinder token) {
+            mActivityDreamToken = token;
+        }
+
+        void onActivityCreated(DreamActivity activity) {
+            if (mActivityDreamToken != mDreamToken || mFinished) {
+                Slog.d(TAG, "DreamActivity was created after the dream was finished or "
+                        + "a new dream started, finishing DreamActivity");
+                if (!activity.isFinishing()) {
+                    activity.finishAndRemoveTask();
+                }
+                return;
+            }
+            if (mActivity != null) {
+                Slog.w(TAG, "A DreamActivity has already been started, "
+                        + "finishing latest DreamActivity");
+                if (!activity.isFinishing()) {
+                    activity.finishAndRemoveTask();
+                }
+                return;
+            }
+
+            mActivity = activity;
+            onWindowCreated(activity.getWindow());
         }
     }
 
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index c83869c..fb562d8 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -32,7 +32,6 @@
 import android.os.Bundle;
 import android.os.IRemoteCallback;
 import android.os.ParcelFileDescriptor;
-import android.view.ContentRecordingSession;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.IAppTransitionAnimationSpecsFuture;
@@ -874,17 +873,6 @@
     void detachWindowContextFromWindowContainer(IBinder clientToken);
 
     /**
-     * Updates the content recording session. If a different session is already in progress, then
-     * the pre-existing session is stopped, and the new incoming session takes over.
-     *
-     * The DisplayContent for the new session will begin recording when
-     * {@link RootWindowContainer#onDisplayChanged} is invoked for the new {@link VirtualDisplay}.
-     *
-     * @param incomingSession the nullable incoming content recording session
-     */
-    void setContentRecordingSession(in ContentRecordingSession incomingSession);
-
-    /**
      * Registers a listener, which is to be called whenever cross-window blur is enabled/disabled.
      *
      * @param listener the listener to be registered
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 38ca248..90497e7 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4781,9 +4781,6 @@
     @UnsupportedAppUsage
     ListenerInfo mListenerInfo;
 
-    private boolean mPreferKeepClearForFocus;
-    private Runnable mMarkPreferKeepClearForFocus;
-
     private static class TooltipInfo {
         /**
          * Text to be displayed in a tooltip popup.
@@ -11962,8 +11959,9 @@
     @NonNull
     List<Rect> collectPreferKeepClearRects() {
         ListenerInfo info = mListenerInfo;
-        boolean keepBoundsClear =
-                (info != null && info.mPreferKeepClear) || mPreferKeepClearForFocus;
+        boolean keepClearForFocus = isFocused()
+                && ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled();
+        boolean keepBoundsClear = (info != null && info.mPreferKeepClear) || keepClearForFocus;
         boolean hasCustomKeepClearRects = info != null && info.mKeepClearRects != null;
 
         if (!keepBoundsClear && !hasCustomKeepClearRects) {
@@ -11985,31 +11983,10 @@
     }
 
     private void updatePreferKeepClearForFocus() {
-        if (mMarkPreferKeepClearForFocus != null) {
-            removeCallbacks(mMarkPreferKeepClearForFocus);
-            mMarkPreferKeepClearForFocus = null;
+        if (ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled()) {
+            updatePositionUpdateListener();
+            post(this::updateKeepClearRects);
         }
-
-        final ViewConfiguration configuration = ViewConfiguration.get(mContext);
-        final int delay = configuration.getPreferKeepClearForFocusDelay();
-        if (delay >= 0) {
-            mMarkPreferKeepClearForFocus = () -> {
-                mPreferKeepClearForFocus = isFocused();
-                mMarkPreferKeepClearForFocus = null;
-
-                updatePositionUpdateListener();
-                post(this::updateKeepClearRects);
-            };
-            postDelayed(mMarkPreferKeepClearForFocus, delay);
-        }
-    }
-
-    private void cancelMarkPreferKeepClearForFocus() {
-        if (mMarkPreferKeepClearForFocus != null) {
-            removeCallbacks(mMarkPreferKeepClearForFocus);
-            mMarkPreferKeepClearForFocus = null;
-        }
-        mPreferKeepClearForFocus = false;
     }
 
     /**
@@ -13754,7 +13731,6 @@
             }
             invalidate();
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
-            updatePreferKeepClearForFocus();
             return true;
         }
         return false;
@@ -21154,7 +21130,6 @@
         removePerformClickCallback();
         clearAccessibilityThrottles();
         stopNestedScroll();
-        cancelMarkPreferKeepClearForFocus();
 
         // Anything that started animating right before detach should already
         // be in its final state when re-attached.
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index ebc409e..638b8f9 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -347,7 +347,7 @@
     private final long mScreenshotChordKeyTimeout;
     private final int mSmartSelectionInitializedTimeout;
     private final int mSmartSelectionInitializingTimeout;
-    private final int mPreferKeepClearForFocusDelay;
+    private final boolean mPreferKeepClearForFocusEnabled;
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768915)
     private boolean sHasPermanentMenuKey;
@@ -393,7 +393,7 @@
         mMinScalingSpan = 0;
         mSmartSelectionInitializedTimeout = SMART_SELECTION_INITIALIZED_TIMEOUT_IN_MILLISECOND;
         mSmartSelectionInitializingTimeout = SMART_SELECTION_INITIALIZING_TIMEOUT_IN_MILLISECOND;
-        mPreferKeepClearForFocusDelay = -1;
+        mPreferKeepClearForFocusEnabled = false;
     }
 
     /**
@@ -508,8 +508,8 @@
                 com.android.internal.R.integer.config_smartSelectionInitializedTimeoutMillis);
         mSmartSelectionInitializingTimeout = res.getInteger(
                 com.android.internal.R.integer.config_smartSelectionInitializingTimeoutMillis);
-        mPreferKeepClearForFocusDelay = res.getInteger(
-                com.android.internal.R.integer.config_preferKeepClearForFocusDelayMillis);
+        mPreferKeepClearForFocusEnabled = res.getBoolean(
+                com.android.internal.R.bool.config_preferKeepClearForFocus);
     }
 
     /**
@@ -1100,13 +1100,13 @@
     }
 
     /**
-     * @return The delay in milliseconds before focused Views set themselves as preferred to keep
-     *         clear, or -1 if Views should not set themselves as preferred to keep clear.
+     * @return {@code true} if Views should set themselves as preferred to keep clear when focused,
+     * {@code false} otherwise.
      * @hide
      */
     @TestApi
-    public int getPreferKeepClearForFocusDelay() {
-        return mPreferKeepClearForFocusDelay;
+    public boolean isPreferKeepClearForFocusEnabled() {
+        return mPreferKeepClearForFocusEnabled;
     }
 
     /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index eabc13a..127c7b7 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -222,7 +222,6 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
@@ -800,8 +799,7 @@
             new ViewRootRectTracker(v -> v.collectPreferKeepClearRects());
     private final ViewRootRectTracker mUnrestrictedKeepClearRectsTracker =
             new ViewRootRectTracker(v -> v.collectUnrestrictedPreferKeepClearRects());
-    private List<Rect> mPendingKeepClearAreas;
-    private List<Rect> mPendingUnrestrictedKeepClearAreas;
+    private boolean mHasPendingKeepClearAreaChange;
 
     private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
 
@@ -4819,45 +4817,31 @@
     }
 
     void keepClearRectsChanged() {
-        List<Rect> restrictedKeepClearRects = mKeepClearRectsTracker.computeChangedRects();
-        List<Rect> unrestrictedKeepClearRects =
-                mUnrestrictedKeepClearRectsTracker.computeChangedRects();
-        if ((restrictedKeepClearRects != null || unrestrictedKeepClearRects != null)
-                && mView != null) {
-            if (restrictedKeepClearRects == null) {
-                restrictedKeepClearRects = Collections.emptyList();
-            }
-            if (unrestrictedKeepClearRects == null) {
-                unrestrictedKeepClearRects = Collections.emptyList();
-            }
+        boolean restrictedKeepClearRectsChanged = mKeepClearRectsTracker.computeChanges();
+        boolean unrestrictedKeepClearRectsChanged =
+                mUnrestrictedKeepClearRectsTracker.computeChanges();
 
-            if (mHandler.hasMessages(MSG_REPORT_KEEP_CLEAR_RECTS)) {
-                // Keep clear areas have been reported recently, wait before reporting new set
-                // of keep clear areas
-                mPendingKeepClearAreas = restrictedKeepClearRects;
-                mPendingUnrestrictedKeepClearAreas = unrestrictedKeepClearRects;
-            } else {
+        if ((restrictedKeepClearRectsChanged || unrestrictedKeepClearRectsChanged)
+                && mView != null) {
+            mHasPendingKeepClearAreaChange = true;
+            // Only report keep clear areas immediately if they have not been reported recently
+            if (!mHandler.hasMessages(MSG_REPORT_KEEP_CLEAR_RECTS)) {
                 mHandler.sendEmptyMessageDelayed(MSG_REPORT_KEEP_CLEAR_RECTS,
                         KEEP_CLEAR_AREA_REPORT_RATE_MILLIS);
-                try {
-                    mWindowSession.reportKeepClearAreasChanged(mWindow, restrictedKeepClearRects,
-                            unrestrictedKeepClearRects);
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                }
+                reportKeepClearAreasChanged();
             }
         }
     }
 
     void reportKeepClearAreasChanged() {
-        final List<Rect> restrictedKeepClearRects = mPendingKeepClearAreas;
-        final List<Rect> unrestrictedKeepClearRects = mPendingUnrestrictedKeepClearAreas;
-        if (restrictedKeepClearRects == null && unrestrictedKeepClearRects == null) {
+        if (!mHasPendingKeepClearAreaChange) {
             return;
         }
+        mHasPendingKeepClearAreaChange = false;
 
-        mPendingKeepClearAreas = null;
-        mPendingUnrestrictedKeepClearAreas = null;
+        final List<Rect> restrictedKeepClearRects = mKeepClearRectsTracker.getLastComputedRects();
+        final List<Rect> unrestrictedKeepClearRects =
+                mUnrestrictedKeepClearRectsTracker.getLastComputedRects();
 
         try {
             mWindowSession.reportKeepClearAreasChanged(mWindow, restrictedKeepClearRects,
diff --git a/core/java/android/view/ViewRootRectTracker.java b/core/java/android/view/ViewRootRectTracker.java
index fd9cc19..152729b 100644
--- a/core/java/android/view/ViewRootRectTracker.java
+++ b/core/java/android/view/ViewRootRectTracker.java
@@ -73,10 +73,25 @@
     }
 
     /**
-     * @return all visible rects from all views in the global (root) coordinate system
+     * @return all Rects from all visible Views in the global (root) coordinate system,
+     * or {@code null} if Rects are unchanged since the last call to this method.
      */
     @Nullable
     public List<Rect> computeChangedRects() {
+        if (computeChanges()) {
+            return mRects;
+        }
+        return null;
+    }
+
+    /**
+     * Computes changes to all Rects from all Views.
+     * After calling this method, the updated list of Rects can be retrieved
+     * with {@link #getLastComputedRects()}.
+     *
+     * @return {@code true} if there were changes, {@code false} otherwise.
+     */
+    public boolean computeChanges() {
         boolean changed = mRootRectsChanged;
         final Iterator<ViewInfo> i = mViewInfos.iterator();
         final List<Rect> rects = new ArrayList<>(mRootRects);
@@ -100,10 +115,22 @@
             mRootRectsChanged = false;
             if (!mRects.equals(rects)) {
                 mRects = rects;
-                return rects;
+                return true;
             }
         }
-        return null;
+        return false;
+    }
+
+    /**
+     * Returns a List of all Rects from all visible Views in the global (root) coordinate system.
+     * This list is only updated when calling {@link #computeChanges()} or
+     * {@link #computeChangedRects()}.
+     *
+     * @return all Rects from all visible Views in the global (root) coordinate system
+     */
+    @NonNull
+    public List<Rect> getLastComputedRects() {
+        return mRects;
     }
 
     /**
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 2dcc585..65e7abf 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -20,6 +20,7 @@
 import static com.android.internal.jank.FrameTracker.REASON_CANCEL_TIMEOUT;
 import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
 import static com.android.internal.jank.FrameTracker.REASON_END_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BIOMETRIC_PROMPT_TRANSITION;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP;
@@ -46,6 +47,7 @@
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_PAGE_SCROLL;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_SLIDER;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_TOGGLE;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER;
@@ -198,6 +200,8 @@
     public static final int CUJ_SETTINGS_SLIDER = 53;
     public static final int CUJ_TAKE_SCREENSHOT = 54;
     public static final int CUJ_VOLUME_CONTROL = 55;
+    public static final int CUJ_BIOMETRIC_PROMPT_TRANSITION = 56;
+    public static final int CUJ_SETTINGS_TOGGLE = 57;
 
     private static final int NO_STATSD_LOGGING = -1;
 
@@ -262,6 +266,8 @@
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_SLIDER,
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TAKE_SCREENSHOT,
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__VOLUME_CONTROL,
+            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BIOMETRIC_PROMPT_TRANSITION,
+            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_TOGGLE,
     };
 
     private static volatile InteractionJankMonitor sInstance;
@@ -338,6 +344,8 @@
             CUJ_SETTINGS_SLIDER,
             CUJ_TAKE_SCREENSHOT,
             CUJ_VOLUME_CONTROL,
+            CUJ_BIOMETRIC_PROMPT_TRANSITION,
+            CUJ_SETTINGS_TOGGLE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface CujType {
@@ -768,6 +776,10 @@
                 return "TAKE_SCREENSHOT";
             case CUJ_VOLUME_CONTROL:
                 return "VOLUME_CONTROL";
+            case CUJ_BIOMETRIC_PROMPT_TRANSITION:
+                return "BIOMETRIC_PROMPT_TRANSITION";
+            case CUJ_SETTINGS_TOGGLE:
+                return "SETTINGS_TOGGLE";
         }
         return "UNKNOWN";
     }
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsStore.java b/core/java/com/android/internal/os/BatteryUsageStatsStore.java
index 09c9cfc..04f72c7 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsStore.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsStore.java
@@ -320,4 +320,19 @@
             mFileSizes.remove(file);
         }
     }
+
+    public void removeAllSnapshots() {
+        lockSnapshotDirectory();
+        try {
+            for (File file : mStoreDir.listFiles()) {
+                if (file.getName().endsWith(SNAPSHOT_FILE_EXTENSION)) {
+                    if (!file.delete()) {
+                        Slog.e(TAG, "Cannot delete battery usage stats " + file);
+                    }
+                }
+            }
+        } finally {
+            unlockSnapshotDirectory();
+        }
+    }
 }
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index c4ff49c..00127c1 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -1073,6 +1073,7 @@
         RARE = 3;
         NEVER = 4;
         RESTRICTED = 5;
+        EXEMPTED = 6;
     }
     optional Bucket standby_bucket = 17;
     optional bool is_exempted_from_app_standby = 27;
diff --git a/core/res/res/color/hint_foreground_material_dark.xml b/core/res/res/color/hint_foreground_material_dark.xml
index 5cc9559..66fcb04 100644
--- a/core/res/res/color/hint_foreground_material_dark.xml
+++ b/core/res/res/color/hint_foreground_material_dark.xml
@@ -15,10 +15,6 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="true"
-          android:state_pressed="true"
-          android:alpha="@dimen/hint_pressed_alpha_material_dark"
-          android:color="@color/foreground_material_dark" />
-    <item android:alpha="@dimen/hint_alpha_material_dark"
+    <item android:alpha="@dimen/secondary_content_alpha_material_dark"
           android:color="@color/foreground_material_dark" />
 </selector>
diff --git a/core/res/res/color/hint_foreground_material_light.xml b/core/res/res/color/hint_foreground_material_light.xml
index f7465e0..63dd3b013 100644
--- a/core/res/res/color/hint_foreground_material_light.xml
+++ b/core/res/res/color/hint_foreground_material_light.xml
@@ -15,10 +15,6 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="true"
-          android:state_pressed="true"
-          android:alpha="@dimen/hint_pressed_alpha_material_light"
-          android:color="@color/foreground_material_light" />
-    <item android:alpha="@dimen/hint_alpha_material_light"
+    <item android:alpha="@dimen/secondary_content_alpha_material_light"
           android:color="@color/foreground_material_light" />
 </selector>
diff --git a/core/res/res/layout/autofill_fill_dialog.xml b/core/res/res/layout/autofill_fill_dialog.xml
index e638764..ba27d90 100644
--- a/core/res/res/layout/autofill_fill_dialog.xml
+++ b/core/res/res/layout/autofill_fill_dialog.xml
@@ -62,18 +62,24 @@
         android:layout_marginEnd="24dp"
         android:background="@drawable/autofill_dataset_picker_background"/>
 
-    <ListView
-        android:id="@+id/autofill_dialog_list"
-        android:layout_weight="1"
+    <LinearLayout
         android:layout_width="fill_parent"
-        android:layout_height="0dp"
-        android:drawSelectorOnTop="true"
-        android:clickable="true"
-        android:divider="?android:attr/listDivider"
+        android:layout_height="wrap_content"
         android:layout_marginStart="24dp"
         android:layout_marginEnd="24dp"
-        android:background="@drawable/autofill_dataset_picker_background"
-        android:visibility="gone"/>
+        android:theme="@style/Theme.DeviceDefault.AutofillHalfScreenDialogList"
+        android:orientation="vertical">
+        <ListView
+            android:id="@+id/autofill_dialog_list"
+            android:layout_weight="1"
+            android:layout_width="fill_parent"
+            android:layout_height="0dp"
+            android:drawSelectorOnTop="true"
+            android:clickable="true"
+            android:divider="@drawable/list_divider_material"
+            android:background="@drawable/autofill_dataset_picker_background"
+            android:visibility="gone"/>
+    </LinearLayout>
 
     <com.android.internal.widget.ButtonBarLayout
         android:layout_width="match_parent"
diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml
index 8a1a9c7..49539cf 100644
--- a/core/res/res/layout/autofill_save.xml
+++ b/core/res/res/layout/autofill_save.xml
@@ -23,45 +23,38 @@
     android:orientation="vertical">
 
     <LinearLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/autofill_save"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:layout_marginTop="@dimen/autofill_save_outer_top_margin"
-        android:paddingTop="@dimen/autofill_save_outer_top_padding"
+        android:layout_marginStart="24dp"
+        android:layout_marginEnd="24dp"
         android:elevation="@dimen/autofill_elevation"
         android:background="?android:attr/colorSurface"
+        android:gravity="center_horizontal"
         android:orientation="vertical">
 
         <LinearLayout
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:paddingStart="@dimen/autofill_save_inner_padding"
-            android:paddingEnd="@dimen/autofill_save_inner_padding"
             android:orientation="vertical">
 
-            <LinearLayout
+            <ImageView
+                android:id="@+id/autofill_save_icon"
+                android:scaleType="fitStart"
+                android:layout_gravity="center"
+                android:layout_width="@dimen/autofill_save_icon_size"
+                android:layout_height="@dimen/autofill_save_icon_size"/>
+
+            <TextView
+                android:id="@+id/autofill_save_title"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
-                android:orientation="horizontal">
-
-                <ImageView
-                    android:id="@+id/autofill_save_icon"
-                    android:scaleType="fitStart"
-                    android:layout_width="@dimen/autofill_save_icon_size"
-                    android:layout_height="@dimen/autofill_save_icon_size"/>
-
-                <TextView
-                    android:id="@+id/autofill_save_title"
-                    android:paddingStart="@dimen/autofill_save_title_start_padding"
-                    android:layout_width="fill_parent"
-                    android:layout_height="wrap_content"
-                    android:text="@string/autofill_save_title"
-                    android:textAppearance="@style/TextAppearance.DeviceDefault.Subhead"
-                    android:layout_weight="1">
-                </TextView>
-
-            </LinearLayout>
+                android:text="@string/autofill_save_title"
+                android:layout_marginTop="16dp"
+                android:gravity="center"
+                android:textAppearance="@style/AutofillSaveUiTitle">
+            </TextView>
 
             <com.android.server.autofill.ui.CustomScrollView
                 android:id="@+id/autofill_save_custom_subtitle"
@@ -79,8 +72,6 @@
             android:clipToPadding="false"
             android:layout_marginTop="32dp"
             android:layout_marginBottom="18dp"
-            android:layout_marginStart="24dp"
-            android:layout_marginEnd="24dp"
             android:theme="@style/Theme.DeviceDefault.AutofillHalfScreenDialogButton"
             android:orientation="horizontal">
 
diff --git a/core/res/res/layout/log_access_user_consent_dialog_permission.xml b/core/res/res/layout/log_access_user_consent_dialog_permission.xml
index c88bc92..1a395b9 100644
--- a/core/res/res/layout/log_access_user_consent_dialog_permission.xml
+++ b/core/res/res/layout/log_access_user_consent_dialog_permission.xml
@@ -26,8 +26,7 @@
               android:paddingLeft="24dp"
               android:paddingRight="24dp"
               android:paddingTop="24dp"
-              android:paddingBottom="24dp"
-              android:background="?attr/colorSurface">
+              android:paddingBottom="24dp">
 
     <ImageView
             android:id="@+id/log_access_image_view"
@@ -37,8 +36,7 @@
             android:src="@drawable/ic_doc_document"
             tools:layout_editor_absoluteX="148dp"
             tools:layout_editor_absoluteY="35dp"
-            android:gravity="center"
-            android:tint="?attr/colorAccentPrimaryVariant"/>
+            android:gravity="center" />
 
     <TextView
             android:id="@+id/log_access_dialog_title"
@@ -60,29 +58,35 @@
             android:textColor="?android:attr/textColorPrimary"
             android:gravity="center" />
 
-    <Button
-            android:id="@+id/log_access_dialog_allow_button"
+    <LinearLayout
+            android:orientation="vertical"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:text="@string/log_access_confirmation_allow"
-            style="@style/PermissionGrantButtonTop"
-            android:layout_marginBottom="5dp"
-            android:layout_centerHorizontal="true"
-            android:layout_alignParentTop="true"
-            android:layout_alignParentBottom="true"
-            android:clipToOutline="true"
-            android:gravity="center" />
+            android:layout_height="wrap_content">
+        <Button
+                android:id="@+id/log_access_dialog_allow_button"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/log_access_confirmation_allow"
+                style="@style/PermissionGrantButtonTop"
+                android:textAppearance="@style/PermissionGrantButtonTextAppearance"
+                android:layout_marginBottom="5dp"
+                android:layout_centerHorizontal="true"
+                android:layout_alignParentTop="true"
+                android:layout_alignParentBottom="true"
+                android:clipToOutline="true"
+                android:gravity="center" />
 
-    <Button
-            android:id="@+id/log_access_dialog_deny_button"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:text="@string/log_access_confirmation_deny"
-            style="@style/PermissionGrantButtonBottom"
-            android:layout_centerHorizontal="true"
-            android:layout_alignParentTop="true"
-            android:layout_alignParentBottom="true"
-            android:clipToOutline="true"
-            android:gravity="center" />
-
+        <Button
+                android:id="@+id/log_access_dialog_deny_button"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/log_access_confirmation_deny"
+                style="@style/PermissionGrantButtonBottom"
+                android:textAppearance="@style/PermissionGrantButtonTextAppearance"
+                android:layout_centerHorizontal="true"
+                android:layout_alignParentTop="true"
+                android:layout_alignParentBottom="true"
+                android:clipToOutline="true"
+                android:gravity="center" />
+    </LinearLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/search_view.xml b/core/res/res/layout/search_view.xml
index 0c462fd..39034dc 100644
--- a/core/res/res/layout/search_view.xml
+++ b/core/res/res/layout/search_view.xml
@@ -96,8 +96,8 @@
                 android:id="@+id/search_close_btn"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
-                android:paddingStart="8dip"
-                android:paddingEnd="8dip"
+                android:paddingStart="12dip"
+                android:paddingEnd="12dip"
                 android:layout_gravity="center_vertical"
                 android:background="?attr/selectableItemBackgroundBorderless"
                 android:focusable="true"
diff --git a/core/res/res/values-night/themes_device_defaults.xml b/core/res/res/values-night/themes_device_defaults.xml
index 366e6f9..7cfdba7 100644
--- a/core/res/res/values-night/themes_device_defaults.xml
+++ b/core/res/res/values-night/themes_device_defaults.xml
@@ -98,5 +98,10 @@
         <item name="colorAccentPrimary">@color/system_accent1_700</item>
         <item name="textColorPrimary">@color/system_neutral1_100</item>
         <item name="textColorSecondary">@color/system_neutral2_100</item>
+        <item name="colorListDivider">@color/white</item>
+    </style>
+
+    <style name="Theme.DeviceDefault.AutofillHalfScreenDialogList" parent="Theme.DeviceDefault.DayNight">
+        <item name="colorForeground">@android:color/white</item>
     </style>
 </resources>
diff --git a/core/res/res/values-television/styles.xml b/core/res/res/values-television/styles.xml
new file mode 100644
index 0000000..ad9140c
--- /dev/null
+++ b/core/res/res/values-television/styles.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+    <style name="PermissionGrantButtonTop"
+        parent="@style/Widget.Leanback.Button.ButtonBarGravityStart" />
+    <style name="PermissionGrantButtonBottom"
+        parent="@style/Widget.Leanback.Button.ButtonBarGravityStart" />
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index d357f01..ea6e1f1 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -65,18 +65,12 @@
     <!-- 70% white -->
     <color name="secondary_text_default_material_dark">#b3ffffff</color>
 
-    <item name="hint_alpha_material_dark" format="float" type="dimen">0.50</item>
-    <item name="hint_alpha_material_light" format="float" type="dimen">0.38</item>
-
-    <item name="hint_pressed_alpha_material_dark" format="float" type="dimen">0.70</item>
-    <item name="hint_pressed_alpha_material_light" format="float" type="dimen">0.54</item>
-
     <item name="disabled_alpha_material_light" format="float" type="dimen">0.26</item>
     <item name="disabled_alpha_material_dark" format="float" type="dimen">0.30</item>
     <item name="primary_content_alpha_material_dark" format="float" type="dimen">1</item>
     <item name="primary_content_alpha_material_light" format="float" type="dimen">0.87</item>
     <item name="secondary_content_alpha_material_dark" format="float" type="dimen">.7</item>
-    <item name="secondary_content_alpha_material_light" format="float" type="dimen">0.54</item>
+    <item name="secondary_content_alpha_material_light" format="float" type="dimen">0.60</item>
 
     <item name="highlight_alpha_material_light" format="float" type="dimen">0.10</item>
     <item name="highlight_alpha_material_dark" format="float" type="dimen">0.10</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 054695e..70766cc 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5163,9 +5163,8 @@
          when TextClassifier has not been initialized. -->
     <integer name="config_smartSelectionInitializingTimeoutMillis">500</integer>
 
-    <!-- The delay in milliseconds before focused Views set themselves as preferred to keep clear.
-         Set to -1 if Views should not set themselves as preferred to keep clear. -->
-    <integer name="config_preferKeepClearForFocusDelayMillis">-1</integer>
+    <!-- If true, Views will declare they prefer to be kept clear from overlays when focused. -->
+    <bool name="config_preferKeepClearForFocus">false</bool>
 
     <!-- Indicates that default fitness tracker app needs to request sensor and location permissions. -->
     <bool name="config_trackerAppNeedsPermissions">false</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 211bf7f..43ca4f0 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -865,13 +865,13 @@
     <dimen name="autofill_dataset_picker_max_height">90%</dimen>
 
     <!-- Autofill save dialog padding -->
-    <dimen name="autofill_save_outer_top_margin">32dp</dimen>
+    <dimen name="autofill_save_outer_top_margin">24dp</dimen>
     <dimen name="autofill_save_outer_top_padding">16dp</dimen>
     <dimen name="autofill_elevation">32dp</dimen>
     <dimen name="autofill_save_inner_padding">16dp</dimen>
-    <dimen name="autofill_save_icon_size">24dp</dimen>
+    <dimen name="autofill_save_icon_size">32dp</dimen>
     <dimen name="autofill_save_title_start_padding">8dp</dimen>
-    <dimen name="autofill_save_scroll_view_top_margin">4dp</dimen>
+    <dimen name="autofill_save_scroll_view_top_margin">16dp</dimen>
     <dimen name="autofill_save_button_bar_padding">16dp</dimen>
     <dimen name="autofill_dialog_corner_radius">28dp</dimen>
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 0c35f93..5d17047 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1495,7 +1495,14 @@
         <item name="background">@drawable/autofill_dataset_picker_background</item>
     </style>
 
-    <!-- @hide -->
+    <!-- @hide Autofill save dialog title -->
+    <style name="AutofillSaveUiTitle" parent="TextAppearance.DeviceDefault.Subhead">
+        <item name="textColor">?attr/textColorPrimary</item>
+        <item name="fontFamily">google-sans</item>
+        <item name="textSize">24sp</item>
+    </style>
+
+    <!--@hide -->
     <style name="AutofillHalfScreenAnimation">
         <item name="android:windowEnterAnimation">@anim/slide_in_up</item>
         <item name="android:windowExitAnimation">@anim/slide_out_down</item>
@@ -1526,26 +1533,27 @@
 
     <!-- The style for log access consent text -->
     <style name="AllowLogAccess">
-        <item name="android:layout_width">332dp</item>
         <item name="android:textSize">24sp</item>
         <item name="android:fontFamily">google-sans</item>
     </style>
 
     <style name="PrimaryAllowLogAccess">
-        <item name="android:layout_width">332dp</item>
         <item name="android:textSize">14sp</item>
         <item name="android:fontFamily">google-sans-text</item>
     </style>
 
+    <style name="PermissionGrantButtonTextAppearance">
+        <item name="android:fontFamily">google-sans-medium</item>
+        <item name="android:textSize">14sp</item>
+        <item name="android:textColor">@android:color/system_neutral1_900</item>
+    </style>
+
     <style name="PermissionGrantButtonTop"
            parent="@android:style/Widget.DeviceDefault.Button.Borderless.Colored">
         <item name="android:layout_width">332dp</item>
         <item name="android:layout_height">56dp</item>
         <item name="android:layout_marginTop">2dp</item>
         <item name="android:layout_marginBottom">2dp</item>
-        <item name="android:fontFamily">google-sans-medium</item>
-        <item name="android:textSize">14sp</item>
-        <item name="android:textColor">@android:color/system_neutral1_900</item>
         <item name="android:background">@drawable/grant_permissions_buttons_top</item>
     </style>
 
@@ -1555,9 +1563,6 @@
         <item name="android:layout_height">56dp</item>
         <item name="android:layout_marginTop">2dp</item>
         <item name="android:layout_marginBottom">2dp</item>
-        <item name="android:fontFamily">google-sans-medium</item>
-        <item name="android:textSize">14sp</item>
-        <item name="android:textColor">@android:color/system_neutral1_900</item>
         <item name="android:background">@drawable/grant_permissions_buttons_bottom</item>
     </style>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5bfc568..e111ee1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -479,7 +479,7 @@
   <java-symbol type="bool" name="config_useAssistantVolume" />
   <java-symbol type="integer" name="config_smartSelectionInitializedTimeoutMillis" />
   <java-symbol type="integer" name="config_smartSelectionInitializingTimeoutMillis" />
-  <java-symbol type="integer" name="config_preferKeepClearForFocusDelayMillis" />
+  <java-symbol type="bool" name="config_preferKeepClearForFocus" />
   <java-symbol type="bool" name="config_hibernationDeletesOatArtifactsEnabled"/>
   <java-symbol type="integer" name="config_defaultAnalogClockSecondsHandFps"/>
 
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 5000b58..c603c83 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -2704,4 +2704,8 @@
         <item name="textColorPrimary">@color/system_neutral1_900</item>
         <item name="textColorSecondary">@color/system_neutral2_700</item>
     </style>
+    <style name="Theme.DeviceDefault.AutofillHalfScreenDialogList" parent="Theme.DeviceDefault.DayNight">
+        <item name="colorListDivider">@color/list_divider_opacity_device_default_light</item>
+        <item name="opacityListDivider">@color/list_divider_opacity_device_default_light</item>
+    </style>
 </resources>
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java
index 21f6e7c..c9729fa 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java
@@ -132,6 +132,26 @@
     }
 
     @Test
+    public void testRemoveAllSnapshots() throws Exception {
+        prepareBatteryStats();
+
+        for (int i = 0; i < 3; i++) {
+            mMockClock.realtime += 10_000_000;
+            mMockClock.uptime += 10_000_000;
+            mMockClock.currentTime += 10_000_000;
+            prepareBatteryStats();
+
+            mBatteryStats.resetAllStatsCmdLocked();
+        }
+
+        assertThat(getDirectorySize(mStoreDirectory)).isNotEqualTo(0);
+
+        mBatteryUsageStatsStore.removeAllSnapshots();
+
+        assertThat(getDirectorySize(mStoreDirectory)).isEqualTo(0);
+    }
+
+    @Test
     public void testSavingStatsdAtomPullTimestamp() {
         mBatteryUsageStatsStore.setLastBatteryUsageStatsBeforeResetAtomPullTimestamp(1234);
         assertThat(mBatteryUsageStatsStore.getLastBatteryUsageStatsBeforeResetAtomPullTimestamp())
diff --git a/libs/WindowManager/Shell/res/values/strings_tv.xml b/libs/WindowManager/Shell/res/values/strings_tv.xml
index 09ed9b8..2b7a13e 100644
--- a/libs/WindowManager/Shell/res/values/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values/strings_tv.xml
@@ -26,23 +26,38 @@
     <!-- Picture-in-Picture (PIP) menu -->
     <eat-comment />
     <!-- Button to close picture-in-picture (PIP) in PIP menu [CHAR LIMIT=30] -->
-    <string name="pip_close">Close PIP</string>
+    <string name="pip_close">Close</string>
 
     <!-- Button to move picture-in-picture (PIP) screen to the fullscreen in PIP menu [CHAR LIMIT=30] -->
     <string name="pip_fullscreen">Full screen</string>
 
     <!-- Button to move picture-in-picture (PIP) via DPAD in the PIP menu [CHAR LIMIT=30] -->
-    <string name="pip_move">Move PIP</string>
+    <string name="pip_move">Move</string>
 
     <!-- Button to expand the picture-in-picture (PIP) window [CHAR LIMIT=30] -->
-    <string name="pip_expand">Expand PIP</string>
+    <string name="pip_expand">Expand</string>
 
     <!-- Button to collapse/shrink the picture-in-picture (PIP) window [CHAR LIMIT=30] -->
-    <string name="pip_collapse">Collapse PIP</string>
+    <string name="pip_collapse">Collapse</string>
 
     <!-- Educative text instructing the user to double press the HOME button to access the pip
         controls menu [CHAR LIMIT=50] -->
     <string name="pip_edu_text"> Double press <annotation icon="home_icon"> HOME </annotation> for
         controls </string>
+
+    <!-- Accessibility announcement when opening the PiP menu. [CHAR LIMIT=NONE] -->
+    <string name="a11y_pip_menu_entered">Picture-in-Picture menu.</string>
+
+    <!-- Accessibility action: move the PiP window to the left [CHAR LIMIT=30] -->
+    <string name="a11y_action_pip_move_left">Move left</string>
+    <!-- Accessibility action: move the PiP window to the right [CHAR LIMIT=30] -->
+    <string name="a11y_action_pip_move_right">Move right</string>
+    <!-- Accessibility action: move the PiP window up [CHAR LIMIT=30] -->
+    <string name="a11y_action_pip_move_up">Move up</string>
+    <!-- Accessibility action: move the PiP window down [CHAR LIMIT=30] -->
+    <string name="a11y_action_pip_move_down">Move down</string>
+    <!-- Accessibility action: done with moving the PiP [CHAR LIMIT=30] -->
+    <string name="a11y_action_pip_move_done">Done</string>
+
 </resources>
 
diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl
index d190fce..1d58a40 100644
--- a/media/java/android/media/projection/IMediaProjectionManager.aidl
+++ b/media/java/android/media/projection/IMediaProjectionManager.aidl
@@ -21,6 +21,7 @@
 import android.media.projection.IMediaProjectionWatcherCallback;
 import android.media.projection.MediaProjectionInfo;
 import android.os.IBinder;
+import android.view.ContentRecordingSession;
 
 /** {@hide} */
 interface IMediaProjectionManager {
@@ -33,4 +34,15 @@
     void stopActiveProjection();
     void addCallback(IMediaProjectionWatcherCallback callback);
     void removeCallback(IMediaProjectionWatcherCallback callback);
+
+    /**
+     * Updates the content recording session. If a different session is already in progress, then
+     * the pre-existing session is stopped, and the new incoming session takes over. Only updates
+     * the session if the given projection is valid.
+     *
+     * @param incomingSession the nullable incoming content recording session
+     * @param projection      the non-null projection the session describes
+     */
+    void setContentRecordingSession(in ContentRecordingSession incomingSession,
+            in IMediaProjection projection);
 }
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index b5f9593..ba7bf3f 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -26,12 +26,11 @@
 import android.hardware.display.VirtualDisplayConfig;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.ContentRecordingSession;
-import android.view.IWindowManager;
 import android.view.Surface;
-import android.view.WindowManagerGlobal;
 import android.window.WindowContainerToken;
 
 import java.util.Map;
@@ -53,6 +52,7 @@
     private final IMediaProjection mImpl;
     private final Context mContext;
     private final Map<Callback, CallbackRecord> mCallbacks;
+    @Nullable private IMediaProjectionManager mProjectionService = null;
 
     /** @hide */
     public MediaProjection(Context context, IMediaProjection impl) {
@@ -172,7 +172,6 @@
             @NonNull VirtualDisplayConfig.Builder virtualDisplayConfig,
             @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
         try {
-            final IWindowManager wmService = WindowManagerGlobal.getWindowManagerService();
             final WindowContainerToken taskWindowContainerToken =
                     mImpl.getTaskRecordingWindowContainerToken();
             Context windowContext = null;
@@ -199,7 +198,7 @@
             }
             session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
             // Successfully set up, so save the current session details.
-            wmService.setContentRecordingSession(session);
+            getProjectionService().setContentRecordingSession(session, mImpl);
             return virtualDisplay;
         } catch (RemoteException e) {
             // Can not capture if WMS is not accessible, so bail out.
@@ -207,6 +206,14 @@
         }
     }
 
+    private IMediaProjectionManager getProjectionService() {
+        if (mProjectionService == null) {
+            mProjectionService = IMediaProjectionManager.Stub.asInterface(
+                    ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE));
+        }
+        return mProjectionService;
+    }
+
     /**
      * Stops projection.
      */
diff --git a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
index 6766cdd..8cda376 100644
--- a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
@@ -44,7 +44,6 @@
     int mIconVisibility = View.VISIBLE;
     private CharSequence mContentDescription;
     private CharSequence mLearnMoreText;
-    private CharSequence mLearnMoreContentDescription;
     private FooterLearnMoreSpan mLearnMoreSpan;
 
     public FooterPreference(Context context, AttributeSet attrs) {
@@ -80,9 +79,6 @@
             learnMoreText.setSpan(mLearnMoreSpan, 0,
                     learnMoreText.length(), 0);
             learnMore.setText(learnMoreText);
-            if (!TextUtils.isEmpty(mLearnMoreContentDescription)) {
-                learnMore.setContentDescription(mLearnMoreContentDescription);
-            }
         } else {
             learnMore.setVisibility(View.GONE);
         }
@@ -140,27 +136,6 @@
     }
 
     /**
-     * To set content description of the learn more text. This can use for talkback
-     * environment if developer wants to have a customization content.
-     *
-     * @param learnMoreContentDescription The resource id of the content description.
-     */
-    public void setLearnMoreContentDescription(CharSequence learnMoreContentDescription) {
-        if (!TextUtils.equals(mContentDescription, learnMoreContentDescription)) {
-            mLearnMoreContentDescription = learnMoreContentDescription;
-            notifyChanged();
-        }
-    }
-
-    /**
-     * Return the content description of learn more link.
-     */
-    @VisibleForTesting
-    CharSequence getLearnMoreContentDescription() {
-        return mLearnMoreContentDescription;
-    }
-
-    /**
      * Assign an action for the learn more link.
      */
     public void setLearnMoreAction(View.OnClickListener listener) {
@@ -201,7 +176,7 @@
         private String mKey;
         private CharSequence mTitle;
         private CharSequence mContentDescription;
-        private CharSequence mLearnMoreContentDescription;
+        private CharSequence mLearnMoreText;
 
         public Builder(@NonNull Context context) {
             mContext = context;
@@ -260,25 +235,24 @@
         }
 
         /**
-         * To set content description of the learn more text. This can use for talkback
+         * To set learn more string of the learn more text. This can use for talkback
          * environment if developer wants to have a customization content.
          *
-         * @param learnMoreContentDescription The resource id of the content description.
+         * @param learnMoreText The resource id of the learn more string.
          */
-        public Builder setLearnMoreContentDescription(CharSequence learnMoreContentDescription) {
-            mLearnMoreContentDescription = learnMoreContentDescription;
+        public Builder setLearnMoreText(CharSequence learnMoreText) {
+            mLearnMoreText = learnMoreText;
             return this;
         }
 
         /**
-         * To set content description of the {@link FooterPreference}. This can use for talkback
+         * To set learn more string of the {@link FooterPreference}. This can use for talkback
          * environment if developer wants to have a customization content.
          *
-         * @param learnMoreContentDescriptionResId The resource id of the content description.
+         * @param learnMoreTextResId The resource id of the learn more string.
          */
-        public Builder setLearnMoreContentDescription(
-                @StringRes int learnMoreContentDescriptionResId) {
-            mLearnMoreContentDescription = mContext.getText(learnMoreContentDescriptionResId);
+        public Builder setLearnMoreText(@StringRes int learnMoreTextResId) {
+            mLearnMoreText = mContext.getText(learnMoreTextResId);
             return this;
         }
 
@@ -301,8 +275,8 @@
                 footerPreference.setContentDescription(mContentDescription);
             }
 
-            if (!TextUtils.isEmpty(mLearnMoreContentDescription)) {
-                footerPreference.setLearnMoreContentDescription(mLearnMoreContentDescription);
+            if (!TextUtils.isEmpty(mLearnMoreText)) {
+                footerPreference.setLearnMoreText(mLearnMoreText);
             }
             return footerPreference;
         }
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
index 5e3907c..5411591 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
@@ -48,8 +48,6 @@
 
     <color name="settingslib_text_color_preference_category_title">@android:color/system_accent1_100</color>
 
-    <color name="settingslib_ripple_color">@color/settingslib_material_grey_900</color>
-
     <color name="settingslib_surface_dark">@android:color/system_neutral1_800</color>
 
     <color name="settingslib_colorSurface">@color/settingslib_surface_dark</color>
diff --git a/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
index b43b444..fb06976 100644
--- a/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
@@ -19,8 +19,6 @@
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
 import android.widget.Switch;
 
 import androidx.annotation.Keep;
@@ -28,6 +26,7 @@
 import androidx.preference.PreferenceViewHolder;
 
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import com.android.settingslib.core.instrumentation.SettingsJankMonitor;
 
 /**
  * A custom preference that provides inline switch toggle. It has a mandatory field for title, and
@@ -65,31 +64,25 @@
     @Override
     public void onBindViewHolder(PreferenceViewHolder holder) {
         super.onBindViewHolder(holder);
-        final View switchWidget = holder.findViewById(R.id.switchWidget);
-        if (switchWidget != null) {
-            switchWidget.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    if (mSwitch != null && !mSwitch.isEnabled()) {
-                        return;
-                    }
-                    setChecked(!mChecked);
-                    if (!callChangeListener(mChecked)) {
-                        setChecked(!mChecked);
-                    } else {
-                        persistBoolean(mChecked);
-                    }
+        mSwitch = (Switch) holder.findViewById(R.id.switchWidget);
+        if (mSwitch != null) {
+            mSwitch.setOnClickListener(v -> {
+                if (mSwitch != null && !mSwitch.isEnabled()) {
+                    return;
+                }
+                final boolean newChecked = !mChecked;
+                if (callChangeListener(newChecked)) {
+                    SettingsJankMonitor.detectToggleJank(getKey(), mSwitch);
+                    setChecked(newChecked);
+                    persistBoolean(newChecked);
                 }
             });
 
             // Consumes move events to ignore drag actions.
-            switchWidget.setOnTouchListener((v, event) -> {
+            mSwitch.setOnTouchListener((v, event) -> {
                 return event.getActionMasked() == MotionEvent.ACTION_MOVE;
             });
-        }
 
-        mSwitch = (Switch) holder.findViewById(R.id.switchWidget);
-        if (mSwitch != null) {
             mSwitch.setContentDescription(getTitle());
             mSwitch.setChecked(mChecked);
             mSwitch.setEnabled(mEnableSwitch);
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 2f30baa..cb8e7e8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -198,10 +198,9 @@
         if (mDisabledByAdmin != disabled) {
             mDisabledByAdmin = disabled;
             changed = true;
+            updateDisabledState();
         }
 
-        updateDisabledState();
-
         return changed;
     }
 
@@ -210,10 +209,9 @@
         if (mDisabledByAppOps != disabled) {
             mDisabledByAppOps = disabled;
             changed = true;
+            updateDisabledState();
         }
 
-        updateDisabledState();
-
         return changed;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index e6160bb..b5e4fa3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -254,9 +254,11 @@
         final boolean ecmEnabled = getContext().getResources().getBoolean(
                 com.android.internal.R.bool.config_enhancedConfirmationModeEnabled);
         final boolean appOpsAllowed = !ecmEnabled || mode == AppOpsManager.MODE_ALLOWED;
-        if (appOpsAllowed || isEnabled) {
+        if (isEnabled) {
             setEnabled(true);
-        } else {
+        } else if (appOpsAllowed && isDisabledByAppOps()) {
+            setEnabled(true);
+        } else if (!appOpsAllowed){
             setDisabledByAppOps(true);
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SettingsJankMonitor.kt b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SettingsJankMonitor.kt
new file mode 100644
index 0000000..a5f69ff
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SettingsJankMonitor.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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.settingslib.core.instrumentation
+
+import android.view.View
+import androidx.annotation.VisibleForTesting
+import androidx.preference.PreferenceGroupAdapter
+import androidx.preference.SwitchPreference
+import androidx.recyclerview.widget.RecyclerView
+import com.android.internal.jank.InteractionJankMonitor
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit
+
+/**
+ * Helper class for Settings library to trace jank.
+ */
+object SettingsJankMonitor {
+    private val jankMonitor = InteractionJankMonitor.getInstance()
+    private val scheduledExecutorService = Executors.newSingleThreadScheduledExecutor()
+
+    // Switch toggle animation duration is 250ms, and there is also a ripple effect animation when
+    // clicks, which duration is variable. Use 300ms here to cover.
+    @VisibleForTesting
+    const val MONITORED_ANIMATION_DURATION_MS = 300L
+
+    /**
+     * Detects the jank when click on a SwitchPreference.
+     *
+     * @param recyclerView the recyclerView contains the preference
+     * @param preference the clicked preference
+     */
+    @JvmStatic
+    fun detectSwitchPreferenceClickJank(recyclerView: RecyclerView, preference: SwitchPreference) {
+        val adapter = recyclerView.adapter as? PreferenceGroupAdapter ?: return
+        val adapterPosition = adapter.getPreferenceAdapterPosition(preference)
+        val viewHolder = recyclerView.findViewHolderForAdapterPosition(adapterPosition) ?: return
+        detectToggleJank(preference.key, viewHolder.itemView)
+    }
+
+    /**
+     * Detects the animation jank on the given view.
+     *
+     * @param tag the tag for jank monitor
+     * @param view the instrumented view
+     */
+    @JvmStatic
+    fun detectToggleJank(tag: String?, view: View) {
+        val builder = InteractionJankMonitor.Configuration.Builder.withView(
+            InteractionJankMonitor.CUJ_SETTINGS_TOGGLE,
+            view
+        )
+        if (tag != null) {
+            builder.setTag(tag)
+        }
+        if (jankMonitor.begin(builder)) {
+            scheduledExecutorService.schedule({
+                jankMonitor.end(InteractionJankMonitor.CUJ_SETTINGS_TOGGLE)
+            }, MONITORED_ANIMATION_DURATION_MS, TimeUnit.MILLISECONDS)
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/Android.bp b/packages/SettingsLib/tests/robotests/Android.bp
index 2d1a516..5c55a43 100644
--- a/packages/SettingsLib/tests/robotests/Android.bp
+++ b/packages/SettingsLib/tests/robotests/Android.bp
@@ -63,6 +63,7 @@
 
     libs: [
         "Robolectric_all-target",
+        "mockito-robolectric-prebuilt",
         "truth-prebuilt",
     ],
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
index 9c16740..74c2fc8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
@@ -30,14 +30,17 @@
 import androidx.preference.PreferenceViewHolder;
 
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowInteractionJankMonitor.class})
 public class PrimarySwitchPreferenceTest {
 
     private Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java
new file mode 100644
index 0000000..d67d44b
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2022 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.settingslib.core.instrumentation;
+
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_SETTINGS_TOGGLE;
+import static com.android.settingslib.core.instrumentation.SettingsJankMonitor.MONITORED_ANIMATION_DURATION_MS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.view.View;
+
+import androidx.preference.PreferenceGroupAdapter;
+import androidx.preference.SwitchPreference;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.internal.jank.InteractionJankMonitor;
+import com.android.internal.jank.InteractionJankMonitor.CujType;
+import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowInteractionJankMonitor.class, SettingsJankMonitorTest.ShadowBuilder.class})
+public class SettingsJankMonitorTest {
+    private static final String TEST_KEY = "key";
+
+    @Rule
+    public MockitoRule mocks = MockitoJUnit.rule();
+
+    @Mock
+    private View mView;
+
+    @Mock
+    private RecyclerView mRecyclerView;
+
+    @Mock
+    private PreferenceGroupAdapter mPreferenceGroupAdapter;
+
+    @Mock
+    private SwitchPreference mSwitchPreference;
+
+    @Mock
+    private ScheduledExecutorService mScheduledExecutorService;
+
+    @Before
+    public void setUp() {
+        ShadowInteractionJankMonitor.reset();
+        when(ShadowInteractionJankMonitor.MOCK_INSTANCE.begin(any())).thenReturn(true);
+        ReflectionHelpers.setStaticField(SettingsJankMonitor.class, "scheduledExecutorService",
+                mScheduledExecutorService);
+    }
+
+    @Test
+    public void detectToggleJank() {
+        SettingsJankMonitor.detectToggleJank(TEST_KEY, mView);
+
+        verifyToggleJankMonitored();
+    }
+
+    @Test
+    public void detectSwitchPreferenceClickJank() {
+        int adapterPosition = 7;
+        when(mRecyclerView.getAdapter()).thenReturn(mPreferenceGroupAdapter);
+        when(mPreferenceGroupAdapter.getPreferenceAdapterPosition(mSwitchPreference))
+                .thenReturn(adapterPosition);
+        when(mRecyclerView.findViewHolderForAdapterPosition(adapterPosition))
+                .thenReturn(new RecyclerView.ViewHolder(mView) {
+                });
+        when(mSwitchPreference.getKey()).thenReturn(TEST_KEY);
+
+        SettingsJankMonitor.detectSwitchPreferenceClickJank(mRecyclerView, mSwitchPreference);
+
+        verifyToggleJankMonitored();
+    }
+
+    private void verifyToggleJankMonitored() {
+        verify(ShadowInteractionJankMonitor.MOCK_INSTANCE).begin(ShadowBuilder.sBuilder);
+        assertThat(ShadowBuilder.sView).isSameInstanceAs(mView);
+        ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+        verify(mScheduledExecutorService).schedule(runnableCaptor.capture(),
+                eq(MONITORED_ANIMATION_DURATION_MS), eq(TimeUnit.MILLISECONDS));
+        runnableCaptor.getValue().run();
+        verify(ShadowInteractionJankMonitor.MOCK_INSTANCE).end(CUJ_SETTINGS_TOGGLE);
+    }
+
+    @Implements(InteractionJankMonitor.Configuration.Builder.class)
+    static class ShadowBuilder {
+        private static InteractionJankMonitor.Configuration.Builder sBuilder;
+        private static View sView;
+
+        @Resetter
+        public static void reset() {
+            sBuilder = null;
+            sView = null;
+        }
+
+        @Implementation
+        public static InteractionJankMonitor.Configuration.Builder withView(
+                @CujType int cuj, @NonNull View view) {
+            assertThat(cuj).isEqualTo(CUJ_SETTINGS_TOGGLE);
+            sView = view;
+            sBuilder = mock(InteractionJankMonitor.Configuration.Builder.class);
+            when(sBuilder.setTag(TEST_KEY)).thenReturn(sBuilder);
+            return sBuilder;
+        }
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
index 9abb27e..55125c5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
@@ -74,13 +74,6 @@
     }
 
     @Test
-    public void setLearnMoreContentDescription_contentSet_shouldGetSameContentDescription() {
-        mFooterPreference.setLearnMoreContentDescription("test");
-
-        assertThat(mFooterPreference.getLearnMoreContentDescription()).isEqualTo("test");
-    }
-
-    @Test
     public void setLearnMoreAction_actionSet_shouldGetAction() {
         mFooterPreference.setLearnMoreAction(v -> {
         });
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowInteractionJankMonitor.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowInteractionJankMonitor.java
new file mode 100644
index 0000000..855da16
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowInteractionJankMonitor.java
@@ -0,0 +1,41 @@
+/*
+ * 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.settingslib.testutils.shadow;
+
+import static org.mockito.Mockito.mock;
+
+import com.android.internal.jank.InteractionJankMonitor;
+
+import org.mockito.Mockito;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+@Implements(InteractionJankMonitor.class)
+public class ShadowInteractionJankMonitor {
+    public static final InteractionJankMonitor MOCK_INSTANCE = mock(InteractionJankMonitor.class);
+
+    @Resetter
+    public static void reset() {
+        Mockito.reset(MOCK_INSTANCE);
+    }
+
+    @Implementation
+    public static InteractionJankMonitor getInstance() {
+        return MOCK_INSTANCE;
+    }
+}
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index d146fc9..b01fd6d 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -124,49 +124,5 @@
         }
       ]
     }
-  ],
-  "hubui-postsubmit": [
-      {
-        "name": "PlatformScenarioTests",
-        "options": [
-          {
-              "include-filter": "android.platform.test.scenario.hubui"
-          },
-          {
-              "include-annotation": "android.platform.test.scenario.annotation.HubUi"
-          },
-          {
-              "exclude-annotation": "org.junit.Ignore"
-          },
-          {
-              "exclude-annotation": "androidx.test.filters.FlakyTest"
-          }
-      ]
-    }
-  ],
-  "hubui-presubmit": [
-      {
-        "name": "PlatformScenarioTests",
-        "options": [
-          {
-              "include-annotation": "android.platform.test.annotations.Presubmit"
-          },
-          {
-              "include-annotation": "android.platform.test.scenario.annotation.HubUi"
-          },
-          {
-              "include-filter": "android.platform.test.scenario.hubui"
-          },
-          {
-              "exclude-annotation": "org.junit.Ignore"
-          },
-          {
-              "exclude-annotation": "androidx.test.filters.FlakyTest"
-          },
-          {
-              "exclude-annotation": "android.platform.test.annotations.Postsubmit"
-          }
-      ]
-    }
   ]
 }
diff --git a/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
index 1c09e81f..18f870d 100644
--- a/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
+++ b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
@@ -58,6 +58,7 @@
             android:id="@+id/edit_text"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:minHeight="48dp"
             android:background="@null"
             android:gravity="start|top"
             android:textSize="24sp" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7010a28..1351ec1 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2485,7 +2485,7 @@
     <!-- Text informing user where text being edited was copied from [CHAR LIMIT=NONE] -->
     <string name="clipboard_edit_source">From <xliff:g id="appName" example="Gmail">%1$s</xliff:g></string>
     <!-- Label for button to dismiss clipboard overlay [CHAR LIMIT=NONE] -->
-    <string name="clipboard_dismiss_description">Dismiss copy UI</string>
+    <string name="clipboard_dismiss_description">Dismiss copied text</string>
     <!-- Label for button to edit text that was copied to the clipboard [CHAR LIMIT=NONE] -->
     <string name="clipboard_edit_text_description">Edit copied text</string>
     <!-- Label for button to edit an image that was copied to the clipboard [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 685c585..088dfb4 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -159,6 +159,8 @@
     @VisibleForTesting
     protected DisplayDecorationSupport mHwcScreenDecorationSupport;
     private Display.Mode mDisplayMode;
+    @VisibleForTesting
+    protected DisplayInfo mDisplayInfo = new DisplayInfo();
 
     private CameraAvailabilityListener.CameraTransitionCallback mCameraTransitionCallback =
             new CameraAvailabilityListener.CameraTransitionCallback() {
@@ -325,9 +327,10 @@
     private void startOnScreenDecorationsThread() {
         mWindowManager = mContext.getSystemService(WindowManager.class);
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
-        mRotation = mContext.getDisplay().getRotation();
-        mDisplayMode = mContext.getDisplay().getMode();
-        mDisplayUniqueId = mContext.getDisplay().getUniqueId();
+        mContext.getDisplay().getDisplayInfo(mDisplayInfo);
+        mRotation = mDisplayInfo.rotation;
+        mDisplayMode = mDisplayInfo.getMode();
+        mDisplayUniqueId = mDisplayInfo.uniqueId;
         mRoundedCornerResDelegate = new RoundedCornerResDelegate(mContext.getResources(),
                 mDisplayUniqueId);
         mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio(
@@ -351,8 +354,9 @@
 
             @Override
             public void onDisplayChanged(int displayId) {
-                final int newRotation = mContext.getDisplay().getRotation();
-                final Display.Mode newDisplayMode = mContext.getDisplay().getMode();
+                mContext.getDisplay().getDisplayInfo(mDisplayInfo);
+                final int newRotation = mDisplayInfo.rotation;
+                final Display.Mode newDisplayMode = mDisplayInfo.getMode();
                 if ((mOverlays != null || mScreenDecorHwcWindow != null)
                         && (mRotation != newRotation
                         || displayModeChanged(mDisplayMode, newDisplayMode))) {
@@ -398,7 +402,7 @@
                     }
                 }
 
-                final String newUniqueId = mContext.getDisplay().getUniqueId();
+                final String newUniqueId = mDisplayInfo.uniqueId;
                 if (!Objects.equals(newUniqueId, mDisplayUniqueId)) {
                     mDisplayUniqueId = newUniqueId;
                     final DisplayDecorationSupport newScreenDecorationSupport =
@@ -923,11 +927,10 @@
     @VisibleForTesting
     float getPhysicalPixelDisplaySizeRatio() {
         final Point stableDisplaySize = mDisplayManager.getStableDisplaySize();
-        final DisplayInfo displayInfo = new DisplayInfo();
-        mContext.getDisplay().getDisplayInfo(displayInfo);
+        mContext.getDisplay().getDisplayInfo(mDisplayInfo);
         return DisplayUtils.getPhysicalPixelDisplaySizeRatio(
-                stableDisplaySize.x, stableDisplaySize.y, displayInfo.getNaturalWidth(),
-                displayInfo.getNaturalHeight());
+                stableDisplaySize.x, stableDisplaySize.y, mDisplayInfo.getNaturalWidth(),
+                mDisplayInfo.getNaturalHeight());
     }
 
     @Override
@@ -1004,11 +1007,12 @@
                 "must call on " + mHandler.getLooper().getThread()
                         + ", but was " + Thread.currentThread());
 
-        int newRotation = mContext.getDisplay().getRotation();
+        mContext.getDisplay().getDisplayInfo(mDisplayInfo);
+        final int newRotation = mDisplayInfo.rotation;
         if (mRotation != newRotation) {
             mDotViewController.setNewRotation(newRotation);
         }
-        final Display.Mode newMod = mContext.getDisplay().getMode();
+        final Display.Mode newMod = mDisplayInfo.getMode();
 
         if (!mPendingConfigChange
                 && (newRotation != mRotation || displayModeChanged(mDisplayMode, newMod))) {
@@ -1220,7 +1224,7 @@
         @Override
         public void updateRotation(int rotation) {
             mRotation = rotation;
-            updateCutout();
+            super.updateRotation(rotation);
         }
 
         @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
@@ -1431,9 +1435,10 @@
 
         @Override
         public boolean onPreDraw() {
-            final int displayRotation = mContext.getDisplay().getRotation();
-            final Display.Mode displayMode = mContext.getDisplay().getMode();
-            if (displayRotation != mRotation && displayModeChanged(mDisplayMode, displayMode)
+            mContext.getDisplay().getDisplayInfo(mDisplayInfo);
+            final int displayRotation = mDisplayInfo.rotation;
+            final Display.Mode displayMode = mDisplayInfo.getMode();
+            if ((displayRotation != mRotation || displayModeChanged(mDisplayMode, displayMode))
                     && !mPendingConfigChange) {
                 if (DEBUG) {
                     if (displayRotation != mRotation) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index 44879aa..b8a0013 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -261,7 +261,7 @@
                     taskViewFactory.get().create(context, uiExecutor, {
                         dialog = DetailDialog(
                             activityContext, broadcastSender,
-                            it, pendingIntent, cvh
+                            it, pendingIntent, cvh, keyguardStateController, activityStarter
                         ).also {
                             it.setOnDismissListener { _ -> dialog = null }
                             it.show()
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index 80589a2..edd1c68 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -34,6 +34,8 @@
 import com.android.internal.policy.ScreenDecorationsUtils
 import com.android.systemui.R
 import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.wm.shell.TaskView
 
 /**
@@ -46,7 +48,9 @@
     val broadcastSender: BroadcastSender,
     val taskView: TaskView,
     val pendingIntent: PendingIntent,
-    val cvh: ControlViewHolder
+    val cvh: ControlViewHolder,
+    val keyguardStateController: KeyguardStateController,
+    val activityStarter: ActivityStarter
 ) : Dialog(
     activityContext,
     R.style.Theme_SystemUI_Dialog_Control_DetailPanel
@@ -145,12 +149,25 @@
 
         requireViewById<ImageView>(R.id.control_detail_open_in_app).apply {
             setOnClickListener { v: View ->
-                // Remove the task explicitly, since onRelease() callback will be executed after
-                // startActivity() below is called.
                 removeDetailTask()
                 dismiss()
-                broadcastSender.closeSystemDialogs()
-                pendingIntent.send()
+
+                val action = ActivityStarter.OnDismissAction {
+                    // Remove the task explicitly, since onRelease() callback will be executed after
+                    // startActivity() below is called.
+                    broadcastSender.closeSystemDialogs()
+                    pendingIntent.send()
+                    false
+                }
+                if (keyguardStateController.isUnlocked()) {
+                    action.onDismiss()
+                } else {
+                    activityStarter.dismissKeyguardThenExecute(
+                        action,
+                        null /* cancel */,
+                        true /* afterKeyguardGone */
+                    )
+                }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 0f868718..e9caaaf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -150,12 +150,13 @@
         }
     private val configListener = object : ConfigurationController.ConfigurationListener {
         override fun onDensityOrFontScaleChanged() {
-            recreatePlayers()
+            // System font changes should only happen when UMO is offscreen or a flicker may occur
+            updatePlayers(recreateMedia = true)
             inflateSettingsButton()
         }
 
         override fun onThemeChanged() {
-            recreatePlayers()
+            updatePlayers(recreateMedia = false)
             inflateSettingsButton()
         }
 
@@ -165,7 +166,7 @@
         }
 
         override fun onUiModeChanged() {
-            recreatePlayers()
+            updatePlayers(recreateMedia = false)
             inflateSettingsButton()
         }
     }
@@ -539,7 +540,7 @@
         }
     }
 
-    private fun recreatePlayers() {
+    private fun updatePlayers(recreateMedia: Boolean) {
         pageIndicator.tintList = ColorStateList.valueOf(
             context.getColor(R.color.media_paging_indicator)
         )
@@ -554,7 +555,9 @@
                 }
             } else {
                 val isSsReactivated = MediaPlayerData.isSsReactivated(key)
-                removePlayer(key, dismissMediaData = false, dismissRecommendation = false)
+                if (recreateMedia) {
+                    removePlayer(key, dismissMediaData = false, dismissRecommendation = false)
+                }
                 addOrUpdatePlayer(
                         key = key, oldKey = null, data = data, isSsReactivated = isSsReactivated)
             }
@@ -945,6 +948,7 @@
         .thenByDescending { shouldPrioritizeSs == it.isSsMediaRec }
         .thenByDescending { !it.data.resumption }
         .thenByDescending { it.data.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE }
+        .thenByDescending { it.data.lastActive }
         .thenByDescending { it.updateTime }
         .thenByDescending { it.data.notificationKey }
 
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 429f2df..731e177 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -292,10 +292,8 @@
             return;
         }
 
-        final int warningLevel = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_lowBatteryWarningLevel);
         final String percentage = NumberFormat.getPercentInstance()
-                .format((double) warningLevel / 100.0);
+                .format((double) mCurrentBatterySnapshot.getBatteryLevel() / 100.0);
         final String title = mContext.getString(R.string.battery_low_title);
         final String contentText = mContext.getString(
                 R.string.battery_low_description, percentage);
@@ -309,7 +307,6 @@
                         .setContentText(contentText)
                         .setContentTitle(title)
                         .setOnlyAlertOnce(true)
-                        .setOngoing(true)
                         .setStyle(new Notification.BigTextStyle().bigText(contentText))
                         .setVisibility(Notification.VISIBILITY_PUBLIC);
         if (hasBatterySettings()) {
@@ -340,8 +337,7 @@
     }
 
     private boolean showSevereLowBatteryDialog() {
-        final boolean isSevereState = !mCurrentBatterySnapshot.isHybrid() || mBucket < -1;
-        return isSevereState && mUseSevereDialog;
+        return mBucket < -1 && mUseSevereDialog;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index dcdd784..67dae9e 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -359,11 +359,7 @@
         }
 
         mWarnings.updateSnapshot(mCurrentBatteryStateSnapshot);
-        if (mCurrentBatteryStateSnapshot.isHybrid()) {
-            maybeShowHybridWarning(mCurrentBatteryStateSnapshot, mLastBatteryStateSnapshot);
-        } else {
-            maybeShowBatteryWarning(mCurrentBatteryStateSnapshot, mLastBatteryStateSnapshot);
-        }
+        maybeShowHybridWarning(mCurrentBatteryStateSnapshot, mLastBatteryStateSnapshot);
     }
 
     // updates the time estimate if we don't have one or battery level has changed.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index 90a3d45..f1fdae7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -451,11 +451,11 @@
         final SignalStrength strength = mTelephonyManager.getSignalStrength();
         int level = (strength == null) ? 0 : strength.getLevel();
         int numLevels = SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
-        if ((mSubscriptionManager != null && shouldInflateSignalStrength(mDefaultDataSubId))
-                || isCarrierNetworkActive) {
-            level = isCarrierNetworkActive
-                    ? SignalStrength.NUM_SIGNAL_STRENGTH_BINS
-                    : (level + 1);
+        if (isCarrierNetworkActive) {
+            level = getCarrierNetworkLevel();
+            numLevels = WifiEntry.WIFI_LEVEL_MAX + 1;
+        } else if (mSubscriptionManager != null && shouldInflateSignalStrength(mDefaultDataSubId)) {
+            level += 1;
             numLevels += 1;
         }
         return getSignalStrengthIcon(mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON,
@@ -689,6 +689,17 @@
         return mergedCarrierEntry != null && mergedCarrierEntry.isDefaultNetwork();
     }
 
+    int getCarrierNetworkLevel() {
+        final MergedCarrierEntry mergedCarrierEntry =
+                mAccessPointController.getMergedCarrierEntry();
+        if (mergedCarrierEntry == null) return WifiEntry.WIFI_LEVEL_MIN;
+
+        int level = mergedCarrierEntry.getLevel();
+        // To avoid icons not found with WIFI_LEVEL_UNREACHABLE(-1), use WIFI_LEVEL_MIN(0) instead.
+        if (level < WifiEntry.WIFI_LEVEL_MIN) level = WifiEntry.WIFI_LEVEL_MIN;
+        return level;
+    }
+
     @WorkerThread
     void setMergedCarrierWifiEnabledIfNeed(int subId, boolean enabled) {
         // If the Carrier Provisions Wi-Fi Merged Networks enabled, do not set the merged carrier
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 22a6b0a..929dda6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -157,7 +157,7 @@
 
     @Override
     public boolean pointInView(float localX, float localY, float slop) {
-        float top = mClipTopAmount;
+        float top = Math.max(0, mClipTopAmount);
         float bottom = mActualHeight;
         return localX >= -slop && localY >= top - slop && localX < ((mRight - mLeft) + slop) &&
                 localY < (bottom + slop);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 62bb85a..81270c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -4712,6 +4712,11 @@
                     duration = StackStateAnimator.ANIMATION_DURATION_STANDARD;
                 }
                 mKeyguardStatusBarViewController.animateKeyguardStatusBarOut(startDelay, duration);
+                if (mSplitShadeEnabled) {
+                    // temporary workaround for QS height not being updated during lockscreen to
+                    // shade transition
+                    setQsExpanded(true);
+                }
                 updateQSMinHeight();
             } else if (oldState == StatusBarState.SHADE_LOCKED
                     && statusBarState == KEYGUARD) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 0e77866..5e7dc11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -906,9 +906,19 @@
         }
         if (mQsExpansion > 0) {
             behindAlpha = MathUtils.lerp(behindAlpha, mDefaultScrimAlpha, mQsExpansion);
+            float tintProgress = mQsExpansion;
+            if (mStatusBarKeyguardViewManager.isBouncerInTransit()) {
+                // this is case of - on lockscreen - going from expanded QS to bouncer.
+                // Because mQsExpansion is already interpolated and transition between tints
+                // is too slow, we want to speed it up and make it more aligned to bouncer
+                // showing up progress. This issue is visible on large screens, both portrait and
+                // split shade because then transition is between very different tints
+                tintProgress = BouncerPanelExpansionCalculator
+                        .showBouncerProgress(mPanelExpansionFraction);
+            }
             int stateTint = mClipsQsScrim ? ScrimState.SHADE_LOCKED.getNotifTint()
                     : ScrimState.SHADE_LOCKED.getBehindTint();
-            behindTint = ColorUtils.blendARGB(behindTint, stateTint, mQsExpansion);
+            behindTint = ColorUtils.blendARGB(behindTint, stateTint, tintProgress);
         }
 
         // If the keyguard is going away, we should not be opaque.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 57253af..92e4947 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -63,6 +63,7 @@
 import android.util.Size;
 import android.view.Display;
 import android.view.DisplayCutout;
+import android.view.DisplayInfo;
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewGroup;
@@ -136,6 +137,8 @@
     private CornerDecorProvider mPrivacyDotBottomRightDecorProvider;
     @Mock
     private Display.Mode mDisplayMode;
+    @Mock
+    private DisplayInfo mDisplayInfo;
     private PrivacyDotViewController.ShowingListener mPrivacyDotShowingListener;
 
     @Before
@@ -159,7 +162,7 @@
         when(mContext.getDisplay()).thenReturn(mDisplay);
         // Not support hwc layer by default
         doReturn(null).when(mDisplay).getDisplayDecorationSupport();
-        doReturn(mDisplayMode).when(mDisplay).getMode();
+        doReturn(mDisplayMode).when(mDisplayInfo).getMode();
 
         when(mMockTypedArray.length()).thenReturn(0);
         mPrivacyDotTopLeftDecorProvider = spy(new PrivacyDotCornerDecorProviderImpl(
@@ -214,6 +217,7 @@
                 mExecutor.runAllReady();
             }
         });
+        mScreenDecorations.mDisplayInfo = mDisplayInfo;
         doReturn(1f).when(mScreenDecorations).getPhysicalPixelDisplaySizeRatio();
         reset(mTunerService);
 
@@ -977,7 +981,7 @@
                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px)
                 /* roundedBottomDrawable */,
                 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */);
-        doReturn(Surface.ROTATION_0).when(mDisplay).getRotation();
+        mDisplayInfo.rotation = Surface.ROTATION_0;
 
         mScreenDecorations.start();
 
@@ -991,7 +995,7 @@
                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px)
                 /* roundedBottomDrawable */,
                 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */);
-        doReturn(Surface.ROTATION_270).when(mDisplay).getRotation();
+        mDisplayInfo.rotation = Surface.ROTATION_270;
 
         mScreenDecorations.onConfigurationChanged(null);
 
@@ -1274,7 +1278,6 @@
         final ScreenDecorHwcLayer hwcLayer = mScreenDecorations.mScreenDecorHwcLayer;
         spyOn(hwcLayer);
         doReturn(mDisplay).when(hwcLayer).getDisplay();
-        doReturn(mDisplayMode).when(mDisplay).getMode();
 
         mScreenDecorations.mDisplayListener.onDisplayChanged(1);
 
@@ -1298,7 +1301,6 @@
                 mScreenDecorations.mCutoutViews[BOUNDS_POSITION_TOP];
         spyOn(cutoutView);
         doReturn(mDisplay).when(cutoutView).getDisplay();
-        doReturn(mDisplayMode).when(mDisplay).getMode();
 
         mScreenDecorations.mDisplayListener.onDisplayChanged(1);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
index 0166fa2..6a6a65a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
@@ -22,6 +22,8 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.wm.shell.TaskView
 import org.junit.Before
 import org.junit.Test
@@ -45,6 +47,10 @@
     private lateinit var controlViewHolder: ControlViewHolder
     @Mock
     private lateinit var pendingIntent: PendingIntent
+    @Mock
+    private lateinit var keyguardStateController: KeyguardStateController
+    @Mock
+    private lateinit var activityStarter: ActivityStarter
 
     @Before
     fun setUp() {
@@ -69,7 +75,9 @@
             broadcastSender,
             taskView,
             pendingIntent,
-            controlViewHolder
+            controlViewHolder,
+            keyguardStateController,
+            activityStarter
         )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
index ceb811b..219b3c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -136,9 +136,18 @@
 
         val resume2 = Triple("resume 2",
             DATA.copy(active = false, isPlaying = false,
-                    playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true),
+                playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true),
             1000L)
 
+        val activeMoreRecent = Triple("active more recent",
+            DATA.copy(active = false, isPlaying = false,
+                playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true, lastActive = 2L),
+            1000L)
+
+        val activeLessRecent = Triple("active less recent",
+            DATA.copy(active = false, isPlaying = false,
+                playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true, lastActive = 1L),
+            1000L)
         // Expected ordering for media players:
         // Actively playing local sessions
         // Actively playing cast sessions
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index e42ae1c..9a7b129 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -38,6 +38,7 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -574,6 +575,7 @@
                 .onSmartspaceMediaDataLoaded(anyObject(), anyObject(), anyBoolean())
     }
 
+    @Ignore("b/233283726")
     @Test
     fun testOnSmartspaceMediaDataLoaded_hasNoneMediaTarget_callsRemoveListener() {
         smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index 4a8cb0b..7b1e5c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -1,9 +1,15 @@
 package com.android.systemui.qs.tiles.dialog;
 
 import static android.provider.Settings.Global.AIRPLANE_MODE_ON;
+import static android.telephony.SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
+import static android.telephony.SignalStrength.SIGNAL_STRENGTH_GREAT;
+import static android.telephony.SignalStrength.SIGNAL_STRENGTH_POOR;
 
 import static com.android.systemui.qs.tiles.dialog.InternetDialogController.TOAST_PARAMS_HORIZONTAL_WEIGHT;
 import static com.android.systemui.qs.tiles.dialog.InternetDialogController.TOAST_PARAMS_VERTICAL_WEIGHT;
+import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX;
+import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN;
+import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -17,6 +23,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -28,6 +35,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.testing.AndroidTestingRunner;
@@ -140,6 +148,8 @@
     private View mDialogLaunchView;
     @Mock
     private WifiStateWorker mWifiStateWorker;
+    @Mock
+    private SignalStrength mSignalStrength;
 
     private TestableResources mTestableResources;
     private InternetDialogController mInternetDialogController;
@@ -152,6 +162,8 @@
         MockitoAnnotations.initMocks(this);
         mTestableResources = mContext.getOrCreateTestableResources();
         doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
+        when(mTelephonyManager.getSignalStrength()).thenReturn(mSignalStrength);
+        when(mSignalStrength.getLevel()).thenReturn(SIGNAL_STRENGTH_GREAT);
         when(mKeyguardStateController.isUnlocked()).thenReturn(true);
         when(mConnectedEntry.isDefaultNetwork()).thenReturn(true);
         when(mConnectedEntry.hasInternetAccess()).thenReturn(true);
@@ -380,7 +392,7 @@
 
     @Test
     public void getInternetWifiDrawable_withWifiLevelUnreachable_returnNull() {
-        when(mConnectedEntry.getLevel()).thenReturn(WifiEntry.WIFI_LEVEL_UNREACHABLE);
+        when(mConnectedEntry.getLevel()).thenReturn(WIFI_LEVEL_UNREACHABLE);
 
         Drawable drawable = mInternetDialogController.getInternetWifiDrawable(mConnectedEntry);
 
@@ -638,6 +650,57 @@
         assertThat(mInternetDialogController.isWifiScanEnabled()).isTrue();
     }
 
+    @Test
+    public void getSignalStrengthDrawableWithLevel_carrierNetworkIsNotActive_useMobileDataLevel() {
+        // Fake mobile data level as SIGNAL_STRENGTH_POOR(1)
+        when(mSignalStrength.getLevel()).thenReturn(SIGNAL_STRENGTH_POOR);
+        // Fake carrier network level as WIFI_LEVEL_MAX(4)
+        when(mInternetDialogController.getCarrierNetworkLevel()).thenReturn(WIFI_LEVEL_MAX);
+
+        InternetDialogController spyController = spy(mInternetDialogController);
+        spyController.getSignalStrengthDrawableWithLevel(false /* isCarrierNetworkActive */);
+
+        verify(spyController).getSignalStrengthIcon(any(), eq(SIGNAL_STRENGTH_POOR),
+                eq(NUM_SIGNAL_STRENGTH_BINS), anyInt(), anyBoolean());
+    }
+
+    @Test
+    public void getSignalStrengthDrawableWithLevel_carrierNetworkIsActive_useCarrierNetworkLevel() {
+        // Fake mobile data level as SIGNAL_STRENGTH_POOR(1)
+        when(mSignalStrength.getLevel()).thenReturn(SIGNAL_STRENGTH_POOR);
+        // Fake carrier network level as WIFI_LEVEL_MAX(4)
+        when(mInternetDialogController.getCarrierNetworkLevel()).thenReturn(WIFI_LEVEL_MAX);
+
+        InternetDialogController spyController = spy(mInternetDialogController);
+        spyController.getSignalStrengthDrawableWithLevel(true /* isCarrierNetworkActive */);
+
+        verify(spyController).getSignalStrengthIcon(any(), eq(WIFI_LEVEL_MAX),
+                eq(WIFI_LEVEL_MAX + 1), anyInt(), anyBoolean());
+    }
+
+    @Test
+    public void getCarrierNetworkLevel_mergedCarrierEntryIsNull_returnMinLevel() {
+        when(mAccessPointController.getMergedCarrierEntry()).thenReturn(null);
+
+        assertThat(mInternetDialogController.getCarrierNetworkLevel()).isEqualTo(WIFI_LEVEL_MIN);
+    }
+
+    @Test
+    public void getCarrierNetworkLevel_getUnreachableLevel_returnMinLevel() {
+        when(mMergedCarrierEntry.getLevel()).thenReturn(WIFI_LEVEL_UNREACHABLE);
+
+        assertThat(mInternetDialogController.getCarrierNetworkLevel()).isEqualTo(WIFI_LEVEL_MIN);
+    }
+
+    @Test
+    public void getCarrierNetworkLevel_getAvailableLevel_returnSameLevel() {
+        for (int level = WIFI_LEVEL_MIN; level <= WIFI_LEVEL_MAX; level++) {
+            when(mMergedCarrierEntry.getLevel()).thenReturn(level);
+
+            assertThat(mInternetDialogController.getCarrierNetworkLevel()).isEqualTo(level);
+        }
+    }
+
     private String getResourcesString(String name) {
         return mContext.getResources().getString(getResourcesId(name));
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 5f8dda3..09009c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -19,6 +19,8 @@
 import static com.android.systemui.statusbar.phone.ScrimController.OPAQUE;
 import static com.android.systemui.statusbar.phone.ScrimController.SEMI_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.ScrimController.TRANSPARENT;
+import static com.android.systemui.statusbar.phone.ScrimState.BOUNCER;
+import static com.android.systemui.statusbar.phone.ScrimState.SHADE_LOCKED;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -275,7 +277,7 @@
 
     @Test
     public void transitionToShadeLocked() {
-        mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+        mScrimController.transitionTo(SHADE_LOCKED);
         mScrimController.setQsPosition(1f, 0);
         finishAnimationsImmediately();
 
@@ -293,7 +295,7 @@
     @Test
     public void transitionToShadeLocked_clippingQs() {
         mScrimController.setClipsQsScrim(true);
-        mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+        mScrimController.transitionTo(SHADE_LOCKED);
         mScrimController.setQsPosition(1f, 0);
         finishAnimationsImmediately();
 
@@ -542,7 +544,7 @@
 
     @Test
     public void transitionToKeyguardBouncer() {
-        mScrimController.transitionTo(ScrimState.BOUNCER);
+        mScrimController.transitionTo(BOUNCER);
         finishAnimationsImmediately();
         // Front scrim should be transparent
         // Back scrim should be visible without tint
@@ -561,7 +563,7 @@
     @Test
     public void transitionToKeyguardBouncer_clippingQs() {
         mScrimController.setClipsQsScrim(true);
-        mScrimController.transitionTo(ScrimState.BOUNCER);
+        mScrimController.transitionTo(BOUNCER);
         finishAnimationsImmediately();
         // Front scrim should be transparent
         // Back scrim should be clipping QS
@@ -581,7 +583,7 @@
     @Test
     public void disableClipQsScrimWithoutStateTransition_updatesTintAndAlpha() {
         mScrimController.setClipsQsScrim(true);
-        mScrimController.transitionTo(ScrimState.BOUNCER);
+        mScrimController.transitionTo(BOUNCER);
 
         mScrimController.setClipsQsScrim(false);
 
@@ -602,7 +604,7 @@
     @Test
     public void enableClipQsScrimWithoutStateTransition_updatesTintAndAlpha() {
         mScrimController.setClipsQsScrim(false);
-        mScrimController.transitionTo(ScrimState.BOUNCER);
+        mScrimController.transitionTo(BOUNCER);
 
         mScrimController.setClipsQsScrim(true);
 
@@ -672,9 +674,9 @@
         finishAnimationsImmediately();
         assertEquals(mScrimState, ScrimState.UNLOCKED);
 
-        mScrimController.transitionTo(ScrimState.BOUNCER);
+        mScrimController.transitionTo(BOUNCER);
         finishAnimationsImmediately();
-        assertEquals(mScrimState, ScrimState.BOUNCER);
+        assertEquals(mScrimState, BOUNCER);
 
         mScrimController.transitionTo(ScrimState.BOUNCER_SCRIMMED);
         finishAnimationsImmediately();
@@ -1081,9 +1083,9 @@
         HashSet<ScrimState> lowPowerModeStates = new HashSet<>(Arrays.asList(
                 ScrimState.OFF, ScrimState.AOD, ScrimState.PULSING));
         HashSet<ScrimState> regularStates = new HashSet<>(Arrays.asList(
-                ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, ScrimState.BOUNCER,
+                ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, BOUNCER,
                 ScrimState.DREAMING, ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR,
-                ScrimState.UNLOCKED, ScrimState.SHADE_LOCKED, ScrimState.AUTH_SCRIMMED,
+                ScrimState.UNLOCKED, SHADE_LOCKED, ScrimState.AUTH_SCRIMMED,
                 ScrimState.AUTH_SCRIMMED_SHADE));
 
         for (ScrimState state : ScrimState.values()) {
@@ -1228,7 +1230,7 @@
     @Test
     public void testNotificationScrimVisible_afterOpeningShadeFromLockscreen() {
         mScrimController.setRawPanelExpansionFraction(1);
-        mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+        mScrimController.transitionTo(SHADE_LOCKED);
         finishAnimationsImmediately();
 
         assertScrimAlpha(Map.of(
@@ -1237,10 +1239,26 @@
     }
 
     @Test
+    public void qsExpansion_BehindTint_shadeLocked_bouncerActive_usesBouncerProgress() {
+        when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(true);
+        // clipping doesn't change tested logic but allows to assert scrims more in line with
+        // their expected large screen behaviour
+        mScrimController.setClipsQsScrim(false);
+        mScrimController.transitionTo(SHADE_LOCKED);
+
+        mScrimController.setQsPosition(1f, 100 /* value doesn't matter */);
+        assertTintAfterExpansion(mScrimBehind, SHADE_LOCKED.getBehindTint(), /* expansion= */ 1f);
+
+        mScrimController.setQsPosition(0.8f, 100 /* value doesn't matter */);
+        // panel expansion of 0.6 means its fully transitioned with bouncer progress interpolation
+        assertTintAfterExpansion(mScrimBehind, BOUNCER.getBehindTint(), /* expansion= */ 0.6f);
+    }
+
+    @Test
     public void expansionNotificationAlpha_shadeLocked_bouncerActive_usesBouncerInterpolator() {
         when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(true);
 
-        mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+        mScrimController.transitionTo(SHADE_LOCKED);
 
         float expansion = 0.8f;
         float expectedAlpha =
@@ -1256,7 +1274,7 @@
     public void expansionNotificationAlpha_shadeLocked_bouncerNotActive_usesShadeInterpolator() {
         when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(false);
 
-        mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+        mScrimController.transitionTo(SHADE_LOCKED);
 
         float expansion = 0.8f;
         float expectedAlpha = ShadeInterpolation.getNotificationScrimAlpha(expansion);
@@ -1352,7 +1370,7 @@
 
     @Test
     public void testNotificationTransparency_followsTransitionToFullShade() {
-        mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+        mScrimController.transitionTo(SHADE_LOCKED);
         mScrimController.setRawPanelExpansionFraction(1.0f);
         finishAnimationsImmediately();
         float shadeLockedAlpha = mNotificationsScrim.getViewAlpha();
@@ -1379,7 +1397,7 @@
 
     @Test
     public void notificationTransparency_followsNotificationScrimProgress() {
-        mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+        mScrimController.transitionTo(SHADE_LOCKED);
         mScrimController.setRawPanelExpansionFraction(1.0f);
         finishAnimationsImmediately();
         mScrimController.transitionTo(ScrimState.KEYGUARD);
@@ -1473,7 +1491,7 @@
                 mScrimBehind, TRANSPARENT,
                 mNotificationsScrim, TRANSPARENT));
 
-        mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+        mScrimController.transitionTo(SHADE_LOCKED);
         finishAnimationsImmediately();
         assertScrimAlpha(Map.of(
                 mScrimInFront, TRANSPARENT,
@@ -1504,6 +1522,15 @@
         assertEquals(expectedAlpha, scrim.getViewAlpha(), 0.2);
     }
 
+    private void assertTintAfterExpansion(ScrimView scrim, int expectedTint, float expansion) {
+        String message = "Tint test failed with expected scrim tint: "
+                + Integer.toHexString(expectedTint) + " and actual tint: "
+                + Integer.toHexString(scrim.getTint()) + " for scrim: " + getScrimName(scrim);
+        mScrimController.setRawPanelExpansionFraction(expansion);
+        finishAnimationsImmediately();
+        assertEquals(message, expectedTint, scrim.getTint(), 0.1);
+    }
+
     private void assertScrimTinted(Map<ScrimView, Boolean> scrimToTint) {
         scrimToTint.forEach((scrim, hasTint) -> assertScrimTint(scrim, hasTint));
     }
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 826a98a..078a1d9 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -348,7 +348,9 @@
         window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
         window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_DIM_BEHIND
                 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+        window.setDimAmount(0.6f);
         window.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS);
         window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
         window.setGravity(Gravity.BOTTOM | Gravity.CENTER);
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index f26d9f9..76cac93 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -24,6 +24,7 @@
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+import static android.telephony.SubscriptionManager.isValidSubscriptionId;
 
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
@@ -167,6 +168,10 @@
     static final String VCN_CONFIG_FILE =
             new File(Environment.getDataSystemDirectory(), "vcn/configs.xml").getPath();
 
+    // TODO(b/176956496): Directly use CarrierServiceBindHelper.UNBIND_DELAY_MILLIS
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    static final long CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS = TimeUnit.SECONDS.toMillis(30);
+
     /* Binder context for this service */
     @NonNull private final Context mContext;
     @NonNull private final Dependencies mDeps;
@@ -360,15 +365,12 @@
 
     /** Notifies the VcnManagementService that external dependencies can be set up. */
     public void systemReady() {
-        // Always run on the handler thread to ensure consistency.
-        mHandler.post(() -> {
-            mNetworkProvider.register();
-            mContext.getSystemService(ConnectivityManager.class)
-                    .registerNetworkCallback(
-                            new NetworkRequest.Builder().clearCapabilities().build(),
-                            mTrackingNetworkCallback);
-            mTelephonySubscriptionTracker.register();
-        });
+        mNetworkProvider.register();
+        mContext.getSystemService(ConnectivityManager.class)
+                .registerNetworkCallback(
+                        new NetworkRequest.Builder().clearCapabilities().build(),
+                        mTrackingNetworkCallback);
+        mTelephonySubscriptionTracker.register();
     }
 
     private void enforcePrimaryUser() {
@@ -509,15 +511,22 @@
                         if (!mVcns.containsKey(subGrp)) {
                             startVcnLocked(subGrp, entry.getValue());
                         }
+
+                        // Cancel any scheduled teardowns for active subscriptions
+                        mHandler.removeCallbacksAndMessages(mVcns.get(subGrp));
                     }
                 }
 
-                // Schedule teardown of any VCN instances that have lost carrier privileges
+                // Schedule teardown of any VCN instances that have lost carrier privileges (after a
+                // delay)
                 for (Entry<ParcelUuid, Vcn> entry : mVcns.entrySet()) {
                     final ParcelUuid subGrp = entry.getKey();
                     final VcnConfig config = mConfigs.get(subGrp);
 
                     final boolean isActiveSubGrp = isActiveSubGroup(subGrp, snapshot);
+                    final boolean isValidActiveDataSubIdNotInVcnSubGrp =
+                            isValidSubscriptionId(snapshot.getActiveDataSubscriptionId())
+                                    && !isActiveSubGroup(subGrp, snapshot);
 
                     // TODO(b/193687515): Support multiple VCNs active at the same time
                     if (config == null
@@ -527,12 +536,31 @@
                         final ParcelUuid uuidToTeardown = subGrp;
                         final Vcn instanceToTeardown = entry.getValue();
 
-                        stopVcnLocked(uuidToTeardown);
+                        // TODO(b/193687515): Support multiple VCNs active at the same time
+                        // If directly switching to a subscription not in the current group,
+                        // teardown immediately to prevent other subscription's network from being
+                        // outscored by the VCN. Otherwise, teardown after a delay to ensure that
+                        // SIM profile switches do not trigger the VCN to cycle.
+                        final long teardownDelayMs =
+                                isValidActiveDataSubIdNotInVcnSubGrp
+                                        ? 0
+                                        : CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS;
+                        mHandler.postDelayed(() -> {
+                            synchronized (mLock) {
+                                // Guard against case where this is run after a old instance was
+                                // torn down, and a new instance was started. Verify to ensure
+                                // correct instance is torn down. This could happen as a result of a
+                                // Carrier App manually removing/adding a VcnConfig.
+                                if (mVcns.get(uuidToTeardown) == instanceToTeardown) {
+                                    stopVcnLocked(uuidToTeardown);
 
-                        // TODO(b/181789060): invoke asynchronously after Vcn notifies
-                        // through VcnCallback
-                        notifyAllPermissionedStatusCallbacksLocked(
-                                uuidToTeardown, VCN_STATUS_CODE_INACTIVE);
+                                    // TODO(b/181789060): invoke asynchronously after Vcn notifies
+                                    // through VcnCallback
+                                    notifyAllPermissionedStatusCallbacksLocked(
+                                            uuidToTeardown, VCN_STATUS_CODE_INACTIVE);
+                                }
+                            }
+                        }, instanceToTeardown, teardownDelayMs);
                     } else {
                         // If this VCN's status has not changed, update it with the new snapshot
                         entry.getValue().updateSubscriptionSnapshot(mLastSnapshot);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 48b3d0e..e9eebbf 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -76,6 +76,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
 import android.Manifest;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UptimeMillisLong;
@@ -174,6 +175,8 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -211,6 +214,24 @@
                     | ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE
                     | ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION;
 
+    // Foreground service is stopped for unknown reason.
+    static final int FGS_STOP_REASON_UNKNOWN = 0;
+    // Foreground service is stopped by app calling Service.stopForeground().
+    static final int FGS_STOP_REASON_STOP_FOREGROUND = 1;
+    // Foreground service is stopped because service is brought down either by app calling
+    // stopService() or unbindService(), or service process is killed by the system.
+    static final int FGS_STOP_REASON_STOP_SERVICE = 2;
+    /**
+     * The list of FGS stop reasons.
+     */
+    @IntDef(flag = true, prefix = { "FGS_STOP_REASON_" }, value = {
+            FGS_STOP_REASON_UNKNOWN,
+            FGS_STOP_REASON_STOP_FOREGROUND,
+            FGS_STOP_REASON_STOP_SERVICE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface FgsStopReason {}
+
     final ActivityManagerService mAm;
 
     // Maximum number of services that we allow to start in the background
@@ -721,7 +742,7 @@
                 showFgsBgRestrictedNotificationLocked(r);
                 logFGSStateChangeLocked(r,
                         FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED,
-                        0);
+                        0, FGS_STOP_REASON_UNKNOWN);
                 if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, callingUid)) {
                     throw new ForegroundServiceStartNotAllowedException(msg);
                 }
@@ -1909,7 +1930,7 @@
                         ignoreForeground = true;
                         logFGSStateChangeLocked(r,
                                 FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED,
-                                0);
+                                0, FGS_STOP_REASON_UNKNOWN);
                         if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID,
                                 r.appInfo.uid)) {
                             throw new ForegroundServiceStartNotAllowedException(msg);
@@ -1984,7 +2005,7 @@
                         mAm.updateForegroundServiceUsageStats(r.name, r.userId, true);
                         logFGSStateChangeLocked(r,
                                 FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER,
-                                0);
+                                0, FGS_STOP_REASON_UNKNOWN);
                     }
                     // Even if the service is already a FGS, we need to update the notification,
                     // so we need to call it again.
@@ -2066,7 +2087,8 @@
                 logFGSStateChangeLocked(r,
                         FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT,
                         r.mFgsExitTime > r.mFgsEnterTime
-                                ? (int)(r.mFgsExitTime - r.mFgsEnterTime) : 0);
+                                ? (int) (r.mFgsExitTime - r.mFgsEnterTime) : 0,
+                        FGS_STOP_REASON_STOP_FOREGROUND);
                 r.mFgsNotificationWasDeferred = false;
                 signalForegroundServiceObserversLocked(r);
                 resetFgsRestrictionLocked(r);
@@ -4652,7 +4674,8 @@
             logFGSStateChangeLocked(r,
                     FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT,
                     r.mFgsExitTime > r.mFgsEnterTime
-                            ? (int)(r.mFgsExitTime - r.mFgsEnterTime) : 0);
+                            ? (int) (r.mFgsExitTime - r.mFgsEnterTime) : 0,
+                    FGS_STOP_REASON_STOP_SERVICE);
             mAm.updateForegroundServiceUsageStats(r.name, r.userId, false);
         }
 
@@ -6846,7 +6869,8 @@
      * @param state one of ENTER/EXIT/DENIED event.
      * @param durationMs Only meaningful for EXIT event, the duration from ENTER and EXIT state.
      */
-    private void logFGSStateChangeLocked(ServiceRecord r, int state, int durationMs) {
+    private void logFGSStateChangeLocked(ServiceRecord r, int state, int durationMs,
+            @FgsStopReason int fgsStopReason) {
         if (!ActivityManagerUtils.shouldSamplePackageForAtom(
                 r.packageName, mAm.mConstants.mFgsAtomSampleRate)) {
             return;
@@ -6861,6 +6885,8 @@
             allowWhileInUsePermissionInFgs = r.mAllowWhileInUsePermissionInFgs;
             fgsStartReasonCode = r.mAllowStartForeground;
         }
+        final int callerTargetSdkVersion = r.mRecentCallerApplicationInfo != null
+                ? r.mRecentCallerApplicationInfo.targetSdkVersion : 0;
         FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
                 r.appInfo.uid,
                 r.shortInstanceName,
@@ -6869,8 +6895,7 @@
                 fgsStartReasonCode,
                 r.appInfo.targetSdkVersion,
                 r.mRecentCallingUid,
-                r.mRecentCallerApplicationInfo != null
-                        ? r.mRecentCallerApplicationInfo.targetSdkVersion : 0,
+                callerTargetSdkVersion,
                 r.mInfoTempFgsAllowListReason != null
                         ? r.mInfoTempFgsAllowListReason.mCallingUid : INVALID_UID,
                 r.mFgsNotificationWasDeferred,
@@ -6879,6 +6904,30 @@
                 r.mStartForegroundCount,
                 ActivityManagerUtils.hashComponentNameForAtom(r.shortInstanceName),
                 r.mFgsHasNotificationPermission);
+
+        int event = 0;
+        if (state == FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER) {
+            event = EventLogTags.AM_FOREGROUND_SERVICE_START;
+        } else if (state == FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT) {
+            event = EventLogTags.AM_FOREGROUND_SERVICE_STOP;
+        } else if (state == FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED) {
+            event = EventLogTags.AM_FOREGROUND_SERVICE_DENIED;
+        } else {
+            // Unknown event.
+            return;
+        }
+        EventLog.writeEvent(event,
+                r.userId,
+                r.shortInstanceName,
+                allowWhileInUsePermissionInFgs ? 1 : 0,
+                reasonCodeToString(fgsStartReasonCode),
+                r.appInfo.targetSdkVersion,
+                callerTargetSdkVersion,
+                r.mFgsNotificationWasDeferred ? 1 : 0,
+                r.mFgsNotificationShown ? 1 : 0,
+                durationMs,
+                r.mStartForegroundCount,
+                fgsStopReasonToString(fgsStopReason));
     }
 
     boolean canAllowWhileInUsePermissionInFgsLocked(int callingPid, int callingUid,
@@ -6903,4 +6952,15 @@
         return mAm.getPackageManagerInternal().isSameApp(packageName, uid,
                 UserHandle.getUserId(uid));
     }
+
+    private static String fgsStopReasonToString(@FgsStopReason int stopReason) {
+        switch (stopReason) {
+            case FGS_STOP_REASON_STOP_SERVICE:
+                return "STOP_SERVICE";
+            case FGS_STOP_REASON_STOP_FOREGROUND:
+                return "STOP_FOREGROUND";
+            default:
+                return "UNKNOWN";
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index 1a566a9..6619025 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -839,6 +839,8 @@
 
     @Override
     void dumpAsProto(ProtoOutputStream proto, int uid) {
+        // Force an update.
+        updateBatteryUsageStatsIfNecessary(mInjector.currentTimeMillis(), true);
         synchronized (mLock) {
             final SparseArray<ImmutableBatteryUsage> uidConsumers = mUidBatteryUsageInWindow;
             if (uid != android.os.Process.INVALID_UID) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 7253b494..7fe3c1f 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -2260,7 +2260,8 @@
     private void dumpHelp(PrintWriter pw) {
         pw.println("Battery stats (batterystats) dump options:");
         pw.println("  [--checkin] [--proto] [--history] [--history-start] [--charged] [-c]");
-        pw.println("  [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]");
+        pw.println("  [--daily] [--reset] [--reset-all] [--write] [--new-daily] [--read-daily]");
+        pw.println("  [-h] [<package.name>]");
         pw.println("  --checkin: generate output for a checkin report; will write (and clear) the");
         pw.println("             last old completed stats when they had been reset.");
         pw.println("  -c: write the current stats in checkin format.");
@@ -2271,6 +2272,7 @@
         pw.println("  --charged: only output data since last charged.");
         pw.println("  --daily: only output full daily data.");
         pw.println("  --reset: reset the stats, clearing all current data.");
+        pw.println("  --reset-all: reset the stats, clearing all current and past data.");
         pw.println("  --write: force write current collected stats to disk.");
         pw.println("  --new-daily: immediately create and write new daily stats record.");
         pw.println("  --read-daily: read-load last written daily stats.");
@@ -2407,6 +2409,14 @@
                     flags |= BatteryStats.DUMP_CHARGED_ONLY;
                 } else if ("--daily".equals(arg)) {
                     flags |= BatteryStats.DUMP_DAILY_ONLY;
+                } else if ("--reset-all".equals(arg)) {
+                    awaitCompletion();
+                    synchronized (mStats) {
+                        mStats.resetAllStatsCmdLocked();
+                        mBatteryUsageStatsStore.removeAllSnapshots();
+                        pw.println("Battery stats and history reset.");
+                        noOutput = true;
+                    }
                 } else if ("--reset".equals(arg)) {
                     awaitCompletion();
                     synchronized (mStats) {
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index b250a0c..d080036 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -116,3 +116,11 @@
 30086 ssm_user_stopping (userId|1|5)
 30087 ssm_user_stopped (userId|1|5)
 30088 ssm_user_completed_event (userId|1|5),(eventFlag|1|5)
+
+# Foreground service start/stop events.
+30100 am_foreground_service_start (User|1|5),(Component Name|3),(allowWhileInUse|1),(startReasonCode|3),(targetSdk|1|1),(callerTargetSdk|1|1),(notificationWasDeferred|1),(notificationShown|1),(durationMs|1|3),(startForegroundCount|1|1),(stopReason|3)
+30101 am_foreground_service_denied (User|1|5),(Component Name|3),(allowWhileInUse|1),(startReasonCode|3),(targetSdk|1|1),(callerTargetSdk|1|1),(notificationWasDeferred|1),(notificationShown|1),(durationMs|1|3),(startForegroundCount|1|1),(stopReason|3)
+30102 am_foreground_service_stop (User|1|5),(Component Name|3),(allowWhileInUse|1),(startReasonCode|3),(targetSdk|1|1),(callerTargetSdk|1|1),(notificationWasDeferred|1),(notificationShown|1),(durationMs|1|3),(startForegroundCount|1|1),(stopReason|3)
+
+
+
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index 03eddc9..e4f624d 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -63,6 +63,32 @@
       ]
     }
   ],
+  "presubmit-large": [
+    {
+      "name": "CtsUsageStatsTestCases",
+      "file_patterns": [
+        "ActivityManagerService\\.java",
+        "BroadcastQueue\\.java"
+      ],
+      "options": [
+        {
+          "include-filter": "android.app.usage.cts.BroadcastResponseStatsTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.MediumTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.LargeTest"
+        }
+      ]
+    }
+  ],
   "postsubmit": [
     {
       "name": "FrameworksServicesTests",
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 565783f..a4468a3 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -494,7 +494,7 @@
             }
             pw.println("\n");
             // muted players:
-            pw.print("\n  muted players (piids) awaiting device connection: BL3 ####");
+            pw.print("\n  muted players (piids) awaiting device connection:");
             for (int piid : mMutedPlayersAwaitingConnection) {
                 pw.print(" " + piid);
             }
@@ -1235,9 +1235,7 @@
 
     @GuardedBy("mPlayerLock")
     private void unmutePlayersExpectingDevice() {
-        if (mMutedPlayersAwaitingConnection.isEmpty()) {
-            return;
-        }
+        mMutedUsagesAwaitingConnection = null;
         for (int piid : mMutedPlayersAwaitingConnection) {
             final AudioPlaybackConfiguration apc = mPlayers.get(piid);
             if (apc == null) {
@@ -1254,7 +1252,6 @@
             }
         }
         mMutedPlayersAwaitingConnection.clear();
-        mMutedUsagesAwaitingConnection = null;
     }
 
     //=================================================================
@@ -1278,8 +1275,8 @@
             public void handleMessage(Message msg) {
                 switch (msg.what) {
                     case MSG_L_TIMEOUT_MUTE_AWAIT_CONNECTION:
-                        Log.i(TAG, "Timeout for muting waiting for "
-                                + (AudioDeviceAttributes) msg.obj + ", unmuting");
+                        sEventLogger.loglogi("Timeout for muting waiting for "
+                                + (AudioDeviceAttributes) msg.obj + ", unmuting", TAG);
                         synchronized (mPlayerLock) {
                             unmutePlayersExpectingDevice();
                         }
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index f93e06d..2564ae8 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -26,6 +26,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
+import android.app.ActivityManager.RestrictionLevel;
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
@@ -52,6 +53,7 @@
 import android.database.IContentObserver;
 import android.database.sqlite.SQLiteException;
 import android.net.Uri;
+import android.os.AppBackgroundRestrictionsInfo;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -1544,7 +1546,8 @@
         }
         if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND || isUidActive) {
             FrameworkStatsLog.write(FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED,
-                    callingUid, getProcStateForStatsd(procState), isUidActive);
+                    callingUid, getProcStateForStatsd(procState), isUidActive,
+                    getRestrictionLevelForStatsd(ami.getRestrictionLevel(callingUid)));
             return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET;
         }
         return ContentResolver.SYNC_EXEMPTION_NONE;
@@ -1599,6 +1602,27 @@
         }
     }
 
+    private int getRestrictionLevelForStatsd(@RestrictionLevel int level) {
+        switch (level) {
+            case ActivityManager.RESTRICTION_LEVEL_UNKNOWN:
+                return AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN;
+            case ActivityManager.RESTRICTION_LEVEL_UNRESTRICTED:
+                return AppBackgroundRestrictionsInfo.LEVEL_UNRESTRICTED;
+            case ActivityManager.RESTRICTION_LEVEL_EXEMPTED:
+                return AppBackgroundRestrictionsInfo.LEVEL_EXEMPTED;
+            case ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET:
+                return AppBackgroundRestrictionsInfo.LEVEL_ADAPTIVE_BUCKET;
+            case ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET:
+                return AppBackgroundRestrictionsInfo.LEVEL_RESTRICTED_BUCKET;
+            case ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED:
+                return AppBackgroundRestrictionsInfo.LEVEL_BACKGROUND_RESTRICTED;
+            case ActivityManager.RESTRICTION_LEVEL_HIBERNATION:
+                return AppBackgroundRestrictionsInfo.LEVEL_HIBERNATION;
+            default:
+                return AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN;
+        }
+    }
+
     /** {@hide} */
     @VisibleForTesting
     public static final class ObserverNode {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index b624d43..72612a0 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -146,6 +146,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.OptionalInt;
+import java.util.function.Consumer;
 
 /** The system implementation of {@link IInputManager} that manages input devices. */
 public class InputManagerService extends IInputManager.Stub
@@ -168,6 +169,8 @@
     private static final int MSG_POINTER_DISPLAY_ID_CHANGED = 7;
 
     private static final int DEFAULT_VIBRATION_MAGNITUDE = 192;
+    private static final AdditionalDisplayInputProperties
+            DEFAULT_ADDITIONAL_DISPLAY_INPUT_PROPERTIES = new AdditionalDisplayInputProperties();
 
     /**
      * We know the issue and are working to fix it, so suppressing the toast to not annoy
@@ -281,6 +284,7 @@
     // Guards per-display input properties and properties relating to the mouse pointer.
     // Threads can wait on this lock to be notified the next time the display on which the mouse
     // pointer is shown has changed.
+    // WARNING: Do not call other services outside of input while holding this lock.
     private final Object mAdditionalDisplayInputPropertiesLock = new Object();
 
     // Forces the PointerController to target a specific display id.
@@ -299,6 +303,11 @@
     @GuardedBy("mAdditionalDisplayInputPropertiesLock")
     private final SparseArray<AdditionalDisplayInputProperties> mAdditionalDisplayInputProperties =
             new SparseArray<>();
+    // This contains the per-display properties that are currently applied by native code. It should
+    // be kept in sync with the properties for mRequestedPointerDisplayId.
+    @GuardedBy("mAdditionalDisplayInputPropertiesLock")
+    private final AdditionalDisplayInputProperties mCurrentDisplayProperties =
+            new AdditionalDisplayInputProperties();
     @GuardedBy("mAdditionalDisplayInputPropertiesLock")
     private int mIconType = PointerIcon.TYPE_NOT_SPECIFIED;
     @GuardedBy("mAdditionalDisplayInputPropertiesLock")
@@ -571,27 +580,19 @@
     }
 
     private void setDisplayViewportsInternal(List<DisplayViewport> viewports) {
-        synchronized (mAdditionalDisplayInputPropertiesLock) {
-            final DisplayViewport[] vArray = new DisplayViewport[viewports.size()];
-            for (int i = viewports.size() - 1; i >= 0; --i) {
-                vArray[i] = viewports.get(i);
-            }
-            mNative.setDisplayViewports(vArray);
-            // Always attempt to update the pointer display when viewports change.
-            updatePointerDisplayId();
+        final DisplayViewport[] vArray = new DisplayViewport[viewports.size()];
+        for (int i = viewports.size() - 1; i >= 0; --i) {
+            vArray[i] = viewports.get(i);
+        }
+        mNative.setDisplayViewports(vArray);
 
-            if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
-                final AdditionalDisplayInputProperties properties =
-                        mAdditionalDisplayInputProperties.get(mOverriddenPointerDisplayId);
-                if (properties != null) {
-                    updatePointerIconVisibleLocked(properties.pointerIconVisible);
-                    updatePointerAccelerationLocked(properties.pointerAcceleration);
-                    return;
-                }
+        // Attempt to update the pointer display when viewports change when there is no override.
+        // Take care to not make calls to window manager while holding internal locks.
+        final int pointerDisplayId = mWindowManagerCallbacks.getPointerDisplayId();
+        synchronized (mAdditionalDisplayInputPropertiesLock) {
+            if (mOverriddenPointerDisplayId == Display.INVALID_DISPLAY) {
+                updatePointerDisplayIdLocked(pointerDisplayId);
             }
-            updatePointerIconVisibleLocked(
-                    AdditionalDisplayInputProperties.DEFAULT_POINTER_ICON_VISIBLE);
-            updatePointerAccelerationLocked(IInputConstants.DEFAULT_POINTER_ACCELERATION);
         }
     }
 
@@ -1743,12 +1744,7 @@
             mPointerIconDisplayContext = null;
         }
 
-        synchronized (mAdditionalDisplayInputPropertiesLock) {
-            setPointerIconVisible(AdditionalDisplayInputProperties.DEFAULT_POINTER_ICON_VISIBLE,
-                    displayId);
-            setPointerAcceleration(AdditionalDisplayInputProperties.DEFAULT_POINTER_ACCELERATION,
-                    displayId);
-        }
+        updateAdditionalDisplayInputProperties(displayId, AdditionalDisplayInputProperties::reset);
 
         mNative.displayRemoved(displayId);
     }
@@ -1835,57 +1831,13 @@
     }
 
     private void setPointerAcceleration(float acceleration, int displayId) {
-        synchronized (mAdditionalDisplayInputPropertiesLock) {
-            AdditionalDisplayInputProperties properties =
-                    mAdditionalDisplayInputProperties.get(displayId);
-            if (properties == null) {
-                properties = new AdditionalDisplayInputProperties();
-                mAdditionalDisplayInputProperties.put(displayId, properties);
-            }
-            properties.pointerAcceleration = acceleration;
-            if (properties.allDefaults()) {
-                mAdditionalDisplayInputProperties.remove(displayId);
-            }
-            if (mOverriddenPointerDisplayId == displayId) {
-                updatePointerAccelerationLocked(acceleration);
-            }
-        }
-    }
-
-    @GuardedBy("mAdditionalDisplayInputPropertiesLock")
-    private void updatePointerAccelerationLocked(float acceleration) {
-        mNative.setPointerAcceleration(acceleration);
+        updateAdditionalDisplayInputProperties(displayId,
+                properties -> properties.pointerAcceleration = acceleration);
     }
 
     private void setPointerIconVisible(boolean visible, int displayId) {
-        synchronized (mAdditionalDisplayInputPropertiesLock) {
-            AdditionalDisplayInputProperties properties =
-                    mAdditionalDisplayInputProperties.get(displayId);
-            if (properties == null) {
-                properties = new AdditionalDisplayInputProperties();
-                mAdditionalDisplayInputProperties.put(displayId, properties);
-            }
-            properties.pointerIconVisible = visible;
-            if (properties.allDefaults()) {
-                mAdditionalDisplayInputProperties.remove(displayId);
-            }
-            if (mOverriddenPointerDisplayId == displayId) {
-                updatePointerIconVisibleLocked(visible);
-            }
-        }
-    }
-
-    @GuardedBy("mAdditionalDisplayInputPropertiesLock")
-    private void updatePointerIconVisibleLocked(boolean visible) {
-        if (visible) {
-            if (mIconType == PointerIcon.TYPE_CUSTOM) {
-                mNative.setCustomPointerIcon(mIcon);
-            } else {
-                mNative.setPointerIconType(mIconType);
-            }
-        } else {
-            mNative.setPointerIconType(PointerIcon.TYPE_NULL);
-        }
+        updateAdditionalDisplayInputProperties(displayId,
+                properties -> properties.pointerIconVisible = visible);
     }
 
     private void registerPointerSpeedSettingObserver() {
@@ -2023,22 +1975,18 @@
 
     /**
      * Update the display on which the mouse pointer is shown.
-     * If there is an overridden display for the mouse pointer, use that. Otherwise, query
-     * WindowManager for the pointer display.
      *
      * @return true if the pointer displayId changed, false otherwise.
      */
-    private boolean updatePointerDisplayId() {
-        synchronized (mAdditionalDisplayInputPropertiesLock) {
-            final int pointerDisplayId = mOverriddenPointerDisplayId != Display.INVALID_DISPLAY
-                    ? mOverriddenPointerDisplayId : mWindowManagerCallbacks.getPointerDisplayId();
-            if (mRequestedPointerDisplayId == pointerDisplayId) {
-                return false;
-            }
-            mRequestedPointerDisplayId = pointerDisplayId;
-            mNative.setPointerDisplayId(pointerDisplayId);
-            return true;
+    @GuardedBy("mAdditionalDisplayInputPropertiesLock")
+    private boolean updatePointerDisplayIdLocked(int pointerDisplayId) {
+        if (mRequestedPointerDisplayId == pointerDisplayId) {
+            return false;
         }
+        mRequestedPointerDisplayId = pointerDisplayId;
+        mNative.setPointerDisplayId(pointerDisplayId);
+        applyAdditionalDisplayInputProperties();
+        return true;
     }
 
     private void handlePointerDisplayIdChanged(PointerDisplayIdChangedArgs args) {
@@ -2051,25 +1999,23 @@
                 args.mPointerDisplayId, args.mXPosition, args.mYPosition);
     }
 
-    private boolean setVirtualMousePointerDisplayIdBlocking(int displayId) {
-        // Indicates whether this request is for removing the override.
-        final boolean removingOverride = displayId == Display.INVALID_DISPLAY;
+    private boolean setVirtualMousePointerDisplayIdBlocking(int overrideDisplayId) {
+        final boolean isRemovingOverride = overrideDisplayId == Display.INVALID_DISPLAY;
+
+        // Take care to not make calls to window manager while holding internal locks.
+        final int resolvedDisplayId = isRemovingOverride
+                ? mWindowManagerCallbacks.getPointerDisplayId()
+                : overrideDisplayId;
 
         synchronized (mAdditionalDisplayInputPropertiesLock) {
-            mOverriddenPointerDisplayId = displayId;
-            if (!removingOverride) {
-                final AdditionalDisplayInputProperties properties =
-                        mAdditionalDisplayInputProperties.get(displayId);
-                if (properties != null) {
-                    updatePointerAccelerationLocked(properties.pointerAcceleration);
-                    updatePointerIconVisibleLocked(properties.pointerIconVisible);
-                }
-            }
-            if (!updatePointerDisplayId() && mAcknowledgedPointerDisplayId == displayId) {
+            mOverriddenPointerDisplayId = overrideDisplayId;
+
+            if (!updatePointerDisplayIdLocked(resolvedDisplayId)
+                    && mAcknowledgedPointerDisplayId == resolvedDisplayId) {
                 // The requested pointer display is already set.
                 return true;
             }
-            if (removingOverride && mAcknowledgedPointerDisplayId == Display.INVALID_DISPLAY) {
+            if (isRemovingOverride && mAcknowledgedPointerDisplayId == Display.INVALID_DISPLAY) {
                 // The pointer display override is being removed, but the current pointer display
                 // is already invalid. This can happen when the PointerController is destroyed as a
                 // result of the removal of all input devices that can control the pointer.
@@ -2087,7 +2033,7 @@
             //   reported new displayId is the one we requested. This check ensures that if two
             //   competing overrides are requested in succession, the caller can be notified if one
             //   of them fails.
-            return  removingOverride || mAcknowledgedPointerDisplayId == displayId;
+            return  isRemovingOverride || mAcknowledgedPointerDisplayId == overrideDisplayId;
         }
     }
 
@@ -2393,15 +2339,10 @@
         synchronized (mAdditionalDisplayInputPropertiesLock) {
             mIcon = null;
             mIconType = iconType;
-            if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
-                final AdditionalDisplayInputProperties properties =
-                        mAdditionalDisplayInputProperties.get(mOverriddenPointerDisplayId);
-                if (properties == null || properties.pointerIconVisible) {
-                    mNative.setPointerIconType(mIconType);
-                }
-            } else {
-                mNative.setPointerIconType(mIconType);
-            }
+
+            if (!mCurrentDisplayProperties.pointerIconVisible) return;
+
+            mNative.setPointerIconType(mIconType);
         }
     }
 
@@ -2412,17 +2353,10 @@
         synchronized (mAdditionalDisplayInputPropertiesLock) {
             mIconType = PointerIcon.TYPE_CUSTOM;
             mIcon = icon;
-            if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
-                final AdditionalDisplayInputProperties properties =
-                        mAdditionalDisplayInputProperties.get(mOverriddenPointerDisplayId);
-                if (properties == null || properties.pointerIconVisible) {
-                    // Only set the icon if it is not currently hidden; otherwise, it will be set
-                    // once it's no longer hidden.
-                    mNative.setCustomPointerIcon(mIcon);
-                }
-            } else {
-                mNative.setCustomPointerIcon(mIcon);
-            }
+
+            if (!mCurrentDisplayProperties.pointerIconVisible) return;
+
+            mNative.setCustomPointerIcon(mIcon);
         }
     }
 
@@ -3852,14 +3786,79 @@
                 (float) IInputConstants.DEFAULT_POINTER_ACCELERATION;
 
         // The pointer acceleration for this display.
-        public float pointerAcceleration = DEFAULT_POINTER_ACCELERATION;
+        public float pointerAcceleration;
 
         // Whether the pointer icon should be visible or hidden on this display.
-        public boolean pointerIconVisible = DEFAULT_POINTER_ICON_VISIBLE;
+        public boolean pointerIconVisible;
+
+        AdditionalDisplayInputProperties() {
+            reset();
+        }
 
         public boolean allDefaults() {
             return Float.compare(pointerAcceleration, DEFAULT_POINTER_ACCELERATION) == 0
                     && pointerIconVisible == DEFAULT_POINTER_ICON_VISIBLE;
         }
+
+        public void reset() {
+            pointerAcceleration = DEFAULT_POINTER_ACCELERATION;
+            pointerIconVisible = DEFAULT_POINTER_ICON_VISIBLE;
+        }
+    }
+
+    private void applyAdditionalDisplayInputProperties() {
+        synchronized (mAdditionalDisplayInputPropertiesLock) {
+            AdditionalDisplayInputProperties properties =
+                    mAdditionalDisplayInputProperties.get(mRequestedPointerDisplayId);
+            if (properties == null) properties = DEFAULT_ADDITIONAL_DISPLAY_INPUT_PROPERTIES;
+            applyAdditionalDisplayInputPropertiesLocked(properties);
+        }
+    }
+
+    @GuardedBy("mAdditionalDisplayInputPropertiesLock")
+    private void applyAdditionalDisplayInputPropertiesLocked(
+            AdditionalDisplayInputProperties properties) {
+        // Handle changes to each of the individual properties.
+        if (properties.pointerIconVisible != mCurrentDisplayProperties.pointerIconVisible) {
+            mCurrentDisplayProperties.pointerIconVisible = properties.pointerIconVisible;
+            if (properties.pointerIconVisible) {
+                if (mIconType == PointerIcon.TYPE_CUSTOM) {
+                    Objects.requireNonNull(mIcon);
+                    mNative.setCustomPointerIcon(mIcon);
+                } else {
+                    mNative.setPointerIconType(mIconType);
+                }
+            } else {
+                mNative.setPointerIconType(PointerIcon.TYPE_NULL);
+            }
+        }
+
+        if (properties.pointerAcceleration != mCurrentDisplayProperties.pointerAcceleration) {
+            mCurrentDisplayProperties.pointerAcceleration = properties.pointerAcceleration;
+            mNative.setPointerAcceleration(properties.pointerAcceleration);
+        }
+    }
+
+    private void updateAdditionalDisplayInputProperties(int displayId,
+            Consumer<AdditionalDisplayInputProperties> updater) {
+        synchronized (mAdditionalDisplayInputPropertiesLock) {
+            AdditionalDisplayInputProperties properties =
+                    mAdditionalDisplayInputProperties.get(displayId);
+            if (properties == null) {
+                properties = new AdditionalDisplayInputProperties();
+                mAdditionalDisplayInputProperties.put(displayId, properties);
+            }
+            updater.accept(properties);
+            if (properties.allDefaults()) {
+                mAdditionalDisplayInputProperties.remove(displayId);
+            }
+            if (displayId != mRequestedPointerDisplayId) {
+                Log.i(TAG, "Not applying additional properties for display " + displayId
+                        + " because the pointer is currently targeting display "
+                        + mRequestedPointerDisplayId + ".");
+                return;
+            }
+            applyAdditionalDisplayInputPropertiesLocked(properties);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 31d5136..e5eed99 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.location;
 
 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
 import static android.app.compat.CompatChanges.isChangeEnabled;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -1030,8 +1031,10 @@
 
     @Override
     public void addProviderRequestListener(IProviderRequestListener listener) {
-        for (LocationProviderManager manager : mProviderManagers) {
-            manager.addProviderRequestListener(listener);
+        if (mContext.checkCallingOrSelfPermission(INTERACT_ACROSS_USERS) == PERMISSION_GRANTED) {
+            for (LocationProviderManager manager : mProviderManagers) {
+                manager.addProviderRequestListener(listener);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
index 70b8689..2e1aaf8 100644
--- a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
@@ -16,6 +16,8 @@
 
 package com.android.server.location.gnss;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.LinkAddress;
@@ -47,7 +49,6 @@
 import java.util.List;
 import java.util.Map;
 
-
 /**
  * Handles network connection requests and network state change updates for AGPS data download.
  */
@@ -582,6 +583,7 @@
         if (mNiHandler.getInEmergency() && mActiveSubId >= 0) {
             if (DEBUG) Log.d(TAG, "Adding Network Specifier: " + Integer.toString(mActiveSubId));
             networkRequestBuilder.setNetworkSpecifier(Integer.toString(mActiveSubId));
+            networkRequestBuilder.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
         }
         NetworkRequest networkRequest = networkRequestBuilder.build();
         // Make sure we only have a single request.
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 1937852..098e8f7 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -45,14 +45,15 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.view.ContentRecordingSession;
 import android.window.WindowContainerToken;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
 import com.android.server.Watchdog;
+import com.android.server.wm.WindowManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -381,6 +382,27 @@
             }
         }
 
+        /**
+         * Updates the current content mirroring session.
+         */
+        @Override
+        public void setContentRecordingSession(@Nullable ContentRecordingSession incomingSession,
+                @NonNull IMediaProjection projection) {
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    if (!isValidMediaProjection(projection)) {
+                        throw new SecurityException("Invalid media projection");
+                    }
+                    LocalServices.getService(
+                            WindowManagerInternal.class).setContentRecordingSession(
+                            incomingSession);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+
         @Override // Binder call
         public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
index 3911994..c2f2b0a 100644
--- a/services/core/java/com/android/server/pm/ApkChecksums.java
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -77,6 +77,7 @@
 import java.io.OutputStream;
 import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.nio.file.Files;
 import java.security.DigestException;
 import java.security.InvalidParameterException;
@@ -584,7 +585,7 @@
                         });
                 checksums.put(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256,
                         new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256,
-                                generatedRootHash));
+                                verityHashForFile(file, generatedRootHash)));
             } catch (IOException | NoSuchAlgorithmException | DigestException e) {
                 Slog.e(TAG, "Error calculating WHOLE_MERKLE_ROOT_4K_SHA256", e);
             }
@@ -649,19 +650,20 @@
         // Skip /product folder.
         // TODO(b/231354111): remove this hack once we are allowed to change SELinux rules.
         if (!containsFile(Environment.getProductDirectory(), filePath)) {
-            byte[] hash = VerityUtils.getFsverityRootHash(filePath);
-            if (hash != null) {
-                return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, hash);
+            byte[] verityHash = VerityUtils.getFsverityRootHash(filePath);
+            if (verityHash != null) {
+                return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, verityHash);
             }
         }
         // v4 next
         try {
             ApkSignatureSchemeV4Verifier.VerifiedSigner signer =
                     ApkSignatureSchemeV4Verifier.extractCertificates(filePath);
-            byte[] hash = signer.contentDigests.getOrDefault(CONTENT_DIGEST_VERITY_CHUNKED_SHA256,
-                    null);
-            if (hash != null) {
-                return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, hash);
+            byte[] rootHash = signer.contentDigests.getOrDefault(
+                    CONTENT_DIGEST_VERITY_CHUNKED_SHA256, null);
+            if (rootHash != null) {
+                return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256,
+                        verityHashForFile(new File(filePath), rootHash));
             }
         } catch (SignatureNotFoundException e) {
             // Nothing
@@ -671,6 +673,41 @@
         return null;
     }
 
+    /**
+     * Returns fs-verity digest as described in
+     * https://www.kernel.org/doc/html/latest/filesystems/fsverity.html#fs-verity-descriptor
+     * @param file the Merkle tree is built over
+     * @param rootHash Merkle tree root hash
+     */
+    static byte[] verityHashForFile(File file, byte[] rootHash) {
+        try {
+            ByteBuffer buffer = ByteBuffer.allocate(256); // sizeof(fsverity_descriptor)
+            buffer.order(ByteOrder.LITTLE_ENDIAN);
+            buffer.put((byte) 1);               // __u8 version, must be 1
+            buffer.put((byte) 1);               // __u8 hash_algorithm, FS_VERITY_HASH_ALG_SHA256
+            buffer.put((byte) 12);              // __u8, FS_VERITY_LOG_BLOCKSIZE
+            buffer.put((byte) 0);               // __u8, size of salt in bytes; 0 if none
+            buffer.putInt(0);                   // __le32 __reserved_0x04, must be 0
+            buffer.putLong(file.length());      // __le64 data_size
+            buffer.put(rootHash);               // root_hash, first 32 bytes
+            final int padding = 32 + 32 + 144;  // root_hash, last 32 bytes, we are using sha256.
+            // salt, 32 bytes
+            // reserved, 144 bytes
+            for (int i = 0; i < padding; ++i) {
+                buffer.put((byte) 0);
+            }
+
+            buffer.flip();
+
+            final MessageDigest md = MessageDigest.getInstance(ALGO_SHA256);
+            md.update(buffer);
+            return md.digest();
+        } catch (NoSuchAlgorithmException e) {
+            Slog.e(TAG, "Device does not support MessageDigest algorithm", e);
+            return null;
+        }
+    }
+
     private static Map<Integer, ApkChecksum> extractHashFromV2V3Signature(
             String split, String filePath, int types) {
         Map<Integer, byte[]> contentDigests = null;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 703be16..719c3b7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -1069,7 +1069,7 @@
             if (ArrayUtils.isEmpty(hashInfo.rawRootHash)) {
                 throw new IOException("Root has not present");
             }
-            return hashInfo.rawRootHash;
+            return ApkChecksums.verityHashForFile(new File(filename), hashInfo.rawRootHash);
         } catch (IOException ignore) {
             Slog.e(TAG, "ERROR: could not load root hash from incremental install");
         }
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 6796065..cc1c943 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -603,15 +603,10 @@
         final String setupWizardPackage = ArrayUtils.firstOrNull(getKnownPackages(
                 KnownPackages.PACKAGE_SETUP_WIZARD, userId));
         grantPermissionsToSystemPackage(pm, setupWizardPackage, userId, PHONE_PERMISSIONS,
-                CONTACTS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS, CAMERA_PERMISSIONS);
+                CONTACTS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS, CAMERA_PERMISSIONS,
+                NEARBY_DEVICES_PERMISSIONS);
         grantSystemFixedPermissionsToSystemPackage(pm, setupWizardPackage, userId,
                 NOTIFICATION_PERMISSIONS);
-        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0)
-                || mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE,
-                0)) {
-            grantPermissionsToSystemPackage(
-                    pm, setupWizardPackage, userId, NEARBY_DEVICES_PERMISSIONS);
-        }
 
         // SearchSelector
         grantPermissionsToSystemPackage(pm, getDefaultSearchSelectorPackage(), userId,
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 8552bba..d34682d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -2516,7 +2516,6 @@
         final int[] userIds = filterUserId == UserHandle.USER_ALL ? getAllUserIds()
                 : new int[] { filterUserId };
 
-        boolean installPermissionsChanged = false;
         boolean runtimePermissionsRevoked = false;
         int[] updatedUserIds = EMPTY_INT_ARRAY;
 
@@ -2635,7 +2634,7 @@
 
                 UidPermissionState origState = uidState;
 
-                boolean installPermissionsChangedForUser = false;
+                boolean changedInstallPermission = false;
 
                 if (replace) {
                     userState.setInstallPermissionsFixed(ps.getPackageName(), false);
@@ -2801,7 +2800,7 @@
                                                     && origState.isPermissionGranted(permName))))) {
                         // Grant an install permission.
                         if (uidState.grantPermission(bp)) {
-                            installPermissionsChangedForUser = true;
+                            changedInstallPermission = true;
                         }
                     } else if (bp.isRuntime()) {
                         boolean hardRestricted = bp.isHardRestricted();
@@ -2941,12 +2940,12 @@
                             }
                         }
                         if (uidState.removePermissionState(bp.getName())) {
-                            installPermissionsChangedForUser = true;
+                            changedInstallPermission = true;
                         }
                     }
                 }
 
-                if ((installPermissionsChangedForUser || replace)
+                if ((changedInstallPermission || replace)
                         && !userState.areInstallPermissionsFixed(ps.getPackageName())
                         && !ps.isSystem() || ps.getTransientState().isUpdatedSystemApp()) {
                     // This is the first that we have heard about this package, so the
@@ -2955,12 +2954,6 @@
                     userState.setInstallPermissionsFixed(ps.getPackageName(), true);
                 }
 
-                if (installPermissionsChangedForUser) {
-                    installPermissionsChanged = true;
-                    if (replace) {
-                        updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
-                    }
-                }
                 updatedUserIds = revokePermissionsNoLongerImplicitLocked(uidState,
                         pkg.getPackageName(), uidImplicitPermissions, uidTargetSdkVersion, userId,
                         updatedUserIds);
@@ -2977,12 +2970,8 @@
         // Persist the runtime permissions state for users with changes. If permissions
         // were revoked because no app in the shared user declares them we have to
         // write synchronously to avoid losing runtime permissions state.
-        // Also write synchronously if we changed any install permission for an updated app, because
-        // the install permission state is likely already fixed before update, and if we lose the
-        // changes here the app won't be reconsidered for newly-added install permissions.
         if (callback != null) {
-            callback.onPermissionUpdated(updatedUserIds,
-                    (replace && installPermissionsChanged) || runtimePermissionsRevoked);
+            callback.onPermissionUpdated(updatedUserIds, runtimePermissionsRevoked);
         }
 
         for (int userId : updatedUserIds) {
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index e7c03aa..fcdf175 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -126,6 +126,10 @@
         mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration);
         resolveOverrideConfiguration(newParentConfig);
         mFullConfiguration.setTo(newParentConfig);
+        // Do not inherit always-on-top property from parent, otherwise the always-on-top
+        // property is propagated to all children. In that case, newly added child is
+        // always being positioned at bottom (behind the always-on-top siblings).
+        mFullConfiguration.windowConfiguration.unsetAlwaysOnTop();
         mFullConfiguration.updateFrom(mResolvedOverrideConfiguration);
         onMergedOverrideConfigurationChanged();
         if (!mResolvedTmpConfig.equals(mResolvedOverrideConfiguration)) {
@@ -228,6 +232,10 @@
         final ConfigurationContainer parent = getParent();
         if (parent != null) {
             mMergedOverrideConfiguration.setTo(parent.getMergedOverrideConfiguration());
+            // Do not inherit always-on-top property from parent, otherwise the always-on-top
+            // property is propagated to all children. In that case, newly added child is
+            // always being positioned at bottom (behind the always-on-top siblings).
+            mMergedOverrideConfiguration.windowConfiguration.unsetAlwaysOnTop();
             mMergedOverrideConfiguration.updateFrom(mResolvedOverrideConfiguration);
         } else {
             mMergedOverrideConfiguration.setTo(mResolvedOverrideConfiguration);
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 87523f4..5d2d582 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -207,7 +207,8 @@
         // Update the cached session state first, since updating the service will result in always
         // returning to this instance to update recording state.
         mContentRecordingSession = null;
-        mDisplayContent.mWmService.setContentRecordingSession(null);
+        mDisplayContent.mWmService.mContentRecordingController.setContentRecordingSessionLocked(
+                null, mDisplayContent.mWmService);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index c0d7d13..9eee7ba 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -30,6 +30,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.util.Pair;
+import android.view.ContentRecordingSession;
 import android.view.Display;
 import android.view.IInputFilter;
 import android.view.IRemoteAnimationFinishedCallback;
@@ -869,4 +870,16 @@
      */
     public abstract boolean isPointInsideWindow(
             @NonNull IBinder windowToken, int displayId, float displayX, float displayY);
+
+    /**
+     * Updates the content recording session. If a different session is already in progress, then
+     * the pre-existing session is stopped, and the new incoming session takes over.
+     *
+     * The DisplayContent for the new session will begin recording when
+     * {@link RootWindowContainer#onDisplayChanged} is invoked for the new {@link VirtualDisplay}.
+     * Must be invoked for a valid MediaProjection session.
+     *
+     * @param incomingSession the nullable incoming content recording session
+     */
+    public abstract void setContentRecordingSession(ContentRecordingSession incomingSession);
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7a54804..9022186 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2956,16 +2956,6 @@
         }
     }
 
-    /**
-     * Updates the current content mirroring session.
-     */
-    @Override
-    public void setContentRecordingSession(@Nullable ContentRecordingSession incomingSession) {
-        synchronized (mGlobalLock) {
-            mContentRecordingController.setContentRecordingSessionLocked(incomingSession, this);
-        }
-    }
-
     // TODO(multi-display): remove when no default display use case.
     void prepareAppTransitionNone() {
         if (!checkCallingPermission(MANAGE_APP_TOKENS, "prepareAppTransition()")) {
@@ -8242,6 +8232,14 @@
                 return w.getBounds().contains((int) displayX, (int) displayY);
             }
         }
+
+        @Override
+        public void setContentRecordingSession(@Nullable ContentRecordingSession incomingSession) {
+            synchronized (mGlobalLock) {
+                mContentRecordingController.setContentRecordingSessionLocked(incomingSession,
+                        WindowManagerService.this);
+            }
+        }
     }
 
     void registerAppFreezeListener(AppFreezeListener listener) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index ac115a2..cb14864 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -284,7 +284,7 @@
         @Override
         public void onDeviceStationaryChanged(boolean isStationary) {
             if (isStationary == motionExpected) {
-                fail("Unexpected device stationary status: " + isStationary);
+                fail("Got unexpected device stationary status: " + isStationary);
             }
             this.isStationary = isStationary;
         }
@@ -2096,6 +2096,70 @@
                         eq(SensorManager.SENSOR_DELAY_NORMAL));
     }
 
+    @Test
+    public void testStationaryDetection_NoDoze_AfterMotion() {
+        // Short timeout for testing.
+        mConstants.MOTION_INACTIVE_TIMEOUT = 6000L;
+        doReturn(Sensor.REPORTING_MODE_CONTINUOUS).when(mMotionSensor).getReportingMode();
+        setAlarmSoon(true);
+
+        final ArgumentCaptor<AlarmManager.OnAlarmListener> regAlarmListener = ArgumentCaptor
+                .forClass(AlarmManager.OnAlarmListener.class);
+        final ArgumentCaptor<AlarmManager.OnAlarmListener> motionAlarmListener = ArgumentCaptor
+                .forClass(AlarmManager.OnAlarmListener.class);
+        doNothing().when(mAlarmManager).setWindow(
+                anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion"),
+                motionAlarmListener.capture(), any());
+        doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
+                eq("DeviceIdleController.motion_registration"),
+                regAlarmListener.capture(), any());
+        ArgumentCaptor<SensorEventListener> listenerCaptor =
+                ArgumentCaptor.forClass(SensorEventListener.class);
+
+        StationaryListenerForTest stationaryListener = new StationaryListenerForTest();
+        spyOn(stationaryListener);
+        InOrder inOrder = inOrder(stationaryListener, mSensorManager, mAlarmManager);
+
+        stationaryListener.motionExpected = true;
+        mDeviceIdleController.registerStationaryListener(stationaryListener);
+        inOrder.verify(stationaryListener, timeout(1000L).times(1))
+                .onDeviceStationaryChanged(eq(false));
+        assertFalse(stationaryListener.isStationary);
+        inOrder.verify(mSensorManager)
+                .registerListener(listenerCaptor.capture(), eq(mMotionSensor),
+                        eq(SensorManager.SENSOR_DELAY_NORMAL));
+        inOrder.verify(mAlarmManager).setWindow(
+                anyInt(), eq(mInjector.nowElapsed + mConstants.MOTION_INACTIVE_TIMEOUT), anyLong(),
+                eq("DeviceIdleController.motion"), any(), any());
+        final SensorEventListener listener = listenerCaptor.getValue();
+
+        // Trigger motion
+        listener.onSensorChanged(mock(SensorEvent.class));
+        inOrder.verify(stationaryListener, timeout(1000L).times(1))
+                .onDeviceStationaryChanged(eq(false));
+        final ArgumentCaptor<Long> registrationTimeCaptor = ArgumentCaptor.forClass(Long.class);
+        inOrder.verify(mAlarmManager).setWindow(
+                anyInt(), registrationTimeCaptor.capture(), anyLong(),
+                eq("DeviceIdleController.motion_registration"), any(), any());
+
+        // Make sure the listener is re-registered.
+        mInjector.nowElapsed = registrationTimeCaptor.getValue();
+        regAlarmListener.getValue().onAlarm();
+        inOrder.verify(mSensorManager)
+                .registerListener(eq(listener), eq(mMotionSensor),
+                        eq(SensorManager.SENSOR_DELAY_NORMAL));
+        final ArgumentCaptor<Long> timeoutCaptor = ArgumentCaptor.forClass(Long.class);
+        inOrder.verify(mAlarmManager).setWindow(anyInt(), timeoutCaptor.capture(), anyLong(),
+                eq("DeviceIdleController.motion"), any(), any());
+
+        // No motion before timeout
+        stationaryListener.motionExpected = false;
+        mInjector.nowElapsed = timeoutCaptor.getValue();
+        motionAlarmListener.getValue().onAlarm();
+        inOrder.verify(stationaryListener, timeout(1000L).times(1))
+                .onDeviceStationaryChanged(eq(true));
+    }
+
     private void enterDeepState(int state) {
         switch (state) {
             case STATE_ACTIVE:
diff --git a/services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt b/services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt
index e78f0c7..844f5d4 100644
--- a/services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt
@@ -36,6 +36,7 @@
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
 import org.mockito.Mockito.`when`
+import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.doAnswer
 import org.mockito.Mockito.never
 import org.mockito.Mockito.spy
@@ -226,7 +227,8 @@
 
     @Test
     fun onDisplayRemoved_resetAllAdditionalInputProperties() {
-        localService.setVirtualMousePointerDisplayId(10)
+        setVirtualMousePointerDisplayIdAndVerify(10)
+
         localService.setPointerIconVisible(false, 10)
         verify(native).setPointerIconType(eq(PointerIcon.TYPE_NULL))
         localService.setPointerAcceleration(5f, 10)
@@ -237,9 +239,66 @@
         verify(native).setPointerIconType(eq(PointerIcon.TYPE_NOT_SPECIFIED))
         verify(native).setPointerAcceleration(
             eq(IInputConstants.DEFAULT_POINTER_ACCELERATION.toFloat()))
+        verifyNoMoreInteractions(native)
 
+        // This call should not block because the virtual mouse pointer override was never removed.
         localService.setVirtualMousePointerDisplayId(10)
+
         verify(native).setPointerDisplayId(eq(10))
         verifyNoMoreInteractions(native)
     }
+
+    @Test
+    fun updateAdditionalInputPropertiesForOverrideDisplay() {
+        setVirtualMousePointerDisplayIdAndVerify(10)
+
+        localService.setPointerIconVisible(false, 10)
+        verify(native).setPointerIconType(eq(PointerIcon.TYPE_NULL))
+        localService.setPointerAcceleration(5f, 10)
+        verify(native).setPointerAcceleration(eq(5f))
+
+        localService.setPointerIconVisible(true, 10)
+        verify(native).setPointerIconType(eq(PointerIcon.TYPE_NOT_SPECIFIED))
+        localService.setPointerAcceleration(1f, 10)
+        verify(native).setPointerAcceleration(eq(1f))
+
+        // Verify that setting properties on a different display is not propagated until the
+        // pointer is moved to that display.
+        localService.setPointerIconVisible(false, 20)
+        localService.setPointerAcceleration(6f, 20)
+        verifyNoMoreInteractions(native)
+
+        clearInvocations(native)
+        setVirtualMousePointerDisplayIdAndVerify(20)
+
+        verify(native).setPointerIconType(eq(PointerIcon.TYPE_NULL))
+        verify(native).setPointerAcceleration(eq(6f))
+    }
+
+    @Test
+    fun setAdditionalInputPropertiesBeforeOverride() {
+        localService.setPointerIconVisible(false, 10)
+        localService.setPointerAcceleration(5f, 10)
+
+        verifyNoMoreInteractions(native)
+
+        setVirtualMousePointerDisplayIdAndVerify(10)
+
+        verify(native).setPointerIconType(eq(PointerIcon.TYPE_NULL))
+        verify(native).setPointerAcceleration(eq(5f))
+    }
+
+    private fun setVirtualMousePointerDisplayIdAndVerify(overrideDisplayId: Int) {
+        val thread = Thread { localService.setVirtualMousePointerDisplayId(overrideDisplayId) }
+        thread.start()
+
+        // Allow some time for the set override call to park while waiting for the native callback.
+        Thread.sleep(100 /*millis*/)
+        verify(native).setPointerDisplayId(overrideDisplayId)
+
+        service.onPointerDisplayIdChanged(overrideDisplayId, 0f, 0f)
+        testLooper.dispatchNext()
+        verify(wmCallbacks).notifyPointerDisplayIdChanged(overrideDisplayId, 0f, 0f)
+        thread.join(100 /*millis*/)
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
index 59b12e4..5d824e9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
@@ -21,6 +21,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
@@ -210,6 +211,20 @@
     }
 
     @Test
+    public void testSetAlwaysOnTop() {
+        final TestConfigurationContainer root = new TestConfigurationContainer();
+        final TestConfigurationContainer child1 = root.addChild();
+        final TestConfigurationContainer child2 = root.addChild();
+        root.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        root.setAlwaysOnTop(true);
+        final TestConfigurationContainer child3 = root.addChild();
+        assertEquals(true, root.isAlwaysOnTop());
+        assertEquals(false, child1.isAlwaysOnTop());
+        assertEquals(false, child2.isAlwaysOnTop());
+        assertEquals(false, child3.isAlwaysOnTop());
+    }
+
+    @Test
     public void testSetWindowingMode() {
         final TestConfigurationContainer root = new TestConfigurationContainer();
         root.setWindowingMode(WINDOWING_MODE_UNDEFINED);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index c5f785e..32f3bfe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -2441,7 +2441,7 @@
         ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
                 tokenToMirror);
         session.setDisplayId(displayId);
-        mWm.setContentRecordingSession(session);
+        mWm.mContentRecordingController.setContentRecordingSessionLocked(session, mWm);
         actualDC.updateRecording();
 
         // THEN mirroring is not started, since a null surface indicates the VirtualDisplay is off.
@@ -2470,7 +2470,7 @@
         ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
                 tokenToMirror);
         session.setDisplayId(displayId);
-        mWm.setContentRecordingSession(session);
+        mWm.mContentRecordingController.setContentRecordingSessionLocked(session, mWm);
         mWm.mRoot.onDisplayAdded(displayId);
 
         // WHEN getting the DisplayContent for the new virtual display.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index e5e0145..e8f1d23 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -674,8 +674,6 @@
         taskDisplayArea.positionChildAt(POSITION_TOP, alwaysOnTopRootTask,
                 false /* includingParents */);
         assertTrue(alwaysOnTopRootTask.isAlwaysOnTop());
-        // Ensure always on top state is synced to the children of the root task.
-        assertTrue(alwaysOnTopRootTask.getTopNonFinishingActivity().isAlwaysOnTop());
         assertEquals(alwaysOnTopRootTask, taskDisplayArea.getTopRootTask());
 
         final Task pinnedRootTask = taskDisplayArea.createRootTask(
diff --git a/services/usage/java/com/android/server/usage/TEST_MAPPING b/services/usage/java/com/android/server/usage/TEST_MAPPING
index 523d5f9..1c0c71b 100644
--- a/services/usage/java/com/android/server/usage/TEST_MAPPING
+++ b/services/usage/java/com/android/server/usage/TEST_MAPPING
@@ -20,6 +20,28 @@
       ]
     }
   ],
+  "presubmit-large": [
+    {
+      "name": "CtsUsageStatsTestCases",
+      "options": [
+        {
+          "include-filter": "android.app.usage.cts.BroadcastResponseStatsTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.MediumTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.LargeTest"
+        }
+      ]
+    }
+  ],
   "postsubmit": [
     {
       "name": "CtsUsageStatsTestCases",
diff --git a/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java b/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java
index dc96c66..df9fc66 100644
--- a/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java
@@ -80,9 +80,13 @@
     // of cycles and not being permanently stuck.
     private static final int BULK_TRANSFER_TIMEOUT_MILLISECONDS = 10;
 
+    // Arbitrary number for timeout when closing a thread
+    private static final int THREAD_JOIN_TIMEOUT_MILLISECONDS = 50;
+
     private ArrayList<UsbDeviceConnection> mUsbDeviceConnections;
     private ArrayList<ArrayList<UsbEndpoint>> mInputUsbEndpoints;
     private ArrayList<ArrayList<UsbEndpoint>> mOutputUsbEndpoints;
+    private ArrayList<Thread> mThreads;
 
     private UsbMidiBlockParser mMidiBlockParser = new UsbMidiBlockParser();
     private int mDefaultMidiProtocol = MidiDeviceInfo.PROTOCOL_UMP_MIDI_1_0_UP_TO_64_BITS;
@@ -273,9 +277,10 @@
         // to USB MIDI for each USB output.
         mUsbMidiPacketConverter = new UsbMidiPacketConverter(mNumOutputs);
 
-        mUsbDeviceConnections = new ArrayList<UsbDeviceConnection>(mUsbInterfaces.size());
-        mInputUsbEndpoints = new ArrayList<ArrayList<UsbEndpoint>>(mUsbInterfaces.size());
-        mOutputUsbEndpoints = new ArrayList<ArrayList<UsbEndpoint>>(mUsbInterfaces.size());
+        mUsbDeviceConnections = new ArrayList<UsbDeviceConnection>();
+        mInputUsbEndpoints = new ArrayList<ArrayList<UsbEndpoint>>();
+        mOutputUsbEndpoints = new ArrayList<ArrayList<UsbEndpoint>>();
+        mThreads = new ArrayList<Thread>();
 
         for (int interfaceIndex = 0; interfaceIndex < mUsbInterfaces.size(); interfaceIndex++) {
             ArrayList<UsbEndpoint> inputEndpoints = new ArrayList<UsbEndpoint>();
@@ -327,7 +332,7 @@
                         mInputUsbEndpoints.get(connectionIndex).get(endpointIndex);
                 final int portFinal = portNumber;
 
-                new Thread("UsbDirectMidiDevice input thread " + portFinal) {
+                Thread newThread = new Thread("UsbDirectMidiDevice input thread " + portFinal) {
                     @Override
                     public void run() {
                         final UsbRequest request = new UsbRequest();
@@ -335,9 +340,12 @@
                             request.initialize(connectionFinal, endpointFinal);
                             byte[] inputBuffer = new byte[endpointFinal.getMaxPacketSize()];
                             while (true) {
+                                if (Thread.currentThread().interrupted()) {
+                                    Log.w(TAG, "input thread interrupted");
+                                    break;
+                                }
                                 // Record time of event immediately after waking.
                                 long timestamp = System.nanoTime();
-                                if (!mIsOpen) break;
                                 final ByteBuffer byteBuffer = ByteBuffer.wrap(inputBuffer);
                                 if (!request.queue(byteBuffer)) {
                                     Log.w(TAG, "Cannot queue request");
@@ -382,8 +390,9 @@
                         }
                         Log.d(TAG, "input thread exit");
                     }
-                }.start();
-
+                };
+                newThread.start();
+                mThreads.add(newThread);
                 portNumber++;
             }
         }
@@ -402,18 +411,23 @@
                 final int portFinal = portNumber;
                 final MidiEventScheduler eventSchedulerFinal = mEventSchedulers[portFinal];
 
-                new Thread("UsbDirectMidiDevice output thread " + portFinal) {
+                Thread newThread = new Thread("UsbDirectMidiDevice output thread " + portFinal) {
                     @Override
                     public void run() {
                         while (true) {
+                            if (Thread.currentThread().interrupted()) {
+                                Log.w(TAG, "output thread interrupted");
+                                break;
+                            }
                             MidiEvent event;
                             try {
                                 event = (MidiEvent) eventSchedulerFinal.waitNextEvent();
                             } catch (InterruptedException e) {
-                                // try again
-                                continue;
+                                Log.w(TAG, "event scheduler interrupted");
+                                break;
                             }
                             if (event == null) {
+                                Log.w(TAG, "event is null");
                                 break;
                             }
 
@@ -446,8 +460,9 @@
                         }
                         Log.d(TAG, "output thread exit");
                     }
-                }.start();
-
+                };
+                newThread.start();
+                mThreads.add(newThread);
                 portNumber++;
             }
         }
@@ -523,6 +538,27 @@
 
     private void closeLocked() {
         Log.d(TAG, "closeLocked()");
+
+        // Send an interrupt signal to threads.
+        for (Thread thread : mThreads) {
+            if (thread != null) {
+                thread.interrupt();
+            }
+        }
+
+        // Wait for threads to actually stop.
+        for (Thread thread : mThreads) {
+            if (thread != null) {
+                try {
+                    thread.join(THREAD_JOIN_TIMEOUT_MILLISECONDS);
+                } catch (InterruptedException e) {
+                    Log.w(TAG, "thread join interrupted");
+                    break;
+                }
+            }
+        }
+        mThreads = null;
+
         for (int i = 0; i < mEventSchedulers.length; i++) {
             mMidiInputPortReceivers[i].setReceiver(null);
             mEventSchedulers[i].close();
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 54b3c40..f924b2e 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -23,6 +23,7 @@
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
 
@@ -276,7 +277,6 @@
     @Test
     public void testSystemReady() throws Exception {
         mVcnMgmtSvc.systemReady();
-        mTestLooper.dispatchAll();
 
         verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class));
         verify(mSubscriptionTracker).register();
@@ -494,8 +494,10 @@
         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
 
         triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
-        mTestLooper.dispatchAll();
 
+        // Verify teardown after delay
+        mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+        mTestLooper.dispatchAll();
         verify(vcn).teardownAsynchronously();
         verify(mMockPolicyListener).onPolicyChanged();
     }
@@ -521,6 +523,92 @@
         assertEquals(0, mVcnMgmtSvc.getAllVcns().size());
     }
 
+    /**
+     * Tests an intermediate state where carrier privileges are marked as lost before active data
+     * subId changes during a SIM ejection.
+     *
+     * <p>The expected outcome is that the VCN is torn down after a delay, as opposed to
+     * immediately.
+     */
+    @Test
+    public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges()
+            throws Exception {
+        setupActiveSubscription(TEST_UUID_2);
+
+        final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+        final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
+
+        // Simulate privileges lost
+        triggerSubscriptionTrackerCbAndGetSnapshot(
+                TEST_SUBSCRIPTION_ID,
+                TEST_UUID_2,
+                Collections.emptySet(),
+                Collections.emptyMap(),
+                false /* hasCarrierPrivileges */);
+
+        // Verify teardown after delay
+        mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+        mTestLooper.dispatchAll();
+        verify(vcn).teardownAsynchronously();
+    }
+
+    @Test
+    public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances()
+            throws Exception {
+        setupActiveSubscription(TEST_UUID_2);
+
+        final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+        final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
+
+        // Simulate SIM unloaded
+        triggerSubscriptionTrackerCbAndGetSnapshot(
+                INVALID_SUBSCRIPTION_ID,
+                null /* activeDataSubscriptionGroup */,
+                Collections.emptySet(),
+                Collections.emptyMap(),
+                false /* hasCarrierPrivileges */);
+
+        // Simulate new SIM loaded right during teardown delay.
+        mTestLooper.moveTimeForward(
+                VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
+        mTestLooper.dispatchAll();
+        triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
+
+        // Verify that even after the full timeout duration, the VCN instance is not torn down
+        mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+        mTestLooper.dispatchAll();
+        verify(vcn, never()).teardownAsynchronously();
+    }
+
+    @Test
+    public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception {
+        setupActiveSubscription(TEST_UUID_2);
+
+        final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+        final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2);
+
+        // Simulate SIM unloaded
+        triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
+
+        // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new
+        // vcnInstance.
+        mTestLooper.moveTimeForward(
+                VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
+        mTestLooper.dispatchAll();
+        mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
+        triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
+        final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2);
+
+        // Verify that new instance was different, and the old one was torn down
+        assertTrue(oldInstance != newInstance);
+        verify(oldInstance).teardownAsynchronously();
+
+        // Verify that even after the full timeout duration, the new VCN instance is not torn down
+        mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+        mTestLooper.dispatchAll();
+        verify(newInstance, never()).teardownAsynchronously();
+    }
+
     @Test
     public void testPackageChangeListenerRegistered() throws Exception {
         verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> {
@@ -910,8 +998,6 @@
     private void setupSubscriptionAndStartVcn(
             int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) {
         mVcnMgmtSvc.systemReady();
-        mTestLooper.dispatchAll();
-
         triggerSubscriptionTrackerCbAndGetSnapshot(
                 subGrp,
                 Collections.singleton(subGrp),
@@ -1007,7 +1093,6 @@
 
     private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) {
         mVcnMgmtSvc.systemReady();
-        mTestLooper.dispatchAll();
 
         final ArgumentCaptor<NetworkCallback> captor =
                 ArgumentCaptor.forClass(NetworkCallback.class);
@@ -1252,14 +1337,15 @@
                 true /* isActive */,
                 true /* hasCarrierPrivileges */);
 
-        // VCN is currently active. Lose carrier privileges for TEST_PACKAGE so the VCN goes
-        // inactive.
+        // VCN is currently active. Lose carrier privileges for TEST_PACKAGE and hit teardown
+        // timeout so the VCN goes inactive.
         final TelephonySubscriptionSnapshot snapshot =
                 triggerSubscriptionTrackerCbAndGetSnapshot(
                         TEST_UUID_1,
                         Collections.singleton(TEST_UUID_1),
                         Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1),
                         false /* hasCarrierPrivileges */);
+        mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
         mTestLooper.dispatchAll();
 
         // Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE